Repository: davechurchill/ualbertabot Branch: master Commit: 558899d87934 Files: 639 Total size: 6.2 MB Directory structure: gitextract_8ijeqeyy/ ├── .gitignore ├── BOSS/ │ ├── .gitignore │ ├── Makefile │ ├── Qt/ │ │ ├── BOSSGUI.pro │ │ ├── main.cpp │ │ ├── mainwindow.cpp │ │ ├── mainwindow.h │ │ └── mainwindow.ui │ ├── VisualStudio/ │ │ ├── BOSS.sln │ │ ├── BOSS.vcxproj │ │ ├── BOSS.vcxproj.filters │ │ ├── BOSS_combatsearch.vcxproj │ │ ├── BOSS_main.psess │ │ ├── BOSS_main.vcxproj │ │ └── BOSS_main.vcxproj.filters │ ├── bin/ │ │ ├── buildorders/ │ │ │ ├── Protoss_DarkTemplarRush.txt │ │ │ ├── Protoss_DragoonRange.txt │ │ │ ├── Terran_TankPush.txt │ │ │ ├── Zerg_2HatchHydra.txt │ │ │ └── Zerg_3HatchMuta.txt │ │ └── images/ │ │ ├── command_icons/ │ │ │ └── fix.bat │ │ └── units/ │ │ └── fix.bat │ ├── emscripten/ │ │ ├── BOSS.html │ │ ├── BOSS2.html │ │ ├── config.html │ │ └── config.txt │ ├── lib/ │ │ ├── SDL2.lib │ │ ├── SDL2_image.lib │ │ └── opengl32.lib │ ├── make_windows.bat │ └── source/ │ ├── ActionInProgress.cpp │ ├── ActionInProgress.h │ ├── ActionSet.cpp │ ├── ActionSet.h │ ├── ActionType.cpp │ ├── ActionType.h │ ├── ActionTypeData.cpp │ ├── ActionTypeData.h │ ├── Array.hpp │ ├── BOSS.cpp │ ├── BOSS.h │ ├── BOSSAssert.cpp │ ├── BOSSAssert.h │ ├── BOSSException.cpp │ ├── BOSSException.h │ ├── BOSSExperiments.cpp │ ├── BOSSExperiments.h │ ├── BOSSLogger.cpp │ ├── BOSSLogger.h │ ├── BOSSParameters.cpp │ ├── BOSSParameters.h │ ├── BOSSPlotBuildOrders.cpp │ ├── BOSSPlotBuildOrders.h │ ├── BOSS_main.cpp │ ├── BaseTypes.h │ ├── BuildOrder.cpp │ ├── BuildOrder.h │ ├── BuildOrderPlot.cpp │ ├── BuildOrderPlot.h │ ├── BuildOrderSearchGoal.cpp │ ├── BuildOrderSearchGoal.h │ ├── BuildOrderTester.cpp │ ├── BuildOrderTester.h │ ├── BuildingData.cpp │ ├── BuildingData.h │ ├── CImg/ │ │ └── CImg.h │ ├── CombatSearch.cpp │ ├── CombatSearch.h │ ├── CombatSearchExperiment.cpp │ ├── CombatSearchExperiment.h │ ├── CombatSearchParameters.cpp │ ├── CombatSearchParameters.h │ ├── CombatSearchResults.cpp │ ├── CombatSearchResults.h │ ├── CombatSearch_BestResponse.cpp │ ├── CombatSearch_BestResponse.h │ ├── CombatSearch_BestResponseData.cpp │ ├── CombatSearch_BestResponseData.h │ ├── CombatSearch_Bucket.cpp │ ├── CombatSearch_Bucket.h │ ├── CombatSearch_BucketData.cpp │ ├── CombatSearch_BucketData.h │ ├── CombatSearch_Integral.cpp │ ├── CombatSearch_Integral.h │ ├── CombatSearch_IntegralData.cpp │ ├── CombatSearch_IntegralData.h │ ├── Common.h │ ├── Constants.cpp │ ├── Constants.h │ ├── DFBB_BuildOrderSearchParameters.cpp │ ├── DFBB_BuildOrderSearchParameters.h │ ├── DFBB_BuildOrderSearchResults.cpp │ ├── DFBB_BuildOrderSearchResults.h │ ├── DFBB_BuildOrderSearchSaveState.cpp │ ├── DFBB_BuildOrderSearchSaveState.h │ ├── DFBB_BuildOrderSmartSearch.cpp │ ├── DFBB_BuildOrderSmartSearch.h │ ├── DFBB_BuildOrderStackSearch.cpp │ ├── DFBB_BuildOrderStackSearch.h │ ├── Eval.cpp │ ├── Eval.h │ ├── GameState.cpp │ ├── GameState.h │ ├── GraphViz.hpp │ ├── HatcheryData.cpp │ ├── HatcheryData.h │ ├── JSONTools.cpp │ ├── JSONTools.h │ ├── NaiveBuildOrderSearch.cpp │ ├── NaiveBuildOrderSearch.h │ ├── Position.hpp │ ├── PrerequisiteSet.cpp │ ├── PrerequisiteSet.h │ ├── StarCraftGUI.cpp │ ├── StarCraftGUI.h │ ├── Timer.hpp │ ├── Tools.cpp │ ├── Tools.h │ ├── UnitData.cpp │ ├── UnitData.h │ ├── deprecated/ │ │ ├── BOSSAssert.cpp │ │ ├── BOSSAssert.h │ │ ├── BOSSVisExperiment.cpp │ │ ├── BOSSVisExperiment.h │ │ ├── GUI.cpp │ │ ├── GUI.h │ │ ├── GUITools.cpp │ │ ├── GUITools.h │ │ └── bwapidata/ │ │ ├── README.txt │ │ └── include/ │ │ ├── AIModule.cpp │ │ ├── BWAPI/ │ │ │ ├── AIModule.h │ │ │ ├── Bitmap.h │ │ │ ├── Bullet.h │ │ │ ├── BulletType.h │ │ │ ├── Client/ │ │ │ │ ├── BulletData.h │ │ │ │ ├── BulletImpl.h │ │ │ │ ├── Client.h │ │ │ │ ├── Command.h │ │ │ │ ├── CommandType.h │ │ │ │ ├── Event.h │ │ │ │ ├── ForceData.h │ │ │ │ ├── ForceImpl.h │ │ │ │ ├── GameData.h │ │ │ │ ├── GameImpl.h │ │ │ │ ├── PlayerData.h │ │ │ │ ├── PlayerImpl.h │ │ │ │ ├── Shape.h │ │ │ │ ├── ShapeType.h │ │ │ │ ├── UnitCommand.h │ │ │ │ ├── UnitData.h │ │ │ │ └── UnitImpl.h │ │ │ ├── Client.h │ │ │ ├── Color.h │ │ │ ├── Constants.h │ │ │ ├── CoordinateType.h │ │ │ ├── DamageType.h │ │ │ ├── Error.h │ │ │ ├── Event.h │ │ │ ├── EventType.h │ │ │ ├── ExplosionType.h │ │ │ ├── Flag.h │ │ │ ├── Force.h │ │ │ ├── Game.h │ │ │ ├── GameType.h │ │ │ ├── Input.h │ │ │ ├── Latency.h │ │ │ ├── Order.h │ │ │ ├── Player.h │ │ │ ├── PlayerType.h │ │ │ ├── Position.h │ │ │ ├── Race.h │ │ │ ├── TechType.h │ │ │ ├── TilePosition.h │ │ │ ├── Unit.h │ │ │ ├── UnitCommand.h │ │ │ ├── UnitCommandType.h │ │ │ ├── UnitSizeType.h │ │ │ ├── UnitType.h │ │ │ ├── UpgradeType.h │ │ │ └── WeaponType.h │ │ ├── BWAPI.cpp │ │ ├── BWAPI.h │ │ ├── Bitmap.cpp │ │ ├── BulletType.cpp │ │ ├── Color.cpp │ │ ├── Common.cpp │ │ ├── Common.h │ │ ├── DamageType.cpp │ │ ├── Error.cpp │ │ ├── Event.cpp │ │ ├── ExplosionType.cpp │ │ ├── GameType.cpp │ │ ├── Order.cpp │ │ ├── PlayerType.cpp │ │ ├── Position.cpp │ │ ├── Race.cpp │ │ ├── TechType.cpp │ │ ├── TilePosition.cpp │ │ ├── UnitCommandType.cpp │ │ ├── UnitSizeType.cpp │ │ ├── UnitType.cpp │ │ ├── UpgradeType.cpp │ │ ├── Util/ │ │ │ ├── Bitmask.h │ │ │ ├── Exceptions.cpp │ │ │ ├── Exceptions.h │ │ │ ├── FileLogger.cpp │ │ │ ├── FileLogger.h │ │ │ ├── Foreach.h │ │ │ ├── Gnu.h │ │ │ ├── LogLevel.h │ │ │ ├── Logger.cpp │ │ │ ├── Logger.h │ │ │ ├── RectangleArray.h │ │ │ ├── RegionQuadTree.h │ │ │ ├── Strings.cpp │ │ │ ├── Strings.h │ │ │ ├── Types.h │ │ │ ├── sha1.cpp │ │ │ └── sha1.h │ │ └── WeaponType.cpp │ └── rapidjson/ │ ├── document.h │ ├── filestream.h │ ├── internal/ │ │ ├── pow10.h │ │ ├── stack.h │ │ └── strfunc.h │ ├── prettywriter.h │ ├── rapidjson.h │ ├── reader.h │ ├── stringbuffer.h │ └── writer.h ├── License.md ├── README.md ├── SparCraft/ │ ├── .gitignore │ ├── LINUX_HOW_TO_COMPILE.txt │ ├── Makefile │ ├── README.txt │ ├── VisualStudio/ │ │ ├── SparCraft.sln │ │ ├── SparCraft.vcxproj │ │ ├── SparCraft.vcxproj.filters │ │ ├── SparCraft_main.vcxproj │ │ ├── SparCraft_main.vcxproj.filters │ │ ├── bwapidata.vcxproj │ │ ├── bwapidata.vcxproj.filters │ │ └── set_environment_variables.bat │ ├── asset/ │ │ └── images/ │ │ ├── command_icons/ │ │ │ └── fix.bat │ │ └── units/ │ │ └── fix.bat │ ├── bin/ │ │ └── .gitkeep │ ├── bwapidata/ │ │ ├── README.txt │ │ └── include/ │ │ ├── AIModule.cpp │ │ ├── BWAPI/ │ │ │ ├── AIModule.h │ │ │ ├── Bitmap.h │ │ │ ├── Bullet.h │ │ │ ├── BulletType.h │ │ │ ├── Client/ │ │ │ │ ├── BulletData.h │ │ │ │ ├── BulletImpl.h │ │ │ │ ├── Client.h │ │ │ │ ├── Command.h │ │ │ │ ├── CommandType.h │ │ │ │ ├── Event.h │ │ │ │ ├── ForceData.h │ │ │ │ ├── ForceImpl.h │ │ │ │ ├── GameData.h │ │ │ │ ├── GameImpl.h │ │ │ │ ├── PlayerData.h │ │ │ │ ├── PlayerImpl.h │ │ │ │ ├── Shape.h │ │ │ │ ├── ShapeType.h │ │ │ │ ├── UnitCommand.h │ │ │ │ ├── UnitData.h │ │ │ │ └── UnitImpl.h │ │ │ ├── Client.h │ │ │ ├── Color.h │ │ │ ├── Constants.h │ │ │ ├── CoordinateType.h │ │ │ ├── DamageType.h │ │ │ ├── Error.h │ │ │ ├── Event.h │ │ │ ├── EventType.h │ │ │ ├── ExplosionType.h │ │ │ ├── Flag.h │ │ │ ├── Force.h │ │ │ ├── Game.h │ │ │ ├── GameType.h │ │ │ ├── Input.h │ │ │ ├── Latency.h │ │ │ ├── Order.h │ │ │ ├── Player.h │ │ │ ├── PlayerType.h │ │ │ ├── Position.h │ │ │ ├── Race.h │ │ │ ├── TechType.h │ │ │ ├── TilePosition.h │ │ │ ├── Unit.h │ │ │ ├── UnitCommand.h │ │ │ ├── UnitCommandType.h │ │ │ ├── UnitSizeType.h │ │ │ ├── UnitType.h │ │ │ ├── UpgradeType.h │ │ │ └── WeaponType.h │ │ ├── BWAPI.cpp │ │ ├── BWAPI.h │ │ ├── Bitmap.cpp │ │ ├── BulletType.cpp │ │ ├── Color.cpp │ │ ├── Common.cpp │ │ ├── Common.h │ │ ├── DamageType.cpp │ │ ├── Error.cpp │ │ ├── Event.cpp │ │ ├── ExplosionType.cpp │ │ ├── GameType.cpp │ │ ├── Order.cpp │ │ ├── PlayerType.cpp │ │ ├── Position.cpp │ │ ├── Race.cpp │ │ ├── TechType.cpp │ │ ├── TilePosition.cpp │ │ ├── UnitCommandType.cpp │ │ ├── UnitSizeType.cpp │ │ ├── UnitType.cpp │ │ ├── UpgradeType.cpp │ │ ├── Util/ │ │ │ ├── Bitmask.h │ │ │ ├── Exceptions.cpp │ │ │ ├── Exceptions.h │ │ │ ├── FileLogger.cpp │ │ │ ├── FileLogger.h │ │ │ ├── Foreach.h │ │ │ ├── Gnu.h │ │ │ ├── LogLevel.h │ │ │ ├── Logger.cpp │ │ │ ├── Logger.h │ │ │ ├── RectangleArray.h │ │ │ ├── RegionQuadTree.h │ │ │ ├── Strings.cpp │ │ │ ├── Strings.h │ │ │ ├── Types.h │ │ │ ├── sha1.cpp │ │ │ └── sha1.h │ │ └── WeaponType.cpp │ ├── external_binaries/ │ │ └── lib/ │ │ ├── SDL.lib │ │ ├── SDL_gfx.lib │ │ ├── SDL_image.lib │ │ ├── SDLmain.lib │ │ └── opengl32.lib │ ├── lib/ │ │ ├── SDL2.lib │ │ ├── SDL2_image.lib │ │ └── opengl32.lib │ ├── sample_experiment/ │ │ ├── sample_exp.txt │ │ ├── sample_exp_linux.txt │ │ ├── sample_map_files/ │ │ │ ├── destination.txt │ │ │ └── map_file_format.txt │ │ ├── sample_results/ │ │ │ ├── sample_exp_2013-03-22_17-49-13_config.txt │ │ │ ├── sample_exp_2013-03-22_17-49-13_results_raw.txt │ │ │ └── sample_exp_2013-03-22_17-49-13_results_summary.txt │ │ └── sample_state.txt │ ├── source/ │ │ ├── Action.cpp │ │ ├── Action.h │ │ ├── AllPlayers.cpp │ │ ├── AllPlayers.h │ │ ├── AlphaBetaMove.cpp │ │ ├── AlphaBetaMove.h │ │ ├── AlphaBetaSearch.cpp │ │ ├── AlphaBetaSearch.h │ │ ├── AlphaBetaSearchParameters.hpp │ │ ├── AlphaBetaSearchResults.hpp │ │ ├── AnimationFrameData.cpp │ │ ├── AnimationFrameData.h │ │ ├── Array.hpp │ │ ├── BaseTypes.hpp │ │ ├── Common.cpp │ │ ├── Common.h │ │ ├── ConfigFileGenerator.h │ │ ├── EnumData.cpp │ │ ├── EnumData.h │ │ ├── Game.cpp │ │ ├── Game.h │ │ ├── GameState.cpp │ │ ├── GameState.h │ │ ├── GraphViz.hpp │ │ ├── Hash.cpp │ │ ├── Hash.h │ │ ├── Logger.cpp │ │ ├── Logger.h │ │ ├── Map.hpp │ │ ├── MoveArray.cpp │ │ ├── MoveArray.h │ │ ├── MoveSet.hpp │ │ ├── Player.cpp │ │ ├── Player.h │ │ ├── PlayerProperties.cpp │ │ ├── PlayerProperties.h │ │ ├── Player_AlphaBeta.cpp │ │ ├── Player_AlphaBeta.h │ │ ├── Player_AttackClosest.cpp │ │ ├── Player_AttackClosest.h │ │ ├── Player_AttackDPS.cpp │ │ ├── Player_AttackDPS.h │ │ ├── Player_AttackWeakest.cpp │ │ ├── Player_AttackWeakest.h │ │ ├── Player_Cluster.cpp │ │ ├── Player_Cluster.h │ │ ├── Player_Kiter.cpp │ │ ├── Player_Kiter.h │ │ ├── Player_KiterDPS.cpp │ │ ├── Player_KiterDPS.h │ │ ├── Player_Kiter_NOKDPS.cpp │ │ ├── Player_Kiter_NOKDPS.h │ │ ├── Player_NOKDPS.cpp │ │ ├── Player_NOKDPS.h │ │ ├── Player_PortfolioGreedySearch.cpp │ │ ├── Player_PortfolioGreedySearch.h │ │ ├── Player_Random.cpp │ │ ├── Player_Random.h │ │ ├── Player_UCT.cpp │ │ ├── Player_UCT.h │ │ ├── PortfolioGreedySearch.cpp │ │ ├── PortfolioGreedySearch.h │ │ ├── Position.hpp │ │ ├── Random.hpp │ │ ├── SparCraft.cpp │ │ ├── SparCraft.h │ │ ├── SparCraftAssert.cpp │ │ ├── SparCraftAssert.h │ │ ├── SparCraftException.cpp │ │ ├── SparCraftException.h │ │ ├── Timer.cpp │ │ ├── Timer.h │ │ ├── TranspositionTable.cpp │ │ ├── TranspositionTable.h │ │ ├── TutorialCode.cpp │ │ ├── UCTMemoryPool.hpp │ │ ├── UCTNode.h │ │ ├── UCTSearch.cpp │ │ ├── UCTSearch.h │ │ ├── UCTSearchParameters.hpp │ │ ├── UCTSearchResults.hpp │ │ ├── Unit.cpp │ │ ├── Unit.h │ │ ├── UnitAction.hpp │ │ ├── UnitProperties.cpp │ │ ├── UnitProperties.h │ │ ├── UnitScriptData.cpp │ │ ├── UnitScriptData.h │ │ ├── UnitType.hpp │ │ ├── WeaponProperties.cpp │ │ ├── WeaponProperties.h │ │ ├── glext/ │ │ │ ├── glext.h │ │ │ └── wglext.h │ │ ├── glfont2/ │ │ │ ├── glfont.cc │ │ │ └── glfont.h │ │ ├── gui/ │ │ │ ├── GUI.cpp │ │ │ ├── GUI.h │ │ │ ├── GUIGame.cpp │ │ │ ├── GUIGame.h │ │ │ ├── GUITools.cpp │ │ │ └── GUITools.h │ │ └── main/ │ │ ├── SearchExperiment.cpp │ │ ├── SearchExperiment.h │ │ └── main.cpp │ └── starcraft_images/ │ └── fonts/ │ └── couriernew.glf └── UAlbertaBot/ ├── .gitignore ├── Source/ │ ├── AutoObserver.cpp │ ├── AutoObserver.h │ ├── BOSSManager.cpp │ ├── BOSSManager.h │ ├── BaseLocation.cpp │ ├── BaseLocation.h │ ├── BaseLocationManager.cpp │ ├── BaseLocationManager.h │ ├── BuildOrder.cpp │ ├── BuildOrder.h │ ├── BuildOrderQueue.cpp │ ├── BuildOrderQueue.h │ ├── BuildingData.cpp │ ├── BuildingData.h │ ├── BuildingManager.cpp │ ├── BuildingManager.h │ ├── BuildingPlacerManager.cpp │ ├── BuildingPlacerManager.h │ ├── CombatCommander.cpp │ ├── CombatCommander.h │ ├── CombatSimulation.cpp │ ├── CombatSimulation.h │ ├── Common.cpp │ ├── Common.h │ ├── Config.cpp │ ├── Config.h │ ├── DetectorManager.cpp │ ├── DetectorManager.h │ ├── DistanceMap.cpp │ ├── DistanceMap.h │ ├── GameCommander.cpp │ ├── GameCommander.h │ ├── Global.cpp │ ├── Global.h │ ├── Grid.hpp │ ├── InformationManager.cpp │ ├── InformationManager.h │ ├── JSONTools.cpp │ ├── JSONTools.h │ ├── Logger.cpp │ ├── Logger.h │ ├── MapTools.cpp │ ├── MapTools.h │ ├── MedicManager.cpp │ ├── MedicManager.h │ ├── MeleeManager.cpp │ ├── MeleeManager.h │ ├── MetaType.cpp │ ├── MetaType.h │ ├── Micro.cpp │ ├── Micro.h │ ├── MicroManager.cpp │ ├── MicroManager.h │ ├── ParseUtils.cpp │ ├── ParseUtils.h │ ├── ProductionManager.cpp │ ├── ProductionManager.h │ ├── Profiler.hpp │ ├── RangedManager.cpp │ ├── RangedManager.h │ ├── ScoutManager.cpp │ ├── ScoutManager.h │ ├── Squad.cpp │ ├── Squad.h │ ├── SquadData.cpp │ ├── SquadData.h │ ├── SquadOrder.h │ ├── StarDraftMap.hpp │ ├── StrategyManager.cpp │ ├── StrategyManager.h │ ├── TankManager.cpp │ ├── TankManager.h │ ├── TimerManager.cpp │ ├── TimerManager.h │ ├── TransportManager.cpp │ ├── TransportManager.h │ ├── UABAssert.cpp │ ├── UABAssert.h │ ├── UAlbertaBotModule.cpp │ ├── UAlbertaBotModule.h │ ├── UnitData.cpp │ ├── UnitData.h │ ├── UnitInfoManager.cpp │ ├── UnitInfoManager.h │ ├── UnitUtil.cpp │ ├── UnitUtil.h │ ├── WorkerData.cpp │ ├── WorkerData.h │ ├── WorkerManager.cpp │ ├── WorkerManager.h │ ├── main.cpp │ ├── rapidjson/ │ │ ├── allocators.h │ │ ├── document.h │ │ ├── encodedstream.h │ │ ├── encodings.h │ │ ├── error/ │ │ │ ├── en.h │ │ │ └── error.h │ │ ├── filereadstream.h │ │ ├── filewritestream.h │ │ ├── internal/ │ │ │ ├── biginteger.h │ │ │ ├── diyfp.h │ │ │ ├── dtoa.h │ │ │ ├── ieee754.h │ │ │ ├── itoa.h │ │ │ ├── meta.h │ │ │ ├── pow10.h │ │ │ ├── stack.h │ │ │ ├── strfunc.h │ │ │ └── strtod.h │ │ ├── memorybuffer.h │ │ ├── memorystream.h │ │ ├── msinttypes/ │ │ │ ├── inttypes.h │ │ │ └── stdint.h │ │ ├── pointer.h │ │ ├── prettywriter.h │ │ ├── rapidjson.h │ │ ├── reader.h │ │ ├── stringbuffer.h │ │ └── writer.h │ ├── research/ │ │ ├── CombatData.cpp │ │ ├── CombatData.h │ │ ├── GameHistory.hpp │ │ ├── HardCodedInfo.cpp │ │ ├── HardCodedInfo.h │ │ ├── MapGrid.cpp │ │ ├── MapGrid.h │ │ ├── combatpredictor/ │ │ │ ├── CombatPredictor.cpp │ │ │ └── CombatPredictor.h │ │ ├── hlsearch/ │ │ │ ├── HLCombatCommander.cpp │ │ │ ├── HLCombatCommander.h │ │ │ ├── HLManager.cpp │ │ │ ├── HLManager.h │ │ │ ├── HLSearch.cpp │ │ │ ├── HLSearch.h │ │ │ ├── HLSquad.cpp │ │ │ ├── HLSquad.h │ │ │ ├── HLState.cpp │ │ │ ├── HLState.h │ │ │ ├── HLStatistics.cpp │ │ │ ├── HLStatistics.h │ │ │ ├── HLStrategyManager.cpp │ │ │ ├── HLStrategyManager.h │ │ │ ├── HLTranspositionTable.cpp │ │ │ ├── HLTranspositionTable.h │ │ │ ├── HLUnitData.cpp │ │ │ └── HLUnitData.h │ │ ├── sparcraft/ │ │ │ ├── SparCraftManager.cpp │ │ │ ├── SparCraftManager.h │ │ │ ├── UnitCommandData.cpp │ │ │ ├── UnitCommandData.h │ │ │ ├── UnitCommandManager.cpp │ │ │ └── UnitCommandManager.h │ │ └── visualizer/ │ │ ├── Display.cpp │ │ ├── Display.h │ │ ├── EnhancedInterface.hpp │ │ ├── ReplayVisualizer.cpp │ │ ├── ReplayVisualizer.h │ │ ├── Visualizer.cpp │ │ └── Visualizer.h │ └── stardraft/ │ ├── BaseBorderFinder.hpp │ ├── Grid2D.hpp │ ├── StarDraft.h │ └── StarDraftMap.hpp ├── VisualStudio/ │ ├── StarterBot.vcxproj │ ├── StarterBot.vcxproj.filters │ ├── UAlbertaBot.sln │ ├── UAlbertaBot.vcxproj │ └── UAlbertaBot.vcxproj.filters ├── bin/ │ └── UAlbertaBot_Config.txt ├── starterbot/ │ ├── Grid.hpp │ ├── MapTools.cpp │ ├── MapTools.h │ ├── StarterBot.cpp │ ├── StarterBot.h │ ├── Tools.cpp │ ├── Tools.h │ └── main.cpp └── uml/ └── ualbertabot.dia ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.sdf *.suo *.opensdf *.user *.dll *.exe *.o UAlbertaBot/UAB_ErrorLog.txt UAlbertaBot/UAB_ErrorLog.txt *.pd_ UAlbertaBot/UAB_ErrorLog.txt BOSS/VisualStudio/BOSS.VC.db *.bwta *.db *.ipch *.opendb *.db-shm *.db-wal *.json *.zip *.iobj *.ipdb *.map *.pdb *.ilk ================================================ FILE: BOSS/.gitignore ================================================ VisualStudio/Release VisualStudio/Debug VisualStudio/ipch VisualStudio/*.txt VisualStudio/*.vsp emscripten/*.js emscripten/*.mem emscripten/*.data bin/*.exe bin/*.pdb bin/*.ilk bin/*.txt bin/*.map bin/*.bsc bin/*.lib bin/*.gpl bin/*.zip bin/qtdeploy/* bin/deploy/* bin/gnuplot/* source/*.o qtgui/* build-BOSSGUI-Desktop_Qt_5_6_0_MSVC2013_32bit-Release ================================================ FILE: BOSS/Makefile ================================================ SHELL=C:/Windows/System32/cmd.exe CC=em++ CFLAGS=-O3 -Wno-tautological-constant-out-of-range-compare LDFLAGS=-O3 -s ALLOW_MEMORY_GROWTH=1 --llvm-lto 1 -s DISABLE_EXCEPTION_CATCHING=0 INCLUDES=-Isource/rapidjson -Isource -Isource/bwapidata/include SOURCES=$(wildcard source/*.cpp source/bwapidata/include/*.cpp) OBJECTS=$(SOURCES:.cpp=.o) HTMLFLAGS=-s EXPORTED_FUNCTIONS="['_main', '_ResetExperiment']" --preload-file asset -s LEGACY_GL_EMULATION=1 all:emscripten/BOSS.html emscripten/BOSS.html:$(OBJECTS) Makefile $(CC) $(OBJECTS) -o $@ $(LDFLAGS) $(HTMLFLAGS) .cpp.o: $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ clean: rm $(OBJECTS) ================================================ FILE: BOSS/Qt/BOSSGUI.pro ================================================ #------------------------------------------------- # # Project created by QtCreator 2016-04-20T14:07:30 # #------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = BOSSGUI TEMPLATE = app INCLUDEPATH += C:\\libraries\\BWAPI_412\\include\\ INCLUDEPATH += d:\\ualbertabot\\BOSS\\source\\ SOURCES += main.cpp\ mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui win32:RC_ICONS += Protoss_Probe.ico LIBS += -L$$PWD/../bin/ -lBOSS LIBS += -LC:/libraries/BWAPI_412/lib/ -lBWAPI DESTDIR = $$PWD/../../bin/ ================================================ FILE: BOSS/Qt/main.cpp ================================================ #include "mainwindow.h" #include #include "BOSS.h" int main(int argc, char *argv[]) { srand(time(NULL)); QCoreApplication::addLibraryPath("./"); BOSS::init(); QApplication a(argc, argv); MainWindow w; w.setWindowTitle("StarCraft Build-Order Visualization"); w.show(); return a.exec(); } ================================================ FILE: BOSS/Qt/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include "BOSS.h" #include "BuildOrderPlot.h" #include "BOSSException.h" std::map iconMap; std::map itemMap; std::map imageMap; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { for (size_t r(0); r < BOSS::Races::NUM_RACES; ++r) { const std::vector & actions = BOSS::ActionTypes::GetAllActionTypes((r)); for (size_t a(0); a < actions.size(); ++a) { const std::string & name = actions[a].getName(); QString imageFile = getImageName(actions[a]); iconMap[name] = QIcon(imageFile); itemMap[name] = QListWidgetItem(iconMap[name], QString::fromStdString(name)); imageMap[name] = QImage(imageFile); } } ui->setupUi(this); ui->raceComboBox->addItem(iconMap["Protoss_Probe"], "Protoss"); ui->raceComboBox->addItem(iconMap["Terran_SCV"], "Terran"); ui->raceComboBox->addItem(iconMap["Zerg_Drone"], "Zerg"); ui->armyValueGraph->setToolTip("Visualizes sum of resouces spent on fighting units over time.\n\nWorkers are not counted."); ui->resourceGraphButton->setToolTip("Visualizes resource totals over time.\n\nWill create separate graphs for minerals and gas collected.\n\nAppends _minerals and _gas to file chosen."); ui->visualizeButton->setToolTip("Visualizes build order concurrency and timings."); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_deleteItemsButton_clicked() { qDeleteAll(ui->buildOrderList->selectedItems()); } void MainWindow::on_addToBuildOrderButton_clicked() { const QString & actionName = ui->actionTypeComboBox->currentText(); addToList(ui->buildOrderList, actionName.toStdString()); //ui->buildOrderList->addItem(); ui->buildOrderList->scrollToBottom(); } void MainWindow::on_addToStateButton_clicked() { const QString & actionName = ui->actionTypeComboBox->currentText(); addToList(ui->initialStateList, actionName.toStdString()); //ui->buildOrderList->addItem(); ui->initialStateList->scrollToBottom(); } void MainWindow::setInitialState(const std::string & raceString) { BOSS::RaceID race = BOSS::Races::GetRaceID(raceString); ui->initialStateList->clear(); // set the initial state items to the default starting state addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->initialStateList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->initialStateList, BOSS::ActionTypes::GetResourceDepot(race)); if (race == BOSS::Races::Zerg) { addToList(ui->initialStateList, BOSS::ActionTypes::GetSupplyProvider(race)); } } void MainWindow::setInitialBuildOrder(const std::string & raceString) { BOSS::RaceID race = BOSS::Races::GetRaceID(raceString); ui->buildOrderList->clear(); // add a sample build order to the build order list addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetSupplyProvider(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); addToList(ui->buildOrderList, BOSS::ActionTypes::GetWorker(race)); if (race == BOSS::Races::Protoss) { addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType("Protoss_Gateway")); } else if (race == BOSS::Races::Terran) { addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType("Terran_Barracks")); } else if (race == BOSS::Races::Zerg) { addToList(ui->buildOrderList, BOSS::ActionTypes::GetActionType("Zerg_Spawning_Pool")); } } void MainWindow::on_raceComboBox_currentIndexChanged(const QString &arg1) { std::string raceString = arg1.toStdString();; BOSS::RaceID race = BOSS::Races::GetRaceID(raceString); ui->actionTypeComboBox->clear(); ui->initialStateList->clear(); ui->mineralsSpinBox->setValue(50); ui->gasSpinBox->setValue(0); setInitialState(raceString); setInitialBuildOrder(raceString); const auto & actionTypes = BOSS::ActionTypes::GetAllActionTypes(race); for (const auto & type : actionTypes) { if (type.getName() == "Zerg_Larva") continue; if (type.getName() == "Protoss_Dark_Archon") continue; if (type.getName() == "Protoss_Archon") continue; ui->actionTypeComboBox->addItem(iconMap[type.getName()], QString::fromStdString(type.getName())); } } void MainWindow::addToList(QListWidget * list, const BOSS::ActionType & type) { list->insertItem(list->count(), new QListWidgetItem(itemMap[type.getName()])); } void MainWindow::addToList(QListWidget * list, const std::string & typeName) { list->insertItem(list->count(), new QListWidgetItem(itemMap[typeName])); } void MainWindow::on_clearAllItems_clicked() { ui->buildOrderList->clear(); } void MainWindow::on_deleteItemsButtonState_clicked() { qDeleteAll(ui->initialStateList->selectedItems()); } void MainWindow::on_clearAllItemsState_clicked() { ui->initialStateList->clear(); } void MainWindow::on_actionTypeComboBox_currentIndexChanged(const QString &arg1) { if (arg1.length() == 0) { return; } BOSS::ActionType type = BOSS::ActionTypes::GetActionType(arg1.toStdString()); std::stringstream minerals, gas, buildTime, builder, hpShield; minerals << type.mineralPrice()/1000; gas << type.gasPrice()/1000; buildTime << type.buildTime(); builder << type.whatBuildsActionType().getName(); if (type.isUnit()) { hpShield << type.getUnitType().maxHitPoints() << " / " << type.getUnitType().maxShields(); } else { hpShield << "N/A"; } ui->itemInformationLabel->setText(arg1); ui->mineralCost->setText(QString::fromStdString(minerals.str())); ui->gasCost->setText(QString::fromStdString(gas.str())); ui->buildTime->setText(QString::fromStdString(buildTime.str())); ui->builder->setText(QString::fromStdString(builder.str())); ui->hpShield->setText(QString::fromStdString(hpShield.str())); ui->imageLabel->setPixmap(QPixmap::fromImage(imageMap[type.getName()])); } BOSS::GameState MainWindow::getState() { BOSS::GameState state(BOSS::Races::GetRaceID(ui->raceComboBox->currentText().toStdString())); state.setMinerals(ui->mineralsSpinBox->value()); state.setGas(ui->gasSpinBox->value()); for(int row = 0; row < ui->initialStateList->count(); row++) { state.addCompletedAction(BOSS::ActionTypes::GetActionType(ui->initialStateList->item(row)->text().toStdString())); } return state; } BOSS::BuildOrder MainWindow::getBuildOrder() { BOSS::BuildOrder buildOrder; for(int row = 0; row < ui->buildOrderList->count(); row++) { buildOrder.add(BOSS::ActionTypes::GetActionType(ui->buildOrderList->item(row)->text().toStdString())); } return buildOrder; } QString MainWindow::getImageName(const BOSS::ActionType & type) { std::string filename = "images/"; if (type.isUnit()) { filename += "units/" + type.getName() + ".png"; } else if (type.isUpgrade() || type.isTech()) { filename += "command_icons/" + type.getName() + ".png"; } return QString::fromStdString(filename); } void MainWindow::on_visualizeButton_clicked() { generatePlot(PlotTypes::BuildOrderPlot); } void MainWindow::on_resourceGraphButton_clicked() { generatePlot(PlotTypes::ResourcePlot); } void MainWindow::on_armyValueGraph_clicked() { generatePlot(PlotTypes::ArmyPlot); } void MainWindow::generatePlot(int plotType) { try { BOSS::GameState state = getState(); BOSS::BuildOrder buildOrder = getBuildOrder(); if (buildOrder.size() == 0) { QMessageBox::information(this, tr("BOSS Visualization Error"), tr("Cannot visualize an empty build order. Try adding some units.") ); return; } if (buildOrder.isLegalFromState(state)) { QString file = QFileDialog::getSaveFileName(this, tr("Save Visualization Gnuplot File"), QDir::currentPath(), tr("gnuplot files (*.gpl);;All files (*.*)")); BOSS::BuildOrderPlot plot(state, buildOrder); if (plotType == PlotTypes::BuildOrderPlot) { plot.writeRectanglePlot(file.toStdString()); } else if (plotType == PlotTypes::ArmyPlot) { plot.writeArmyValuePlot(file.toStdString()); } else if (plotType == PlotTypes::ResourcePlot) { plot.writeResourcePlot(file.toStdString()); } } else { std::string why = buildOrder.whyIsNotLegalFromState(state); QMessageBox::information(this, tr("BOSS Visualization Error"), tr(why.c_str()) ); } } catch (BOSS::BOSSException e) { std::stringstream ss; ss << "Build-Order Exception Thrown\n\nPlease contact author with error details\n\n" << e.what(); QMessageBox::information(this, "BOSS Visualization Error", ss.str().c_str()); } } void MainWindow::on_loadBuildOrderButton_clicked() { QString file = QFileDialog::getOpenFileName(this, tr("Load Build-Order File"), QDir::currentPath(), tr("Text Files (*.txt);;All files (*.*)")); if (file.size() == 0) return; std::ifstream fin(file.toStdString()); std::string line; std::string raceString; // read the first line of the file which should be the race std::getline(fin, raceString); BOSS::RaceID race = BOSS::Races::GetRaceID(raceString); if (race == BOSS::Races::None) { QMessageBox::information(this, tr("BOSS Visualization Error"), tr("First line of the build-order file was not a valid race.\n\nIt must be Protoss, Terran, or Zerg.") ); return; } size_t lineNum = 1; std::vector types; // read the remaining lines which each should be one build-order item while (std::getline(fin, line)) { // break when we reach a blank line if (line.size() == 0) { break; } ++lineNum; if (!BOSS::ActionTypes::TypeExists(line)) { std::stringstream ss; ss << "Line " << lineNum << " of the build order file was not a valid Build-Order ActionType."; QMessageBox::information(this, tr("BOSS Visualization Error"), tr(ss.str().c_str()) ); return; } BOSS::ActionType type = BOSS::ActionTypes::GetActionType(line); if (type.getRace() != race) { std::stringstream ss; ss << "Build order file specifies " << raceString << " race.\n\nLine " << lineNum << ": " << type.getName() << " is not a " << raceString << " unit."; ss << "\n\nPlease ensure all units are of the same race and try again."; QMessageBox::information(this, tr("BOSS Visualization Error"), tr(ss.str().c_str()) ); return; } types.push_back(type); } // we must change the selected race to the race loaded if (raceString != ui->raceComboBox->currentText().toStdString()) { for (int i=0; i < ui->raceComboBox->count(); ++i) { std::string itemRace = ui->raceComboBox->itemText(i).toStdString(); if (itemRace == raceString) { ui->raceComboBox->setCurrentIndex(i); break; } } } ui->buildOrderList->clear(); for (const auto & type : types) { addToList(ui->buildOrderList, type.getName()); } fin.close(); ui->buildOrderList->scrollToBottom(); } void MainWindow::on_saveBuildOrderButton_clicked() { QString file = QFileDialog::getSaveFileName(this, tr("Save Build-Order"), QDir::currentPath(), tr("Text Files (*.txt);;All files (*.*)")); if (file.size() == 0) return; std::ofstream fout(file.toStdString()); fout << ui->raceComboBox->currentText().toStdString() << "\n"; for(int row = 0; row < ui->buildOrderList->count(); row++) { fout << ui->buildOrderList->item(row)->text().toStdString() << "\n"; } ui->buildOrderList->scrollToBottom(); fout.close(); } void MainWindow::on_actionAbout_triggered() { QMessageBox msgBox(this); msgBox.setWindowTitle("About"); msgBox.setIconPixmap(QPixmap::fromImage(imageMap["Protoss_Probe"])); msgBox.setTextFormat(Qt::RichText); //this is what makes the links clickable msgBox.setText("StarCraft Build-Order Visualizer

Written by David Churchill

Source and details available on GitHub

To view output graphs, use gnuplot"); msgBox.exec(); } void MainWindow::on_loadStateButton_clicked() { QString file = QFileDialog::getOpenFileName(this, tr("Load State File"), QDir::currentPath(), tr("Text Files (*.txt);;All files (*.*)")); if (file.size() == 0) return; std::ifstream fin(file.toStdString()); std::string line; std::string raceString; // read the first line of the file which should be the race std::getline(fin, raceString); BOSS::RaceID race = BOSS::Races::GetRaceID(raceString); if (race == BOSS::Races::None) { QMessageBox::information(this, tr("BOSS Visualization Error"), tr("First line of the state file was not a valid race.\n\nIt must be Protoss, Terran, or Zerg.") ); return; } size_t lineNum = 1; std::vector types; // read the remaining lines which each should be one build-order item while (std::getline(fin, line)) { // break when we reach a blank line if (line.size() == 0) { break; } ++lineNum; if (!BOSS::ActionTypes::TypeExists(line)) { std::stringstream ss; ss << "Line " << lineNum << " of the state file was not a valid ActionType."; QMessageBox::information(this, tr("BOSS Visualization Error"), tr(ss.str().c_str()) ); return; } BOSS::ActionType type = BOSS::ActionTypes::GetActionType(line); if (type.getRace() != race) { std::stringstream ss; ss << "State file specifies " << raceString << " race.\n\nLine " << lineNum << ": " << type.getName() << " is not a " << raceString << " unit."; ss << "\n\nPlease ensure all units are of the same race and try again."; QMessageBox::information(this, tr("BOSS Visualization Error"), tr(ss.str().c_str()) ); return; } types.push_back(type); } // we must change the selected race to the race loaded if (raceString != ui->raceComboBox->currentText().toStdString()) { for (int i=0; i < ui->raceComboBox->count(); ++i) { std::string itemRace = ui->raceComboBox->itemText(i).toStdString(); if (itemRace == raceString) { ui->raceComboBox->setCurrentIndex(i); break; } } } ui->initialStateList->clear(); for (const auto & type : types) { addToList(ui->initialStateList, type.getName()); } fin.close(); ui->initialStateList->scrollToBottom(); } void MainWindow::on_saveStateButton_clicked() { QString file = QFileDialog::getSaveFileName(this, tr("Save State"), QDir::currentPath(), tr("Text Files (*.txt);;All files (*.*)")); if (file.size() == 0) return; std::ofstream fout(file.toStdString()); fout << ui->raceComboBox->currentText().toStdString() << "\n"; for(int row = 0; row < ui->initialStateList->count(); row++) { fout << ui->initialStateList->item(row)->text().toStdString() << "\n"; } fout.close(); } void MainWindow::on_viewStateButton_clicked() { BOSS::GameState state = getState(); QMessageBox::about(this, "State Details", state.toString().c_str()); } void MainWindow::on_buildOrderDetails_clicked() { std::stringstream ss; BOSS::GameState state = getState(); BOSS::BuildOrder buildOrder = getBuildOrder(); if (buildOrder.isLegalFromState(state)) { ss << "Build-Order can be built from the chosen initial state.\n\n"; buildOrder.doActions(state); int totalFrames = state.getLastActionFinishTime(); ss << "Total time to completion: " << totalFrames << " frames " << " (" << (totalFrames / (60 * 24)) << "m " << ((totalFrames / 24) % 60) << "s)\n\n"; int totalMinerals = 0; int totalGas = 0; for (size_t a(0); a < buildOrder.size(); ++a) { totalMinerals += buildOrder[a].mineralPrice(); totalGas+= buildOrder[a].gasPrice(); } ss << "Total Minerals Gathered: " << (state.getMinerals() + totalMinerals)/BOSS::Constants::RESOURCE_SCALE << "\n"; ss << "Total Gas Gathered: " << (state.getGas() + totalGas)/BOSS::Constants::RESOURCE_SCALE << "\n\n"; } else { ss << buildOrder.whyIsNotLegalFromState(state); } QMessageBox::about(this, "Build-Order Details", ss.str().c_str() ); } void MainWindow::on_viewFinalStateButton_clicked() { std::stringstream ss; BOSS::GameState state = getState(); BOSS::BuildOrder buildOrder = getBuildOrder(); if (buildOrder.isLegalFromState(state)) { ss << "Final state after build-order has completed:\n"; buildOrder.doActions(state); state.fastForward(state.getLastActionFinishTime()); ss << state.toString() << "\n"; int totalMinerals = 0; int totalGas = 0; for (size_t a(0); a < buildOrder.size(); ++a) { totalMinerals += buildOrder[a].mineralPrice(); totalGas+= buildOrder[a].gasPrice(); } ss << "Total Minerals Gathered: " << (state.getMinerals() + totalMinerals)/BOSS::Constants::RESOURCE_SCALE << "\n"; ss << "Total Gas Gathered: " << (state.getGas() + totalGas)/BOSS::Constants::RESOURCE_SCALE << "\n\n"; } else { ss << buildOrder.whyIsNotLegalFromState(state); } QMessageBox::about(this, "Final State Details", ss.str().c_str() ); } ================================================ FILE: BOSS/Qt/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "BOSS.h" namespace PlotTypes { enum { BuildOrderPlot, ArmyPlot, ResourcePlot }; } namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_deleteItemsButton_clicked(); void on_addToBuildOrderButton_clicked(); void on_visualizeButton_clicked(); void on_raceComboBox_currentIndexChanged(const QString &arg1); void on_addToStateButton_clicked(); void on_clearAllItems_clicked(); void on_deleteItemsButtonState_clicked(); void on_clearAllItemsState_clicked(); void on_actionTypeComboBox_currentIndexChanged(const QString &arg1); void on_saveBuildOrderButton_clicked(); void on_resourceGraphButton_clicked(); void on_armyValueGraph_clicked(); void on_actionAbout_triggered(); void on_loadStateButton_clicked(); void on_saveStateButton_clicked(); QString getImageName(const BOSS::ActionType & type); BOSS::GameState getState(); BOSS::BuildOrder getBuildOrder(); void generatePlot(int plotType); void on_loadBuildOrderButton_clicked(); void setInitialState(const std::string & raceString); void setInitialBuildOrder(const std::string & raceString); void addToList(QListWidget * list, const BOSS::ActionType & type); void addToList(QListWidget * list, const std::string & typeName); void on_viewStateButton_clicked(); void on_buildOrderDetails_clicked(); void on_viewFinalStateButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H ================================================ FILE: BOSS/Qt/mainwindow.ui ================================================ MainWindow 0 0 640 480 0 0 640 480 640 480 MainWindow 20 70 101 23 Add to Build Order 20 40 211 22 120 10 111 22 20 150 211 231 QAbstractItemView::MultiSelection 20 390 101 23 Clear Selected 20 10 91 21 Arial 12 Select Race 130 390 101 23 Clear All 20 120 91 21 Arial 12 Build-Order 250 150 211 231 QAbstractItemView::MultiSelection 130 70 101 23 Add to Initial State 250 120 101 21 Arial 12 Initial State 250 390 101 23 Clear Selected 360 390 101 23 Clear All 490 170 121 22 Qt::AlignCenter 99999 510 150 91 16 Starting Minerals 520 200 91 16 Starting Gas 490 220 121 22 Qt::AlignCenter 99999 250 10 241 21 Arial 12 Item: 250 60 71 16 Minerals: 250 80 51 16 Gas: 340 60 61 16 Build Time: 310 60 31 16 0 310 80 31 16 0 410 60 51 16 0 250 40 51 16 Producer: 310 40 131 16 0 340 80 61 16 HP / Shield: 410 80 51 16 0 470 10 161 121 Image Here Qt::AlignCenter 490 420 121 23 Build-Order Graph 130 420 101 23 Save Build-Order 20 420 101 23 Load Build-Order 360 420 101 23 Save State 250 420 101 23 Load State 490 330 131 21 Arial 12 Generate Graphs 490 390 121 23 Resource Graphs 490 360 121 23 Army Value Graph 380 120 81 23 View Details 150 120 81 23 View Details 490 280 121 23 View Final State 0 0 640 21 Help About ================================================ FILE: BOSS/VisualStudio/BOSS.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BOSS", "BOSS.vcxproj", "{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BOSS_main", "BOSS_main.vcxproj", "{25544976-2D9A-4669-8EF6-B622C3B5A42E}" ProjectSection(ProjectDependencies) = postProject {9F8709E3-AC4F-45F2-8105-4A99D8E2A127} = {9F8709E3-AC4F-45F2-8105-4A99D8E2A127} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.ActiveCfg = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.Build.0 = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|x64.ActiveCfg = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.ActiveCfg = Release|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.Build.0 = Release|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|x64.ActiveCfg = Release|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|Win32.ActiveCfg = Debug|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|Win32.Build.0 = Debug|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Debug|x64.ActiveCfg = Debug|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|Win32.ActiveCfg = Release|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|Win32.Build.0 = Release|Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: BOSS/VisualStudio/BOSS.vcxproj ================================================  Debug Win32 Release Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127} Win32Proj StarcraftBuildOrderSearch StaticLibrary true Unicode v142 StaticLibrary false true Unicode v142 true ../bin/ $(ProjectName)_d .lib $(SolutionDir)\$(Configuration)\$(ProjectName)\ false ../bin/ $(SolutionDir)\$(Configuration)\$(ProjectName)\ Level3 Disabled WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include/;%(AdditionalIncludeDirectories) true false Console true ../../bwapidata/lib/bwapidatad_$(PlatformToolset).lib;%(AdditionalDependencies) Level3 Full true true WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include;%(AdditionalIncludeDirectories) 4996 ProgramDatabase true MultiThreadedDLL true Console true true true ../../bwapidata/lib/bwapidata_$(PlatformToolset).lib;%(AdditionalDependencies) true true ================================================ FILE: BOSS/VisualStudio/BOSS.vcxproj.filters ================================================  common engine engine engine search\CombatSearch engine search\util engine engine search\CombatSearch search\CombatSearch util util search\util search\BuildOrderSearch search\BuildOrderSearch search\BuildOrderSearch search\BuildOrderSearch common engine util util search\NaiveSearch search\util util search\CombatSearch search\CombatSearch search\CombatSearch search\CombatSearch search\CombatSearch util search\CombatSearch common common util common common engine engine engine search\CombatSearch util engine search\util common engine engine util search\CombatSearch search\CombatSearch common util util search\util search\BuildOrderSearch search\BuildOrderSearch search\BuildOrderSearch search\BuildOrderSearch engine util util search\NaiveSearch search\util util search\CombatSearch search\CombatSearch search\CombatSearch search\CombatSearch search\CombatSearch util search\CombatSearch common common {c90b8009-1e1e-42e5-a28e-017e8e72cfe1} {f458ce38-5149-4277-8582-e76bc9eaab52} {0f8d0d91-8735-4269-b306-24e4a55588ad} {e1d1becf-4265-4c2c-aa97-d66a9a961a6d} {c231a723-7f0a-4414-bbef-4928739d854e} {be1fbb05-de74-477b-9915-4a5ef14b38db} {533866dc-7d6d-4bc0-a795-ae6e41d9eac0} {975df5db-5385-4879-9a2a-e0f7d4354574} ================================================ FILE: BOSS/VisualStudio/BOSS_combatsearch.vcxproj ================================================  Debug Win32 Release Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E} Win32Proj StarcraftBuildOrderSearch Application true Unicode v120 Application false true Unicode v120 true $(SolutionDir)..\bin\ $(ProjectName)_d $(Configuration)\BOSS_main\ false $(SolutionDir)..\bin\ $(Configuration)\BOSS_main\ Level3 Disabled WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include;$(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories) Console true $(BWAPI_DIR)/lib/BWAPId.lib;$(SolutionDir)\$(Configuration)\BOSS\BOSS_d.lib;../lib/opengl32.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include;$(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories) 4996 ProgramDatabase true Console true true true $(BWAPI_DIR)/lib/BWAPI.lib;$(SolutionDir)\$(Configuration)\BOSS\BOSS.lib;../lib/opengl32.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;%(AdditionalDependencies) true ================================================ FILE: BOSS/VisualStudio/BOSS_main.psess ================================================  BOSS.sln Sampling None true true Timestamp Cycles 10000000 10 10 false false 500 \Memory\Pages/sec \PhysicalDisk(_Total)\Avg. Disk Queue Length \Processor(_Total)\% Processor Time true false false false false ..\bin\BOSS_main.exe 01/01/0001 00:00:00 true true false false false false false true false Executable ..\bin\BOSS_main.exe ..\bin IIS InternetExplorer true false false false {25544976-2D9A-4669-8EF6-B622C3B5A42E}|BOSS_main.vcxproj BOSS_main.vcxproj BOSS_main BOSS_main150112.vsp :PB:{25544976-2D9A-4669-8EF6-B622C3B5A42E}|BOSS_main.vcxproj ================================================ FILE: BOSS/VisualStudio/BOSS_main.vcxproj ================================================  Debug Win32 Release Win32 {25544976-2D9A-4669-8EF6-B622C3B5A42E} Win32Proj StarcraftBuildOrderSearch Application true Unicode v120 Application false true Unicode v120 true $(SolutionDir)..\bin\ $(ProjectName)_d $(Configuration)\BOSS_main\ false $(SolutionDir)..\bin\ $(Configuration)\BOSS_main\ Level3 Disabled WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories) Console true $(BWAPI_DIR)/lib/BWAPId.lib;../bin/BOSS_d.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) $(BWAPI_DIR)/include;../source/rapidjson;%(AdditionalIncludeDirectories) 4996;4099 ProgramDatabase true MultiThreadedDLL true Console true true true $(BWAPI_DIR)/lib/BWAPI.lib;../bin/BOSS.lib;%(AdditionalDependencies) true true ================================================ FILE: BOSS/VisualStudio/BOSS_main.vcxproj.filters ================================================  testing experiments experiments experiments experiments {1d1bf021-f0f5-44d7-abf5-ded9f0d6ed4d} {b8dbb056-eafb-4ae0-8475-538af1b4bae4} testing experiments experiments experiments experiments ================================================ FILE: BOSS/bin/buildorders/Protoss_DarkTemplarRush.txt ================================================ Protoss Protoss_Probe Protoss_Probe Protoss_Probe Protoss_Probe Protoss_Pylon Protoss_Probe Protoss_Gateway Protoss_Probe Protoss_Assimilator Protoss_Probe Protoss_Cybernetics_Core Protoss_Probe Protoss_Citadel_of_Adun Protoss_Probe Protoss_Templar_Archives Protoss_Gateway Protoss_Dark_Templar Protoss_Dark_Templar Protoss_Pylon Protoss_Dark_Templar Protoss_Dark_Templar Protoss_Probe Protoss_Pylon Protoss_Probe ================================================ FILE: BOSS/bin/buildorders/Protoss_DragoonRange.txt ================================================ Protoss Protoss_Probe Protoss_Probe Protoss_Probe Protoss_Probe Protoss_Pylon Protoss_Probe Protoss_Probe Protoss_Gateway Protoss_Probe Protoss_Assimilator Protoss_Probe Protoss_Probe Protoss_Cybernetics_Core Protoss_Probe Protoss_Probe Protoss_Gateway Singularity_Charge Protoss_Dragoon Protoss_Gateway Protoss_Pylon Protoss_Dragoon Protoss_Dragoon Protoss_Probe Protoss_Gateway Protoss_Pylon Protoss_Probe Protoss_Dragoon Protoss_Dragoon Protoss_Dragoon ================================================ FILE: BOSS/bin/buildorders/Terran_TankPush.txt ================================================ Terran Terran_SCV Terran_SCV Terran_SCV Terran_SCV Terran_SCV Terran_Supply_Depot Terran_SCV Terran_Barracks Terran_Refinery Terran_SCV Terran_SCV Terran_SCV Terran_SCV Terran_Factory Terran_Factory Terran_SCV Terran_SCV Terran_SCV Terran_SCV Terran_Machine_Shop Terran_Machine_Shop Terran_Supply_Depot Tank_Siege_Mode Terran_Siege_Tank_Tank_Mode Terran_Siege_Tank_Tank_Mode Terran_Siege_Tank_Tank_Mode Terran_Siege_Tank_Tank_Mode ================================================ FILE: BOSS/bin/buildorders/Zerg_2HatchHydra.txt ================================================ Zerg Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Overlord Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Hatchery Zerg_Spawning_Pool Zerg_Drone Zerg_Extractor Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Hydralisk_Den Zerg_Drone Zerg_Overlord Zerg_Drone Zerg_Drone Zerg_Drone Grooved_Spines Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk Zerg_Overlord Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk Zerg_Overlord Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk Zerg_Hydralisk ================================================ FILE: BOSS/bin/buildorders/Zerg_3HatchMuta.txt ================================================ Zerg Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Overlord Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Hatchery Zerg_Spawning_Pool Zerg_Drone Zerg_Drone Zerg_Hatchery Zerg_Extractor Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Overlord Zerg_Lair Zerg_Extractor Zerg_Drone Zerg_Drone Zerg_Zergling Zerg_Zergling Zerg_Zergling Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Overlord Zerg_Drone Zerg_Overlord Zerg_Drone Zerg_Overlord Zerg_Spire Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Drone Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk Zerg_Mutalisk ================================================ FILE: BOSS/bin/images/command_icons/fix.bat ================================================ for %%f in (*.png) DO ( convert "%%f" -strip -resize 32x32! "%%f" ) ================================================ FILE: BOSS/bin/images/units/fix.bat ================================================ for %%f in (*.png) DO ( convert "%%f" -strip "%%f" ) ================================================ FILE: BOSS/emscripten/BOSS.html ================================================ Emscripten-Generated Code image/svg+xml
Downloading...
Resize canvas Lock/hide mouse pointer    
================================================ FILE: BOSS/emscripten/BOSS2.html ================================================ BOSS Test
Resize canvas Lock/hide mouse pointer    

Downloading...

================================================ FILE: BOSS/emscripten/config.html ================================================ ================================================ FILE: BOSS/emscripten/config.txt ================================================ { "Experiments" : { "Visualize Build Orders" : { "run" : true, "type" : "BuildOrderVisualization", "fps" : 1000, "outputFile" : "UAB_Openers.txt", "scenarios" : [ { "state":"Protoss Start State", "buildOrder" : "UAB DT Rush" }, { "state":"Zerg Start State", "buildOrder" : "3 Hatch Muta" } ] } }, "States" : { "Protoss Start State" : { "race" : "Protoss", "minerals" : 50, "gas" : 0, "units" : [ ["Protoss_Probe", 4], ["Protoss_Nexus", 1] ] }, "Zerg Start State" : { "race" : "Zerg", "minerals" : 50, "gas" : 0, "units" : [ ["Zerg_Drone", 4], ["Zerg_Hatchery", 1], ["Zerg_Overlord", 1] ] }, "Terran Start State" : { "race" : "Terran", "minerals" : 50, "gas" : 0, "units" : [ ["Terran_SCV", 4], ["Terran_Command_Center", 1] ] } }, "Build Orders" : { "3 Hatch Muta" : [ "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Overlord", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Hatchery", "Zerg_Spawning_Pool", "Zerg_Drone", "Zerg_Drone", "Zerg_Hatchery", "Zerg_Extractor", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Overlord", "Zerg_Lair", "Zerg_Extractor", "Zerg_Drone", "Zerg_Drone", "Zerg_Zergling", "Zerg_Zergling", "Zerg_Zergling", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Overlord", "Zerg_Drone", "Zerg_Overlord", "Zerg_Drone", "Zerg_Overlord", "Zerg_Spire", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Drone", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk", "Zerg_Mutalisk" ], "UAB Zealot Rush" : [ "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Pylon", "Protoss_Probe", "Protoss_Gateway", "Protoss_Gateway", "Protoss_Probe", "Protoss_Probe", "Protoss_Zealot", "Protoss_Pylon", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Probe", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Probe", "Protoss_Pylon", "Protoss_Zealot", "Protoss_Gateway", "Protoss_Probe", "Protoss_Pylon", "Protoss_Probe", "Protoss_Zealot", "Protoss_Probe", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Pylon", "Protoss_Probe", "Protoss_Zealot", "Protoss_Zealot", "Protoss_Zealot" ], "UAB DT Rush" : [ "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Pylon", "Protoss_Probe", "Protoss_Gateway", "Protoss_Probe", "Protoss_Assimilator", "Protoss_Probe", "Protoss_Cybernetics_Core", "Protoss_Probe", "Protoss_Citadel_of_Adun", "Protoss_Probe", "Protoss_Templar_Archives", "Protoss_Gateway", "Protoss_Dark_Templar", "Protoss_Dark_Templar", "Protoss_Pylon", "Protoss_Dark_Templar", "Protoss_Dark_Templar", "Protoss_Probe", "Protoss_Pylon", "Protoss_Probe"], "UAB Dragoon Rush" : [ "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Probe", "Protoss_Pylon", "Protoss_Probe", "Protoss_Probe", "Protoss_Gateway", "Protoss_Probe", "Protoss_Assimilator", "Protoss_Probe", "Protoss_Probe", "Protoss_Cybernetics_Core", "Protoss_Probe", "Protoss_Probe", "Protoss_Gateway", "Singularity_Charge", "Protoss_Dragoon", "Protoss_Gateway", "Protoss_Pylon", "Protoss_Dragoon", "Protoss_Dragoon", "Protoss_Probe", "Protoss_Gateway", "Protoss_Pylon", "Protoss_Probe", "Protoss_Dragoon", "Protoss_Dragoon", "Protoss_Dragoon"] } } ================================================ FILE: BOSS/make_windows.bat ================================================ @echo off set original_dir=%CD% echo. echo ********************************************* echo * COMPILING BOSS WITH EMSCRIPTEN * echo ********************************************* echo. make -j 8 ================================================ FILE: BOSS/source/ActionInProgress.cpp ================================================ #include "ActionInProgress.h" using namespace BOSS; ActionsInProgress::ActionsInProgress() : _numProgress(Constants::MAX_ACTIONS, 0) { } UnitCountType ActionsInProgress::numInProgress(const ActionType & a) const { return _numProgress[a.ID()]; } void ActionsInProgress::addAction(const ActionType & action, FrameCountType time) { // deprecated, code below should be faster //inProgress.push_back(ActionInProgress(a, (unsigned short)time)); //inProgress.sort(); // inProgress should always be sorted, so add the action in its place _inProgress.addSorted(ActionInProgress(action, time)); // increase the specific count of a _numProgress[action.ID()]++; } void ActionsInProgress::popNextAction() { BOSS_ASSERT(_inProgress.size() > 0, "Can't pop from empty set"); // there is one less of the last unit in progress _numProgress[_inProgress[_inProgress.size()-1]._action.ID()]--; // the number of things in progress goes down _inProgress.pop_back(); } bool ActionsInProgress::isEmpty() const { return _inProgress.size() == 0; } FrameCountType ActionsInProgress::nextActionFinishTime() const { BOSS_ASSERT(_inProgress.size() > 0, "Set is empty"); return _inProgress[_inProgress.size()-1]._time; } const UnitCountType ActionsInProgress::size() const { return _inProgress.size(); } FrameCountType ActionsInProgress::getLastFinishTime() const { if (_inProgress.size() == 0) { return 0; } return _inProgress[0]._time; } FrameCountType ActionsInProgress::nextActionFinishTime(const ActionType & a) const { BOSS_ASSERT(numInProgress(a) > 0, "Tried to get next finish time from empty set"); for (size_t i=_inProgress.size()-1; i >=0; --i) { if (_inProgress[i]._action == a) { return _inProgress[i]._time; } } BOSS_ASSERT(false, "Next Action Finish Time didn't find anything"); return -1; } FrameCountType ActionsInProgress::nextBuildingFinishTime() const { BOSS_ASSERT(_inProgress.size() > 0, "There are no buildings in progress"); for (size_t i(0); i<_inProgress.size(); ++i) { size_t ri = _inProgress.size()-1-i; if (_inProgress[ri]._action.isBuilding() && !_inProgress[ri]._action.isAddon() && !_inProgress[ri]._action.isMorphed()) { return _inProgress[ri]._time; } } for (size_t i(0); i<_inProgress.size(); ++i) { size_t ri = _inProgress.size()-1-i; std::cout << _inProgress[ri]._action.getName() << std::endl; } BOSS_ASSERT(false, "There were no buildings in progress"); return -1; } const ActionType & ActionsInProgress::getAction(const UnitCountType i) const { BOSS_ASSERT(i < (int)_inProgress.size(), "index out of bounds"); return _inProgress[i]._action; } FrameCountType ActionsInProgress::getTime(const UnitCountType i) const { BOSS_ASSERT(i < (int)_inProgress.size(), "index out of bounds"); return _inProgress[i]._time; } const ActionType & ActionsInProgress::nextAction() const { BOSS_ASSERT(_inProgress.size() > 0, "Tried to get nextAction() from empty set"); return _inProgress[_inProgress.size()-1]._action; } void ActionsInProgress::printActionsInProgress() { for (int i(0); i 0) { printf("Progress: %d %d %d\n", i, (int)_numProgress[i], (int)_inProgress[i]._time); } } } //bool ActionsInProgress::willBuildingFinsishBeforeRefinery() //{ // int firstBuildingIndex = 100000; // int lastRefineryIndex = 0; // // for (size_t i(0); i < _inProgress.size(); ++i) // { // if (_inProgress.) // } //} FrameCountType ActionsInProgress::whenActionsFinished(const PrerequisiteSet & actions) const { BOSS_ASSERT(!actions.isEmpty(), "Action set is empty!"); // the maximum of the (minimums for each action) int totalMax = 0; // if there are actions still left for (UnitCountType uc(0); uc < (int)actions.size(); ++uc) { // pop an action off the set const ActionType & a = actions.getActionType(uc); // define a new minimum int actionMin = std::numeric_limits::max(); // for each unit in our progress vector for (size_t i(0); i<_inProgress.size(); ++i) { // if the action matches if (_inProgress[i]._action == a) { // check to see if we have a new minimum actionMin = (_inProgress[i]._time < actionMin) ? _inProgress[i]._time : actionMin; } } // if we found a new minimum if (actionMin < std::numeric_limits::max()) { // check to see if we have a new maximum totalMax = (actionMin > totalMax) ? actionMin : totalMax; } } // return the new maximum return totalMax; } ================================================ FILE: BOSS/source/ActionInProgress.h ================================================ #pragma once #include "Common.h" #include #include #include #include #include "PrerequisiteSet.h" #include #include "Array.hpp" #include "ActionType.h" namespace BOSS { class ActionInProgress { public: ActionType _action; FrameCountType _time; ActionInProgress() : _time(0) { } ActionInProgress(const ActionType & action, FrameCountType t) : _action(action) , _time(t) { } // we want to sort these in descending order in ActionsInProgress const bool operator < (const ActionInProgress & rhs) const { return _time > rhs._time; } }; class ActionsInProgress { Vec _inProgress; Vec _numProgress; // how many of each unit are in progress public: ActionsInProgress(); UnitCountType operator [] (const ActionType & action) const; UnitCountType numInProgress(const ActionType & action) const; void addAction(const ActionType & a, int time); void popNextAction(); bool isEmpty() const; const UnitCountType size() const; //bool willBuildingFinsishBeforeRefinery(); FrameCountType getLastFinishTime() const; FrameCountType nextActionFinishTime(const ActionType & a) const; FrameCountType getTime(const UnitCountType i) const; FrameCountType nextActionFinishTime() const; FrameCountType nextBuildingFinishTime() const; FrameCountType whenActionsFinished(const PrerequisiteSet & actions) const; const ActionType & getAction(const UnitCountType index) const; const ActionType & nextAction() const; void printActionsInProgress(); }; } ================================================ FILE: BOSS/source/ActionSet.cpp ================================================ #include "ActionSet.h" using namespace BOSS; ActionSet::ActionSet() { } const size_t ActionSet::size() const { return _actionTypes.size(); } const bool ActionSet::isEmpty() const { return size() == 0; } const ActionType & ActionSet::operator [] (const size_t & index) const { return _actionTypes[index]; } ActionType & ActionSet::operator [] (const size_t & index) { return _actionTypes[index]; } const bool ActionSet::contains(const ActionType & action) const { return _actionTypes.contains(action); } void ActionSet::add(const ActionType & action) { _actionTypes.push_back(action); } void ActionSet::remove(const ActionType & action) { for (size_t i(0); i<_actionTypes.size(); ++i) { if (_actionTypes[i] == action) { _actionTypes.removeByShift(i); return; } } } void ActionSet::clear() { _actionTypes.clear(); } ================================================ FILE: BOSS/source/ActionSet.h ================================================ #pragma once #include "Common.h" #include "Constants.h" #include "Array.hpp" #include "ActionType.h" namespace BOSS { class ActionSet { Vec _actionTypes; public: ActionSet(); const size_t size() const; const bool isEmpty() const; const bool contains(const ActionType & type) const; const ActionType & operator [] (const size_t & index) const; ActionType & operator [] (const size_t & index); void add(const ActionType & action); void addAllActions(const RaceID & race); void remove(const ActionType & action); void clear(); }; } ================================================ FILE: BOSS/source/ActionType.cpp ================================================ #include "ActionType.h" #include "ActionTypeData.h" #include "ActionSet.h" using namespace BOSS; ActionType::ActionType() : _race(Races::None) , _id(0) { } ActionType::ActionType(const RaceID & race, const ActionID & id) : _race(race) , _id(id) { } ActionType::ActionType(const ActionType & type) : _race(type._race) , _id(type._id) { } ActionType::ActionType(const BWAPI::UnitType & type) : _race(ActionTypeData::GetRaceID(type.getRace())) , _id(ActionTypeData::GetActionID(type)) { } ActionType::ActionType(const BWAPI::UpgradeType & type) : _race(ActionTypeData::GetRaceID(type.getRace())) , _id(ActionTypeData::GetActionID(type)) { } ActionType::ActionType(const BWAPI::TechType & type) : _race(ActionTypeData::GetRaceID(type.getRace())) , _id(ActionTypeData::GetActionID(type)) { } ActionType & ActionType::operator = (const ActionType & rhs) { if (this != &rhs) { new (this) ActionType(rhs); } return *this; } const ActionID ActionType::ID() const { return _id; } const RaceID ActionType::getRace() const { return _race; } BWAPI::UnitType ActionType::getUnitType() const { return ActionTypeData::GetActionTypeData(_race, _id).getUnitType(); } BWAPI::UpgradeType ActionType::getUpgradeType() const { return ActionTypeData::GetActionTypeData(_race, _id).getUpgradeType(); } BWAPI::TechType ActionType::getTechType() const { return ActionTypeData::GetActionTypeData(_race, _id).getTechType(); } BWAPI::UnitType ActionType::whatBuildsBWAPI() const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsBWAPI(); } ActionType ActionType::whatBuildsActionType() const { return ActionTypes::GetActionType(_race, whatBuildsAction()); } ActionID ActionType::whatBuildsAction() const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsAction(); } const PrerequisiteSet & ActionType::getPrerequisites() const { return ActionTypeData::GetActionTypeData(_race, _id).getPrerequisites(); } const PrerequisiteSet & ActionType::getRecursivePrerequisites() const { return ActionTypeData::GetActionTypeData(_race, _id).getRecursivePrerequisites(); } int ActionType::getType() const { return ActionTypeData::GetActionTypeData(_race, _id).getType(); } const std::string & ActionType::getName() const { return ActionTypeData::GetActionTypeData(_race, _id).getName(); } const std::string & ActionType::getShortName() const { return ActionTypeData::GetActionTypeData(_race, _id).getShortName(); } const std::string & ActionType::getMetaName() const { return ActionTypeData::GetActionTypeData(_race, _id).getMetaName(); } FrameCountType ActionType::buildTime() const { return ActionTypeData::GetActionTypeData(_race, _id).buildTime(); } ResourceCountType ActionType::mineralPrice() const { return ActionTypeData::GetActionTypeData(_race, _id).mineralPrice(); } ResourceCountType ActionType::mineralPriceScaled() const { return ActionTypeData::GetActionTypeData(_race, _id).mineralPriceScaled(); } ResourceCountType ActionType::gasPrice() const { return ActionTypeData::GetActionTypeData(_race, _id).gasPrice(); } ResourceCountType ActionType::gasPriceScaled() const { return ActionTypeData::GetActionTypeData(_race, _id).gasPriceScaled(); } SupplyCountType ActionType::supplyRequired() const { return ActionTypeData::GetActionTypeData(_race, _id).supplyRequired(); } SupplyCountType ActionType::supplyProvided() const { return ActionTypeData::GetActionTypeData(_race, _id).supplyProvided(); } UnitCountType ActionType::numProduced() const { return ActionTypeData::GetActionTypeData(_race, _id).numProduced(); } bool ActionType::isAddon() const { return ActionTypeData::GetActionTypeData(_race, _id).isAddon(); } bool ActionType::isRefinery() const { return ActionTypeData::GetActionTypeData(_race, _id).isRefinery(); } bool ActionType::isWorker() const { return ActionTypeData::GetActionTypeData(_race, _id).isWorker(); } bool ActionType::isBuilding() const { return ActionTypeData::GetActionTypeData(_race, _id).isBuilding(); } bool ActionType::isResourceDepot() const { return ActionTypeData::GetActionTypeData(_race, _id).isResourceDepot(); } bool ActionType::isSupplyProvider() const { return ActionTypeData::GetActionTypeData(_race, _id).isSupplyProvider(); } bool ActionType::isUnit() const { return ActionTypeData::GetActionTypeData(_race, _id).isUnit(); } bool ActionType::isTech() const { return ActionTypeData::GetActionTypeData(_race, _id).isTech(); } bool ActionType::isUpgrade() const { return ActionTypeData::GetActionTypeData(_race, _id).isUpgrade(); } bool ActionType::whatBuildsIsBuilding() const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsIsBuilding(); } bool ActionType::whatBuildsIsLarva() const { return ActionTypeData::GetActionTypeData(_race, _id).whatBuildsIsLarva(); } bool ActionType::canProduce() const { return ActionTypeData::GetActionTypeData(_race, _id).canProduce(); } bool ActionType::requiresAddon() const { return ActionTypeData::GetActionTypeData(_race, _id).requiresAddon(); } bool ActionType::isMorphed() const { return ActionTypeData::GetActionTypeData(_race, _id).isMorphed(); } bool ActionType::canBuild(const ActionType & t) const { if (t.getRace() != getRace()) { return false; } static const ActionType & Hatchery = ActionTypes::GetActionType("Zerg_Hatchery"); static const ActionType & Lair = ActionTypes::GetActionType("Zerg_Lair"); static const ActionType & Hive = ActionTypes::GetActionType("Zerg_Hive"); static const ActionType & Spire = ActionTypes::GetActionType("Zerg_Spire"); static const ActionType & GreaterSpire = ActionTypes::GetActionType("Zerg_Greater_Spire"); const ActionType & whatBuilds = t.whatBuildsActionType(); if (whatBuilds == *this) { return true; } // if this is a zerg unit which is not morphed // then an upgraded version of the building can construct it // morphed units need the *exact* unit to morph from which is covered above if ((t.getRace() == Races::Zerg) && !t.isMorphed()) { if (whatBuilds == Hatchery) { return (*this == Lair || *this == Hive); } else if (whatBuilds == Lair) { return (*this == Hive); } else if (whatBuilds == Spire) { return (*this == GreaterSpire); } } return false; } ActionType ActionType::requiredAddonType() const { return ActionTypes::GetActionType(_race, ActionTypeData::GetActionTypeData(_race, _id).requiredAddonID()); } const bool ActionType::operator == (const ActionType & rhs) const { return _race == rhs._race && _id == rhs._id; } const bool ActionType::operator != (const ActionType & rhs) const { return _race != rhs._race || _id != rhs._id; } const bool ActionType::operator < (const ActionType & rhs) const { return _id < rhs._id; } namespace BOSS { namespace ActionTypes { std::vector< std::vector > allActionTypes; std::map nameMap; std::vector workerActionTypes; std::vector refineryActionTypes; std::vector supplyProviderActionTypes; std::vector resourceDepotActionTypes; size_t numActionTypes[Races::NUM_RACES] = {0, 0, 0}; void init() { for (RaceID r(0); r < Races::NUM_RACES; ++r) { allActionTypes.push_back(std::vector()); for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a) { ActionType type(r, a); allActionTypes[r].push_back(type); // add the name with spaces nameMap[type.getName()] = type; // add the name with underscores std::string name = type.getName(); for (size_t i(0); isecond; //} const ActionType & GetActionType(const RaceID & race, const ActionID & id) { BOSS_ASSERT(race < Races::NUM_RACES && id < (int)ActionTypes::GetAllActionTypes(race).size(), "Race / Action does not exist"); return allActionTypes[race][id]; } const ActionType & GetActionType(const std::string & name) { BOSS_ASSERT(TypeExists(name), "ActionType name not found: %s", name.c_str()); return nameMap[name]; } const bool TypeExists(const std::string & name) { return nameMap.find(name) != nameMap.end(); } const std::vector & GetAllActionTypes(const RaceID race) { BOSS_ASSERT(race < Races::NUM_RACES, "Race is not valid: %d", race); return allActionTypes[race]; } const bool TypeExists(const BWAPI::UnitType & type) { const RaceID raceID = ActionTypeData::GetRaceID(type.getRace()); if (raceID >= Races::NUM_RACES) { return false; } for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionType & data = GetActionType(raceID, a); if (data.isUnit() && data.getUnitType() == type) { return true; } } return false; } const bool TypeExists(const BWAPI::UpgradeType & type) { const RaceID raceID = ActionTypeData::GetRaceID(type.getRace()); if (raceID >= Races::NUM_RACES) { return false; } for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionType & data = GetActionType(raceID, a); if (data.isUpgrade() && data.getUpgradeType() == type) { return true; } } return false; } const bool TypeExists(const BWAPI::TechType & type) { const RaceID raceID = ActionTypeData::GetRaceID(type.getRace()); if (raceID >= Races::NUM_RACES) { return false; } for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionType & data = GetActionType(raceID, a); if (data.isTech() && data.getTechType() == type) { return true; } } return false; } ActionType None(Races::None, 0); // ActionType Protoss_Probe (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Pylon (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Assimilator (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Gateway (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Nexus (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Zealot (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Cybernetics_Core (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Dragoon (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Singularity_Charge (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Forge (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Photon_Cannon (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_High_Templar (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Citadel_of_Adun (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Templar_Archives (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Robotics_Facility (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Robotics_Support_Bay (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Observatory (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Stargate (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Scout (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Arbiter_Tribunal (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Arbiter (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Shield_Battery (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Dark_Templar (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Shuttle (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Reaver (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Observer (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Corsair (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Fleet_Beacon (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Carrier (Races::Protoss, numActionTypes[Races::Protoss]++); //ActionType Protoss_Leg_Enhancements (Races::Protoss, numActionTypes[Races::Protoss]++); // //ActionType Protoss_Archon(Races::Protoss, 31); // ActionType Terran_SCV(Races::Terran, 0); //ActionType Terran_Supply_Depot(Races::Terran, 1); //ActionType Terran_Command_Center(Races::Terran, 2); //ActionType Terran_Barracks(Races::Terran, 3); //ActionType Terran_Refinery(Races::Terran, 4); //ActionType Terran_Marine(Races::Terran, 5); //ActionType Terran_Academy(Races::Terran, 6); //ActionType Terran_Stim_Packs(Races::Terran, 7); //ActionType Terran_Medic(Races::Terran, 8); //ActionType Terran_Factory(Races::Terran, 9); //ActionType Terran_Starport(Races::Terran, 10); //ActionType Terran_Wraith(Races::Terran, 11); // ActionType Terran_Siege_Tank(Races::Terran, 12); // ActionType Terran_Machine_Shop(Races::Terran, 13); // ActionType Terran_Tank_Siege_Mode(Races::Terran, 14); // ActionType Terran_Cloaking_Field(Races::Terran, 15); // ActionType Terran_Control_Tower(Races::Terran, 16); // ActionType Terran_Battlecruiser(Races::Terran, 17); // ActionType Terran_Physics_Lab(Races::Terran, 18); // ActionType Terran_Science_Facility(Races::Terran, 19); // ActionType Terran_Science_Vessel(Races::Terran, 20); // ActionType Terran_Vulture(Races::Terran, 21); // ActionType Terran_Goliath(Races::Terran, 22); // ActionType Terran_Firebat(Races::Terran, 23); // ActionType Terran_Armory(Races::Terran, 24); // ActionType Terran_Ghost(Races::Terran, 25); // ActionType Terran_Covert_Ops(Races::Terran, 26); // ActionType Terran_Comsat_Station(Races::Terran, 27); // ActionType Terran_Bunker(Races::Terran, 28); // ActionType Terran_Valkyrie(Races::Terran, 29); // // ActionType Zerg_Drone(Races::Zerg, 0); //ActionType Zerg_Overlord(Races::Zerg, 1); //ActionType Zerg_Hatchery(Races::Zerg, 2); //ActionType Zerg_Spawning_Pool(Races::Zerg, 3); //ActionType Zerg_Zergling(Races::Zerg, 4); //ActionType Zerg_Extractor(Races::Zerg, 5); //ActionType Zerg_Lair(Races::Zerg, 6); //ActionType Zerg_Hydralisk_Den(Races::Zerg, 7); //ActionType Zerg_Spire(Races::Zerg, 8); //ActionType Zerg_Hydralisk(Races::Zerg, 9); //ActionType Zerg_Mutalisk(Races::Zerg, 10); // ActionType Zerg_Larva(Races::Zerg, 11); // ActionType Zerg_Hive(Races::Zerg, 12); // ActionType Zerg_Greater_Spire(Races::Zerg, 13); // ActionType Zerg_Guardian(Races::Zerg, 14); // ActionType Zerg_Defiler(Races::Zerg, 15); // ActionType Zerg_Defiler_Mound(Races::Zerg, 16); // ActionType Zerg_Devourer(Races::Zerg, 17); // ActionType Zerg_Scourge(Races::Zerg, 18); // ActionType Zerg_Queen(Races::Zerg, 19); // ActionType Zerg_Queens_Nest(Races::Zerg, 20); // ActionType Zerg_Ultralisk(Races::Zerg, 21); // ActionType Zerg_Ultralisk_Cavern(Races::Zerg, 22); // ActionType Zerg_Creep_Colony(Races::Zerg, 23); // ActionType Zerg_Sunken_Colony(Races::Zerg, 24); // ActionType Zerg_Spore_Colony(Races::Zerg, 25); // ActionType Zerg_Evolution_Chamber(Races::Zerg, 26); // ActionType Zerg_Lurker(Races::Zerg, 27); // ActionType Zerg_Lurker_Aspect(Races::Zerg, 28); } } ================================================ FILE: BOSS/source/ActionType.h ================================================ #pragma once #include "Common.h" namespace BOSS { class PrerequisiteSet; class ActionType { const ActionID _id; const RaceID _race; public: ActionType(); ActionType(const RaceID & race, const ActionID & id); ActionType(const ActionType & type); ActionType(const BWAPI::UnitType & type); ActionType(const BWAPI::UpgradeType & type); ActionType(const BWAPI::TechType & type); ActionType & operator = (const ActionType & rhs); const ActionID ID() const; const RaceID getRace() const; BWAPI::UnitType getUnitType() const; BWAPI::UnitType whatBuildsBWAPI() const; ActionType whatBuildsActionType() const; BWAPI::UpgradeType getUpgradeType() const; BWAPI::TechType getTechType() const; ActionID whatBuildsAction() const; const PrerequisiteSet & getPrerequisites() const; const PrerequisiteSet & getRecursivePrerequisites() const; int getType() const; const std::string & getName() const; const std::string & getShortName() const; const std::string & getMetaName() const; FrameCountType buildTime() const; ResourceCountType mineralPrice() const; ResourceCountType mineralPriceScaled() const; ResourceCountType gasPrice() const; ResourceCountType gasPriceScaled() const; SupplyCountType supplyRequired() const; SupplyCountType supplyProvided() const; UnitCountType numProduced() const; bool isRefinery() const; bool isWorker() const; bool isBuilding() const; bool isResourceDepot() const; bool isSupplyProvider() const; bool isUnit() const; bool isTech() const; bool isUpgrade() const; bool whatBuildsIsBuilding() const; bool whatBuildsIsLarva() const; bool canProduce() const; bool canAttack() const; bool isAddon() const; bool requiresAddon() const; bool isMorphed() const; bool canBuild(const ActionType & t) const; ActionType requiredAddonType() const; const bool operator == (const ActionType & rhs) const; const bool operator != (const ActionType & rhs) const; const bool operator < (const ActionType & rhs) const; }; class ActionSet; namespace ActionTypes { void init(); const std::vector & GetAllActionTypes(const RaceID race); const ActionType & GetActionType(const RaceID & race, const ActionID & id); const ActionType & GetWorker(const RaceID raceID); const ActionType & GetSupplyProvider(const RaceID raceID); const ActionType & GetRefinery(const RaceID raceID); const ActionType & GetResourceDepot(const RaceID raceID); const ActionType & GetActionType(const std::string & name); const bool TypeExists(const std::string & name); const bool TypeExists(const BWAPI::UnitType & a); const bool TypeExists(const BWAPI::TechType & a); const bool TypeExists(const BWAPI::UpgradeType & a); extern ActionType None; } } ================================================ FILE: BOSS/source/ActionTypeData.cpp ================================================ #include "ActionTypeData.h" #include "ActionType.h" using namespace BOSS; // default constructor, should never be called ActionTypeData::ActionTypeData() : type(Error) { } // UnitType constructor ActionTypeData::ActionTypeData(BWAPI::UnitType t, const ActionID id) : type (UnitType) , unit (t) , raceID (GetRaceID(t.getRace())) , actionID (id) , mineralPriceVal (t.mineralPrice() * Constants::RESOURCE_SCALE) , gasPriceVal (t.gasPrice() * Constants::RESOURCE_SCALE) , supplyRequiredVal (t.supplyRequired()) , supplyProvidedVal (t.supplyProvided()) , buildTimeVal (t.buildTime()) , numberProduced (1) , name (t.getName()) , metaName (t.getName()) , building (t.isBuilding()) , worker (t.isWorker()) , refinery (t.isRefinery()) , resourceDepot (t.isResourceDepot()) , supplyProvider (t.supplyProvided() > 0 && !t.isResourceDepot()) , canProduceBool (t.isBuilding() && t.canProduce()) , canAttackBool (t.canAttack()) , whatBuildsUnitType (t.whatBuilds().first) , addon (t.isAddon()) , morphed (false) , reqAddon (false) , reqAddonID (0) { if (t == BWAPI::UnitTypes::Zerg_Zergling || t == BWAPI::UnitTypes::Zerg_Scourge) { numberProduced = 2; } if (t == BWAPI::UnitTypes::Zerg_Lair || t == BWAPI::UnitTypes::Zerg_Hive || t == BWAPI::UnitTypes::Zerg_Greater_Spire || t == BWAPI::UnitTypes::Zerg_Lurker || t == BWAPI::UnitTypes::Zerg_Guardian || t == BWAPI::UnitTypes::Zerg_Sunken_Colony || t == BWAPI::UnitTypes::Zerg_Spore_Colony) { morphed = true; } setShortName(); } // UpgradeType action ActionTypeData::ActionTypeData(BWAPI::UpgradeType t, const ActionID id) : type(UpgradeType) , upgrade(t) , actionID(id) , raceID(GetRaceID(t.getRace())) , mineralPriceVal(t.mineralPrice() * Constants::RESOURCE_SCALE) , gasPriceVal(t.gasPrice() * Constants::RESOURCE_SCALE) , supplyRequiredVal(0) , supplyProvidedVal(0) , buildTimeVal(t.upgradeTime()) , numberProduced(1) , name(t.getName()) , metaName(t.getName()) , building(false) , worker(false) , refinery(false) , resourceDepot(false) , supplyProvider(false) , canProduceBool(false) , canAttackBool(false) , whatBuildsUnitType(t.whatUpgrades()) , addon(false) , reqAddon(false) , reqAddonID(0) , morphed(false) { setShortName(); } // TechType action ActionTypeData::ActionTypeData(BWAPI::TechType t, const ActionID id) : type(TechType) , tech(t) , actionID(id) , raceID(GetRaceID(t.getRace())) , mineralPriceVal(t.mineralPrice() * Constants::RESOURCE_SCALE) , gasPriceVal(t.gasPrice() * Constants::RESOURCE_SCALE) , supplyRequiredVal(0) , supplyProvidedVal(0) , buildTimeVal(t.researchTime()) , numberProduced(1) , name(t.getName()) , metaName(t.getName()) , building(false) , worker(false) , refinery(false) , resourceDepot(false) , supplyProvider(false) , canProduceBool(false) , canAttackBool(false) , whatBuildsUnitType(t.whatResearches()) , addon(false) , reqAddon(false) , reqAddonID(0) , morphed(false) { setShortName(); } RaceID ActionTypeData::getRaceID() const { return raceID; } ActionID ActionTypeData::getActionID() const { return actionID; } BWAPI::UnitType ActionTypeData::getUnitType() const { return unit; } BWAPI::UnitType ActionTypeData::whatBuildsBWAPI() const { return whatBuildsUnitType; } BWAPI::UpgradeType ActionTypeData::getUpgradeType() const { return upgrade; } BWAPI::TechType ActionTypeData::getTechType() const { return tech; } ActionID ActionTypeData::whatBuildsAction() const { return whatBuildsActionID; } int ActionTypeData::getType() const { return type; } const std::string & ActionTypeData::getName() const { return name; } const std::string & ActionTypeData::getShortName() const { return shortName; } const std::string & ActionTypeData::getMetaName() const { return metaName; } FrameCountType ActionTypeData::buildTime() const { return buildTimeVal; } ResourceCountType ActionTypeData::mineralPrice() const { return mineralPriceVal; } ResourceCountType ActionTypeData::mineralPriceScaled() const { return mineralPriceVal * 100; } ResourceCountType ActionTypeData::gasPrice() const { return gasPriceVal; } ResourceCountType ActionTypeData::gasPriceScaled() const { return gasPriceVal * 100; } SupplyCountType ActionTypeData::supplyRequired() const { return supplyRequiredVal; } SupplyCountType ActionTypeData::supplyProvided() const { return supplyProvidedVal; } UnitCountType ActionTypeData::numProduced() const { return numberProduced; } bool ActionTypeData::isRefinery() const { return refinery; } bool ActionTypeData::isWorker() const { return worker; } bool ActionTypeData::isBuilding() const { return building; } bool ActionTypeData::isResourceDepot() const { return resourceDepot; } bool ActionTypeData::isSupplyProvider() const { return supplyProvider; } bool ActionTypeData::isUnit() const { return type == UnitType; } bool ActionTypeData::isTech() const { return type == TechType; } bool ActionTypeData::isUpgrade() const { return type == UpgradeType; } bool ActionTypeData::isAddon() const { return addon; } bool ActionTypeData::isMorphed() const { return morphed; } bool ActionTypeData::requiresAddon() const { return reqAddon; } ActionID ActionTypeData::requiredAddonID() const { return reqAddonID; } bool ActionTypeData::whatBuildsIsBuilding() const { return whatBuildsIsBuildingBool; } bool ActionTypeData::whatBuildsIsLarva() const { return whatBuildsIsLarvaBool; } bool ActionTypeData::canProduce() const { return canProduceBool; } bool ActionTypeData::canAttack() const { return canAttackBool; } void ActionTypeData::setPrerequisites(const PrerequisiteSet & pre) { prerequisites = pre; } void ActionTypeData::setRecursivePrerequisites(const PrerequisiteSet & pre) { recursivePrerequisites = pre; } bool ActionTypeData::operator == (const ActionTypeData & a) const { return actionID == a.actionID; } bool ActionTypeData::operator < (const ActionTypeData & a) const { return actionID < a.actionID; } const PrerequisiteSet & ActionTypeData::getPrerequisites() const { return prerequisites; } const PrerequisiteSet & ActionTypeData::getRecursivePrerequisites() const { return recursivePrerequisites; } void ActionTypeData::setWhatBuildsActionID(const ActionID a, const bool wbib, const bool wbil) { whatBuildsActionID = a; whatBuildsIsBuildingBool = wbib; whatBuildsIsLarvaBool = wbil; } void ActionTypeData::setRequiredAddon(bool requiresAddon, const ActionID & id) { reqAddon = requiresAddon; reqAddonID = id; } void ActionTypeData::setShortName() { std::string prefix = Races::GetRaceName(raceID); shortName = name; if (name.compare(0, prefix.size(), prefix) == 0) { shortName = name.substr(prefix.size()+1); } } //////////////////////////////////////////////////////////// // STATIC FUNCTIONS BELOW THIS POINT //////////////////////////////////////////////////////////// //Vec< Vec, Races::NUM_RACES> ActionTypeData::allActionTypeDataVec(Races::NUM_RACES); // //template Vec< ActionID, Races::NUM_RACES > ActionTypeData::numActionTypesVec(Races::NUM_RACES); //template Vec< ActionTypeData, Races::NUM_RACES > ActionTypeData::workerActionTypes(Races::NUM_RACES); //template Vec< ActionTypeData, Races::NUM_RACES > ActionTypeData::refineryActionTypes(Races::NUM_RACES); //template Vec< ActionTypeData, Races::NUM_RACES > ActionTypeData::supplyProviderActionTypes(Races::NUM_RACES); //template Vec< ActionTypeData, Races::NUM_RACES > ActionTypeData::resourceDepotActionTypes(Races::NUM_RACES); //template Vec< DependencyGraph, Races::NUM_RACES > ActionTypeData::dependencyGraphs(Races::NUM_RACES); std::vector< std::vector > ActionTypeData::allActionTypeDataVec(Races::NUM_RACES); //std::vector ActionTypeData::dependencyGraphs(Races::NUM_RACES); void ActionTypeData::Init() { // add all the legal actions AddActions(); CalculateWhatBuilds(); // calculate the prerequisites of those actions AddPrerequisites(); } void ActionTypeData::AddActions() { std::string protoss("Protoss"); std::string terran("Terran"); std::string zerg("Zerg");\ std::vector unitTypes; std::copy(BWAPI::UnitTypes::allUnitTypes().begin(), BWAPI::UnitTypes::allUnitTypes().end(), std::back_inserter(unitTypes)); for (size_t i(0); i < unitTypes.size()-1; ++i) { for (size_t j(i+1); j < unitTypes.size(); ++j) { int costi = unitTypes[i].mineralPrice() + 2*unitTypes[i].gasPrice(); int costj = unitTypes[j].mineralPrice() + 2*unitTypes[j].gasPrice(); if (costi > costj) { std::swap(unitTypes[i], unitTypes[j]); } } } for (size_t i(0); i < unitTypes.size(); ++i) { const BWAPI::UnitType & type = unitTypes[i]; // blacklist temporary unit types which aren't buildable if (type == BWAPI::UnitTypes::Zerg_Egg || type == BWAPI::UnitTypes::Zerg_Lurker_Egg || type == BWAPI::UnitTypes::Zerg_Cocoon || type == BWAPI::UnitTypes::Zerg_Infested_Terran || type == BWAPI::UnitTypes::Zerg_Infested_Command_Center || type == BWAPI::UnitTypes::Zerg_Broodling || type == BWAPI::UnitTypes::Protoss_Interceptor || type == BWAPI::UnitTypes::Protoss_Scarab || type == BWAPI::UnitTypes::Terran_Civilian || type == BWAPI::UnitTypes::Terran_Nuclear_Missile || type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine) { continue; } if (type.getName().compare(0, protoss.length(), protoss) == 0) { allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size())); } else if (type.getName().compare(0, terran.length(), terran) == 0) { allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size())); } else if (type.getName().compare(0, zerg.length(), zerg) == 0) { allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size())); } } for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes()) { // blacklisted tech types we cannot create if (type.whatResearches() == BWAPI::UnitTypes::None) { continue; } if (type.getRace() == BWAPI::Races::Protoss) { allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size())); } else if (type.getRace() == BWAPI::Races::Terran) { allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size())); } else if (type.getRace() == BWAPI::Races::Zerg) { allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size())); } } for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes()) { // blacklisted tech types we cannot create if (type.whatUpgrades() == BWAPI::UnitTypes::None) { continue; } if (type.getRace() == BWAPI::Races::Protoss) { allActionTypeDataVec[Races::Protoss].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Protoss].size())); } else if (type.getRace() == BWAPI::Races::Terran) { allActionTypeDataVec[Races::Terran].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Terran].size())); } else if (type.getRace() == BWAPI::Races::Zerg) { allActionTypeDataVec[Races::Zerg].push_back(ActionTypeData(type, allActionTypeDataVec[Races::Zerg].size())); } } } const RaceID ActionTypeData::GetRaceID(BWAPI::Race r) { if (r == BWAPI::Races::Protoss) { return Races::Protoss; } else if (r == BWAPI::Races::Terran) { return Races::Terran; } else if (r == BWAPI::Races::Zerg) { return Races::Zerg; } else { return Races::None; } } const ActionID ActionTypeData::GetNumActionTypes(const RaceID race) { return allActionTypeDataVec[race].size(); } const ActionTypeData & ActionTypeData::GetActionTypeData(const RaceID raceID, const ActionID & id) { BOSS_ASSERT(raceID < Races::NUM_RACES, "Race ID invalid: %d %d", (int)raceID, (int)id); return allActionTypeDataVec[raceID][id]; } ActionID ActionTypeData::GetActionID(const BWAPI::UnitType & type) { const RaceID raceID = GetRaceID(type.getRace()); BOSS_ASSERT(raceID < Races::NUM_RACES, "Race ID invalid: %d %s", (int)raceID, type.getName().c_str()); for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionTypeData & data = GetActionTypeData(raceID, a); if (data.isUnit() && data.getUnitType() == type) { return data.getActionID(); } } BOSS_ASSERT(false, "Could not find UnitType: %d %s", type.getID(), type.getName().c_str()); return 0; } ActionID ActionTypeData::GetActionID(const BWAPI::TechType & type) { const RaceID raceID = GetRaceID(type.getRace()); for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionTypeData & data = GetActionTypeData(raceID, a); if (data.isTech() && data.getTechType() == type) { return data.getActionID(); } } BOSS_ASSERT(false, "Could not find TechType: %d %s", type.getID(), type.getName().c_str()); return 0; } ActionID ActionTypeData::GetActionID(const BWAPI::UpgradeType & type) { const RaceID raceID = GetRaceID(type.getRace()); for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(raceID); ++a) { const ActionTypeData & data = GetActionTypeData(raceID, a); if (data.isUpgrade() && data.getUpgradeType() == type) { return data.getActionID(); } } BOSS_ASSERT(false, "Could not find TechType: %d %s", type.getID(), type.getName().c_str()); return 0; } ActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::UnitType & a) { return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a)); } ActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::TechType & a) { return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a)); } ActionTypeData ActionTypeData::GetActionTypeData(const BWAPI::UpgradeType & a) { return GetActionTypeData(GetRaceID(a.getRace()), GetActionID(a)); } // adds all prerequisites void ActionTypeData::AddPrerequisites() { // set all prerequisites for all action types for (RaceID r(0); r < Races::NUM_RACES; ++r) { for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a) { allActionTypeDataVec[r][a].setPrerequisites(CalculatePrerequisites(allActionTypeDataVec[r][a])); } } // set required addon data for (RaceID r(0); r < Races::NUM_RACES; ++r) { for (ActionID a(0); a < ActionTypeData::GetNumActionTypes(r); ++a) { // set the prerequisite PrerequisiteSet based on the function below ActionTypeData & typeData = allActionTypeDataVec[r][a]; const PrerequisiteSet & pre = typeData.getPrerequisites(); for (size_t p(0); p requiredUnits = action.getUnitType().requiredUnits(); BWAPI::UnitType actionType = action.getUnitType(); // if it's a protoss building that isn't a Nexus or Assimilator, we need a pylon (indirectly) if (actionType.getRace() == BWAPI::Races::Protoss && actionType.isBuilding() && !actionType.isResourceDepot() && !(actionType == BWAPI::UnitTypes::Protoss_Pylon) && !(actionType == BWAPI::UnitTypes::Protoss_Assimilator)) { pre.add(ActionType(Races::Protoss, GetActionID(BWAPI::UnitTypes::Protoss_Pylon)), 1); } // for each of the required UnitTypes for (std::map::iterator unitIt = requiredUnits.begin(); unitIt != requiredUnits.end(); unitIt++) { //if (DEBUG_StarcraftData) printf("\tPRE: %s\n", unitIt->first.getName().c_str()); BWAPI::UnitType type = unitIt->first; int count = unitIt->second; // add the action to the PrerequisiteSet if it is not a larva if (type != BWAPI::UnitTypes::Zerg_Larva) { //printf("\t\tAdding %s\n", type.getName().c_str()); pre.add(ActionType(action.getRaceID(), GetActionID(type)), count); } } // if there is a TechType required if (action.getUnitType().requiredTech() != BWAPI::TechTypes::None) { //if (DEBUG_StarcraftData) printf("\tPRE: %s\n", action.getUnitType().requiredTech().getName().c_str()); BWAPI::TechType required = action.getUnitType().requiredTech(); // add it to the PrerequisiteSet pre.add(ActionType(action.getRaceID(), GetActionID(required)), 1); } } // if it's a TechType if (action.getType() == ActionTypeData::TechType) { if (action.getTechType().whatResearches() != BWAPI::UnitTypes::None) { //if (DEBUG_StarcraftData) printf("\tPRE: %s\n", action.getTechType().whatResearches().getName().c_str()); // add what researches it pre.add(ActionType(action.getRaceID(), GetActionID(action.getTechType().whatResearches())), 1); } } // if it's an UpgradeType if (action.getType() == ActionTypeData::UpgradeType) { if (action.getUpgradeType().whatUpgrades() != BWAPI::UnitTypes::None) { //if (DEBUG_StarcraftData) printf("\tPRE: %s\n", action.getUpgradeType().whatUpgrades().getName().c_str()); // add what upgrades it pre.add(ActionType(action.getRaceID(), GetActionID(action.getUpgradeType().whatUpgrades())), 1); } } //printf("Finish Prerequisites\n"); return pre; } // calculate the recursive prerequisites for an Action, storing them in allPre // assumes that prerequisites have already been calculated void ActionTypeData::CalculateRecursivePrerequisites(PrerequisiteSet & allPre, const ActionTypeData & action) { PrerequisiteSet pre = action.getPrerequisites(); if (action.gasPrice() > 0) { if (action.raceID == Races::Protoss) { pre.add(ActionType(Races::Protoss, GetActionID(BWAPI::UnitTypes::Protoss_Assimilator))); } else if (action.raceID == Races::Terran) { pre.add(ActionType(Races::Terran, GetActionID(BWAPI::UnitTypes::Terran_Refinery))); } if (action.raceID == Races::Zerg) { pre.add(ActionType(Races::Zerg, GetActionID(BWAPI::UnitTypes::Zerg_Extractor))); } } for (size_t a(0); a < pre.size(); ++a) { const ActionType & actionType = pre.getActionType(a); if (!allPre.contains(actionType)) { allPre.add(actionType); CalculateRecursivePrerequisites(allPre, GetActionTypeData(actionType.getRace(), actionType.ID())); } } } ================================================ FILE: BOSS/source/ActionTypeData.h ================================================ #pragma once #include "Common.h" #include "Array.hpp" #include "PrerequisiteSet.h" #include namespace BOSS { class ActionTypeData { public: // types of actions enum { UnitType,UpgradeType,TechType,Error }; private: static std::vector< std::vector > allActionTypeDataVec; //static std::vector dependencyGraphs; ActionID actionID; // unique identifier to this action RaceID raceID; int type; // the enum type of action this is BWAPI::Race race; // the race of this action BWAPI::UnitType unit; // holds UnitType, if it's a unit BWAPI::UpgradeType upgrade; // holds UpgradeType, if it's an upgrade BWAPI::TechType tech; // holds TechType, if it's a tech ResourceCountType mineralPriceVal; // mineral price of the action ResourceCountType gasPriceVal; // gas price of the action SupplyCountType supplyRequiredVal; // supply price of the action SupplyCountType supplyProvidedVal; // supply created by the action FrameCountType buildTimeVal; // build time of the action UnitCountType numberProduced; // the number of units produced std::string name; // name of the action std::string shortName; std::string metaName; // meta name of this action, adds 'repeat' to the string PrerequisiteSet prerequisites; PrerequisiteSet recursivePrerequisites; bool building; // is this a building bool worker; // is this a worker bool refinery; // is this a refinery bool resourceDepot; // is this a resource depot bool supplyProvider; // is this a supply provider bool canProduceBool; bool canAttackBool; bool whatBuildsIsBuildingBool; // is what builds this action a building? bool whatBuildsIsLarvaBool; bool addon; bool reqAddon; bool morphed; ActionID reqAddonID; BWAPI::UnitType whatBuildsUnitType; // the unit type that builds this ActionID whatBuildsActionID; // the action that builds this // Private Constructors ActionTypeData(); ActionTypeData(BWAPI::UnitType t, const ActionID id); ActionTypeData(BWAPI::UpgradeType t, const ActionID id); ActionTypeData(BWAPI::TechType t, const ActionID id); static void AddActions(); static void CalculateWhatBuilds(); static void AddPrerequisites(); static PrerequisiteSet CalculatePrerequisites(const ActionTypeData & action); static void CalculateRecursivePrerequisites(PrerequisiteSet & allPre, const ActionTypeData & action); static ActionTypeData GetActionTypeData(const BWAPI::UnitType & a); static ActionTypeData GetActionTypeData(const BWAPI::TechType & a); static ActionTypeData GetActionTypeData(const BWAPI::UpgradeType & a); void setWhatBuildsActionID(const ActionID a,const bool wbib,const bool wbil); void setShortName(); public: static void Init(); static const ActionID GetNumActionTypes(const RaceID race); static const ActionTypeData & GetActionTypeData(const RaceID raceID,const ActionID & id); static const RaceID GetRaceID(BWAPI::Race r); RaceID getRaceID() const; ActionID getActionID() const; ActionType whatBuildsActionType() const; BWAPI::UnitType getUnitType() const; BWAPI::UnitType whatBuildsBWAPI() const; BWAPI::UpgradeType getUpgradeType() const; BWAPI::TechType getTechType() const; static ActionID GetActionID(const BWAPI::UnitType & a); static ActionID GetActionID(const BWAPI::TechType & a); static ActionID GetActionID(const BWAPI::UpgradeType & a); ActionID whatBuildsAction() const; const PrerequisiteSet & getPrerequisites() const; const PrerequisiteSet & getRecursivePrerequisites() const; int getType() const; const std::string & getName() const; const std::string & getShortName() const; const std::string & getMetaName() const; FrameCountType buildTime() const; ResourceCountType mineralPrice() const; ResourceCountType mineralPriceScaled() const; ResourceCountType gasPrice() const; ResourceCountType gasPriceScaled() const; SupplyCountType supplyRequired() const; SupplyCountType supplyProvided() const; UnitCountType numProduced() const; bool isRefinery() const; bool isWorker() const; bool isBuilding() const; bool isResourceDepot() const; bool isSupplyProvider() const; bool isUnit() const; bool isTech() const; bool isUpgrade() const; bool isAddon() const; bool isMorphed() const; bool requiresAddon() const; ActionID requiredAddonID() const; bool whatBuildsIsBuilding() const; bool whatBuildsIsLarva() const; bool canProduce() const; bool canAttack() const; void setPrerequisites(const PrerequisiteSet & pre); void setRecursivePrerequisites(const PrerequisiteSet & pre); void setRequiredAddon(bool requiresAddon, const ActionID & id); bool operator == (const ActionTypeData & a) const; bool operator < (const ActionTypeData & a) const; }; } ================================================ FILE: BOSS/source/Array.hpp ================================================ #pragma once #include "BOSSAssert.h" #include "Common.h" #include namespace BOSS { template class Vec { size_t _size; size_t _capacity; T _arr[max_capacity]; public: Vec() : _size(0) ,_capacity(max_capacity) { BOSS_ASSERT(max_capacity>0, "Vec initializing with capacity = 0"); } Vec(const size_t & size) : _size(size) ,_capacity(max_capacity) { BOSS_ASSERT(size <= max_capacity,"Vec initializing with size > capacity, Size = %d, Capacity = %d",size,_capacity); } Vec(const size_t & size,const T & val) : _size(size) ,_capacity(max_capacity) { BOSS_ASSERT(size <= max_capacity,"Vec initializing with size > capacity, Size = %d, Capacity = %d",size,_capacity); fill(val); } void resize(const size_t & size) { BOSS_ASSERT(size <= max_capacity,"Vec resizing with size > capacity, Size = %d, Cpacity = %d",size,_capacity); _size = size; } T & get(const size_t & index) { BOSS_ASSERT(index < size(),"Vec out of bounds exception, Size = %d, Index = %d",size(),index); return _arr[index]; } const T & get(const size_t & index) const { BOSS_ASSERT(index < size(),"Vec out of bounds exception, Size = %d, Index = %d",size(),index); return _arr[index]; } T & operator [] (const size_t & index) { return get(index); } const T & operator [] (const size_t & index) const { return get(index); } const bool contains(const T & e) const { for (size_t i(0); i index; --i) { _arr[i] = _arr[i-1]; } _size++; } void copyShiftLeft(const size_t & index) { BOSS_ASSERT(size() > 0, "Can't shift left when empty"); for (size_t i(index); i < size()-1; ++i) { _arr[i] = _arr[i+1]; } _size--; } const size_t & capacity() const { return _capacity; } void push_back(const T & e) { BOSS_ASSERT(_size < capacity(),"Array over capacity: Capacity = %d, Size = %d",capacity(), _size); _arr[_size] = e; ++_size; } const T & back() const { BOSS_ASSERT(!empty(),"Vector back() with empty array"); return get(_size); } void remove(const size_t & index) { remove_by_swap(index); } void removeByShift(const size_t & index) { copyShiftLeft(index); } void remove_by_swap(const size_t & index) { BOSS_ASSERT(index < size(),"Vector out of bounds exception, Size = %d, Index = %d",size(),index); std::swap(_arr[index],_arr[size()-1]); pop_back(); } void pop_back() { BOSS_ASSERT(!empty(),"Vector pop_back() with empty array"); _size--; } void sort() { std::sort(_arr, _arr + _size); } const bool empty() const { return size() == 0; } void clear() { _size = 0; } const size_t & size() const { return _size; } inline void fill(const T & val) { std::fill(_arr,_arr + _size,val); } class iterator { T * _ptr; public: iterator(T * ptr) : _ptr(ptr) { } iterator operator ++ () { iterator i = *this; _ptr++; return i; } iterator operator ++ (int junk) { _ptr++; return *this; } T & operator * () { return *_ptr; } T * operator -> () { return _ptr; } bool operator == (const iterator & rhs) { return _ptr == rhs._ptr; } bool operator != (const iterator & rhs) { return _ptr != rhs._ptr; } }; class const_iterator { T * _ptr; public: const_iterator(T * ptr) : _ptr(ptr) { } const_iterator operator ++ () { const_iterator i = *this; _ptr++; return i; } const_iterator operator ++ (int junk) { _ptr++; return *this; } const T & operator * () { return *_ptr; } const T * operator -> () { return _ptr; } bool operator == (const const_iterator & rhs) { return _ptr == rhs._ptr; } bool operator != (const const_iterator & rhs) { return _ptr != rhs._ptr; } }; iterator begin() { return iterator(_arr); } iterator end() { return iterator(_arr + size()); } }; } ================================================ FILE: BOSS/source/BOSS.cpp ================================================ #include "BOSS.h" namespace BOSS { void init() { ActionTypeData::Init(); ActionTypes::init(); } void printData() { for (RaceID r(0); r < Races::NUM_RACES; ++r) { const std::vector & allActions = ActionTypes::GetAllActionTypes(r); for (size_t i(0); i #include "BOSSException.h" #include namespace BOSS { class GameState; namespace Assert { const std::string currentDateTime(); void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...); } } #define BOSS_ASSERT_ENABLE #ifdef BOSS_ASSERT_ENABLE #define BOSS_ASSERT(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ BOSS::Assert::ReportFailure(nullptr, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ } \ } while(0) #define BOSS_ASSERT_STATE(cond, state, filename, msg, ...) \ do \ { \ if (!(cond)) \ { \ BOSS::Assert::ReportFailure(&state, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ } \ } while(0) #else #define SPARCRAFT_ASSERT(cond, msg, ...) #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) #endif ================================================ FILE: BOSS/source/BOSSException.cpp ================================================ #include "BOSSException.h" using namespace BOSS; BOSSException::BOSSException(std::string ss) : _s(ss) , _hasState(false) { } //BOSSException::BOSSException(std::string ss, const GameState * state) // : _s(ss) // , _hasState(false) //{ // if (state != nullptr) // { // _state = *state; // _hasState = true; // } //} BOSSException::~BOSSException() throw () { } const char* BOSSException::what() const throw() { return _s.c_str(); } bool BOSSException::hasState() const { return _hasState; } //const GameState & BOSSException::getState() const //{ // return _state; //} ================================================ FILE: BOSS/source/BOSSException.h ================================================ #pragma once #include "Common.h" namespace BOSS { class BOSSException : public std::exception { std::string _s; bool _hasState; public : //BOSSException(std::string ss, const GameState * state); BOSSException(std::string ss); ~BOSSException() throw (); const char* what() const throw(); bool hasState() const; //const GameState & getState() const; }; } ================================================ FILE: BOSS/source/BOSSExperiments.cpp ================================================ #include "BOSSExperiments.h" #include "CombatSearchExperiment.h" #include "BOSSPlotBuildOrders.h" using namespace BOSS; void Experiments::RunExperiments(const std::string & experimentFilename) { rapidjson::Document document; JSONTools::ParseJSONFile(document, experimentFilename); BOSS_ASSERT(document.HasMember("Experiments"), "No 'Experiments' member found"); const rapidjson::Value & experiments = document["Experiments"]; for (rapidjson::Value::ConstMemberIterator itr = experiments.MemberBegin(); itr != experiments.MemberEnd(); ++itr) { const std::string & name = itr->name.GetString(); const rapidjson::Value & val = itr->value; //std::cout << "Found Experiment: " << name << std::endl; BOSS_ASSERT(val.HasMember("Type") && val["Type"].IsString(), "Experiment has no 'Type' string"); if (val.HasMember("Run") && val["Run"].IsBool() && (val["Run"].GetBool() == true)) { const std::string & type = val["Type"].GetString(); if (type == "CombatSearch") { RunCombatExperiment(name, val); } else if (type == "BuildOrderPlot") { RunBuildOrderPlot(name, val); } else { BOSS_ASSERT(false, "Unknown Experiment Type: %s", type.c_str()); } } } std::cout << "\n\n"; } void Experiments::RunCombatExperiment(const std::string & name, const rapidjson::Value & val) { CombatSearchExperiment exp(name, val); exp.run(); } void Experiments::RunBuildOrderPlot(const std::string & name, const rapidjson::Value & val) { BOSSPlotBuildOrders plot(name, val); plot.doPlots(); } ================================================ FILE: BOSS/source/BOSSExperiments.h ================================================ #pragma once #include "Common.h" #include "JSONTools.h" #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace BOSS { namespace Experiments { void RunExperiments(const std::string & experimentFilename); void RunCombatExperiment(const std::string & name, const rapidjson::Value & val); void RunBuildOrderPlot(const std::string & name, const rapidjson::Value & val); } } ================================================ FILE: BOSS/source/BOSSLogger.cpp ================================================ #include "BOSSLogger.h" namespace BOSS { namespace Logger { void LogAppendToFile(const std::string & logFile, const std::string & msg) { std::ofstream logStream; logStream.open(logFile.c_str(), std::ofstream::app); logStream << msg; logStream.flush(); logStream.close(); } void LogOverwriteToFile(const std::string & logFile, const std::string & msg) { std::ofstream logStream(logFile.c_str()); logStream << msg; logStream.flush(); logStream.close(); } } } ================================================ FILE: BOSS/source/BOSSLogger.h ================================================ #pragma once #include #include #include namespace BOSS { namespace Logger { void LogAppendToFile(const std::string & logFile, const std::string & msg); void LogOverwriteToFile(const std::string & logFile, const std::string & msg); }; } ================================================ FILE: BOSS/source/BOSSParameters.cpp ================================================ #include "BOSSParameters.h" using namespace BOSS; BOSSParameters::BOSSParameters() { } BOSSParameters & BOSSParameters::Instance() { static BOSSParameters params; return params; } void BOSSParameters::ParseParameters(const std::string & configFile) { _configFile = configFile; rapidjson::Document document; JSONTools::ParseJSONFile(document, _configFile); BOSS_ASSERT(document.HasMember("States"), "No 'States' member found"); BOSS_ASSERT(document.HasMember("Build Orders"), "No 'Build Orders' member found"); // BOSS_ASSERT(document.HasMember("Build Order Search Goals"), "No 'Build Order Goals' member found"); // Parse all the States const rapidjson::Value & states = document["States"]; for (rapidjson::Value::ConstMemberIterator itr = states.MemberBegin(); itr != states.MemberEnd(); ++itr) { const std::string & name = itr->name.GetString(); const rapidjson::Value & val = itr->value; _stateMap[name] = JSONTools::GetGameState(val); } // Parse all the Build Orders const rapidjson::Value & buildOrders = document["Build Orders"]; for (rapidjson::Value::ConstMemberIterator itr = buildOrders.MemberBegin(); itr != buildOrders.MemberEnd(); ++itr) { const std::string & name = itr->name.GetString(); const rapidjson::Value & val = itr->value; _buildOrderMap[name] = JSONTools::GetBuildOrder(val); } // Parse all the Build Order Goals if (document.HasMember("Build Order Search Goals")) { const rapidjson::Value & buildOrderGoals = document["Build Order Search Goals"]; for (rapidjson::Value::ConstMemberIterator itr = buildOrderGoals.MemberBegin(); itr != buildOrderGoals.MemberEnd(); ++itr) { const std::string & name = itr->name.GetString(); const rapidjson::Value & val = itr->value; _buildOrderSearchGoalMap[name] = JSONTools::GetBuildOrderSearchGoal(val); } } } const GameState & BOSSParameters::GetState(const std::string & key) { BOSS_ASSERT(_stateMap.find(key) != _stateMap.end(), "Couldn't find state: %s", key.c_str()); return _stateMap[key]; } const BuildOrder & BOSSParameters::GetBuildOrder(const std::string & key) { BOSS_ASSERT(_buildOrderMap.find(key) != _buildOrderMap.end(), "Couldn't find build order: %s", key.c_str()); return _buildOrderMap[key]; } const BuildOrderSearchGoal & BOSSParameters::GetBuildOrderSearchGoalMap(const std::string & key) { BOSS_ASSERT(_buildOrderSearchGoalMap.find(key) != _buildOrderSearchGoalMap.end(), "Couldn't find state: %s", key.c_str()); return _buildOrderSearchGoalMap[key]; } ================================================ FILE: BOSS/source/BOSSParameters.h ================================================ #pragma once #include "BOSS.h" #include "JSONTools.h" #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" #include "CombatSearchExperiment.h" namespace BOSS { class BOSSParameters { std::string _configFile; std::map _stateMap; std::map _buildOrderMap; std::map _buildOrderSearchGoalMap; BOSSParameters(); public: static BOSSParameters & Instance(); void ParseParameters(const std::string & configFile); const GameState & GetState(const std::string & key); const BuildOrder & GetBuildOrder(const std::string & key); const BuildOrderSearchGoal & GetBuildOrderSearchGoalMap(const std::string & key); }; } ================================================ FILE: BOSS/source/BOSSPlotBuildOrders.cpp ================================================ #include "BOSSPlotBuildOrders.h" #include "BuildOrderPlot.h" #include "BOSSParameters.h" using namespace BOSS; BOSSPlotBuildOrders::BOSSPlotBuildOrders(const std::string & name, const rapidjson::Value & val) { BOSS_ASSERT(val.HasMember("Scenarios") && val["Scenarios"].IsArray(), "Experiment has no Scenarios array"); BOSS_ASSERT(val.HasMember("OutputDir") && val["OutputDir"].IsString(), "Experiment has no OutputFile string"); _outputDir = val["OutputDir"].GetString(); const rapidjson::Value & scenarios = val["Scenarios"]; for (size_t i(0); i < scenarios.Size(); ++i) { const rapidjson::Value & scenario = scenarios[i]; BOSS_ASSERT(scenario.HasMember("State") && scenario["State"].IsString(), "Scenario has no 'state' string"); BOSS_ASSERT(scenario.HasMember("BuildOrder") && scenario["BuildOrder"].IsString(), "Scenario has no 'buildOrder' string"); _states.push_back(BOSSParameters::Instance().GetState(scenario["State"].GetString())); _buildOrders.push_back(BOSSParameters::Instance().GetBuildOrder(scenario["BuildOrder"].GetString())); _buildOrderNames.push_back(scenario["BuildOrder"].GetString()); } } void BOSSPlotBuildOrders::doPlots() { for (size_t i(0); i < _buildOrders.size(); ++i) { BuildOrderPlot plot(_states[i], _buildOrders[i]); plot.writeRectanglePlot(_outputDir + _buildOrderNames[i] + ".gpl"); plot.writeArmyValuePlot(_outputDir + _buildOrderNames[i] + "_army"); plot.writeResourcePlot(_outputDir + _buildOrderNames[i] + "_resource"); } BuildOrderPlot allPlots(_states[0], _buildOrders[0]); for (size_t i(1); i < _buildOrders.size(); ++i) { BuildOrderPlot plot(_states[i], _buildOrders[i]); allPlots.addPlot(plot); } allPlots.writeRectanglePlot(_outputDir + "BOall"); } ================================================ FILE: BOSS/source/BOSSPlotBuildOrders.h ================================================ #pragma once #include "BOSS.h" #include "JSONTools.h" #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace BOSS { class BOSSPlotBuildOrders { std::vector _states; std::vector _buildOrders; std::vector _buildOrderNames; std::string _outputDir; public: BOSSPlotBuildOrders(const std::string & name, const rapidjson::Value & experimentVal); void doPlots(); }; } ================================================ FILE: BOSS/source/BOSS_main.cpp ================================================ #include "BOSS.h" #include "BOSSParameters.h" #include "BOSSExperiments.h" #include "CImg/CImg.h" using namespace BOSS; using namespace cimg_library; int main2() { CImg image("logo.bmp"); CImg visu(500,400,1,3,0); const unsigned char red[] = {255,0,0}; const unsigned char green[] = {0,255,0}; const unsigned char blue[] = {0,0,255}; image.blur(2.5); CImgDisplay main_disp(image,"Click a point"); CImgDisplay draw_disp(visu,"Intensity profile"); while (!main_disp.is_closed() && !draw_disp.is_closed()) { main_disp.wait(); if (main_disp.button() && main_disp.mouse_y()>=0) { const int y = main_disp.mouse_y(); visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.width()-1,y,0,0),red,1,1,0,255,0); visu.draw_graph(image.get_crop(0,y,0,1,image.width()-1,y,0,1),green,1,1,0,255,0); visu.draw_graph(image.get_crop(0,y,0,2,image.width()-1,y,0,2),blue,1,1,0,255,0).display(draw_disp); } } return 0; } int main(int argc, char *argv[]) { // Initialize all the BOSS internal data BOSS::init(); // Read in the config parameters that will be used for experiments BOSS::BOSSParameters::Instance().ParseParameters("BOSS_Config.txt"); // Run the experiments BOSS::Experiments::RunExperiments("BOSS_Config.txt"); return 0; } ================================================ FILE: BOSS/source/BaseTypes.h ================================================ #pragma once namespace BOSS { typedef int ResourceCountType; typedef int SupplyCountType; typedef int FrameCountType; typedef int UnitCountType; typedef int ActionID; typedef int RaceID; } ================================================ FILE: BOSS/source/BuildOrder.cpp ================================================ #include "BuildOrder.h" using namespace BOSS; BuildOrder::BuildOrder() : _typeCount(128, 0) { } void BuildOrder::add(const ActionType & type) { BOSS_ASSERT((_buildOrder.size() == 0) || (type.getRace() == _buildOrder.back().getRace()), "Cannot have a build order with multiple races"); _buildOrder.push_back(type); _typeCount[type.ID()]++; } void BuildOrder::add(const ActionType & type, const int & amount) { for (int i(0); i < amount; ++i) { add(type); } } void BuildOrder::add(const BuildOrder & other) { for (size_t i(0); i < other.size(); ++i) { add(other[i]); } } void BuildOrder::clear() { _buildOrder.clear(); _typeCount.clear(); } const bool BuildOrder::empty() const { return size() == 0; } void BuildOrder::sortByPrerequisites() { for (size_t i(0); i < _buildOrder.size()-1; ++i) { for (size_t j(i+1); j < _buildOrder.size(); ++j) { const PrerequisiteSet & recursivePre = _buildOrder[i].getRecursivePrerequisites(); if (recursivePre.contains(_buildOrder[j])) { std::swap(_buildOrder[i], _buildOrder[j]); } } } } const size_t BuildOrder::getTypeCount(const ActionType & type) const { if (empty()) { return 0; } BOSS_ASSERT(type.getRace() == _buildOrder[0].getRace(), "Trying to get type count of a different race type"); return _typeCount[type.ID()]; } void BuildOrder::pop_back() { _buildOrder.pop_back(); } const ActionType & BuildOrder::operator [] (const size_t & i) const { return _buildOrder[i]; } ActionType & BuildOrder::operator [] (const size_t & i) { return _buildOrder[i]; } const size_t BuildOrder::size() const { return _buildOrder.size(); } const bool BuildOrder::isLegalFromState(const GameState & state, size_t buildOrderStartIndex) const { GameState currentState(state); for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i) { if (!currentState.isLegal(_buildOrder[i])) { return false; } else { currentState.doAction(_buildOrder[i]); } } return true; } std::string BuildOrder::whyIsNotLegalFromState(const GameState & state, size_t buildOrderStartIndex) const { GameState currentState(state); for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i) { if (!currentState.isLegal(_buildOrder[i])) { std::stringstream ss; ss << "Build-Order item " << (i+1) << " can't be built.\n\n" << currentState.whyIsNotLegal(_buildOrder[i]); return ss.str(); } else { currentState.doAction(_buildOrder[i]); } } return "Legal"; } std::string BuildOrder::getJSONString() const { std::stringstream ss; ss << "\"Build Order\" : ["; for (size_t i(0); i < _buildOrder.size(); ++i) { ss << "\"" << _buildOrder[i].getName() << "\"" << (i < _buildOrder.size() - 1 ? ", " : ""); } ss << "]"; return ss.str(); } bool BuildOrder::doActions(GameState & state, const size_t buildOrderStartIndex, const size_t buildOrderEndIndex) const { BOSS_ASSERT(buildOrderEndIndex < _buildOrder.size(), "Can't have this end index"); for (size_t i(buildOrderStartIndex); i < buildOrderEndIndex; ++i) { if(!state.isLegal(_buildOrder[i])) { return false; } state.doAction(_buildOrder[i]); } return true; } // returns whether or not all the actions were legal bool BuildOrder::doActions(GameState & state, size_t buildOrderStartIndex) const { for (size_t i(buildOrderStartIndex); i < _buildOrder.size(); ++i) { if(!state.isLegal(_buildOrder[i])) { return false; } state.doAction(_buildOrder[i]); } return true; } const FrameCountType BuildOrder::getCompletionTime(const GameState & state, size_t buildOrderStartIndex) const { if (_buildOrder.size() == 0) { return state.getLastActionFinishTime(); } BOSS_ASSERT(buildOrderStartIndex < _buildOrder.size(), "We can't start at an index that's past the end"); GameState currentState(state); bool isLegal = doActions(currentState, buildOrderStartIndex); BOSS_ASSERT(isLegal, "Build order was not legal"); return currentState.getLastActionFinishTime(); } std::string BuildOrder::getNumberedString() const { std::stringstream ss; for (size_t i(0); i < _buildOrder.size(); ++i) { std::stringstream num; num << i; while (num.str().length() < 5) { num << " "; } ss << num.str() << _buildOrder[i].getName() << std::endl; } return ss.str(); } std::string BuildOrder::getIDString() const { std::stringstream ss; for (size_t i(0); i < _buildOrder.size(); ++i) { ss << (int)_buildOrder[i].ID() << " "; } return ss.str(); } std::string BuildOrder::getNameString(const size_t charactersPerName) const { std::stringstream ss; for (size_t i(0); i < _buildOrder.size(); ++i) { std::string name = charactersPerName == 0 ? _buildOrder[i].getShortName() : _buildOrder[i].getShortName().substr(0, charactersPerName); ss << name << " "; } return ss.str(); } ================================================ FILE: BOSS/source/BuildOrder.h ================================================ #pragma once #include "Common.h" #include "ActionType.h" #include "GameState.h" namespace BOSS { class BuildOrder { std::vector _buildOrder; std::vector _typeCount; public: BuildOrder(); void add(const ActionType & type); void add(const ActionType & type, const int & amount); void add(const BuildOrder & other); void clear(); void pop_back(); void sortByPrerequisites(); bool doActions(GameState & state, const size_t buildOrderStartIndex = 0) const; bool doActions(GameState & state, const size_t buildOrderStartIndex, const size_t buildOrderEndIndex) const; const ActionType & operator [] (const size_t & i) const; ActionType & operator [] (const size_t & i); const size_t size() const; const size_t getTypeCount(const ActionType & type) const; const bool isLegalFromState(const GameState & state, const size_t buildOrderStartIndex = 0) const; std::string whyIsNotLegalFromState(const GameState & state, const size_t buildOrderStartIndex = 0) const; const bool empty() const; const FrameCountType getCompletionTime(const GameState & state, const size_t buildOrderStartIndex = 0) const; std::string getJSONString() const; std::string getNumberedString() const; std::string getIDString() const; std::string getNameString(const size_t charactersPerName = 0) const; }; } ================================================ FILE: BOSS/source/BuildOrderPlot.cpp ================================================ #include "BuildOrderPlot.h" #include "Eval.h" using namespace BOSS; BuildOrderPlot::BuildOrderPlot(const GameState & initialState, const BuildOrder & buildOrder) : _initialState(initialState) , _buildOrder(buildOrder) , _boxHeight(20) , _boxHeightBuffer(3) , _maxLayer(0) , _maxFinishTime(0) { calculateStartEndTimes(); calculatePlot(); } void BuildOrderPlot::calculateStartEndTimes() { GameState state(_initialState); BOSS_ASSERT(_buildOrder.isLegalFromState(state), "Build order isn't legal!"); for (size_t i(0); i < _buildOrder.size(); ++i) { const ActionType & type = _buildOrder[i]; state.doAction(type); _startTimes.push_back(state.getCurrentFrame()); FrameCountType finish = state.getCurrentFrame() + type.buildTime(); if (type.isBuilding() && !type.isAddon() && !type.isMorphed()) { finish += Constants::BUILDING_PLACEMENT; } _finishTimes.push_back(finish); _maxFinishTime = std::max(_maxFinishTime, finish); _armyValues.push_back(Eval::ArmyTotalResourceSum(state)); std::pair mineralsBefore(state.getCurrentFrame(), state.getMinerals() + type.mineralPrice()); std::pair mineralsAfter(state.getCurrentFrame(), state.getMinerals()); std::pair gasBefore(state.getCurrentFrame(), state.getGas() + type.gasPrice()); std::pair gasAfter(state.getCurrentFrame(), state.getGas()); _minerals.push_back(mineralsBefore); _minerals.push_back(mineralsAfter); _gas.push_back(gasBefore); _gas.push_back(gasAfter); } } void BuildOrderPlot::calculatePlot() { _layers = std::vector(_startTimes.size(), -1); // determine the layers for each action for (size_t i(0); i < _startTimes.size(); ++i) { FrameCountType start = _startTimes[i]; FrameCountType finish = _finishTimes[i]; std::vector layerOverlap; // loop through everything up to this action and see which layers it can't be in for (size_t j(0); j < i; ++j) { if (start < _finishTimes[j]) { layerOverlap.push_back(_layers[j]); } } // find a layer we can assign to this value int layerTest = 0; while (true) { if (std::find(layerOverlap.begin(), layerOverlap.end(), layerTest) == layerOverlap.end()) { _layers[i] = layerTest; if (layerTest > _maxLayer) { _maxLayer = layerTest; } break; } layerTest++; } } for (size_t i(0); i < _buildOrder.size(); ++i) { Position topLeft(_startTimes[i], _layers[i] * (_boxHeight + _boxHeightBuffer)); Position bottomRight(_finishTimes[i], topLeft.y() + _boxHeight); _rectangles.push_back(Rectangle(_buildOrder[i].getShortName(), topLeft, bottomRight)); } } void BuildOrderPlot::addPlot(const BuildOrderPlot & plot) { _otherPlots.push_back(plot); } void BuildOrderPlot::writeResourcePlot(const std::string & filename) { std::string noext = RemoveFileExtension(filename); std::stringstream mineralss; for (size_t i(0); i < _minerals.size(); ++i) { mineralss << _minerals[i].first << " " << _minerals[i].second/Constants::RESOURCE_SCALE << std::endl; } std::stringstream gasss; for (size_t i(0); i < _gas.size(); ++i) { gasss << _gas[i].first << " " << _gas[i].second/Constants::RESOURCE_SCALE << std::endl; } WriteGnuPlot(noext + "_minerals", mineralss.str(), " with lines "); WriteGnuPlot(noext + "_gas", gasss.str(), " with lines "); } void BuildOrderPlot::writeRectanglePlot(const std::string & filename) { std::stringstream ss; int maxY = (_maxLayer + 1) * (_boxHeight + _boxHeightBuffer) + 15; for (size_t p(0); p < _otherPlots.size(); ++p) { maxY += (_otherPlots[p]._maxLayer + 2) * (_boxHeight + _boxHeightBuffer) + 15; } //ss << "set title \"Title Goes Here\"" << std::endl; //ss << "set xlabel \"Time (frames)\"" << std::endl; ss << "set style rect fc lt -1 fs transparent solid 0.15" << std::endl; ss << "set xrange [" << -(_maxFinishTime*.03) << ":" << 1.03*_maxFinishTime << "]" << std::endl; ss << "set yrange [-15:" << maxY << "]" << std::endl; ss << "unset ytics" << std::endl; ss << "set grid xtics" << std::endl; ss << "set nokey" << std::endl; //ss << "set size ratio " << (0.05 * _maxLayer) << std::endl; ss << "set terminal wxt size 960,300" << std::endl; ss << "plotHeight = " << 1000 << std::endl; ss << "boxHeight = " << _boxHeight << std::endl; ss << "boxHeightBuffer = " << _boxHeightBuffer << std::endl; ss << "boxWidthScale = " << 1.0 << std::endl; for (size_t i(0); i < _buildOrder.size(); ++i) { const Rectangle & rect = _rectangles[i]; const int rectWidth = (rect.bottomRight.x() - rect.topLeft.x()); const int rectCenterX = rect.bottomRight.x() - (rectWidth / 2); std::stringstream pos; pos << "(boxWidthScale * " << rectCenterX << "),"; pos << "((boxHeight + boxHeightBuffer) * " << _layers[i] << " + boxHeight/2)"; ss << "set object " << (i+1) << " rect at "; ss << pos.str(); ss << " size "; ss << "(boxWidthScale * " << (rectWidth) << "),"; ss << "(boxHeight) "; //ss << "(boxWidthScale * " << _finishTimes[i] << "),"; //ss << "((boxHeight + boxHeightBuffer) * " << _layers[i] << " + boxHeight) "; ss << "lw 1"; if (_buildOrder[i].isWorker()) { ss << " fc rgb \"cyan\""; } else if (_buildOrder[i].isSupplyProvider()) { ss << " fc rgb \"gold\""; } else if (_buildOrder[i].isRefinery()) { ss << " fc rgb \"green\""; } else if (_buildOrder[i].isBuilding()) { ss << " fc rgb \"brown\""; } else if (_buildOrder[i].isUpgrade()) { ss << " fc rgb \"purple\""; } else if (_buildOrder[i].isTech()) { ss << " fc rgb \"magenta\""; } ss << std::endl; ss << "set label " << (i+1) << " at " << pos.str() << " \"" << _buildOrder[i].getShortName() << "\" front center"; ss << std::endl; } int currentLayer = _maxLayer + 2; int currentObject = _buildOrder.size(); for (size_t p(0); p < _otherPlots.size(); ++p) { const BuildOrder & buildOrder = _otherPlots[p]._buildOrder; for (size_t i(0); i < buildOrder.size(); ++i) { const Rectangle & rect = _otherPlots[p]._rectangles[i]; const int rectWidth = (rect.bottomRight.x() - rect.topLeft.x()); const int rectCenterX = rect.bottomRight.x() - (rectWidth / 2); std::stringstream pos; pos << "(boxWidthScale * " << rectCenterX << "),"; pos << "((boxHeight + boxHeightBuffer) * " << (_otherPlots[p]._layers[i] + currentLayer) << " + boxHeight/2)"; ss << "set object " << (currentObject+i+1) << " rect at "; ss << pos.str(); ss << " size "; ss << "(boxWidthScale * " << (rectWidth) << "),"; ss << "(boxHeight) "; //ss << "(boxWidthScale * " << _finishTimes[i] << "),"; //ss << "((boxHeight + boxHeightBuffer) * " << _layers[i] << " + boxHeight) "; ss << "lw 1"; if (buildOrder[i].isWorker()) { ss << " fc rgb \"cyan\""; } else if (buildOrder[i].isSupplyProvider()) { ss << " fc rgb \"gold\""; } else if (buildOrder[i].isRefinery()) { ss << " fc rgb \"green\""; } else if (buildOrder[i].isBuilding()) { ss << " fc rgb \"brown\""; } else if (buildOrder[i].isUpgrade()) { ss << " fc rgb \"purple\""; } else if (buildOrder[i].isTech()) { ss << " fc rgb \"magenta\""; } ss << std::endl; ss << "set label " << (currentObject+i+1) << " at " << pos.str() << " \"" << buildOrder[i].getShortName() << "\" front center"; ss << std::endl; } currentLayer += _otherPlots[p]._maxLayer + 2; currentObject += buildOrder.size(); } ss << "plot -10000" << std::endl; std::ofstream out(filename); out << ss.str(); out.close(); } void BuildOrderPlot::writeArmyValuePlot(const std::string & filename) { std::stringstream datass; for (size_t i(0); i < _buildOrder.size(); ++i) { datass << _startTimes[i] << " " << _armyValues[i]/Constants::RESOURCE_SCALE << std::endl; } WriteGnuPlot(filename, datass.str(), " with steps"); } void BuildOrderPlot::WriteGnuPlot(const std::string & filename, const std::string & data, const std::string & args) { std::string file = RemoveFileExtension(GetFileNameFromPath(filename)); std::string noext = RemoveFileExtension(filename); std::ofstream dataout(noext + "_data.txt"); dataout << data; dataout.close(); std::stringstream ss; ss << "set xlabel \"Time (frames)\"" << std::endl; ss << "set ylabel \"Resource Over Time\"" << std::endl; ss << "plot \"" << (file + "_data.txt") << "\" " << args << std::endl; std::ofstream out(noext + ".gpl"); out << ss.str(); out.close(); } std::string BuildOrderPlot::GetFileNameFromPath(const std::string & path) { std::string temp(path); const size_t last_slash_idx = temp.find_last_of("\\/"); if (std::string::npos != last_slash_idx) { temp.erase(0, last_slash_idx + 1); } return temp; } std::string BuildOrderPlot::RemoveFileExtension(const std::string & path) { std::string temp(path); const size_t period_idx = temp.rfind('.'); if (std::string::npos != period_idx) { temp.erase(period_idx); } return temp; } ================================================ FILE: BOSS/source/BuildOrderPlot.h ================================================ #pragma once #include "Common.h" #include "ActionType.h" #include "GameState.h" #include "BuildOrder.h" #include "Position.hpp" namespace BOSS { class Rectangle { public: std::string labelText; Position topLeft; Position bottomRight; Rectangle(const std::string & label, Position & tl, const Position & br) : labelText(label), topLeft(tl), bottomRight(br) { } }; class BuildOrderPlot { const GameState _initialState; const BuildOrder _buildOrder; std::vector _startTimes; std::vector _finishTimes; std::vector _layers; std::vector _armyValues; std::vector< std::pair > _minerals; std::vector< std::pair > _gas; std::vector _rectangles; std::vector _otherPlots; int _maxLayer; int _maxFinishTime; int _boxHeight; int _boxHeightBuffer; void calculateStartEndTimes(); void calculatePlot(); public: BuildOrderPlot(const GameState & initialState, const BuildOrder & buildOrder); void writeResourcePlot(const std::string & filename); void writeRectanglePlot(const std::string & filename); void writeArmyValuePlot(const std::string & filename); void writeHybridPlot(const std::string & filename); void addPlot(const BuildOrderPlot & plot); static std::string GetFileNameFromPath(const std::string & path); static std::string RemoveFileExtension(const std::string & path); static void WriteGnuPlot(const std::string & filename, const std::string & data, const std::string & args); }; } ================================================ FILE: BOSS/source/BuildOrderSearchGoal.cpp ================================================ #include "BuildOrderSearchGoal.h" using namespace BOSS; BuildOrderSearchGoal::BuildOrderSearchGoal(const RaceID race) : _supplyRequiredVal(0) , _goalUnits(race != Races::None ? ActionTypes::GetAllActionTypes(race).size() : 0, 0) , _goalUnitsMax(race != Races::None ? ActionTypes::GetAllActionTypes(race).size() : 0, 0) , _race(race) { } void BuildOrderSearchGoal::calculateSupplyRequired() { _supplyRequiredVal = 0; for (ActionID a(0); a< (int)_goalUnits.size(); ++a) { _supplyRequiredVal += _goalUnits[a] * ActionTypes::GetActionType(_race, a).supplyRequired(); } } bool BuildOrderSearchGoal::operator == (const BuildOrderSearchGoal & g) { for (ActionID a(0); a< (int)_goalUnits.size(); ++a) { if ((_goalUnits[a] != g._goalUnits[a]) || (_goalUnitsMax[a] != g._goalUnitsMax[a])) { return false; } } return true; } void BuildOrderSearchGoal::setGoal(const ActionType & a, const UnitCountType num) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnits.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == _race, "Action type race doesn't match this goal object"); _goalUnits[a.ID()] = num; calculateSupplyRequired(); } bool BuildOrderSearchGoal::hasGoal() const { for (ActionID a(0); a< (int)_goalUnits.size(); ++a) { if (_goalUnits[a] > 0) { return true; } } return false; } void BuildOrderSearchGoal::setGoalMax(const ActionType & a, const UnitCountType num) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnitsMax.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == _race, "Action type race doesn't match this goal object"); _goalUnitsMax[a.ID()] = num; } UnitCountType BuildOrderSearchGoal::getGoal(const ActionType & a) const { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnits.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == _race, "Action type race doesn't match this goal object"); return _goalUnits[a.ID()]; } UnitCountType BuildOrderSearchGoal::getGoalMax(const ActionType & a) const { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)_goalUnitsMax.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == _race, "Action type race doesn't match this goal object"); return _goalUnitsMax[a.ID()]; } SupplyCountType BuildOrderSearchGoal::supplyRequired() const { return _supplyRequiredVal; } std::string BuildOrderSearchGoal::toString() const { std::stringstream ss; ss << "\nSearch Goal Information\n\n"; for (ActionID a(0); a< (int)_goalUnits.size(); ++a) { if (_goalUnits[a] > 0) { ss << " REQ " << _goalUnits[a] << " " << ActionTypes::GetActionType(_race, a).getName() << "\n"; } } for (ActionID a(0); a< (int)_goalUnitsMax.size(); ++a) { if (_goalUnitsMax[a] > 0) { ss << " MAX " << _goalUnitsMax[a] << " " << ActionTypes::GetActionType(_race, a).getName() << "\n"; } } return ss.str(); } bool BuildOrderSearchGoal::isAchievedBy(const GameState & state) { static const ActionType & Hatchery = ActionTypes::GetActionType("Zerg_Hatchery"); static const ActionType & Lair = ActionTypes::GetActionType("Zerg_Lair"); static const ActionType & Hive = ActionTypes::GetActionType("Zerg_Hive"); static const ActionType & Spire = ActionTypes::GetActionType("Zerg_Spire"); static const ActionType & GreaterSpire = ActionTypes::GetActionType("Zerg_Greater_Spire"); for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a); int have = state.getUnitData().getNumTotal(actionType); if (state.getRace() == Races::Zerg) { if (actionType == Hatchery) { have += state.getUnitData().getNumTotal(Lair); have += state.getUnitData().getNumTotal(Hive); } else if (actionType == Lair) { have += state.getUnitData().getNumTotal(Hive); } else if (actionType == Spire) { have += state.getUnitData().getNumTotal(GreaterSpire); } } if (have < getGoal(actionType)) { return false; } } return true; } ================================================ FILE: BOSS/source/BuildOrderSearchGoal.h ================================================ #pragma once #include "Common.h" #include "ActionType.h" #include "ActionSet.h" #include "GameState.h" namespace BOSS { class BuildOrderSearchGoal { std::vector _goalUnits; // vector of goal number of units indexed by ActionType ID std::vector _goalUnitsMax; // vector of goal max number of units indexed by ActionType ID SupplyCountType _supplyRequiredVal; // amount of supply required for all goal units in _goalUnits RaceID _race; // race of the action types in the goal void calculateSupplyRequired(); public: BuildOrderSearchGoal(const RaceID race = Races::None); bool operator == (const BuildOrderSearchGoal & g); bool hasGoal() const; bool isAchievedBy(const GameState & state); SupplyCountType supplyRequired() const; UnitCountType operator [] (const ActionID & a) const; UnitCountType getGoal(const ActionType & a) const; UnitCountType getGoalMax(const ActionType & a) const; void setGoal(const ActionType & a, const UnitCountType num); void setGoalMax(const ActionType & a, const UnitCountType num); std::string toString() const; }; } ================================================ FILE: BOSS/source/BuildOrderTester.cpp ================================================ #include "BuildOrderTester.h" #include "JSONTools.h" #include "NaiveBuildOrderSearch.h" using namespace BOSS; BuildOrderSearchGoal BuildOrderTester::GetRandomGoal(const RaceID race) { BuildOrderSearchGoal goal(race); const std::vector & allActionTypes = ActionTypes::GetAllActionTypes(race); size_t totalActionTypes = allActionTypes.size(); size_t numUnits = 6; size_t maxOfUnit = 5; for (size_t i(0); i < numUnits; ++i) { const ActionType randomAction = allActionTypes[rand() % totalActionTypes]; if (randomAction.getUnitType() == BWAPI::UnitTypes::Protoss_Dark_Archon || randomAction.getUnitType() == BWAPI::UnitTypes::Protoss_Archon || randomAction.getUnitType() == BWAPI::UnitTypes::Zerg_Larva) { continue; } int numToAdd = rand() % maxOfUnit; if (randomAction.isUnit() && !randomAction.isRefinery()) { goal.setGoal(randomAction, numToAdd); } else { goal.setGoal(randomAction, 1); } } return goal; } void BuildOrderTester::TestRandomBuilds(const RaceID race, const size_t numTests) { for (size_t i(0); i < numTests; ++i) { GameState state = GetStartState(race, 20); } } GameState BuildOrderTester::GetStartState(const RaceID race, int randomActions) { GameState state(race); state.setStartingState(); GameState copyState(state); BuildOrder randomBuildOrder; int i = 0; //try { for (i = 0; i < randomActions; ++i) { ActionSet legalActions; state.getAllLegalActions(legalActions); if (legalActions.isEmpty()) { std::cout << i << " Legal Actions Empty!" << std::endl; std::cout << randomBuildOrder.getNumberedString() << std::endl; std::cout << state.toString() << std::endl; } ActionType randomAction = legalActions[rand() % legalActions.size()]; if (!randomAction.isResourceDepot()) { BOSS_ASSERT(state.isLegal(randomAction), "Should be a legal action!"); randomBuildOrder.add(randomAction); state.doAction(randomAction); } } } /*catch (Assert::BOSSException e) { std::cout << std::endl << "Random State Error @ " << i << ": " << randomBuildOrder[i-1].getName() << std::endl << std::endl; std::cout << randomBuildOrder.getJSONString() << std::endl; std::cout << randomBuildOrder.getNumberedString() << std::endl; std::cout << state.toString() << std::endl; for (size_t a(0); a < randomBuildOrder.size(); ++a) { std::cout << "About to do: " << randomBuildOrder[a].getName() << std::endl; std::cout << copyState.toString() << std::endl; copyState.doAction(randomBuildOrder[a]); } randomBuildOrder.doActions(copyState, 0, randomBuildOrder.size()-1); std::cout << copyState.toString(); copyState.doAction(randomBuildOrder[randomBuildOrder.size()-1]); exit(-1); }*/ return state; } void BuildOrderTester::DoRandomTests(const RaceID race, const size_t numTests) { GameState startState(race); startState.setStartingState(); srand((int)time(NULL)); for (size_t i(0); i < numTests; ++i) { if (i && !(i % 100000)) { std::cout << Races::GetRaceName(race) << " " << i << std::endl; } //GameState startState = GetStartState(race, 20); BuildOrderSearchGoal goal = GetRandomGoal(race); NaiveBuildOrderSearch naiveSearch(startState, goal); const BuildOrder & buildOrder = naiveSearch.solve(); GameState currentState(startState); bool buildOrderIsLegal = buildOrder.doActions(currentState); if (buildOrderIsLegal) { if (goal.isAchievedBy(currentState)) { //std::cout << i << " Test Passed!" << std::endl; } else { std::cout << goal.toString(); for (size_t a(0); a < buildOrder.size(); ++a) { std::cout << a << " " << buildOrder[a].getName() << std::endl; } std::cout << i << " Found build order did not meet goal" << std::endl; std::cout << buildOrder.getJSONString() << std::endl; std::cout << currentState.toString() << std::endl; std::cout << goal.toString(); } } else { std::cout << goal.toString(); for (size_t a(0); a < buildOrder.size(); ++a) { std::cout << a << " " << buildOrder[a].getName() << std::endl; } std::cout << buildOrder.getJSONString() << std::endl; std::cout << i << " Found build-order was not legal" << std::endl; std::cout << currentState.toString() << std::endl; } } } ================================================ FILE: BOSS/source/BuildOrderTester.h ================================================ #pragma once #include "BOSS.h" namespace BOSS { namespace BuildOrderTester { GameState GetStartState(const RaceID race, int randomActions); BuildOrderSearchGoal GetRandomGoal(const RaceID race); void DoRandomTests(const RaceID race, const size_t numTests); void TestRandomBuilds(const RaceID race, const size_t numTests); } } ================================================ FILE: BOSS/source/BuildingData.cpp ================================================ #include "BuildingData.h" using namespace BOSS; BuildingStatus::BuildingStatus() : _type(ActionTypes::None) , _timeRemaining(0) , _isConstructing(ActionTypes::None) , _addon(ActionTypes::None) { } BuildingStatus::BuildingStatus(const ActionType & action, const ActionType & addon) : _type(action) , _timeRemaining(0) , _isConstructing(ActionTypes::None) , _addon(addon) { } BuildingStatus::BuildingStatus(const ActionType & action, FrameCountType time, const ActionType & constructing, const ActionType & addon) : _type(action) , _timeRemaining(time) , _isConstructing(constructing) , _addon(addon) { } const bool BuildingStatus::canBuildEventually(const ActionType & action) const { if (!_type.canBuild(action)) { return false; } // if the type is an addon if (action.isAddon()) { // if we already have an addon we can't build it if (_addon != ActionTypes::None) { return false; } // if we are building an addon we can't ever build it if (_timeRemaining > 0 && _isConstructing.isAddon()) { return false; } } if (action.requiresAddon() && (_addon != action.requiredAddonType())) { if (_isConstructing != action.requiredAddonType()) { return false; } } // if the built type is morphed and we are morphing something, we won't be able to build it if (action.isMorphed() && (_timeRemaining > 0) && (_isConstructing.isMorphed())) { return false; } return true; } const bool BuildingStatus::canBuildNow(const ActionType & action) const { if (_timeRemaining > 0) { return false; } if (!_type.canBuild(action)) { return false; } if (action.isAddon() && (_addon != ActionTypes::None)) { return false; } if (action.requiresAddon() && (_addon != action.requiredAddonType())) { return false; } return true; } void BuildingStatus::queueActionType(const ActionType & action) { _timeRemaining = action.buildTime(); _isConstructing = action; } void BuildingStatus::fastForward(const FrameCountType frames) { // if we fastforward more than the current time remaining, we will complete the action bool willComplete = _timeRemaining <= frames; int timeWasRemaining = _timeRemaining; const std::string & name = _type.getName(); if ((_timeRemaining > 0) && willComplete) { BOSS_ASSERT(_isConstructing != ActionTypes::None, "We can't be building a unit without a type %s %d", _type.getName().c_str(), timeWasRemaining); _timeRemaining = 0; // if it's building an addon, add it if (_isConstructing.isAddon()) { _addon = _isConstructing; } // if we are finishing a morphed type, it becomes that type if (_isConstructing.isMorphed()) { _type = _isConstructing; } _isConstructing = ActionTypes::None; } else if (_timeRemaining > 0) { _timeRemaining -= frames; } } BuildingData::BuildingData() { } const size_t & BuildingData::size() const { return _buildings.size(); } void BuildingData::addBuilding(const ActionType & action, const ActionType & addon) { BOSS_ASSERT(action.isBuilding(), "Trying to add a non-building to the building data"); _buildings.push_back(BuildingStatus(action, addon)); } void BuildingData::removeBuilding(const ActionType & action, const ActionType & addon) { BOSS_ASSERT(action.isBuilding(), "Trying to remove a non-building from the building data"); for (size_t i = 0; i < _buildings.size(); i++) { if (_buildings[i]._type == action) { _buildings.remove(i); break; } } } void BuildingData::addBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon) { BOSS_ASSERT(action.isBuilding(), "Trying to add a non-building to the building data"); _buildings.push_back(BuildingStatus(action, timeUntilFree, constructing, addon)); } const BuildingStatus & BuildingData::getBuilding(const UnitCountType i) const { return _buildings[i]; } // how long from now until we can build the given action const FrameCountType BuildingData::getTimeUntilCanBuild(const ActionType & action) const { bool minset = false; FrameCountType min = 0; for (size_t i=0; i<_buildings.size(); ++i) { if (_buildings[i].canBuildEventually(action)) { if (!minset || _buildings[i]._timeRemaining < min) { minset = true; min = _buildings[i]._timeRemaining; } } } BOSS_ASSERT(minset, "Min was not set"); return min; } void BuildingData::queueAction(const ActionType & action) { for (size_t i=0; i<_buildings.size(); ++i) { if (_buildings[i].canBuildNow(action)) { _buildings[i].queueActionType(action); return; } } // this method should always work since we have fast forwarded to the correct point in time BOSS_ASSERT(false, "Didn't find a building to queue this type of unit in: %s", action.getName().c_str()); } // fast forward all the building states by amount: frames void BuildingData::fastForwardBuildings(const FrameCountType frames) { for (size_t i=0; i<_buildings.size(); ++i) { _buildings[i].fastForward(frames); } } std::string BuildingData::toString() const { std::stringstream ss; ss << "Buildings\n\n"; for (size_t i=0; i<_buildings.size(); ++i) { const BuildingStatus & b = _buildings[i]; ss << b._type.getName() << " "; ss << b._timeRemaining << " "; ss << (b._isConstructing != ActionTypes::None ? b._isConstructing.getName() : "None") << " "; ss << (b._addon != ActionTypes::None ? b._addon.getName() : "None") << "\n"; } return ss.str(); } const bool BuildingData::canBuildNow(const ActionType & action) const { for (size_t i=0; i<_buildings.size(); ++i) { if (_buildings[i].canBuildNow(action)) { return true; } } return false; } const bool BuildingData::canBuildEventually(const ActionType & action) const { for (size_t i=0; i<_buildings.size(); ++i) { if (_buildings[i].canBuildEventually(action)) { return true; } } return false; } void BuildingData::printBuildingInformation() const { for (size_t i=0; i<_buildings.size(); ++i) { if (_buildings[i]._timeRemaining == 0) { printf("BUILDING INFO: %s is free to assign\n", _buildings[i]._type.getName().c_str()); } else { printf("BUILDING INFO: %s will be free in %d frames\n", _buildings[i]._type.getName().c_str(), _buildings[i]._timeRemaining); } } printf("-----------------------------------------------------------\n\n"); } ================================================ FILE: BOSS/source/BuildingData.h ================================================ #pragma once #include "Common.h" #include #include #include #include "PrerequisiteSet.h" #include "Array.hpp" #include "ActionType.h" namespace BOSS { class BuildingStatus { public: ActionType _type; // the type of building this is FrameCountType _timeRemaining; // amount of time until the unit is finished constructing ActionType _isConstructing; // the type of unit the building is currently constructing ActionType _addon; // the type of addon that the building currently has (is set once completed) // the number of frames remaining (from currentFrame) until this building is free BuildingStatus(); BuildingStatus(const ActionType & t, const ActionType & addon); BuildingStatus(const ActionType & t, FrameCountType time, const ActionType & constructing, const ActionType & addon); const bool canBuildNow(const ActionType & action) const; const bool canBuildEventually(const ActionType & action) const; void queueActionType(const ActionType & action); void fastForward(const FrameCountType frames); const std::string toString() const; }; class BuildingData { Vec _buildings; public: BuildingData(); void addBuilding(const ActionType & action, const ActionType & addon); void removeBuilding(const ActionType & action, const ActionType & addon); void addBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon); const BuildingStatus & getBuilding(const UnitCountType i) const; const FrameCountType getTimeUntilCanBuild(const ActionType & action) const; // queue an action void queueAction(const ActionType & action); void fastForwardBuildings(const FrameCountType frames); void printBuildingInformation() const; const size_t & size() const; const bool canBuildNow(const ActionType & action) const; const bool canBuildEventually(const ActionType & action) const; std::string toString() const; }; } ================================================ FILE: BOSS/source/CImg/CImg.h ================================================ /* # # File : CImg.h # ( C++ header file ) # # Description : The C++ Template Image Processing Toolkit. # This file is the main component of the CImg Library project. # ( http://cimg.eu ) # # Project manager : David Tschumperle. # ( http://tschumperle.users.greyc.fr/ ) # # A complete list of contributors is available in file 'README.txt' # distributed within the CImg package. # # Licenses : This file is 'dual-licensed', you have to choose one # of the two licenses below to apply. # # CeCILL-C # The CeCILL-C license is close to the GNU LGPL. # ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html ) # # or CeCILL v2.0 # The CeCILL license is compatible with the GNU GPL. # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) # # This software is governed either by the CeCILL or the CeCILL-C license # under French law and abiding by the rules of distribution of free software. # You can use, modify and or redistribute the software under the terms of # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA # at the following URL: "http://www.cecill.info". # # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited # liability. # # In this respect, the user's attention is drawn to the risks associated # with loading, using, modifying and/or developing or reproducing the # software by the user in light of its specific status of free software, # that may mean that it is complicated to manipulate, and that also # therefore means that it is reserved for developers and experienced # professionals having in-depth computer knowledge. Users are therefore # encouraged to load and test the software's suitability as regards their # requirements in conditions enabling the security of their systems and/or # data to be ensured and, more generally, to use and operate it in the # same conditions as regards security. # # The fact that you are presently reading this means that you have had # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms. # */ // Set version number of the library. #ifndef cimg_version #define cimg_version 171 /*----------------------------------------------------------- # # Test and possibly auto-set CImg configuration variables # and include required headers. # # If you find that the default configuration variables are # not adapted to your system, you can override their values # before including the header file "CImg.h" # (use the #define directive). # ------------------------------------------------------------*/ // Include standard C++ headers. // This is the minimal set of required headers to make CImg-based codes compile. #include #include #include #include #include #include #include #include #include // Detect/configure OS variables. // // Define 'cimg_OS' to: '0' for an unknown OS (will try to minize library dependencies). // '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...). // '2' for Microsoft Windows. // (auto-detection is performed if 'cimg_OS' is not set by the user). #ifndef cimg_OS #if defined(unix) || defined(__unix) || defined(__unix__) \ || defined(linux) || defined(__linux) || defined(__linux__) \ || defined(sun) || defined(__sun) \ || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined (__DragonFly__) \ || defined(sgi) || defined(__sgi) \ || defined(__MACOSX__) || defined(__APPLE__) \ || defined(__CYGWIN__) #define cimg_OS 1 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) #define cimg_OS 2 #else #define cimg_OS 0 #endif #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2) #error CImg Library: Invalid configuration variable 'cimg_OS'. #error (correct values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows'). #endif // Disable silly warnings on some Microsoft VC++ compilers. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) #pragma warning(disable:4244) #pragma warning(disable:4311) #pragma warning(disable:4312) #pragma warning(disable:4512) #pragma warning(disable:4571) #pragma warning(disable:4640) #pragma warning(disable:4706) #pragma warning(disable:4710) #pragma warning(disable:4800) #pragma warning(disable:4804) #pragma warning(disable:4820) #pragma warning(disable:4996) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_SECURE_NO_WARNINGS 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif // Define correct string functions for each compiler and OS. #if cimg_OS==2 && defined(_MSC_VER) #define cimg_sscanf std::sscanf #define cimg_sprintf std::sprintf #define cimg_snprintf cimg::_snprintf #define cimg_vsnprintf cimg::_vsnprintf #else #include #if defined(__MACOSX__) || defined(__APPLE__) #define cimg_sscanf cimg::_sscanf #define cimg_sprintf cimg::_sprintf #define cimg_snprintf cimg::_snprintf #define cimg_vsnprintf cimg::_vsnprintf #else #define cimg_sscanf std::sscanf #define cimg_sprintf std::sprintf #define cimg_snprintf snprintf #define cimg_vsnprintf vsnprintf #endif #endif // Include OS-specific headers. #if cimg_OS==1 #include #include #include #include #include #include #elif cimg_OS==2 #ifndef NOMINMAX #define NOMINMAX #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #ifndef _WIN32_IE #define _WIN32_IE 0x0400 #endif #include #include #include #endif // Look for C++11 features. #if !defined(cimg_use_cpp11) && __cplusplus>201100 #define cimg_use_cpp11 1 #endif #if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 #include #include #endif // Define own types 'cimg_long/ulong' and 'cimg_int64/uint64' to ensure portability. // ( constrained to 'sizeof(cimg_ulong/cimg_long) = sizeof(void*)' and 'sizeof(cimg_int64/cimg_uint64)=8' ). #if cimg_OS==2 #define cimg_uint64 unsigned __int64 #define cimg_int64 __int64 #define cimg_ulong UINT_PTR #define cimg_long INT_PTR #else #if UINTPTR_MAX==0xffffffff #define cimg_uint64 unsigned long long #define cimg_int64 long long #else #define cimg_uint64 unsigned long #define cimg_int64 long #endif #define cimg_ulong unsigned long #define cimg_long long #endif // Configure the 'abort' signal handler (does nothing by default). // A typical signal handler can be defined in your own source like this: // Without OpenMP support: #define cimg_test_abort() if (is_abort) throw CImgAbortException("") // // or // // With OpenMP support: #define cimg_test_abort() if (!omp_get_thread_num() && is_abort) throw CImgAbortException("") // // where 'is_abort' is a boolean variable. #ifndef cimg_test_abort #define cimg_test_abort() #endif // Configure filename separator. // // Filename separator is set by default to '/', except for Windows where it is '\'. #ifndef cimg_file_separator #if cimg_OS==2 #define cimg_file_separator '\\' #else #define cimg_file_separator '/' #endif #endif // Configure verbosity of output messages. // // Define 'cimg_verbosity' to: '0' to hide library messages (quiet mode). // '1' to output library messages on the console. // '2' to output library messages on a basic dialog window (default behavior). // '3' to do as '1' + add extra warnings (may slow down the code!). // '4' to do as '2' + add extra warnings (may slow down the code!). // // Define 'cimg_strict_warnings' to replace warning messages by exception throwns. // // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals. #ifndef cimg_verbosity #if cimg_OS==2 #define cimg_verbosity 2 #else #define cimg_verbosity 1 #endif #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4) #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined. #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }). #endif // Configure display framework. // // Define 'cimg_display' to: '0' to disable display capabilities. // '1' to use the X-Window framework (X11). // '2' to use the Microsoft GDI32 framework. #ifndef cimg_display #if cimg_OS==0 #define cimg_display 0 #elif cimg_OS==1 #define cimg_display 1 #elif cimg_OS==2 #define cimg_display 2 #endif #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2) #error CImg Library: Configuration variable 'cimg_display' is badly defined. #error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }). #endif // Include display-specific headers. #if cimg_display==1 #include #include #include #include #ifdef cimg_use_xshm #include #include #include #endif #ifdef cimg_use_xrandr #include #endif #endif #ifndef cimg_appname #define cimg_appname "CImg" #endif // Configure OpenMP support. // (http://www.openmp.org) // // Define 'cimg_use_openmp' to enable OpenMP support. // // OpenMP directives may be used in a (very) few CImg functions to get // advantages of multi-core CPUs. #ifdef cimg_use_openmp #include #endif // Configure OpenCV support. // (http://opencv.willowgarage.com/wiki/) // // Define 'cimg_use_opencv' to enable OpenCV support. // // OpenCV library may be used to access images from cameras // (see method 'CImg::load_camera()'). #ifdef cimg_use_opencv #ifdef True #undef True #define _cimg_redefine_True #endif #ifdef False #undef False #define _cimg_redefine_False #endif #include #include "cv.h" #include "highgui.h" #endif // Configure LibPNG support. // (http://www.libpng.org) // // Define 'cimg_use_png' to enable LibPNG support. // // PNG library may be used to get a native support of '.png' files. // (see methods 'CImg::{load,save}_png()'. #ifdef cimg_use_png extern "C" { #include "png.h" } #endif // Configure LibJPEG support. // (http://en.wikipedia.org/wiki/Libjpeg) // // Define 'cimg_use_jpeg' to enable LibJPEG support. // // JPEG library may be used to get a native support of '.jpg' files. // (see methods 'CImg::{load,save}_jpeg()'). #ifdef cimg_use_jpeg extern "C" { #include "jpeglib.h" #include "setjmp.h" } #endif // Configure LibTIFF support. // (http://www.libtiff.org) // // Define 'cimg_use_tiff' to enable LibTIFF support. // // TIFF library may be used to get a native support of '.tif' files. // (see methods 'CImg[List]::{load,save}_tiff()'). #ifdef cimg_use_tiff extern "C" { #define uint64 uint64_hack_ #define int64 int64_hack_ #include "tiffio.h" #undef uint64 #undef int64 } #endif // Configure LibMINC2 support. // (http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference) // // Define 'cimg_use_minc2' to enable LibMINC2 support. // // MINC2 library may be used to get a native support of '.mnc' files. // (see methods 'CImg::{load,save}_minc2()'). #ifdef cimg_use_minc2 #include "minc_io_simple_volume.h" #include "minc_1_simple.h" #include "minc_1_simple_rw.h" #endif // Configure Zlib support. // (http://www.zlib.net) // // Define 'cimg_use_zlib' to enable Zlib support. // // Zlib library may be used to allow compressed data in '.cimgz' files // (see methods 'CImg[List]::{load,save}_cimg()'). #ifdef cimg_use_zlib extern "C" { #include "zlib.h" } #endif // Configure libcurl support. // (http://curl.haxx.se/libcurl/) // // Define 'cimg_use_curl' to enable libcurl support. // // Libcurl may be used to get a native support of file downloading from the network. // (see method 'cimg::load_network()'.) #ifdef cimg_use_curl #include "curl/curl.h" #endif // Configure Magick++ support. // (http://www.imagemagick.org/Magick++) // // Define 'cimg_use_magick' to enable Magick++ support. // // Magick++ library may be used to get a native support of various image file formats. // (see methods 'CImg::{load,save}()'). #ifdef cimg_use_magick #include "Magick++.h" #endif // Configure FFTW3 support. // (http://www.fftw.org) // // Define 'cimg_use_fftw3' to enable libFFTW3 support. // // FFTW3 library may be used to efficiently compute the Fast Fourier Transform // of image data, without restriction on the image size. // (see method 'CImg[List]::FFT()'). #ifdef cimg_use_fftw3 extern "C" { #include "fftw3.h" } #endif // Configure LibBoard support. // (http://libboard.sourceforge.net/) // // Define 'cimg_use_board' to enable Board support. // // Board library may be used to draw 3d objects in vector-graphics canvas // that can be saved as '.ps' or '.svg' files afterwards. // (see method 'CImg::draw_object3d()'). #ifdef cimg_use_board #ifdef None #undef None #define _cimg_redefine_None #endif #include "Board.h" #endif // Configure OpenEXR support. // (http://www.openexr.com/) // // Define 'cimg_use_openexr' to enable OpenEXR support. // // OpenEXR library may be used to get a native support of '.exr' files. // (see methods 'CImg::{load,save}_exr()'). #ifdef cimg_use_openexr #include "ImfRgbaFile.h" #include "ImfInputFile.h" #include "ImfChannelList.h" #include "ImfMatrixAttribute.h" #include "ImfArray.h" #endif // Lapack configuration. // (http://www.netlib.org/lapack) // // Define 'cimg_use_lapack' to enable LAPACK support. // // Lapack library may be used in several CImg methods to speed up // matrix computations (eigenvalues, inverse, ...). #ifdef cimg_use_lapack extern "C" { extern void sgetrf_(int*, int*, float*, int*, int*, int*); extern void sgetri_(int*, float*, int*, int*, float*, int*, int*); extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*); extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*); extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*); extern void dgetrf_(int*, int*, double*, int*, int*, int*); extern void dgetri_(int*, double*, int*, int*, double*, int*, int*); extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*); extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*); extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*); extern void dgels_(char*, int*,int*,int*,double*,int*,double*,int*,double*,int*,int*); extern void sgels_(char*, int*,int*,int*,float*,int*,float*,int*,float*,int*,int*); } #endif // Check if min/max/PI macros are defined. // // CImg does not compile if macros 'min', 'max' or 'PI' are defined, // because it redefines functions min(), max() and const variable PI in the cimg:: namespace. // so it '#undef' these macros if necessary, and restore them to reasonable // values at the end of this file. #ifdef min #undef min #define _cimg_redefine_min #endif #ifdef max #undef max #define _cimg_redefine_max #endif #ifdef PI #undef PI #define _cimg_redefine_PI #endif // Define 'cimg_library' namespace suffix. // // You may want to add a suffix to the 'cimg_library' namespace, for instance if you need to work // with several versions of the library at the same time. #ifdef cimg_namespace_suffix #define __cimg_library_suffixed(s) cimg_library_##s #define _cimg_library_suffixed(s) __cimg_library_suffixed(s) #define cimg_library_suffixed _cimg_library_suffixed(cimg_namespace_suffix) #else #define cimg_library_suffixed cimg_library #endif /*------------------------------------------------------------------------------ # # Define user-friendly macros. # # These CImg macros are prefixed by 'cimg_' and can be used safely in your own # code. They are useful to parse command line options, or to write image loops. # ------------------------------------------------------------------------------*/ // Macros to define program usage, and retrieve command line arguments. #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false) #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0) #define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage) // Macros to define and manipulate local neighborhoods. #define CImg_2x2(I,T) T I[4]; \ T& I##cc = I[0]; T& I##nc = I[1]; \ T& I##cn = I[2]; T& I##nn = I[3]; \ I##cc = I##nc = \ I##cn = I##nn = 0 #define CImg_3x3(I,T) T I[9]; \ T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \ T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \ T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \ I##pp = I##cp = I##np = \ I##pc = I##cc = I##nc = \ I##pn = I##cn = I##nn = 0 #define CImg_4x4(I,T) T I[16]; \ T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \ T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \ T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \ T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \ I##pp = I##cp = I##np = I##ap = \ I##pc = I##cc = I##nc = I##ac = \ I##pn = I##cn = I##nn = I##an = \ I##pa = I##ca = I##na = I##aa = 0 #define CImg_5x5(I,T) T I[25]; \ T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \ T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \ T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \ T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \ T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \ I##bb = I##pb = I##cb = I##nb = I##ab = \ I##bp = I##pp = I##cp = I##np = I##ap = \ I##bc = I##pc = I##cc = I##nc = I##ac = \ I##bn = I##pn = I##cn = I##nn = I##an = \ I##ba = I##pa = I##ca = I##na = I##aa = 0 #define CImg_2x2x2(I,T) T I[8]; \ T& I##ccc = I[0]; T& I##ncc = I[1]; \ T& I##cnc = I[2]; T& I##nnc = I[3]; \ T& I##ccn = I[4]; T& I##ncn = I[5]; \ T& I##cnn = I[6]; T& I##nnn = I[7]; \ I##ccc = I##ncc = \ I##cnc = I##nnc = \ I##ccn = I##ncn = \ I##cnn = I##nnn = 0 #define CImg_3x3x3(I,T) T I[27]; \ T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \ T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \ T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \ T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \ T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \ T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \ T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \ T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \ T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \ I##ppp = I##cpp = I##npp = \ I##pcp = I##ccp = I##ncp = \ I##pnp = I##cnp = I##nnp = \ I##ppc = I##cpc = I##npc = \ I##pcc = I##ccc = I##ncc = \ I##pnc = I##cnc = I##nnc = \ I##ppn = I##cpn = I##npn = \ I##pcn = I##ccn = I##ncn = \ I##pnn = I##cnn = I##nnn = 0 #define cimg_get2x2(img,x,y,z,c,I,T) \ I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \ I[3] = (T)(img)(_n1##x,_n1##y,z,c) #define cimg_get3x3(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \ I[3] = (T)(img)(_p1##x,y,z,c), I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), \ I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), I[8] = (T)(img)(_n1##x,_n1##y,z,c) #define cimg_get4x4(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \ I[3] = (T)(img)(_n2##x,_p1##y,z,c), I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), \ I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), I[8] = (T)(img)(_p1##x,_n1##y,z,c), \ I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \ I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), \ I[15] = (T)(img)(_n2##x,_n2##y,z,c) #define cimg_get5x5(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \ I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), \ I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), I[8] = (T)(img)(_n1##x,_p1##y,z,c), \ I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \ I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), \ I[15] = (T)(img)(_p2##x,_n1##y,z,c), I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), \ I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), I[20] = (T)(img)(_p2##x,_n2##y,z,c), \ I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \ I[24] = (T)(img)(_n2##x,_n2##y,z,c) #define cimg_get6x6(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \ I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), \ I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), I[8] = (T)(img)(x,_p1##y,z,c), \ I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \ I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), \ I[15] = (T)(img)(_n1##x,y,z,c), I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), \ I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), I[20] = (T)(img)(x,_n1##y,z,c), \ I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \ I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), \ I[27] = (T)(img)(_n1##x,_n2##y,z,c), I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), \ I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), I[32] = (T)(img)(x,_n3##y,z,c), \ I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c) #define cimg_get7x7(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \ I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \ I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), I[8] = (T)(img)(_p2##x,_p2##y,z,c), \ I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \ I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), \ I[15] = (T)(img)(_p2##x,_p1##y,z,c), I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), \ I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), I[20] = (T)(img)(_n3##x,_p1##y,z,c), \ I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \ I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), \ I[27] = (T)(img)(_n3##x,y,z,c), I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), \ I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), I[32] = (T)(img)(_n1##x,_n1##y,z,c), \ I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \ I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), \ I[39] = (T)(img)(_n1##x,_n2##y,z,c), I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), \ I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), I[44] = (T)(img)(_p1##x,_n3##y,z,c), \ I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \ I[48] = (T)(img)(_n3##x,_n3##y,z,c) #define cimg_get8x8(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \ I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \ I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), I[8] = (T)(img)(_p3##x,_p2##y,z,c), \ I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \ I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), \ I[15] = (T)(img)(_n4##x,_p2##y,z,c), I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), \ I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), I[20] = (T)(img)(_n1##x,_p1##y,z,c), \ I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \ I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), \ I[27] = (T)(img)(x,y,z,c), I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), \ I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), I[32] = (T)(img)(_p3##x,_n1##y,z,c), \ I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \ I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), \ I[39] = (T)(img)(_n4##x,_n1##y,z,c), I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), \ I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), I[44] = (T)(img)(_n1##x,_n2##y,z,c), \ I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \ I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), \ I[51] = (T)(img)(x,_n3##y,z,c), I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), \ I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), I[56] = (T)(img)(_p3##x,_n4##y,z,c), \ I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \ I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), \ I[63] = (T)(img)(_n4##x,_n4##y,z,c); #define cimg_get9x9(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), \ I[3] = (T)(img)(_p1##x,_p4##y,z,c), I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), \ I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), I[8] = (T)(img)(_n4##x,_p4##y,z,c), \ I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \ I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), \ I[15] = (T)(img)(_n2##x,_p3##y,z,c), I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), \ I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), I[20] = (T)(img)(_p2##x,_p2##y,z,c), \ I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \ I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), \ I[27] = (T)(img)(_p4##x,_p1##y,z,c), I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), \ I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), I[32] = (T)(img)(_n1##x,_p1##y,z,c), \ I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \ I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), \ I[39] = (T)(img)(_p1##x,y,z,c), I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), \ I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), I[44] = (T)(img)(_n4##x,y,z,c), \ I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \ I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), \ I[51] = (T)(img)(_n2##x,_n1##y,z,c), I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), \ I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), I[56] = (T)(img)(_p2##x,_n2##y,z,c), \ I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \ I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), \ I[63] = (T)(img)(_p4##x,_n3##y,z,c), I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), \ I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), I[68] = (T)(img)(_n1##x,_n3##y,z,c), \ I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \ I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), \ I[75] = (T)(img)(_p1##x,_n4##y,z,c), I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), \ I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), I[80] = (T)(img)(_n4##x,_n4##y,z,c) #define cimg_get2x2x2(img,x,y,z,c,I,T) \ I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \ I[3] = (T)(img)(_n1##x,_n1##y,z,c), I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), \ I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c) #define cimg_get3x3x3(img,x,y,z,c,I,T) \ I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), \ I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), \ I[5] = (T)(img)(_n1##x,y,_p1##z,c), I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), \ I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), \ I[11] = (T)(img)(_n1##x,_p1##y,z,c), I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), \ I[14] = (T)(img)(_n1##x,y,z,c), I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), \ I[17] = (T)(img)(_n1##x,_n1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), \ I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), \ I[23] = (T)(img)(_n1##x,y,_n1##z,c), I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), \ I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c) // Macros to perform various image loops. // // These macros are simpler to use than loops with C++ iterators. #define cimg_for(img,ptrs,T_ptrs) \ for (T_ptrs *ptrs = (img)._data, *_max##ptrs = (img)._data + (img).size(); ptrs<_max##ptrs; ++ptrs) #define cimg_rof(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size() - 1; ptrs>=(img)._data; --ptrs) #define cimg_foroff(img,off) for (cimg_ulong off = 0, _max##off = (img).size(); off<_max##off; ++off) #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i) #define cimg_forX(img,x) cimg_for1((img)._width,x) #define cimg_forY(img,y) cimg_for1((img)._height,y) #define cimg_forZ(img,z) cimg_for1((img)._depth,z) #define cimg_forC(img,c) cimg_for1((img)._spectrum,c) #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x) #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x) #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y) #define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x) #define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y) #define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z) #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y) #define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y) #define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z) #define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z) #define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z) #define cimg_rof1(bound,i) for (int i = (int)(bound) - 1; i>=0; --i) #define cimg_rofX(img,x) cimg_rof1((img)._width,x) #define cimg_rofY(img,y) cimg_rof1((img)._height,y) #define cimg_rofZ(img,z) cimg_rof1((img)._depth,z) #define cimg_rofC(img,c) cimg_rof1((img)._spectrum,c) #define cimg_rofXY(img,x,y) cimg_rofY(img,y) cimg_rofX(img,x) #define cimg_rofXZ(img,x,z) cimg_rofZ(img,z) cimg_rofX(img,x) #define cimg_rofYZ(img,y,z) cimg_rofZ(img,z) cimg_rofY(img,y) #define cimg_rofXC(img,x,c) cimg_rofC(img,c) cimg_rofX(img,x) #define cimg_rofYC(img,y,c) cimg_rofC(img,c) cimg_rofY(img,y) #define cimg_rofZC(img,z,c) cimg_rofC(img,c) cimg_rofZ(img,z) #define cimg_rofXYZ(img,x,y,z) cimg_rofZ(img,z) cimg_rofXY(img,x,y) #define cimg_rofXYC(img,x,y,c) cimg_rofC(img,c) cimg_rofXY(img,x,y) #define cimg_rofXZC(img,x,z,c) cimg_rofC(img,c) cimg_rofXZ(img,x,z) #define cimg_rofYZC(img,y,z,c) cimg_rofC(img,c) cimg_rofYZ(img,y,z) #define cimg_rofXYZC(img,x,y,z,c) cimg_rofC(img,c) cimg_rofXYZ(img,x,y,z) #define cimg_for_in1(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound) - 1; i<=_max##i; ++i) #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x) #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y) #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z) #define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c) #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x) #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x) #define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x) #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y) #define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y) #define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z) #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y) #define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y) #define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z) #define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z) #define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width - 1 - (n),x) #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height - 1 - (n),y) #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth - 1 - (n),z) #define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum - 1 - (n),c) #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) #define cimg_for_insideXYZ(img,x,y,z,n) \ cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_insideXYZC(img,x,y,z,c,n) \ cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_out1(boundi,i0,i1,i) \ for (int i = (int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1) + 1:i) #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \ for (int j = 0; j<(int)(boundj); ++j) \ for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \ for (int k = 0; k<(int)(boundk); ++k) \ for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \ for (int l = 0; l<(int)(boundl); ++l) \ for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \ for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1) + 1; \ i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x) #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y) #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z) #define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c) #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y) #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z) #define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c) #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z) #define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c) #define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c) #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) \ cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) \ cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c) #define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) \ cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c) #define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) \ cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c) #define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width - 1 - (n),x) #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height - 1 - (n),y) #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth - 1 - (n),z) #define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum - 1 - (n),c) #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) #define cimg_for_borderXYZ(img,x,y,z,n) \ cimg_for_outXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_borderXYZC(img,x,y,z,c,n) \ cimg_for_outXYZC(img,n,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n), \ (img)._depth - 1 - (n),(img)._spectrum - 1 - (n),x,y,z,c) #define cimg_for_spiralXY(img,x,y) \ for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \ --_n1##y, _n1##x+=(_n1##x>>2) - ((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width - 1 - ++x:\ ((_n1##x&3)==2?(img)._height - 1 - ++y:--x))))?0:1) #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \ for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \ _dx=(x1)>(x0)?(int)(x1) - (int)(x0):(_sx=-1,(int)(x0) - (int)(x1)), \ _dy=(y1)>(y0)?(int)(y1) - (int)(y0):(_sy=-1,(int)(y0) - (int)(y1)), \ _counter = _dx, \ _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \ _counter>=0; \ --_counter, x+=_steep? \ (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \ (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx)) #define cimg_for2(bound,i) \ for (int i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ ++i, ++_n1##i) #define cimg_for2X(img,x) cimg_for2((img)._width,x) #define cimg_for2Y(img,y) cimg_for2((img)._height,y) #define cimg_for2Z(img,z) cimg_for2((img)._depth,z) #define cimg_for2C(img,c) cimg_for2((img)._spectrum,c) #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x) #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x) #define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x) #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y) #define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y) #define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z) #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y) #define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z) #define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z) #define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z) #define cimg_for_in2(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ ++i, ++_n1##i) #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x) #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y) #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z) #define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c) #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x) #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x) #define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x) #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y) #define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y) #define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z) #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i) #define cimg_for3X(img,x) cimg_for3((img)._width,x) #define cimg_for3Y(img,y) cimg_for3((img)._height,y) #define cimg_for3Z(img,z) cimg_for3((img)._depth,z) #define cimg_for3C(img,c) cimg_for3((img)._spectrum,c) #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x) #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x) #define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x) #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y) #define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y) #define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z) #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y) #define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z) #define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z) #define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z) #define cimg_for_in3(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ _p1##i = i++, ++_n1##i) #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x) #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y) #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z) #define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c) #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x) #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x) #define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x) #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y) #define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y) #define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z) #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for4(bound,i) \ for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for4X(img,x) cimg_for4((img)._width,x) #define cimg_for4Y(img,y) cimg_for4((img)._height,y) #define cimg_for4Z(img,z) cimg_for4((img)._depth,z) #define cimg_for4C(img,c) cimg_for4((img)._spectrum,c) #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x) #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x) #define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x) #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y) #define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y) #define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z) #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y) #define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z) #define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z) #define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z) #define cimg_for_in4(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x) #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y) #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z) #define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c) #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x) #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x) #define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x) #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y) #define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y) #define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z) #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for5(bound,i) \ for (int i = 0, _p2##i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for5X(img,x) cimg_for5((img)._width,x) #define cimg_for5Y(img,y) cimg_for5((img)._height,y) #define cimg_for5Z(img,z) cimg_for5((img)._depth,z) #define cimg_for5C(img,c) cimg_for5((img)._spectrum,c) #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x) #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x) #define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x) #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y) #define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y) #define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z) #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y) #define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z) #define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z) #define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z) #define cimg_for_in5(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p2##i = i - 2<0?0:i - 2, \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x) #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y) #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z) #define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c) #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x) #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x) #define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x) #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y) #define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y) #define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z) #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for6(bound,i) \ for (int i = 0, _p2##i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for6X(img,x) cimg_for6((img)._width,x) #define cimg_for6Y(img,y) cimg_for6((img)._height,y) #define cimg_for6Z(img,z) cimg_for6((img)._depth,z) #define cimg_for6C(img,c) cimg_for6((img)._spectrum,c) #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x) #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x) #define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x) #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y) #define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y) #define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z) #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y) #define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z) #define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z) #define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z) #define cimg_for_in6(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p2##i = i - 2<0?0:i - 2, \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ i<=(int)(i1) && \ (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x) #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y) #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z) #define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c) #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x) #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x) #define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x) #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y) #define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y) #define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z) #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for7(bound,i) \ for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for7X(img,x) cimg_for7((img)._width,x) #define cimg_for7Y(img,y) cimg_for7((img)._height,y) #define cimg_for7Z(img,z) cimg_for7((img)._depth,z) #define cimg_for7C(img,c) cimg_for7((img)._spectrum,c) #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x) #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x) #define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x) #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y) #define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y) #define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z) #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y) #define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z) #define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z) #define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z) #define cimg_for_in7(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p3##i = i - 3<0?0:i - 3, \ _p2##i = i - 2<0?0:i - 2, \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ i<=(int)(i1) && \ (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x) #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y) #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z) #define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c) #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x) #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x) #define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x) #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y) #define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y) #define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z) #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for8(bound,i) \ for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ _n3##i = 3>=(bound)?(int)(bound) - 1:3, \ _n4##i = 4>=(bound)?(int)(bound) - 1:4; \ _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) #define cimg_for8X(img,x) cimg_for8((img)._width,x) #define cimg_for8Y(img,y) cimg_for8((img)._height,y) #define cimg_for8Z(img,z) cimg_for8((img)._depth,z) #define cimg_for8C(img,c) cimg_for8((img)._spectrum,c) #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x) #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x) #define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x) #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y) #define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y) #define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z) #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y) #define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z) #define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z) #define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z) #define cimg_for_in8(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p3##i = i - 3<0?0:i - 3, \ _p2##i = i - 2<0?0:i - 2, \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x) #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y) #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z) #define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c) #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x) #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x) #define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x) #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y) #define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y) #define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z) #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for9(bound,i) \ for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ _n1##i = 1>=(int)(bound)?(int)(bound) - 1:1, \ _n2##i = 2>=(int)(bound)?(int)(bound) - 1:2, \ _n3##i = 3>=(int)(bound)?(int)(bound) - 1:3, \ _n4##i = 4>=(int)(bound)?(int)(bound) - 1:4; \ _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) #define cimg_for9X(img,x) cimg_for9((img)._width,x) #define cimg_for9Y(img,y) cimg_for9((img)._height,y) #define cimg_for9Z(img,z) cimg_for9((img)._depth,z) #define cimg_for9C(img,c) cimg_for9((img)._spectrum,c) #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x) #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x) #define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x) #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y) #define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y) #define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z) #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y) #define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z) #define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z) #define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z) #define cimg_for_in9(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ _p4##i = i - 4<0?0:i - 4, \ _p3##i = i - 3<0?0:i - 3, \ _p2##i = i - 2<0?0:i - 2, \ _p1##i = i - 1<0?0:i - 1, \ _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x) #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y) #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z) #define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c) #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x) #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x) #define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x) #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y) #define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y) #define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z) #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y) #define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z) #define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) #define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for2x2(img,x,y,z,c,I,T) \ cimg_for2((img)._height,y) for (int x = 0, \ _n1##x = (int)( \ (I[0] = (T)(img)(0,y,z,c)), \ (I[2] = (T)(img)(0,_n1##y,z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x; \ I[0] = I[1], \ I[2] = I[3], \ ++x, ++_n1##x) #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _n1##x = (int)( \ (I[0] = (T)(img)(x,y,z,c)), \ (I[2] = (T)(img)(x,_n1##y,z,c)), \ x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x); \ I[0] = I[1], \ I[2] = I[3], \ ++x, ++_n1##x) #define cimg_for3x3(img,x,y,z,c,I,T) \ cimg_for3((img)._height,y) for (int x = 0, \ _p1##x = 0, \ _n1##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x; \ I[0] = I[1], I[1] = I[2], \ I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], \ _p1##x = x++, ++_n1##x) #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = (T)(img)(_p1##x,y,z,c)), \ (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[1] = (T)(img)(x,_p1##y,z,c)), \ (I[4] = (T)(img)(x,y,z,c)), \ (I[7] = (T)(img)(x,_n1##y,z,c)), \ x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x); \ I[0] = I[1], I[1] = I[2], \ I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], \ _p1##x = x++, ++_n1##x) #define cimg_for4x4(img,x,y,z,c,I,T) \ cimg_for4((img)._height,y) for (int x = 0, \ _p1##x = 0, \ _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[4] = I[5] = (T)(img)(0,y,z,c)), \ (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \ (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[6] = (T)(img)(_n1##x,y,z,c)), \ (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ 2>=(img)._width?(img).width() - 1:2); \ (_n2##x<(img).width() && ( \ (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[7] = (T)(img)(_n2##x,y,z,c)), \ (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], \ I[4] = I[5], I[5] = I[6], I[6] = I[7], \ I[8] = I[9], I[9] = I[10], I[10] = I[11], \ I[12] = I[13], I[13] = I[14], I[14] = I[15], \ _p1##x = x++, ++_n1##x, ++_n2##x) #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[4] = (T)(img)(_p1##x,y,z,c)), \ (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[1] = (T)(img)(x,_p1##y,z,c)), \ (I[5] = (T)(img)(x,y,z,c)), \ (I[9] = (T)(img)(x,_n1##y,z,c)), \ (I[13] = (T)(img)(x,_n2##y,z,c)), \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[6] = (T)(img)(_n1##x,y,z,c)), \ (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ x<=(int)(x1) && ((_n2##x<(img).width() && ( \ (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[7] = (T)(img)(_n2##x,y,z,c)), \ (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], \ I[4] = I[5], I[5] = I[6], I[6] = I[7], \ I[8] = I[9], I[9] = I[10], I[10] = I[11], \ I[12] = I[13], I[13] = I[14], I[14] = I[15], \ _p1##x = x++, ++_n1##x, ++_n2##x) #define cimg_for5x5(img,x,y,z,c,I,T) \ cimg_for5((img)._height,y) for (int x = 0, \ _p2##x = 0, _p1##x = 0, \ _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = (int)( \ (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \ (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \ (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \ (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \ (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[13] = (T)(img)(_n1##x,y,z,c)), \ (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ 2>=(img)._width?(img).width() - 1:2); \ (_n2##x<(img).width() && ( \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[14] = (T)(img)(_n2##x,y,z,c)), \ (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p2##x = x - 2<0?0:x - 2, \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = (int)( \ (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \ (I[10] = (T)(img)(_p2##x,y,z,c)), \ (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \ (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \ (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[11] = (T)(img)(_p1##x,y,z,c)), \ (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[2] = (T)(img)(x,_p2##y,z,c)), \ (I[7] = (T)(img)(x,_p1##y,z,c)), \ (I[12] = (T)(img)(x,y,z,c)), \ (I[17] = (T)(img)(x,_n1##y,z,c)), \ (I[22] = (T)(img)(x,_n2##y,z,c)), \ (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[13] = (T)(img)(_n1##x,y,z,c)), \ (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ x<=(int)(x1) && ((_n2##x<(img).width() && ( \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[14] = (T)(img)(_n2##x,y,z,c)), \ (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) #define cimg_for6x6(img,x,y,z,c,I,T) \ cimg_for6((img)._height,y) for (int x = 0, \ _p2##x = 0, _p1##x = 0, \ _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = 2>=(img)._width?(img).width() - 1:2, \ _n3##x = (int)( \ (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \ (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \ (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \ (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \ (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \ (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[15] = (T)(img)(_n1##x,y,z,c)), \ (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[16] = (T)(img)(_n2##x,y,z,c)), \ (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ 3>=(img)._width?(img).width() - 1:3); \ (_n3##x<(img).width() && ( \ (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[17] = (T)(img)(_n3##x,y,z,c)), \ (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \ _p2##x = x - 2<0?0:x - 2, \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ _n3##x = (int)( \ (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \ (I[12] = (T)(img)(_p2##x,y,z,c)), \ (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \ (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \ (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \ (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[13] = (T)(img)(_p1##x,y,z,c)), \ (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \ (I[2] = (T)(img)(x,_p2##y,z,c)), \ (I[8] = (T)(img)(x,_p1##y,z,c)), \ (I[14] = (T)(img)(x,y,z,c)), \ (I[20] = (T)(img)(x,_n1##y,z,c)), \ (I[26] = (T)(img)(x,_n2##y,z,c)), \ (I[32] = (T)(img)(x,_n3##y,z,c)), \ (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[15] = (T)(img)(_n1##x,y,z,c)), \ (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[16] = (T)(img)(_n2##x,y,z,c)), \ (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ x<=(int)(x1) && ((_n3##x<(img).width() && ( \ (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[17] = (T)(img)(_n3##x,y,z,c)), \ (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) #define cimg_for7x7(img,x,y,z,c,I,T) \ cimg_for7((img)._height,y) for (int x = 0, \ _p3##x = 0, _p2##x = 0, _p1##x = 0, \ _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = 2>=(img)._width?(img).width() - 1:2, \ _n3##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \ (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \ (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \ (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \ (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \ (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \ (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[25] = (T)(img)(_n1##x,y,z,c)), \ (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[26] = (T)(img)(_n2##x,y,z,c)), \ (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ 3>=(img)._width?(img).width() - 1:3); \ (_n3##x<(img).width() && ( \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[27] = (T)(img)(_n3##x,y,z,c)), \ (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p3##x = x - 3<0?0:x - 3, \ _p2##x = x - 2<0?0:x - 2, \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ _n3##x = (int)( \ (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \ (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \ (I[21] = (T)(img)(_p3##x,y,z,c)), \ (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \ (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \ (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \ (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \ (I[22] = (T)(img)(_p2##x,y,z,c)), \ (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \ (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \ (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \ (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \ (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[23] = (T)(img)(_p1##x,y,z,c)), \ (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \ (I[3] = (T)(img)(x,_p3##y,z,c)), \ (I[10] = (T)(img)(x,_p2##y,z,c)), \ (I[17] = (T)(img)(x,_p1##y,z,c)), \ (I[24] = (T)(img)(x,y,z,c)), \ (I[31] = (T)(img)(x,_n1##y,z,c)), \ (I[38] = (T)(img)(x,_n2##y,z,c)), \ (I[45] = (T)(img)(x,_n3##y,z,c)), \ (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[25] = (T)(img)(_n1##x,y,z,c)), \ (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[26] = (T)(img)(_n2##x,y,z,c)), \ (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ x<=(int)(x1) && ((_n3##x<(img).width() && ( \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[27] = (T)(img)(_n3##x,y,z,c)), \ (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) #define cimg_for8x8(img,x,y,z,c,I,T) \ cimg_for8((img)._height,y) for (int x = 0, \ _p3##x = 0, _p2##x = 0, _p1##x = 0, \ _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ _n4##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \ (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \ (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \ (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \ (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \ (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \ (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \ (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[28] = (T)(img)(_n1##x,y,z,c)), \ (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[29] = (T)(img)(_n2##x,y,z,c)), \ (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[30] = (T)(img)(_n3##x,y,z,c)), \ (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ 4>=((img)._width)?(img).width() - 1:4); \ (_n4##x<(img).width() && ( \ (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ (I[31] = (T)(img)(_n4##x,y,z,c)), \ (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p3##x = x - 3<0?0:x - 3, \ _p2##x = x - 2<0?0:x - 2, \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ _n4##x = (int)( \ (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \ (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \ (I[24] = (T)(img)(_p3##x,y,z,c)), \ (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \ (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \ (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \ (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \ (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \ (I[25] = (T)(img)(_p2##x,y,z,c)), \ (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \ (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \ (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \ (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \ (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \ (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[26] = (T)(img)(_p1##x,y,z,c)), \ (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \ (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \ (I[3] = (T)(img)(x,_p3##y,z,c)), \ (I[11] = (T)(img)(x,_p2##y,z,c)), \ (I[19] = (T)(img)(x,_p1##y,z,c)), \ (I[27] = (T)(img)(x,y,z,c)), \ (I[35] = (T)(img)(x,_n1##y,z,c)), \ (I[43] = (T)(img)(x,_n2##y,z,c)), \ (I[51] = (T)(img)(x,_n3##y,z,c)), \ (I[59] = (T)(img)(x,_n4##y,z,c)), \ (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[28] = (T)(img)(_n1##x,y,z,c)), \ (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[29] = (T)(img)(_n2##x,y,z,c)), \ (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[30] = (T)(img)(_n3##x,y,z,c)), \ (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ x + 4>=(img).width()?(img).width() - 1:x + 4); \ x<=(int)(x1) && ((_n4##x<(img).width() && ( \ (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ (I[31] = (T)(img)(_n4##x,y,z,c)), \ (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) #define cimg_for9x9(img,x,y,z,c,I,T) \ cimg_for9((img)._height,y) for (int x = 0, \ _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \ _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ _n4##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \ (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \ (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \ (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \ (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \ (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \ (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \ (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \ (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \ (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[41] = (T)(img)(_n1##x,y,z,c)), \ (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[42] = (T)(img)(_n2##x,y,z,c)), \ (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[43] = (T)(img)(_n3##x,y,z,c)), \ (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ 4>=((img)._width)?(img).width() - 1:4); \ (_n4##x<(img).width() && ( \ (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ (I[44] = (T)(img)(_n4##x,y,z,c)), \ (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \ I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \ I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \ I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \ I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \ I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \ I[79] = I[80], \ _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p4##x = x - 4<0?0:x - 4, \ _p3##x = x - 3<0?0:x - 3, \ _p2##x = x - 2<0?0:x - 2, \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ _n4##x = (int)( \ (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \ (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \ (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \ (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \ (I[36] = (T)(img)(_p4##x,y,z,c)), \ (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \ (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \ (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \ (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \ (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \ (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \ (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \ (I[37] = (T)(img)(_p3##x,y,z,c)), \ (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \ (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \ (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \ (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \ (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \ (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \ (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \ (I[38] = (T)(img)(_p2##x,y,z,c)), \ (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \ (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \ (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \ (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \ (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \ (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \ (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \ (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[39] = (T)(img)(_p1##x,y,z,c)), \ (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \ (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \ (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \ (I[4] = (T)(img)(x,_p4##y,z,c)), \ (I[13] = (T)(img)(x,_p3##y,z,c)), \ (I[22] = (T)(img)(x,_p2##y,z,c)), \ (I[31] = (T)(img)(x,_p1##y,z,c)), \ (I[40] = (T)(img)(x,y,z,c)), \ (I[49] = (T)(img)(x,_n1##y,z,c)), \ (I[58] = (T)(img)(x,_n2##y,z,c)), \ (I[67] = (T)(img)(x,_n3##y,z,c)), \ (I[76] = (T)(img)(x,_n4##y,z,c)), \ (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[41] = (T)(img)(_n1##x,y,z,c)), \ (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[42] = (T)(img)(_n2##x,y,z,c)), \ (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ (I[43] = (T)(img)(_n3##x,y,z,c)), \ (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ x + 4>=(img).width()?(img).width() - 1:x + 4); \ x<=(int)(x1) && ((_n4##x<(img).width() && ( \ (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ (I[44] = (T)(img)(_n4##x,y,z,c)), \ (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \ I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \ I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \ I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \ I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \ I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \ I[79] = I[80], \ _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) #define cimg_for2x2x2(img,x,y,z,c,I,T) \ cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \ _n1##x = (int)( \ (I[0] = (T)(img)(0,y,z,c)), \ (I[2] = (T)(img)(0,_n1##y,z,c)), \ (I[4] = (T)(img)(0,y,_n1##z,c)), \ (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ x==--_n1##x; \ I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ ++x, ++_n1##x) #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _n1##x = (int)( \ (I[0] = (T)(img)(x,y,z,c)), \ (I[2] = (T)(img)(x,_n1##y,z,c)), \ (I[4] = (T)(img)(x,y,_n1##z,c)), \ (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \ x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ x==--_n1##x); \ I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ ++x, ++_n1##x) #define cimg_for3x3x3(img,x,y,z,c,I,T) \ cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \ _p1##x = 0, \ _n1##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)), \ (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \ (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \ (I[12] = I[13] = (T)(img)(0,y,z,c)), \ (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \ (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \ (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \ (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,y,z,c)), \ (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ x==--_n1##x; \ I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ _p1##x = x++, ++_n1##x) #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ _p1##x = x - 1<0?0:x - 1, \ _n1##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ (I[3] = (T)(img)(_p1##x,y,_p1##z,c)), \ (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \ (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[12] = (T)(img)(_p1##x,y,z,c)), \ (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \ (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \ (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \ (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \ (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \ (I[4] = (T)(img)(x,y,_p1##z,c)), \ (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \ (I[10] = (T)(img)(x,_p1##y,z,c)), \ (I[13] = (T)(img)(x,y,z,c)), \ (I[16] = (T)(img)(x,_n1##y,z,c)), \ (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \ (I[22] = (T)(img)(x,y,_n1##z,c)), \ (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \ x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,y,z,c)), \ (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ x==--_n1##x); \ I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ _p1##x = x++, ++_n1##x) #define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l) #define cimglist_for_in(list,l0,l1,l) \ for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width - 1; \ l<=_max##l; ++l) #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn // Macros used to display error messages when exceptions are thrown. // You should not use these macros is your own code. #define _cimgdisplay_instance "[instance(%u,%u,%u,%c%s%c)] CImgDisplay::" #define cimgdisplay_instance _width,_height,_normalization,_title?'\"':'[',_title?_title:"untitled",_title?'\"':']' #define _cimg_instance "[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::" #define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?"":"non-",pixel_type() #define _cimglist_instance "[instance(%u,%u,%p)] CImgList<%s>::" #define cimglist_instance _width,_allocated_width,_data,pixel_type() /*------------------------------------------------ # # # Define cimg_library:: namespace # # -------------------------------------------------*/ //! Contains all classes and functions of the \CImg library. /** This namespace is defined to avoid functions and class names collisions that could happen with the inclusion of other C++ header files. Anyway, it should not happen often and you should reasonnably start most of your \CImg-based programs with \code #include "CImg.h" using namespace cimg_library; \endcode to simplify the declaration of \CImg Library objects afterwards. **/ namespace cimg_library_suffixed { // Declare the four classes of the CImg Library. template struct CImg; template struct CImgList; struct CImgDisplay; struct CImgException; // Declare cimg:: namespace. // This is an uncomplete namespace definition here. It only contains some // necessary stuff to ensure a correct declaration order of the classes and functions // defined afterwards. namespace cimg { // Define ascii sequences for colored terminal output. #ifdef cimg_use_vt100 static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 }; static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 }; static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 }; static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 }; static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 }; static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 }; static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 }; static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 }; static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 }; static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 }; static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 }; #else static const char t_normal[] = { 0 }; static const char *const t_black = cimg::t_normal, *const t_red = cimg::t_normal, *const t_green = cimg::t_normal, *const t_yellow = cimg::t_normal, *const t_blue = cimg::t_normal, *const t_magenta = cimg::t_normal, *const t_cyan = cimg::t_normal, *const t_white = cimg::t_normal, *const t_bold = cimg::t_normal, *const t_underscore = cimg::t_normal; #endif inline std::FILE* output(std::FILE *file=0); inline void info(); //! Avoid warning messages due to unused parameters. Do nothing actually. template inline void unused(const T&, ...) {} // [internal] Lock/unlock a mutex for managing concurrent threads. // 'lock_mode' can be { 0=unlock | 1=lock | 2=trylock }. // 'n' can be in [0,31] but mutex range [0,15] is reserved by CImg. inline int mutex(const unsigned int n, const int lock_mode=1); inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) { static unsigned int mode = cimg_verbosity; if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); } return mode; } // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character // at the end of the string. #if cimg_OS==2 && defined(_MSC_VER) inline int _snprintf(char *const s, const size_t size, const char *const format, ...) { va_list ap; va_start(ap,format); const int result = _vsnprintf(s,size,format,ap); va_end(ap); return result; } inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) { int result = -1; cimg::mutex(6); if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap); if (result==-1) result = _vscprintf(format,ap); cimg::mutex(6,0); return result; } // Mutex-protected version of sscanf, sprintf and snprintf. // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX. #elif defined(__MACOSX__) || defined(__APPLE__) inline int _sscanf(const char *const s, const char *const format, ...) { cimg::mutex(6); va_list args; va_start(args,format); const int result = std::vsscanf(s,format,args); va_end(args); cimg::mutex(6,0); return result; } inline int _sprintf(char *const s, const char *const format, ...) { cimg::mutex(6); va_list args; va_start(args,format); const int result = std::vsprintf(s,format,args); va_end(args); cimg::mutex(6,0); return result; } inline int _snprintf(char *const s, const size_t n, const char *const format, ...) { cimg::mutex(6); va_list args; va_start(args,format); const int result = std::vsnprintf(s,n,format,args); va_end(args); cimg::mutex(6,0); return result; } inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) { cimg::mutex(6); const int result = std::vsnprintf(s,size,format,ap); cimg::mutex(6,0); return result; } #endif //! Set current \CImg exception mode. /** The way error messages are handled by \CImg can be changed dynamically, using this function. \param mode Desired exception mode. Possible values are: - \c 0: Hide library messages (quiet mode). - \c 1: Print library messages on the console. - \c 2: Display library messages on a dialog window (default behavior). - \c 3: Do as \c 1 + add extra debug warnings (slow down the code!). - \c 4: Do as \c 2 + add extra debug warnings (slow down the code!). **/ inline unsigned int& exception_mode(const unsigned int mode) { return _exception_mode(mode,true); } //! Return current \CImg exception mode. /** \note By default, return the value of configuration macro \c cimg_verbosity **/ inline unsigned int& exception_mode() { return _exception_mode(0,false); } //! Set current \CImg openmp mode. /** The way openmp-based methods are handled by \CImg can be changed dynamically, using this function. \param mode Desired openmp mode. Possible values are: - \c 0: Never parallelize (quiet mode). - \c 1: Always parallelize. - \c 2: Adaptive parallelization mode (default behavior). **/ inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) { static unsigned int mode = 2; if (is_set) { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); } return mode; } inline unsigned int& openmp_mode(const unsigned int mode) { return _openmp_mode(mode,true); } //! Return current \CImg openmp mode. inline unsigned int& openmp_mode() { return _openmp_mode(0,false); } #define cimg_openmp_if(cond) if (cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond))) // Display a simple dialog box, and wait for the user's response. inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK", const char *const button2_label=0, const char *const button3_label=0, const char *const button4_label=0, const char *const button5_label=0, const char *const button6_label=0, const bool centering=false); // Evaluate math expression. inline double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0); } /*--------------------------------------- # # Define the CImgException structures # --------------------------------------*/ //! Instances of \c CImgException are thrown when errors are encountered in a \CImg function call. /** \par Overview CImgException is the base class of all exceptions thrown by \CImg (except \b CImgAbortException). CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead. These classes can be: - \b CImgAbortException: Thrown when a computationally-intensive function is aborted by an external signal. This is the only \c non-derived exception class. - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid. This is probably one of the most thrown exception by \CImg. For instance, the following example throws a \c CImgArgumentException: \code CImg img(100,100,1,3); // Define a 100x100 color image with float-valued pixels. img.mirror('e'); // Try to mirror image along the (non-existing) 'e'-axis. \endcode - \b CImgDisplayException: Thrown when something went wrong during the display of images in CImgDisplay instances. - \b CImgInstanceException: Thrown when an instance associated to a called \CImg method does not fit the function requirements. For instance, the following example throws a \c CImgInstanceException: \code const CImg img; // Define an empty image. const float value = img.at(0); // Try to read first pixel value (does not exist). \endcode - \b CImgIOException: Thrown when an error occured when trying to load or save image files. This happens when trying to read files that do not exist or with invalid formats. For instance, the following example throws a \c CImgIOException: \code const CImg img("missing_file.jpg"); // Try to load a file that does not exist. \endcode - \b CImgWarningException: Thrown only if configuration macro \c cimg_strict_warnings is set, and when a \CImg function has to display a warning message (see cimg::warn()). It is not recommended to throw CImgException instances by yourself, since they are expected to be thrown only by \CImg. When an error occurs in a library function call, \CImg may display error messages on the screen or on the standard output, depending on the current \CImg exception mode. The \CImg exception mode can be get and set by functions cimg::exception_mode() and cimg::exception_mode(unsigned int). \par Exceptions handling In all cases, when an error occurs in \CImg, an instance of the corresponding exception class is thrown. This may lead the program to break (this is the default behavior), but you can bypass this behavior by handling the exceptions by yourself, using a usual try { ... } catch () { ... } bloc, as in the following example: \code #define "CImg.h" using namespace cimg_library; int main() { cimg::exception_mode(0); // Enable quiet exception mode. try { ... // Here, do what you want to stress CImg. } catch (CImgException &e) { // You succeeded: something went wrong! std::fprintf(stderr,"CImg Library Error: %s",e.what()); // Display your custom error message. ... // Do what you want now to save the ship! } } \endcode **/ struct CImgException : public std::exception { #define _cimg_exception_err(etype,disp_flag) \ std::va_list ap, ap2; \ va_start(ap,format); va_start(ap2,format); \ int size = cimg_vsnprintf(0,0,format,ap2); \ if (size++>=0) { \ delete[] _message; \ _message = new char[size]; \ cimg_vsnprintf(_message,size,format,ap); \ if (cimg::exception_mode()) { \ std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \ catch (CImgException&) {} \ if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \ } \ } \ va_end(ap); va_end(ap2); \ char *_message; CImgException() { _message = new char[1]; *_message = 0; } CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); } CImgException(const CImgException& e):std::exception(e) { const size_t size = std::strlen(e._message); _message = new char[size + 1]; std::strncpy(_message,e._message,size); _message[size] = 0; } ~CImgException() throw() { delete[] _message; } CImgException& operator=(const CImgException& e) { const size_t size = std::strlen(e._message); _message = new char[size + 1]; std::strncpy(_message,e._message,size); _message[size] = 0; return *this; } //! Return a C-string containing the error message associated to the thrown exception. const char *what() const throw() { return _message; } }; // The CImgAbortException class is used to throw an exception when // a computationally-intensive function has been aborted by an external signal. struct CImgAbortException : public std::exception { char *_message; CImgAbortException() { _message = new char[1]; *_message = 0; } CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); } CImgAbortException(const CImgAbortException& e):std::exception(e) { const size_t size = std::strlen(e._message); _message = new char[size + 1]; std::strncpy(_message,e._message,size); _message[size] = 0; } ~CImgAbortException() throw() { delete[] _message; } CImgAbortException& operator=(const CImgAbortException& e) { const size_t size = std::strlen(e._message); _message = new char[size + 1]; std::strncpy(_message,e._message,size); _message[size] = 0; return *this; } //! Return a C-string containing the error message associated to the thrown exception. const char *what() const throw() { return _message; } }; // The CImgArgumentException class is used to throw an exception related // to invalid arguments encountered in a library function call. struct CImgArgumentException : public CImgException { CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); } }; // The CImgDisplayException class is used to throw an exception related // to display problems encountered in a library function call. struct CImgDisplayException : public CImgException { CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); } }; // The CImgInstanceException class is used to throw an exception related // to an invalid instance encountered in a library function call. struct CImgInstanceException : public CImgException { CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } }; // The CImgIOException class is used to throw an exception related // to input/output file problems encountered in a library function call. struct CImgIOException : public CImgException { CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); } }; // The CImgWarningException class is used to throw an exception for warnings // encountered in a library function call. struct CImgWarningException : public CImgException { CImgWarningException(const char *const format, ...) { _cimg_exception_err("CImgWarningException",false); } }; /*------------------------------------- # # Define cimg:: namespace # -----------------------------------*/ //! Contains \a low-level functions and variables of the \CImg Library. /** Most of the functions and variables within this namespace are used by the \CImg library for low-level operations. You may use them to access specific const values or environment variables internally used by \CImg. \warning Never write using namespace cimg_library::cimg; in your source code. Lot of functions in the cimg:: namespace have the same names as standard C functions that may be defined in the global namespace ::. **/ namespace cimg { // Define traits that will be used to determine the best data type to work in CImg functions. // template struct type { static const char* string() { static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24", "unknown32", "unknown40", "unknown48", "unknown56", "unknown64", "unknown72", "unknown80", "unknown88", "unknown96", "unknown104", "unknown112", "unknown120", "unknown128" }; return s[(sizeof(T)<17)?sizeof(T):0]; } static bool is_float() { return false; } static bool is_inf(const T) { return false; } static bool is_nan(const T) { return false; } static T min() { return ~max(); } static T max() { return (T)1<<(8*sizeof(T) - 1); } static T inf() { return max(); } static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; } static const char* format() { return "%s"; } static const char* format(const T& val) { static const char *const s = "unknown"; cimg::unused(val); return s; } }; template<> struct type { static const char* string() { static const char *const s = "bool"; return s; } static bool is_float() { return false; } static bool is_inf(const bool) { return false; } static bool is_nan(const bool) { return false; } static bool min() { return false; } static bool max() { return true; } static bool inf() { return max(); } static bool is_inf() { return false; } static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; } static const char* format() { return "%s"; } static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; } }; template<> struct type { static const char* string() { static const char *const s = "unsigned char"; return s; } static bool is_float() { return false; } static bool is_inf(const unsigned char) { return false; } static bool is_nan(const unsigned char) { return false; } static unsigned char min() { return 0; } static unsigned char max() { return (unsigned char)-1; } static unsigned char inf() { return max(); } static unsigned char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } static const char* format() { return "%u"; } static unsigned int format(const unsigned char val) { return (unsigned int)val; } }; #if defined(CHAR_MAX) && CHAR_MAX==255 template<> struct type { static const char* string() { static const char *const s = "char"; return s; } static bool is_float() { return false; } static bool is_inf(const char) { return false; } static bool is_nan(const char) { return false; } static char min() { return 0; } static char max() { return (char)-1; } static char inf() { return max(); } static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } static const char* format() { return "%u"; } static unsigned int format(const char val) { return (unsigned int)val; } }; #else template<> struct type { static const char* string() { static const char *const s = "char"; return s; } static bool is_float() { return false; } static bool is_inf(const char) { return false; } static bool is_nan(const char) { return false; } static char min() { return ~max(); } static char max() { return (char)((unsigned char)-1>>1); } static char inf() { return max(); } static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; } static const char* format() { return "%d"; } static int format(const char val) { return (int)val; } }; #endif template<> struct type { static const char* string() { static const char *const s = "signed char"; return s; } static bool is_float() { return false; } static bool is_inf(const signed char) { return false; } static bool is_nan(const signed char) { return false; } static signed char min() { return ~max(); } static signed char max() { return (signed char)((unsigned char)-1>>1); } static signed char inf() { return max(); } static signed char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(signed char)val; } static const char* format() { return "%d"; } static int format(const signed char val) { return (int)val; } }; template<> struct type { static const char* string() { static const char *const s = "unsigned short"; return s; } static bool is_float() { return false; } static bool is_inf(const unsigned short) { return false; } static bool is_nan(const unsigned short) { return false; } static unsigned short min() { return 0; } static unsigned short max() { return (unsigned short)-1; } static unsigned short inf() { return max(); } static unsigned short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; } static const char* format() { return "%u"; } static unsigned int format(const unsigned short val) { return (unsigned int)val; } }; template<> struct type { static const char* string() { static const char *const s = "short"; return s; } static bool is_float() { return false; } static bool is_inf(const short) { return false; } static bool is_nan(const short) { return false; } static short min() { return ~max(); } static short max() { return (short)((unsigned short)-1>>1); } static short inf() { return max(); } static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; } static const char* format() { return "%d"; } static int format(const short val) { return (int)val; } }; template<> struct type { static const char* string() { static const char *const s = "unsigned int"; return s; } static bool is_float() { return false; } static bool is_inf(const unsigned int) { return false; } static bool is_nan(const unsigned int) { return false; } static unsigned int min() { return 0; } static unsigned int max() { return (unsigned int)-1; } static unsigned int inf() { return max(); } static unsigned int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; } static const char* format() { return "%u"; } static unsigned int format(const unsigned int val) { return val; } }; template<> struct type { static const char* string() { static const char *const s = "int"; return s; } static bool is_float() { return false; } static bool is_inf(const int) { return false; } static bool is_nan(const int) { return false; } static int min() { return ~max(); } static int max() { return (int)((unsigned int)-1>>1); } static int inf() { return max(); } static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; } static const char* format() { return "%d"; } static int format(const int val) { return val; } }; template<> struct type { static const char* string() { static const char *const s = "unsigned int64"; return s; } static bool is_float() { return false; } static bool is_inf(const cimg_uint64) { return false; } static bool is_nan(const cimg_uint64) { return false; } static cimg_uint64 min() { return 0; } static cimg_uint64 max() { return (cimg_uint64)-1; } static cimg_uint64 inf() { return max(); } static cimg_uint64 cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(cimg_uint64)val; } static const char* format() { return "%lu"; } static unsigned long format(const cimg_uint64 val) { return (unsigned long)val; } }; template<> struct type { static const char* string() { static const char *const s = "int64"; return s; } static bool is_float() { return false; } static bool is_inf(const cimg_int64) { return false; } static bool is_nan(const cimg_int64) { return false; } static cimg_int64 min() { return ~max(); } static cimg_int64 max() { return (cimg_int64)((cimg_uint64)-1>>1); } static cimg_int64 inf() { return max(); } static cimg_int64 cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val; } static const char* format() { return "%ld"; } static long format(const long val) { return (long)val; } }; template<> struct type { static const char* string() { static const char *const s = "double"; return s; } static bool is_float() { return true; } static bool is_inf(const double val) { #ifdef isinf return (bool)isinf(val); #else return !is_nan(val) && (val::min() || val>cimg::type::max()); #endif } static bool is_nan(const double val) { #ifdef isnan return (bool)isnan(val); #else return !(val==val); #endif } static double min() { return -DBL_MAX; } static double max() { return DBL_MAX; } static double inf() { #ifdef INFINITY return (double)INFINITY; #else return max()*max(); #endif } static double nan() { #ifdef NAN return (double)NAN; #else const double val_nan = -std::sqrt(-1.0); return val_nan; #endif } static double cut(const double val) { return valmax()?max():val; } static const char* format() { return "%.16g"; } static double format(const double val) { return val; } }; template<> struct type { static const char* string() { static const char *const s = "float"; return s; } static bool is_float() { return true; } static bool is_inf(const float val) { #ifdef isinf return (bool)isinf(val); #else return !is_nan(val) && (val::min() || val>cimg::type::max()); #endif } static bool is_nan(const float val) { #ifdef isnan return (bool)isnan(val); #else return !(val==val); #endif } static float min() { return -FLT_MAX; } static float max() { return FLT_MAX; } static float inf() { return (float)cimg::type::inf(); } static float nan() { return (float)cimg::type::nan(); } static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; } static const char* format() { return "%.16g"; } static double format(const float val) { return (double)val; } }; template<> struct type { static const char* string() { static const char *const s = "long double"; return s; } static bool is_float() { return true; } static bool is_inf(const long double val) { #ifdef isinf return (bool)isinf(val); #else return !is_nan(val) && (val::min() || val>cimg::type::max()); #endif } static bool is_nan(const long double val) { #ifdef isnan return (bool)isnan(val); #else return !(val==val); #endif } static long double min() { return -LDBL_MAX; } static long double max() { return LDBL_MAX; } static long double inf() { return max()*max(); } static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; } static long double cut(const long double val) { return valmax()?max():val; } static const char* format() { return "%.16g"; } static double format(const long double val) { return (double)val; } }; template struct superset { typedef T type; }; template<> struct superset { typedef unsigned char type; }; template<> struct superset { typedef char type; }; template<> struct superset { typedef signed char type; }; template<> struct superset { typedef unsigned short type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef unsigned int type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_uint64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef unsigned short type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef unsigned int type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_uint64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef short type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef unsigned int type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_uint64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef int type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_uint64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef float type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef cimg_int64 type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef double type; }; template<> struct superset { typedef double type; }; template struct superset2 { typedef typename superset::type>::type type; }; template struct superset3 { typedef typename superset::type>::type type; }; template struct last { typedef t2 type; }; #define _cimg_Tt typename cimg::superset::type #define _cimg_Tfloat typename cimg::superset::type #define _cimg_Ttfloat typename cimg::superset2::type #define _cimg_Ttdouble typename cimg::superset2::type // Define variables used internally by CImg. #if cimg_display==1 struct X11_info { unsigned int nb_wins; pthread_t *events_thread; pthread_cond_t wait_event; pthread_mutex_t wait_event_mutex; CImgDisplay **wins; Display *display; unsigned int nb_bits; bool is_blue_first; bool is_shm_enabled; bool byte_order; #ifdef cimg_use_xrandr XRRScreenSize *resolutions; Rotation curr_rotation; unsigned int curr_resolution; unsigned int nb_resolutions; #endif X11_info():nb_wins(0),events_thread(0),display(0), nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) { #ifdef __FreeBSD__ XInitThreads(); #endif wins = new CImgDisplay*[1024]; pthread_mutex_init(&wait_event_mutex,0); pthread_cond_init(&wait_event,0); #ifdef cimg_use_xrandr resolutions = 0; curr_rotation = 0; curr_resolution = nb_resolutions = 0; #endif } ~X11_info() { delete[] wins; /* if (events_thread) { pthread_cancel(*events_thread); delete events_thread; } if (display) { } // XCloseDisplay(display); } pthread_cond_destroy(&wait_event); pthread_mutex_unlock(&wait_event_mutex); pthread_mutex_destroy(&wait_event_mutex); */ } }; #if defined(cimg_module) X11_info& X11_attr(); #elif defined(cimg_main) X11_info& X11_attr() { static X11_info val; return val; } #else inline X11_info& X11_attr() { static X11_info val; return val; } #endif #define cimg_lock_display() cimg::mutex(15) #define cimg_unlock_display() cimg::mutex(15,0) #elif cimg_display==2 struct Win32_info { HANDLE wait_event; Win32_info() { wait_event = CreateEvent(0,FALSE,FALSE,0); } }; #if defined(cimg_module) Win32_info& Win32_attr(); #elif defined(cimg_main) Win32_info& Win32_attr() { static Win32_info val; return val; } #else inline Win32_info& Win32_attr() { static Win32_info val; return val; } #endif #endif struct Mutex_info { #if cimg_OS==2 HANDLE mutex[32]; Mutex_info() { for (unsigned int i = 0; i<32; ++i) mutex[i] = CreateMutex(0,FALSE,0); } void lock(const unsigned int n) { WaitForSingleObject(mutex[n],INFINITE); } void unlock(const unsigned int n) { ReleaseMutex(mutex[n]); } int trylock(const unsigned int) { return 0; } #elif defined(_PTHREAD_H) pthread_mutex_t mutex[32]; Mutex_info() { for (unsigned int i = 0; i<32; ++i) pthread_mutex_init(&mutex[i],0); } void lock(const unsigned int n) { pthread_mutex_lock(&mutex[n]); } void unlock(const unsigned int n) { pthread_mutex_unlock(&mutex[n]); } int trylock(const unsigned int n) { return pthread_mutex_trylock(&mutex[n]); } #else Mutex_info() {} void lock(const unsigned int) {} void unlock(const unsigned int) {} int trylock(const unsigned int) { return 0; } #endif }; #if defined(cimg_module) Mutex_info& Mutex_attr(); #elif defined(cimg_main) Mutex_info& Mutex_attr() { static Mutex_info val; return val; } #else inline Mutex_info& Mutex_attr() { static Mutex_info val; return val; } #endif #if defined(cimg_use_magick) static struct Magick_info { Magick_info() { Magick::InitializeMagick(""); } } _Magick_info; #endif #if cimg_display==1 // Define keycodes for X11-based graphical systems. const unsigned int keyESC = XK_Escape; const unsigned int keyF1 = XK_F1; const unsigned int keyF2 = XK_F2; const unsigned int keyF3 = XK_F3; const unsigned int keyF4 = XK_F4; const unsigned int keyF5 = XK_F5; const unsigned int keyF6 = XK_F6; const unsigned int keyF7 = XK_F7; const unsigned int keyF8 = XK_F8; const unsigned int keyF9 = XK_F9; const unsigned int keyF10 = XK_F10; const unsigned int keyF11 = XK_F11; const unsigned int keyF12 = XK_F12; const unsigned int keyPAUSE = XK_Pause; const unsigned int key1 = XK_1; const unsigned int key2 = XK_2; const unsigned int key3 = XK_3; const unsigned int key4 = XK_4; const unsigned int key5 = XK_5; const unsigned int key6 = XK_6; const unsigned int key7 = XK_7; const unsigned int key8 = XK_8; const unsigned int key9 = XK_9; const unsigned int key0 = XK_0; const unsigned int keyBACKSPACE = XK_BackSpace; const unsigned int keyINSERT = XK_Insert; const unsigned int keyHOME = XK_Home; const unsigned int keyPAGEUP = XK_Page_Up; const unsigned int keyTAB = XK_Tab; const unsigned int keyQ = XK_q; const unsigned int keyW = XK_w; const unsigned int keyE = XK_e; const unsigned int keyR = XK_r; const unsigned int keyT = XK_t; const unsigned int keyY = XK_y; const unsigned int keyU = XK_u; const unsigned int keyI = XK_i; const unsigned int keyO = XK_o; const unsigned int keyP = XK_p; const unsigned int keyDELETE = XK_Delete; const unsigned int keyEND = XK_End; const unsigned int keyPAGEDOWN = XK_Page_Down; const unsigned int keyCAPSLOCK = XK_Caps_Lock; const unsigned int keyA = XK_a; const unsigned int keyS = XK_s; const unsigned int keyD = XK_d; const unsigned int keyF = XK_f; const unsigned int keyG = XK_g; const unsigned int keyH = XK_h; const unsigned int keyJ = XK_j; const unsigned int keyK = XK_k; const unsigned int keyL = XK_l; const unsigned int keyENTER = XK_Return; const unsigned int keySHIFTLEFT = XK_Shift_L; const unsigned int keyZ = XK_z; const unsigned int keyX = XK_x; const unsigned int keyC = XK_c; const unsigned int keyV = XK_v; const unsigned int keyB = XK_b; const unsigned int keyN = XK_n; const unsigned int keyM = XK_m; const unsigned int keySHIFTRIGHT = XK_Shift_R; const unsigned int keyARROWUP = XK_Up; const unsigned int keyCTRLLEFT = XK_Control_L; const unsigned int keyAPPLEFT = XK_Super_L; const unsigned int keyALT = XK_Alt_L; const unsigned int keySPACE = XK_space; const unsigned int keyALTGR = XK_Alt_R; const unsigned int keyAPPRIGHT = XK_Super_R; const unsigned int keyMENU = XK_Menu; const unsigned int keyCTRLRIGHT = XK_Control_R; const unsigned int keyARROWLEFT = XK_Left; const unsigned int keyARROWDOWN = XK_Down; const unsigned int keyARROWRIGHT = XK_Right; const unsigned int keyPAD0 = XK_KP_0; const unsigned int keyPAD1 = XK_KP_1; const unsigned int keyPAD2 = XK_KP_2; const unsigned int keyPAD3 = XK_KP_3; const unsigned int keyPAD4 = XK_KP_4; const unsigned int keyPAD5 = XK_KP_5; const unsigned int keyPAD6 = XK_KP_6; const unsigned int keyPAD7 = XK_KP_7; const unsigned int keyPAD8 = XK_KP_8; const unsigned int keyPAD9 = XK_KP_9; const unsigned int keyPADADD = XK_KP_Add; const unsigned int keyPADSUB = XK_KP_Subtract; const unsigned int keyPADMUL = XK_KP_Multiply; const unsigned int keyPADDIV = XK_KP_Divide; #elif cimg_display==2 // Define keycodes for Windows. const unsigned int keyESC = VK_ESCAPE; const unsigned int keyF1 = VK_F1; const unsigned int keyF2 = VK_F2; const unsigned int keyF3 = VK_F3; const unsigned int keyF4 = VK_F4; const unsigned int keyF5 = VK_F5; const unsigned int keyF6 = VK_F6; const unsigned int keyF7 = VK_F7; const unsigned int keyF8 = VK_F8; const unsigned int keyF9 = VK_F9; const unsigned int keyF10 = VK_F10; const unsigned int keyF11 = VK_F11; const unsigned int keyF12 = VK_F12; const unsigned int keyPAUSE = VK_PAUSE; const unsigned int key1 = '1'; const unsigned int key2 = '2'; const unsigned int key3 = '3'; const unsigned int key4 = '4'; const unsigned int key5 = '5'; const unsigned int key6 = '6'; const unsigned int key7 = '7'; const unsigned int key8 = '8'; const unsigned int key9 = '9'; const unsigned int key0 = '0'; const unsigned int keyBACKSPACE = VK_BACK; const unsigned int keyINSERT = VK_INSERT; const unsigned int keyHOME = VK_HOME; const unsigned int keyPAGEUP = VK_PRIOR; const unsigned int keyTAB = VK_TAB; const unsigned int keyQ = 'Q'; const unsigned int keyW = 'W'; const unsigned int keyE = 'E'; const unsigned int keyR = 'R'; const unsigned int keyT = 'T'; const unsigned int keyY = 'Y'; const unsigned int keyU = 'U'; const unsigned int keyI = 'I'; const unsigned int keyO = 'O'; const unsigned int keyP = 'P'; const unsigned int keyDELETE = VK_DELETE; const unsigned int keyEND = VK_END; const unsigned int keyPAGEDOWN = VK_NEXT; const unsigned int keyCAPSLOCK = VK_CAPITAL; const unsigned int keyA = 'A'; const unsigned int keyS = 'S'; const unsigned int keyD = 'D'; const unsigned int keyF = 'F'; const unsigned int keyG = 'G'; const unsigned int keyH = 'H'; const unsigned int keyJ = 'J'; const unsigned int keyK = 'K'; const unsigned int keyL = 'L'; const unsigned int keyENTER = VK_RETURN; const unsigned int keySHIFTLEFT = VK_SHIFT; const unsigned int keyZ = 'Z'; const unsigned int keyX = 'X'; const unsigned int keyC = 'C'; const unsigned int keyV = 'V'; const unsigned int keyB = 'B'; const unsigned int keyN = 'N'; const unsigned int keyM = 'M'; const unsigned int keySHIFTRIGHT = VK_SHIFT; const unsigned int keyARROWUP = VK_UP; const unsigned int keyCTRLLEFT = VK_CONTROL; const unsigned int keyAPPLEFT = VK_LWIN; const unsigned int keyALT = VK_LMENU; const unsigned int keySPACE = VK_SPACE; const unsigned int keyALTGR = VK_CONTROL; const unsigned int keyAPPRIGHT = VK_RWIN; const unsigned int keyMENU = VK_APPS; const unsigned int keyCTRLRIGHT = VK_CONTROL; const unsigned int keyARROWLEFT = VK_LEFT; const unsigned int keyARROWDOWN = VK_DOWN; const unsigned int keyARROWRIGHT = VK_RIGHT; const unsigned int keyPAD0 = 0x60; const unsigned int keyPAD1 = 0x61; const unsigned int keyPAD2 = 0x62; const unsigned int keyPAD3 = 0x63; const unsigned int keyPAD4 = 0x64; const unsigned int keyPAD5 = 0x65; const unsigned int keyPAD6 = 0x66; const unsigned int keyPAD7 = 0x67; const unsigned int keyPAD8 = 0x68; const unsigned int keyPAD9 = 0x69; const unsigned int keyPADADD = VK_ADD; const unsigned int keyPADSUB = VK_SUBTRACT; const unsigned int keyPADMUL = VK_MULTIPLY; const unsigned int keyPADDIV = VK_DIVIDE; #else // Define random keycodes when no display is available. // (should rarely be used then!). const unsigned int keyESC = 1U; //!< Keycode for the \c ESC key (architecture-dependent). const unsigned int keyF1 = 2U; //!< Keycode for the \c F1 key (architecture-dependent). const unsigned int keyF2 = 3U; //!< Keycode for the \c F2 key (architecture-dependent). const unsigned int keyF3 = 4U; //!< Keycode for the \c F3 key (architecture-dependent). const unsigned int keyF4 = 5U; //!< Keycode for the \c F4 key (architecture-dependent). const unsigned int keyF5 = 6U; //!< Keycode for the \c F5 key (architecture-dependent). const unsigned int keyF6 = 7U; //!< Keycode for the \c F6 key (architecture-dependent). const unsigned int keyF7 = 8U; //!< Keycode for the \c F7 key (architecture-dependent). const unsigned int keyF8 = 9U; //!< Keycode for the \c F8 key (architecture-dependent). const unsigned int keyF9 = 10U; //!< Keycode for the \c F9 key (architecture-dependent). const unsigned int keyF10 = 11U; //!< Keycode for the \c F10 key (architecture-dependent). const unsigned int keyF11 = 12U; //!< Keycode for the \c F11 key (architecture-dependent). const unsigned int keyF12 = 13U; //!< Keycode for the \c F12 key (architecture-dependent). const unsigned int keyPAUSE = 14U; //!< Keycode for the \c PAUSE key (architecture-dependent). const unsigned int key1 = 15U; //!< Keycode for the \c 1 key (architecture-dependent). const unsigned int key2 = 16U; //!< Keycode for the \c 2 key (architecture-dependent). const unsigned int key3 = 17U; //!< Keycode for the \c 3 key (architecture-dependent). const unsigned int key4 = 18U; //!< Keycode for the \c 4 key (architecture-dependent). const unsigned int key5 = 19U; //!< Keycode for the \c 5 key (architecture-dependent). const unsigned int key6 = 20U; //!< Keycode for the \c 6 key (architecture-dependent). const unsigned int key7 = 21U; //!< Keycode for the \c 7 key (architecture-dependent). const unsigned int key8 = 22U; //!< Keycode for the \c 8 key (architecture-dependent). const unsigned int key9 = 23U; //!< Keycode for the \c 9 key (architecture-dependent). const unsigned int key0 = 24U; //!< Keycode for the \c 0 key (architecture-dependent). const unsigned int keyBACKSPACE = 25U; //!< Keycode for the \c BACKSPACE key (architecture-dependent). const unsigned int keyINSERT = 26U; //!< Keycode for the \c INSERT key (architecture-dependent). const unsigned int keyHOME = 27U; //!< Keycode for the \c HOME key (architecture-dependent). const unsigned int keyPAGEUP = 28U; //!< Keycode for the \c PAGEUP key (architecture-dependent). const unsigned int keyTAB = 29U; //!< Keycode for the \c TAB key (architecture-dependent). const unsigned int keyQ = 30U; //!< Keycode for the \c Q key (architecture-dependent). const unsigned int keyW = 31U; //!< Keycode for the \c W key (architecture-dependent). const unsigned int keyE = 32U; //!< Keycode for the \c E key (architecture-dependent). const unsigned int keyR = 33U; //!< Keycode for the \c R key (architecture-dependent). const unsigned int keyT = 34U; //!< Keycode for the \c T key (architecture-dependent). const unsigned int keyY = 35U; //!< Keycode for the \c Y key (architecture-dependent). const unsigned int keyU = 36U; //!< Keycode for the \c U key (architecture-dependent). const unsigned int keyI = 37U; //!< Keycode for the \c I key (architecture-dependent). const unsigned int keyO = 38U; //!< Keycode for the \c O key (architecture-dependent). const unsigned int keyP = 39U; //!< Keycode for the \c P key (architecture-dependent). const unsigned int keyDELETE = 40U; //!< Keycode for the \c DELETE key (architecture-dependent). const unsigned int keyEND = 41U; //!< Keycode for the \c END key (architecture-dependent). const unsigned int keyPAGEDOWN = 42U; //!< Keycode for the \c PAGEDOWN key (architecture-dependent). const unsigned int keyCAPSLOCK = 43U; //!< Keycode for the \c CAPSLOCK key (architecture-dependent). const unsigned int keyA = 44U; //!< Keycode for the \c A key (architecture-dependent). const unsigned int keyS = 45U; //!< Keycode for the \c S key (architecture-dependent). const unsigned int keyD = 46U; //!< Keycode for the \c D key (architecture-dependent). const unsigned int keyF = 47U; //!< Keycode for the \c F key (architecture-dependent). const unsigned int keyG = 48U; //!< Keycode for the \c G key (architecture-dependent). const unsigned int keyH = 49U; //!< Keycode for the \c H key (architecture-dependent). const unsigned int keyJ = 50U; //!< Keycode for the \c J key (architecture-dependent). const unsigned int keyK = 51U; //!< Keycode for the \c K key (architecture-dependent). const unsigned int keyL = 52U; //!< Keycode for the \c L key (architecture-dependent). const unsigned int keyENTER = 53U; //!< Keycode for the \c ENTER key (architecture-dependent). const unsigned int keySHIFTLEFT = 54U; //!< Keycode for the \c SHIFTLEFT key (architecture-dependent). const unsigned int keyZ = 55U; //!< Keycode for the \c Z key (architecture-dependent). const unsigned int keyX = 56U; //!< Keycode for the \c X key (architecture-dependent). const unsigned int keyC = 57U; //!< Keycode for the \c C key (architecture-dependent). const unsigned int keyV = 58U; //!< Keycode for the \c V key (architecture-dependent). const unsigned int keyB = 59U; //!< Keycode for the \c B key (architecture-dependent). const unsigned int keyN = 60U; //!< Keycode for the \c N key (architecture-dependent). const unsigned int keyM = 61U; //!< Keycode for the \c M key (architecture-dependent). const unsigned int keySHIFTRIGHT = 62U; //!< Keycode for the \c SHIFTRIGHT key (architecture-dependent). const unsigned int keyARROWUP = 63U; //!< Keycode for the \c ARROWUP key (architecture-dependent). const unsigned int keyCTRLLEFT = 64U; //!< Keycode for the \c CTRLLEFT key (architecture-dependent). const unsigned int keyAPPLEFT = 65U; //!< Keycode for the \c APPLEFT key (architecture-dependent). const unsigned int keyALT = 66U; //!< Keycode for the \c ALT key (architecture-dependent). const unsigned int keySPACE = 67U; //!< Keycode for the \c SPACE key (architecture-dependent). const unsigned int keyALTGR = 68U; //!< Keycode for the \c ALTGR key (architecture-dependent). const unsigned int keyAPPRIGHT = 69U; //!< Keycode for the \c APPRIGHT key (architecture-dependent). const unsigned int keyMENU = 70U; //!< Keycode for the \c MENU key (architecture-dependent). const unsigned int keyCTRLRIGHT = 71U; //!< Keycode for the \c CTRLRIGHT key (architecture-dependent). const unsigned int keyARROWLEFT = 72U; //!< Keycode for the \c ARROWLEFT key (architecture-dependent). const unsigned int keyARROWDOWN = 73U; //!< Keycode for the \c ARROWDOWN key (architecture-dependent). const unsigned int keyARROWRIGHT = 74U; //!< Keycode for the \c ARROWRIGHT key (architecture-dependent). const unsigned int keyPAD0 = 75U; //!< Keycode for the \c PAD0 key (architecture-dependent). const unsigned int keyPAD1 = 76U; //!< Keycode for the \c PAD1 key (architecture-dependent). const unsigned int keyPAD2 = 77U; //!< Keycode for the \c PAD2 key (architecture-dependent). const unsigned int keyPAD3 = 78U; //!< Keycode for the \c PAD3 key (architecture-dependent). const unsigned int keyPAD4 = 79U; //!< Keycode for the \c PAD4 key (architecture-dependent). const unsigned int keyPAD5 = 80U; //!< Keycode for the \c PAD5 key (architecture-dependent). const unsigned int keyPAD6 = 81U; //!< Keycode for the \c PAD6 key (architecture-dependent). const unsigned int keyPAD7 = 82U; //!< Keycode for the \c PAD7 key (architecture-dependent). const unsigned int keyPAD8 = 83U; //!< Keycode for the \c PAD8 key (architecture-dependent). const unsigned int keyPAD9 = 84U; //!< Keycode for the \c PAD9 key (architecture-dependent). const unsigned int keyPADADD = 85U; //!< Keycode for the \c PADADD key (architecture-dependent). const unsigned int keyPADSUB = 86U; //!< Keycode for the \c PADSUB key (architecture-dependent). const unsigned int keyPADMUL = 87U; //!< Keycode for the \c PADMUL key (architecture-dependent). const unsigned int keyPADDIV = 88U; //!< Keycode for the \c PADDDIV key (architecture-dependent). #endif const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI // Define a 12x13 font (small size). static const char *const data_font12x13 = " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl" "wlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b{ \\w Wx`xTw_w[wbxawSwkw nynwkyw bwswcwkwuwjwuwozpwtwuwnwtwowkwjwmwuwuwkwIxmxuxowuwmwswowswmxnwjwhwowswowsw0wmwowswuwnwrwowswpwswowkwjwrwqw" "rwpwkwkwtwnwkxsxqxswowswpwswnwswpwswowrwnwmwrwqwqwqwswswrwswowswjwpwlxjwkxuxLw[wcw_wSwkw mw\"wlwiw=wtwmxlwFw cwswnwuwnwkwjwswo{pwrwpwtwtwpwswby`w`yUwlw" "twpwqwpwswowlw\\wrwrxuwHwrwfwuwjwlwlwTyuwVwlwtwawswowswowswcwuwmwuwmwuwmwuwmwuwlwkwuwnwswpwkwkwkwkwkwkwkwkwswoxswowswowswowswowswowswowrwpwswpwrwpwrwpw" "rwpwrwpwswoznwtw Ww (wGwtwtwqwqwqwuwuwuwqwswuwqwqw=wqxtw`{nzp~q{ozowrwnxmwtwow bzawkwuwl}rwuwnwtwuwnwtwowkwjwlyjwIwlwswmwiwkwnwuwnwkwhwnwswowswowkwew" "ewixnwsytwswuwnwrwpwkwrwpwkwkwkwrwpwkwkwuwmwkxsxqwuwtwpwqwqwswowqwqwswowiwmwrwpwswowtwtwpwuwmwuwjwowkwjwlxsxXynzmymznyozlzoznwkwkwtwnwkzuyrzmynzmzowux" "myozmwswpwrwowtwtwrwrwpwrwp{mwlwiwHyuwpwtwkwmxlynzoxswmwmwswnwswowtxq|owtwtwpym{p{owswnwuwmwlwkwqwqxuwuxqwrwpwtwtwqwqwowlwuwuwkwmwlwtwowuwuwdwjznwl{nw" "uwnwkx_wtxtwswtwlwtwWwuytwgyjwmwjwawswoyuwVwlwtwnwtwmwtwnwtwmwuwmwlwuwmwuwmwuwmwuwmwuwmwuwmxuwowkwkwkwkwkwkwkwkwkwrwpwuwtwpwqwqwqwqwqwqwqwqwqwowtwpwsw" "uwqwrwpwrwpwrwpwrwowuwnwswowuwlymymymymymymyuyqymymymymynwkwkwkwjynzmymymymymykwmzowswowswowswowswpwrwozowrwW}q}qwtwtwqwtwtwqwtwtwA}rwuw_{p~r~r}pwtwow" "rwnxmwtwow aw_w]wtwpwuwmxuwmybwjwlyjwIwlwswmwiwnynwtwnznzkwmynwswTyp}pylwmwtwtwtwswuwn{owkwrwp{o{owk|pwkwkxlwkwuwuwuwqwuwtwpwqwqwswowqwqwswoykwmwrwpws" "wowuwuwuwowkwjwnwkwjwDwowswowkwswowswowkwswowswowkwkwuwmwkwswswswswowswowswowswoxlwswowkwswpwrwowtwtwqwtwowrwlwoxkwhxVxuxpwtypwuwjwnwtwnwkwswowtxnxmws" "wowqwqwtwuxqwtwnwtwtwqwswowswmwm{nwuwlxnwkwqwqwtwtwqwrwpwtwtwqwuyuwpwiwhwnwmwrwnwbwkwuwlwlwswoxuxowlwtw`wuwrwszmwtwo}dwuwtwuw[}qymx`wswoyuwow_ylxlwtwo" "yuwoyuwoyuwmwlwuwmwuwmwuwmwuwmwuwmwuwmwt{swk{o{o{o{owkwkwkwlztwpwuwtwpwqwqwqwqwqwqwqwqwqwnxowtwtwqwrwpwrwpwrwpwrwnwmwswowuwiwkwkwkwkwkwkwswswkwswowswo" "wswowswowkwkwkwkwswowswowswowswowswowswowswcwtxowswowswowswowswpwrwowswpwrwWwtwtwqwqwqwuwuwuwqwuwswqwqw>wowuw`}q~q|q}qwrwpwrwowtwnwtwo~ izaw]wtwoykwux" "qwtwswfwjwmwuwuwn}eyaxlwswmwjwjwpwswjwowswmwmwswnzWy]ypwlwtwtwuwswswowrwpwkwrwpwkwkwsyqwrwpwkwkwuwmwkwuwuwuwqwtwuwpwqwqznwqwqzkynwmwrwowuwnwuwuwuwowkw" "jwnwkxkwGzowswowkwswo{owkwswowswowkwkxlwkwswswswswowswowswowswowjxmwkwswowtwnwuwuwuwpxmwtwlwlwlwiwlytwewtwtwqwswowtxoznwswnxmwswnwuwmwuwnwswowtwtwqwtw" "twqwtwnwtwtwqwswowswmwmwswowswmwmwkwqwqwtwtwqwrwowuwuwpwuyuwq~own~own~owbwkwuwmznwswmwbwswawuwrwgwtwhwdwuytwXwJwswnxuw=wtwmwswowtxowswqxmwswowswowswow" "swowswowswnwtwowkwkwkwkwkwkwkwkwkwrwpwtwuwpwqwqwqwqwqwqwqwqwqwnxowtwtwqwrwpwrwpwrwpwrwnwmwswowtwmznznznznznzn~swk{o{o{o{owkwkwkwkwswowswowswowswowswow" "swowswo}qwuwuwowswowswowswowswowtwnwswowtwUwuwuwowswowswowswowsw@}qx`}q~pzo{pwrwpwrwowtwnwtwow aw_w_}owuwmwuwtwrwswuwewjwkwiwJwkwswmwkwiwp|kwowswmwmws" "wkwWym}mypwlwszr{owrwpwkwrwpwkwkwqwqwrwpwkwkwtwnwkwtwtwqwtwuwpwqwqwkwqwqwtwiwnwmwrwowuwnwuwuwuwpwuwlwkwmwjwkwHwswowswowkwswowkwkwswowswowkwkwuwmwkwsws" "wswswowswowswowswowhwnwkwswowtwnwuwuwuwpxmwtwmwkwlwiwmwtydwtwtwqwswowswowtwnwswowkwswnwuwnwtwnwswowtwtwqwtwtwqwtwnwtwtwqwswowswmwmwswowswnwlwkwqwqxuwu" "xqwrwnyowqwpwiwhwpwuwuwowrwpwuwuwdwkwuwlwlwswo{owkxuwawtxtwszmwtwiwdwuwtwuwXwJwswmwuwKzmwtwlwtxowrwpwtxrxl{o{o{o{o{o{o{owkwkwkwkwkwkwkwkwkwrwpwtwuwpwq" "wqwqwqwqwqwqwqwqwowtwpwuwswqwrwpwrwpwrwpwrwnwmznwswowswowswowswowswowswowswowswowkwkwkwkwkwkwkwkwkwswowswowswowswowswowswowswcwuwuwowswowswowswowswowt" "wnwswowtwTymymymymy=wmw^wuwuwmxlxmyowrwowtwnwtwmxmw bwswIwuwmwuwmwuwtwrxswdwjw]wJwkxuxmwlwlwswlwjwowswmwmwswlwSycyawlwswowrwowswpwswowkwjwrwqwrwpwkwkw" "swowkwqwqwsxowswpwjwswpwswowrwnwmxtxnwlwswpwswmwlwlwjwkwHwswowswowkwswowswowkwswowswowkwkwtwnwkwswswswswowswowswowswowkwswowkwswnxlwswpwtwmxmwjwlwiwTx" "uxpwtxowswowtwnwswowkwswnynwtwnwswowtwtwqxuwuxqwtwnwtwtwqwswowswmwlwuwnwswowkwjwswo{pwrwmwmwswnwjwiwnymwtwnycwkwuwlwl{mwmwiw_wrwdwtwVwrw*wswmwuw?wtwlw" "tzqwrwpwtzswkwswowswowswowswowswowswowswnwswpwkwkwkwkwkwkwkwkwswowsxowswowswowswowswowswowrwpwswpxtxpxtxpxtxpxtxnwmwkwswowswowswowswowswowswowswowtxow" "kwswowswowswowswowkwkwkwkwswowswowswowswowswowswowswlwnxtwowswowswowswowswnxmwswnx >wlw\\wkx`wnwrwoznwtwmxl| gybw^wtwozmwsxpzuxfxlx]wnw_wlxjyn{o{nykwnz" "mymwkynymwkwewewjwjwrwswqwp{myozn{owizpwrwpwkwkwrwp{owqwqwsxnyowiyowrwozmwlzmwlwswqxsxnwm}qwjxlwGzozmymznynwjzowswowkwkwswowkwswswswswnynzmzowjymxlznx" "lwswqwrwnwm{mwlwiwHxuxpzmxlymynwswmwnwrwozmxuxo{pwtxn{pzmykwmyo}p{owkyuynwnwrwmwly`w_w_wbwjzo{pwqwnwmwhw_z>zY}M|nwuw2wqwqwryrwqwqyowqwqwqwqwqwqwqwqwqw" "qwqwqwr{qyo{o{o{o{owkwkwkwkznwsxnymymymymycwuynznznznzmwmwkwuynznznznznznznyuzrymymymymynwkwkwkwjynwswnymymymymybzmznznznznwlzmw hwHwlwSwTw {+qnrmqapmp Kpepgpiuhpephscqfqhqfqhqfqhqfqhqfqhqfqhqixgudxdxdxdxdq]q]q]q]wcqjr" "bt`t`t`t`taphpgplt`s_s_s_s_q`q]qmsctnqctnqctnqctnqctnqctnqbsktgs_uauauaucq]q]q]q[saqjqbs_s_s_s_sNpms_snqbsnqbsnqbsnqaq`qns_q !p Zp jp#q\\q6q7q l" "q [sjq Qq -q OqZq]q Cq;q HqWq $rIq`qZq _q iqbqKqFqIq`q hp$q]u JqYpmpLp .p jp ]p Xr`q[r !p Tp\"p\\p6q6q mq Yx Qr -r Ps\\q_s" " Ipkq:q HqWq $qHq`qZq _q iqbqKqFqIq`q hp$q]t IqYpmpLq /q kq Fq_q[q #s Tp\"q^q6p 1p Vu Rs YsJsMy &v])]2_4^U^ 6^T\\5])]1_2]T\\8^U^ K])]2`4^V^3] " " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\" "2a5^U^ 7aV\\4]*\\1a4`V\\8^U^ J]*\\1\\X\\4^V^3\\ " " S],\\1\\W\\5g8^U^6c F],\\1\\V\\5^U^<],\\2]W]6^U^ 8h3],\\0\\W\\5g8^U^ I],\\1\\V\\5^V" "^4\\ ;] " " :\\-]2\\U\\6\\V`7^U^7]U] F\\-]2\\T\\6^U^;\\-]3]U]7^U^ 8\\Va1\\-]1\\U\\6\\V`7^U^ H\\-]2\\T\\6^V^5] =a " " J] " " N\\/]2\\S\\7\\T]6^U^7\\S\\ E\\/]2\\R\\7^U^:\\/]3]S]8^U^ 8\\T^/\\/]1\\S\\7\\T]6^U^ G\\/]2\\R\\7^V^6] =c L^ " " *^ U` O^ )\\S\\ " " !^$^3\\ E]U\\ K^$^4^ G^$^4] J^$^3\\ #^$^3\\ 4^ B[ " "&^ Xe S^ (\\S\\ )Z Q^&^3^2]S\\ A\\S\\ K^&^3^ F^&^4_ >]S" "\\9^&^3^2]S\\ W^&^3^ 6^ Q] M[ ?` ![1^H]?` =]4](\\ %` >b4c Bb ?`2a .a Ib Pb Aa `0`*^ $^.` <^F]F^F]G`G] F\\S\\ ;b %a2a2a2a2a a:]" ".a !^T_ Bg ` Dd2_8n?m7g3]:rD]P]P]@g <] 8] 8] B] 3e J^K^ If7^U^+b@d Fb@f5a Ad4e-] :f Ra0d AaF\\HaF\\HeJ\\?]._0_0_0_0_2\\U\\0tHh@n?n?n?n?].].].]" "-h:_J]w " "P[ 9[/a:aQa7[ Wl \"h E]1]T]+\\R\\;[4dL]Ag=])]2])\\ U^1f8c8k;j1`;k7h?n;h9g 5i*b:_8k6kBl=n?l7mD]H]C].].]L_A].`I`H`K]>kAj6kAj9kBuB]H]F]E]E^L_L^" "R^L^D^I^BrBb7^+b(a D] ;] '] Gd A].].].].] ;] (b:].b #^Q] Dj !a Ff3_8n?m8i4]:rD]P]P]Bk ?_ 9] 9_ C]&[0f I]K]=]0g7^U^-fC\\S] IfBf6c B[" "S]5[S].] `K]>k]*]3]W]6^U^._V_;]Wa5]*]2\\V\\6]Wa7^V^ I]*]2\\V\\5^V^2]7]+^V^ @]W\\=v P[ 9\\1c_8m:`R`Cn?n?l9`QaE]H]C].].]M_@].aKaH`K]?`S`Bk8`S`Bk;_R_BuB]H]F]E]D]MaM]P]L]B^K^ArB]1]&])c D] <] '] G] :].].].].] " ";] (^6]*^ #]P^ E^P\\ V^ H^T^4_8n?m:`S`6]:rD]P]P]C`S` Aa :] :a D]&[1^S\\ I^M^=]0^R[7^U^/^R^EZO\\ L^R^ N]U] :],\\0] \\H]B\\H]=\\M]>" "]._0_0_0_0_0_/uK`R`Cn?n?n?n?].].].]-n@`K]?`S`>`S`>`S`>`S`>`S` H`ScE]H]C]H]C]H]C]H]E^K^@],^T^5],]1\\V\\6\\U`7^V^6]U\\ F],]2\\T\\6^U^=],]2\\U\\6^U^-e9\\U`4],]1\\" "V\\6\\U`7^V^ H],]1\\V\\5^V^3]6]+^V^ B`1`1`1`1`6]W]>u P[ 9]2e>eUf;^ %q $^O\\ F]1]T],]S];[5]T]N\\@]P[=]*]0]2ZR\\RZ $]2]P]<_W]8]N]\\H\\A\\H\\<\\M\\=]/a2a2a" "2a2a1_/]V];_M]C].].].].].].].]-]ObBaL]@^M^@^M^@^M^@^M^@^M^ J^N`D]H]C]H]C]H]C]H]E^K^@]-^Q]5].]1\\T\\7\\S]6^V^5c E].]2]S\\7^U^<].]2\\S\\7^U^,a6\\S]2].]1\\T\\7\\S" "]6^V^ G].]1\\T\\6^V^4]5]+^V^ De6e6e6e6e9\\U\\>u P[ :_3f@gVf<_ &r $]M[ F]1]T],\\R]>d<^T^P]A^OZ=]+].]4]T\\T] &^3^P^=[S]8[K].]4\\X];],]!]<]N]>^O^ " " 8ZM^3`P`Ba9]M^=^J\\C]K_B].],^H\\E]H]C].].]O_>].aKaHaL]A^K^D]N^<^K^D]N^>]JZ6]6]H]E]G]C]MaM]O^P^@^M^-^A]1]&]+_W_ D] >] '] H] 9] B].] ;] )]4](]" " %]N]:c6] G] J^P^7a8_1],^K^;c=]H]D]P]P]E^K^ Ee <] \\I]A\\I]<\\N]=]/a2a2a2a2a2a1]U]<" "^J\\C].].].].].].].]-]K_CaL]A^K^B^K^B^K^B^K^B^K^ K]K^D]H]C]H]C]H]C]H]D^M^?]-]P]4]0]1\\R\\ Ha C]0]2]R] E]0]2\\Q\\ 9c 9]0]1\\R\\ !]0]1\\R\\ ?]4] Di:i:i:i:i" ";\\6]G] P\\ :`5g@gWh>a (_ J]KZ F]1]T],\\R\\?h>]R]P\\@]1]+].]3^V\\V^.] T]2]N]5]8ZJ]-]6]X];]-]!^=]L]?]M] *]5_J_Ec:]L^>]H[C]I^C].],]F[E]H]C].].]" "P_=].]X]M]X]HbM]A]I]D]M]<]I]D]M]?]%]6]H]E]G]C^NaN^N]Q^>^O^-^@]0]'],_U_ &] '] H] 9] B].] ;] )]4](] %]N]:d7] F] K]N]8c8^1],]I]>i@]H" "]D]P]P]E]I] Fg =] =g G]&[2] <]O];]1] 1\\F\\=\\ Q\\F\\ S\\Q\\+]3\\.] IeU\\ M\\3\\N\\ ?\\I\\@\\I\\=]M\\<]0c4c4c4c4c3a1]U]<]H[C].].].].].].].]-]J_DbM]A]I]B]I]B]I]B]I]" "B]I] L]J_E]H]C]H]C]H]C]H]C^O^>].]N] .] '`X_ I] FbWa=bWa=bWa=bWa=bWa<\\6^I^ ?Z2[ :a5gAiXh?c *^ H] 7]1]T]-]S]Aj>]R]Q]@]1]," "],\\1^X\\X^,] T]3]L]6]'].]7]W];]-]!]<]L]?]M^ +]6^F^F]W]:]K]?]FZC]H^D].]-]DZE]H]C].].]Q_<].]X]M]X]H]X]M]B]G]E]M^>]G]E]M^@]%]6]H]E^I^B]O^X]O]M^R^=]O^" "-^@]0]']-_S_ '] '] H] 9] B].] ;] )]4](] %]N]:e8_ H] L]M]8]W]7^2]-]G]AmB]H]D]P]P]F]G] Hi >] >i J[3] ;^Q^;]1] 2\\RbT\\Ge R\\VdR\\ T\\" "Q\\+]4\\2a IfU\\ M\\3\\N\\ ?\\J\\?\\J\\AaM\\ G]W]4]W]4]W]4]W]4]W]4c3^U]=]FZC].].].].].].].]-]H]D]X]M]B]G]D]G]D]G]D]G]D]G]A[H[B]J`E]H]C]H]C]H]C]H]B]O^>g8]N] " " 1]T_ 3[ 9] G_O^?_O^?_O^?_O^?_O^=\\5]I^ @\\3[ ;c6gAy?d7`8]L]7^7]L]>^ H] 6]1]T]-]S]B_W[U]>]R]R]?]1],],]0d*] T]3]L]6]'].]7\\V];]" ".] ]<]L]@]K] 7Z PZ X]7^D^G]W]:]K]?]/]G]D].]-]/]H]C].].]R_;].]X^O^X]H]X^N]B]G]E]L]>]G]E]L]@]%]6]H]D]I]A]O]W]O]L^T^<^Q^-^?]0]'].^O^ Sb7]U`2b4`U]8a8])`" "7]T_ M].]%_O_@_2`0`3`/_3c9] )]4](] N_6]N]3^7a/c0_ <^ D[U^ Ga N]L]9]W]6^3]-]G]B`W]W`C]H]D]P]P]F]G] I_X]X_ ?] ?_X]X_ Nb7]2ZFZ=]Q]:]0] 3[SfU[I" "g R[UfS[ T\\Q\\+]5]2a IfU\\ M\\3\\N\\ ?\\K]?\\K]AaN] G]W]4]W]4]W]4]W]4]W]4]W]3]T]=]/].].].].].].].]-]G]E]X^N]B]G]D]G]D]G]D]G]D]G]B]J]C]KbF]H]C]H]C]H]C]H]B" "^Q^=j;]P_9b3b3b3b3b3b3bN`Bb3a2a2a2a V_2_2`1`1`1`1` ;aU] :]U` S^T]U^A^L^A^L^A^L^A^L^?]5]I] @^5\\ ]R]R\\>]1],],].`(] U^3]L]6]'].]8]V];].]!^<]L]@]K] :] P]#^8^A]I^W^;]K]@].]G^E].].].]H]C].].]S_:].]W]O]W]H]W]N]C]E]F]L]?]E]F]L]@]%]6]H]D]J^A]O]W]O]" "L^U^:^S^-^>]0^(]/^M^ Wh:]Wd6f8dW]:e>h2dW]?]Vd<].].]O_>].]WdScK]Vd8f;]Wd7dW]?]Wa6h>h6]L]B]I]A]P`P]K^L^B^K^@l4]4](] PdU]A]N]2^8e5g;]Vd?^J^8]6]L] E]V`" ">pA]S]S]:e6kDo>]L]:^W^6^4].]E]D_U]U_D]H]D]P]P]G]E] K_W]W_ @] @_W]W_ Qf9]3\\H\\>^S^:]0_ 6[ThT[K]Q\\ S[T\\R]S[ U]S]+]6],] ?]L]@fU\\ M\\3\\N\\ ?\\K\\>\\K\\;]O\\ G" "^W^6^W^6^W^6^W^6^W^5]W]4^T]>].].].].].].].].]-]G^F]W]N]C]E]F]E]F]E]F]E]F]E]D_L_E]K]W]F]H]C]H]C]H]C]H]A^S^^K^ O]S]S]B]I]B]I]B]I]B]I]@]5^K^ @]4[ ;f8gAyAg] F] 6]1]T]-\\R\\B]T[6]R]S]>^2]-]*\\.`(] U" "]2]L]6]'].]9]U];].]!];]L]@]K] =` P`'^7]?\\I]U];]K]@].]F]E].].].]H]C].].]T_9].]W]O]W]H]W^O]C]E]F]L]?]E]F]L]@]%]6]H]C]K]@^P]W]P^K^V^9]S]-^=]/](]0^K^ Xi" ";]Xf9h9fX]h6]L]A]K]@^Q`Q^J^N^@]K]?l4]4](] QfW^A]O^1]6f9h;]Xg@_K]7]6]L]=]G]C^Wc@pA]S]S]]L]:]U" "]5^5].]E]E^S]S^E]H]D]P]P]G]E]@Z+]V]V^-Z4]5ZKZ:]V]V^ Sh9]4^J^>]S]9]._ 8[U_Q[T[L]P\\ S[T\\Q]T[ T]U]*]7]*] @]L]@fU\\ M\\3\\N\\ ?\\L]>\\L]:]Q]:]1]U]6]U]6]U]6]" "U]6]U]6^W^5]S]>].].].].].].].].]-]F]F]W^O]C]E]F]E]F]E]F]E]F]E]C_N_D]L^W]F]H]C]H]C]H]C]H]@]S];]P_=]S^8i:i:i:i:i:i:iVgIh9h9h9h9h<].].].]'d<]Xg:h9h9h9h9h" "0^8k?]L]?]L]?]L]?]L]A]K]>]Xf>]K] O]R]R]D]G]D]VZOZV]D]KZV]D]G]A]4]K] @]3[ j=]L]8`7]N]?] F^ 6]1]T]5uI]T[6]R]S\\<^3]-]*]1d*] U]3]J]7]']" ".]9\\T];].\\Ua-^;]L]@]K^?].] Uc Pc+_8]>]J]U];]K]@].]F]E].].].]H]C].].]U_8].]W^Q^W]H]V]O]C]E]F]L]?]E]F]L]@^&]6]H]C]K]?]Q^V]Q]I^X^8^U^.^<]/](]1^I^ ]R_h6]L]A]K]?]Q`Q]H^P^?]K]?l4]4](] R^U^W]@]O]0^7g;_S];bT^@`L]8_7]L]>]E]E^W]V]@pA]S]S]" "=_T_].].].].].].].].]-]F]F]V]O]C]E]F]E]F]E]F]E]F]E]B_P_C]L]V^G]H]C]H]C]H]C]H]@^U^;]N^>]T]6]R_;]R_;]R_;]R_;]R_;]R_;]R" "_X_T^K_R\\:_S^;_S^;_S^;_S^=].].].]*h=bT^;_T_;_T_;_T_;_T_;_T_1^9_T`>]L]?]L]?]L]?]L]A]K]>aT_?]K] P]Q]R]E]F]E]V\\Q\\W]E]K\\W]E]F]A]4^L] A^@ZN\\ =i8e@yCk?^R^" "=]L]9b8]O^?] Im B]1]T]5uI]T[6]S^T]<^3]-]*]3^X\\X^,] V^3]J]7](^/]9]T];e7]We/]9]N]?]K^?].] Wd Nd._8]O`U\\T\\K]S]<]L^A]-]F^F].]/]-]H]C].].]V_7].]V]Q" "]V]H]V^P]D]C]G]L]@]C]G]L]?^']6]H]C^M^?]Q]U]Q]Ic6^W^._<]/^)]2^G^ !ZM^=`Q^=^NZ;^Q`>^P^=].^Q`?`Q^>].].]R_;].`R^X\\R^M`Q^=^P^>`Q^=^Q`?`1]MZ;].]L]A^M^?]Q`Q]" "G^R^>^M^1^4]4](] D]P^A]R^X]@]P^/]9^Vb=^NZ;`Q^AaN^8_7]L]>]E]F^V]U]>]P]>]S]S]>^P^>`T`7]6]J]<]S]5^6]/]C]G]Q]Q]F]H]D]P]P]H]C]C^&]TZ,^7]7^N^6]TZ H]/^U[TZ9" "]2n;]U]8]0d <[U]F[M\\P]2[R[ M[S\\P\\S[ Tb(]9]'\\ @]L]@fU\\ M\\3]P]9[R[1\\M\\<\\M\\7\\R\\8]2]S]8]S]8]S]8]S]8]S]7]U]6]R]?]-].].].].].].].]-]F]F]V^P]D]C]H]C]H]C]H]" "C]H]C]B_R_C]L]T]G]H]C]H]C]H]C]H]?^W^:]M]>]U^6ZM^].].].]+i=`Q^=^P^=^P^=^P^=^P^=^P^2^:^P^>]L]?]L]?]L]?]L]" "A^M^>`Q^@^M^ P]Q]Q]F]E]F]W^S^W]F]L^W]F]E]B]3]M^ B^B^O[ =k8d?xClA^P^>]L]9]X]8^P]>\\ Hl A] 9uI]T[5]T]T]:^ =]*]5^V\\V^.] V]2]J]7](]/^:]S];h:]Xg0]" "9^P^?]K^?].]!e Je2_7\\PdW\\S\\L]S]<]M^@]-]E]F].]/]-]H]C].].]X_5].]V]Q]V]H]U^Q]D]C]G]L]@]C]G]M^?`)]6]H]B]M]>]Q]U]Q]Hb5c-^;].])] B]=_O]=].]O_>]N^>].]O_?_" "O]>].].]S_:]._P`P]M_O]=]N]>_O]=]O_?_1]-].]L]@]M]>]RbR]G^R^=]M]1^3]4](] FaSaD^Qa?]R_.]9]R`>]._O]>^N]8`7]L]>]E]G^U]U^?]P]>]S]S]>]N]>^P^7]6]J]<]S]4^7]/]" "C]G]Q]Q]F]H]D]P]P]H]C]D_&]&_8]8_N_7] B]/]T[3]1l:^W^8]1]W` >\\U\\E\\N\\P]3\\S\\ N\\S\\P\\S\\ S_']:]&\\ @]L]@fU\\ M\\2\\P\\8\\S\\2\\N]<\\N]7\\S]8]2]S]8]S]8]S]8]S]8]S]8]S]" "7]R]?]-].].].].].].].]-]E]G]U^Q]D]C]H]C]H]C]H]C]H]C]A_T_B]M]S]G]H]C]H]C]H]C]H]>c9]M^?]U]'].].].].].].`O^N].]N^>]N^>]N^>]N^?].].].],_R^>_O]=]N]=]N]=]N]" "=]N]=]N]2^:]O_?]L]?]L]?]L]?]L]@]M]=_O]?]M] O\\P]Q]F\\D]F\\U^U^V]F\\L^V]F\\D]B]3]M] RuJ`O[ >m9c>wCmA]N]>]L]9]X]7]P]?] Im A] 2\\R\\A]T[5^V^T\\:` ?](\\6]T" "\\T]/] V]2]J]7])^1_9]S];i;bS^2^8^S_>]K^?].]$e@u@e6_7]QfX\\S\\M^S^=]N^?]-]E]F].]/]-]H]C].].c4].]U]S]U]H]T]Q]D]C]G]M^@]C]G]M]=c-]6]H]B]M]>^R]U]R^G`4c.^:]" ".])] B]=^M]?^/]M^?]L]>]/]M^?^N^?].].]T_9].^O_O^N^N^?]M^?^M]?]M^?^0]-].]L]@]M]>^S]X]S^F^T^<^O^2_3]4](] GcUcE]Pa?]Vb-]:]O_?].^N^>]O^8a8]L]?]C]H]T]T]?" "]P]>]S]S]?]L]@^N^8]6]J]=^S^4^8]/]C]H^Q]Q^G]H]D]P]P]H]C]E_%]%_9]9_L_8] B]0^T[3]0_T_>cWc=]1]U_ ?[U\\C[N]R^4]T] N[R\\Q]R[ 'uG]&] @]L]?eU\\ M\\2]R]8]T]3\\N\\;" "\\N\\7]S\\7]3^S^:^S^:^S^:^S^:^S^9]S]8^R]?]-].].].].].].].]-]E]G]T]Q]D]C]H]C]H]C]H]C]H]C]@_V_A]N]R]G]H]C]H]C]H]C]H]>c9]L]?]U]'].].].].].]._M]O^/]L]?]L]?]L" "]?]L]?].].].]-^O]>^N^?]M^?]M^?]M^?]M^?]M^ I]O`?]L]?]L]?]L]?]L]@^O^=^M]@^O^ P]P]P\\G]C\\G]T^W^T\\G]M^T\\G]C\\B]3^O^ RuJ[X]P[ >o=\\XaX]BwDoC]L\\>]L]:^X^8]P]?" "] E] 5] 3]S]A^U[4dT];b @](]6ZR\\RZ.] V]2]J]7]*^7d8]R];]R_]-]E]Fm>k=]-rC].].b3].]U]S]U]H]T^R]D]C]G]M]?]C]" "G]N^^M]?].]M^?]L]>]/]M^?^M]?].].]U_8].^N^N]N^M]?]L]?^M]?]M^?^0]-].]L]@^O^=]S]X]S]D^V^:]O]2_2]4](] H\\U^W]U\\E]Pa?" "]Vb-];]M^?].^M]>^P]7a8]L]?]C]H]T]T]?]P]>]S]S]?]L]@]L]8]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]F_$]$_:]:_J_9] B]0]S[3]0]P]>o=]2]S_ @[U\\C[M]T_5^U^;u O[R\\R]" "Q[ 'uH]/ZQ] ?]L]?eU\\ M\\1]T]7^U^4\\O]O]I\\O]T`MZQ]S]O]E]3]Q]:]Q]:]Q]:]Q]:]Q]:^S^9]QmO]-m>m>m>m>].].].]1hL]G]T^R]D]C]H]C]H]C]H]C]H]C]?_X_@]O]Q]G]H]C]H]C]" "H]C]H]=a8]L]?]U]&].].].].].].^M]O].]L]?]L]?]L]?]L]?].].].].^M]?^M]?]L]?]L]?]L]?]L]?]L] I]Pa?]L]?]L]?]L]?]L]?]O]<^M]?]O] O]P]P\\G]C\\G]ScS\\G]N^S\\G]P]P\\B" "]2]O] QuF]Q[ >oAqDuDqD]L]?]L]:^X^8^R^?\\ D] 5] 3]S]@`X[3bS\\R^G]W^N] P](].\\&] W]1]J]7]*^7c8]Q];ZM^=`O^4]4d:]M_?].])d:u:d=_5\\R]O^R\\N]Q]=j<]-]E]F" "m>k=]-rC].].a2].]U^U^U]H]S]R]D]C]G]N^?]C]G]P_:g3]6]H]A]O]<]S]S]S]E^1_.^8]-]*] A]>^M]?]/^M^?]K]?]0^M^?]L]?].].]V_7].]M]M]N]L]@^L]?^M]@^M^?]/]-].]L]?]" "O]<]S]X]S]C^X^9]O]2^1]4](]0_IZ O[R\\X]S\\G^O_>]Vd9_U];]L]?].]L]=]P]8]X^9]L]?]C]I^T]S]@]P]>]S]S]?]L]@]L^9]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]G_#]#_;];_H" "_:] B]0]S[3]0\\N\\>o=]2]Q^ A[U\\C[LcX\\6]T]9u O[RfP[ 'uIf7e >]L]>dU\\<] :f5d4]T]:fT\\O^NfT\\UdOeR\\O^F^3]Q]:]Q]:]Q]:]Q]:]Q]:]Q]:^QmO]-m>m>m>m>].].].]1hL]G]S]R" "]D]C]H]C]H]C]H]C]H]C]>d?]P^Q]G]H]C]H]C]H]C]H]<_7]L]?]U^'].].].].].].^L]P].]K]@]K]@]K]@]K]@].].].].]L]?]L]@^L]@^L]@^L]@^L]@^L] I]Q]X^@]L]?]L]?]L]?]L]?]" "O]<^M]?]O] O\\WmX]H\\WmX]H\\QaR]H\\N^R]H\\O]P]C]2]O] QuF]R\\ ?qCsDtDrE]L]?]L]:]V]7]R]>x '] 5] 3\\R\\?e3^R\\SbJ^V^O] P](].\\&] W]1]J]7]+^6e:]Q]-^>_M]5^6" "h<^O` Qe8u8e@^5]R\\M]R\\O^Q^>m?]-]E]Fm>k=]KdFrC].].b3].]T]U]T]H]S^S]D]C]G]P_>]C]Gk6f5]6]H]A^Q^<]S]S]S]F_1_/_8]-]*] A]>]K]A].]K]@]J]?]0]K]?]L]?].].]W_" "6].]M]M]N]L]@]J]@]K]A]K]?]/^.].]L]?]O]<]T^W]T]C^X^9^Q^3^1]3]']3dN\\ P\\R`Q[G]N_>]Q`;bW];\\K^?]/]L]=]Q^8]W]9]L]?]C]I]S]S]@]P]>]S]S]@]J]B^L^9]6p>^Q^4^9]/]C" "]H]P]P]G]H]C]Q]Q]G]ViV]H_\"]\"_<]<_F_;] B]1]R[3]1]N]8a6]2]P^ B[U\\C[K`V\\7]T]8u O[RdN[ 'uIf5a <]L]=cU\\<] :f3`1]T];fU\\N^NfU\\T[S]NaQ\\N^G^3^Q^<^Q^<^Q^<^Q^<^Q" "^;]Q]:]PmO]-m>m>m>m>].].].]1hL]G]S^S]D]C]H]C]H]C]H]C]H]C]=b>]P]P]G]H]C]H]C]H]C]H]<_7]L]?]U_(].].].].].].]K]Q].]J]A]J]A]J]A]J]@].].].].]L]?]L]@]J]A]J]A" "]J]A]J]A]J] K]P\\V]@]L]?]L]?]L]?]L]?^Q^<]K]@^Q^ O\\WmX]H\\WmX]H\\P_Q]H\\O^Q]H\\O]P]C]2^Q^ D^<]R[ >qDuEsCqD]L]?]L]:]V]7]R]>x '] 5] 3\\R\\=f+]TdL^T^P] P]" "(].\\2u *]1]J]7],^-_=]P],]>_M]5]7_R^<^Qa Sd .dC^4\\R]M]R\\O]O]>]N_@]-]E]F].]/]KdF]H]C].].]X^4].]T]U]T]H]R]S]D]C]Gk=]C]Gj1c6]6]H]@]Q];^T]S]T^Ga1].^7]-]*" "] Lh>]K]A].]K]@]J]?]0]K]?]L]?].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]._0].]L]>]Q];^U]V]U^Bb7]Q]3^1^3]'^6iS^ P[P^P[G]N_>]N^=dX]<]J]>^1]L]=^R]8^W]9]L]@]A]J]S" "]S]@]P]>]S]S]@]J]B]J]9]6]J]>]O]5^8]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]]K]@]" "O[X\\I`3]O]<]O]<]O]<]O]<]O]<]O];]P]?]-].].].].].].].]-]E]G]R]S]D]C]H]C]H]C]H]C]H]C]<`=]Q]O]G]H]C]H]C]H]C]H];]6]L]?]T_4h9h9h9h9h9h9hK]Q].]J]A]J]A]J]A]J]" "@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]Q\\U]@]L]?]L]?]L]?]L]>]Q];]K]?]Q] N\\WmX]H\\WmX]H\\P_Q]H\\P^P]H\\O]P]C]1]Q] C]:]S[ ?sEvEqAoC]L]?]L];^V^8^T^>x " " '] 5] 4]S]]K]A].]K]@p?]0]K]?]L]?].].b3].]M]M]N]L]@]J]@]K]A]K]?].c4].]L]>]Q]:]U]V]U]@`6^S^4^5b2]&b^Ua<]J]=" "c7]L]<]S^8]V^:]L]@]A]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?^O^7^7]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]\\I\\@\\O\\X\\J`3^O^>^O^>^O^>^O^>^O^=]O]<^P]?]-].].].].].].].]-]E]G]R^T]D]C]H]C]H]C]H]C]H]C];^<]R]N]G]H]C]H]C]H]C]H];]6]L]?]S`8j;j;j;j;j" ";j;|Q].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]R]U]@]L]?]L]?]L]?]L]>^S^;]K]?^S^ N\\WmX]H\\WmX]H\\QaR]H\\Q^O]H\\O]P]C]1^S^ D]9]T\\ ?sFwDo?nC]L]?]L];" "]T]7]T]=] Hj ?] 4]S]8d/]T]T]N^R_R\\ O](] =u Se =]0]J]7].^(]?]O]+]?^K]7]7]L]]K]A].]K]@p?]0]K]?]L]?].].a2].]M]M]N]L]@]J]@]K]A]K]?]-f8].]L]>^S^:]U]V]U]?^4]S]4^4`0]$`<^Si O[O" "\\O\\H]N^=]M^@^S`<]J]=c7]L]<]S]8^U]:]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?]M]7]6]/^E^H]P]P]G]H]A]S]S]E]C]Iz<]]M]>]M]>]M]>]M]>^O^=]O]?]-].].].].].].].]-]E]G]Q]T]D]C]H]C]H]C]H]C]H]C]<`=]S]M]G]H]C]H]C]H]" "C]H];]6]M^?]R`;l=l=l=l=l=l=~Q].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]S]T]@]L]?]L]?]L]?]L]=]S]:]K]>]S] M]P]P\\G]C\\G]ScS\\G]S^N\\G]P]P\\B]0]S] D]" "7\\T[ >sFwCn?mB]L]?]L];]T]7]T]=] Hi >] 4]S]7[Xa1]T^T^O]P_T] O](] =u Se =]0]J]7]/^'^A]N]+]?^K]7]8^L^]K]A].]K]@p?]0]K]?]L]?].].b3].]M]M]N]L]@]J]@]K]A]K]?]+e9].]L]=]S]9]V]T]" "V]@_4]S]5_4b2]&b<\\Nd M[O]P\\H]N^=]L]@]Q_<]J]?e7]L];]T]8]T]:]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?]M]8^6].]E]G]P]Q^G]H]A^T]T^E]C]Iz<]]M]>]M]>]M]>]M]>]M]>^O]?]-].].].].].].].]-]E]G]Q^U]D]C]H]C]H]C]H]C]" "H]C]=b>]T]L]G]H]C]H]C]H]C]H];]6]M]>]Qa>`P]>`P]>`P]>`P]>`P]>`P]>`PoQ].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]T]S]@]L]?]L]?]L]?]L]=]S]:]K]>]S] " "L\\P]P\\F\\C\\F\\T^W^T\\F\\T^M\\F\\C\\B]0]S] E^7]U[ >sFwBl=kA]L]?]L]<^T^8^V^=] Ij >] ]K]A].]K]@],]0]K]?]L]?].].c4].]M]M]N]" "L]@]J]@]K]A]K]?](d;].]L]=]S]9^W]T]W^@`5^U^5^/_3]'_8ZJ` K[O]P\\H]N^=]L]@]P];]J]@_0]L];]U^9^T^;]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]@^M^:^5].]E]F]Q]Q]F" "]H]@^U]U^C]E]G_\"]\"_BZT]TZB_F_;] B]1]R[3]1\\L\\?o I_S] A[U]F[ V]T] W] N[S\\R]R[ S] ]L]6\\U\\ ']T]/\\O\\V\\@\\H\\A\\O\\V\\M_0o@o@o@o@o?m>l>].].].].].].].].]-]F^" "G]P]U]C]E]F]E]F]E]F]E]F]E]=d?^V]L]F]H]C]H]C]H]C]H];]6]N^>]O`?]M]>]M]>]M]>]M]>]M]>]M]>]M]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J] K]U]R]@]L]?]L]?" "]L]?]L]=^U^:]K]>^U^ L\\P]Q]F\\D]F\\U^U^V]F\\U^M]F\\D]B\\/^U^ OuD]V[ =sFwBk;i@]L]?]L]<]R]7]V];] F^ Nu=[T^3]S]R]O]N_V\\ N](] 1] ].]L]6]1_%]Aq0]>]K]" "8]7]J]/] Md:u:d>]3\\R\\K\\S\\Po@]J]A].]F]E].].]E]F]H]C].].]S^9].]RaR]H]P^V]C]E]F].]E]F]M],]8]6]H]>]U^8]W^Q^W]H^U^4]2^3]+],] R^M]>]K]A].]K]@],]0]K]?]L]?" "].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]$`;].]L]=^U^8]W]T]W]@b5]U]5^,]3]'] J\\Q_Q[G]N^=]L]A]O];]J]@].]L];]U]8]R];]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]5]L]?]K];" "^4].^G^F]Q]Q]F]H]?_W]W_B]E]F_#]#_B\\U]U\\B_H_A\\U]U[ H]1]R[3]1]N]?o H`V] @[T]G[ U]T] X] N[S\\Q]S[ S] ]L]6\\U\\ (]T]/]P\\U\\A]I]B]P\\U\\M^/o@o@o@o@o@o@m>].]" ".].].].].].].]-]F]F]P^V]C]E]F]E]F]E]F]E]F]E]>_X_?]W^L]F]H]C]H]C]H]C]H];]6]P_=]M^@^M]?^M]?^M]?^M]?^M]?^M]?^M]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]" "A]J] K]U\\Q]@]L]?]L]?]L]?]L]<]U]9]K]=]U] K]Q]Q]F]E]F]W^S^W]F]W^L]F]E]B\\.]U] NuC\\V[ =eXZXdFgXhAi9h@]L]?]L]<]R]7]V];] E] Nu=[S]3\\R]R]O]M_X\\ M](" "] 1] ].]L]6]2_$]Aq0]>]K]8]7]J]/] Ke=u=e<]3\\R\\K\\S\\Po@]J]A].]F]E].].]E]F]H]C].].]R^:].]RaR]H]O^W]C]E]F].]E]F]M^-]8]6]H]>]U]7]W]O]W]I^S^5]3^2]+],] R" "]L]>]K]A].]K]@],]0]K]?]L]?].].]W_6].]M]M]N]L]@]J]@]K]A]K]?]\"_<].]L]<]U]7]W]T]W]Ac5^W^6^+^4](] H[R\\X]S\\G]N^=]L]A]O];]J]A^.]L]:]W^9^R];]L]@]O]O]J]S]S]@" "]P]>]S]S]@]J]B]J]9]5]L]?]K];^4]-]G]D]R]R]E]H]>kA]E]E_$]$_B^V]V^B_J_A^V]V] I]1]R[3]0\\N\\>o G`X] ?\\U_Q[T\\ T]T] ] N\\T\\Q]T\\ S] ]L]6\\U\\ )]T].\\P\\T\\A\\I]A" "\\P\\T\\N^.o@o@o@o@o@o@m>].].].].].].].].]-]F]F]O^W]C]E]F]E]F]E]F]E]F]E]?_V_@]W]K]F]H]C]H]C]H]C]H];]6k<]L^A]L]?]L]?]L]?]L]?]L]?]L]?]L]?].].].].]-].].].]/" "]J]@]L]@]J]A]J]A]J]A]J]A]J] K]V\\P]@]L]?]L]?]L]?]L]<^W^9]K]=^W^ J]R]R]D]G]D]W\\Q\\W]D]W\\L]D]G]A\\.^V] NuC]W[ ]K]9]6]J]/] He@u@e H\\R]M]T]Q^J]A]J]@]/]G^E].]-]F]F]H]C].].]Q^;].]Q_Q]H]N]W]B]G]E]-]G^F]L]-]8]6]I^>^W^7]" "W]O]W]I^R^6]4^1]+],] R]M^>^M^@]/^M^?]-]0^M^?]L]?].].]V_7].]M]M]N]L]@^L]?^M^A^M^?] ]<].]L]<]U]7]X]R]X]B^W^5]W]6^)]4](] H\\T]W]U\\F]O_=]L]A]P^;^L^A]-]L" "]:]W]8]P]<]L]@]O]O]J^T]T]?]P]>]S]S]@^L]A^L]8]5]L]@^J]=^3]-^I^D^S]S^E]H]]G]C_%]%_A_W]W_A_L_@_W]W_ J]0]S[3]0]P]5]4],b =[ThT[ R]T]!] M[T\\P]U[ R] ]L" "]6\\U\\ *]T].]P[S\\B]J]A]P[S\\N].^J]B^J]B^J]B^J]B^J]B^K^A]M]=]/].].].].].].].]-]G^F]N]W]B]G]D]G]D]G]D]G]D]G]?_T_AbK]E]I^C]I^C]I^C]I^;]6j;]K]A]M^?]M^?]M^" "?]M^?]M^?]M^?]M_?].].].].].].].].]/]J]@]L]@^L]@^L]@^L]@^L]@^L] J^X]Q]?]L]?]L]?]L]?]L];]W]8^M^<]W] I]R]S]C]H]C]VZOZW]C]VZL]C]H]@\\-]W] MuC]X[ ;cWZWbDe" "WZXe>e6e>]L]?]L]=]P]8^X^:] F^ H\\R\\5[S]5]Q]R]O^L` K]*] 0] !^.]L]6]4_\"]2],^>^M]8]6]J]0] DeCuCe E]R\\M]T\\P]I]A]J]@]/]G]D].]-]F]F]H]C].].]P^<].]Q" "_Q]H]N^X]B]G]E]-]G]E]L^.]8]5]J]<]W]6^X]O]X^J^Q^6]5^0]+^-] R]M^>^M]?].]M^?]-]/]M^?]L]?].].]U_8].]M]M]N]L]?]L]?^M]?]M^?] ]<].]M^<^W^6aRbB^V^6]W]7^(]4]" "(] GcUcE]P_=]L]A]P]9]L]@]-]L]:^X]9^P]<]M^@]P^O]I]T]T]?]P]>]S]S]@^L]@]L]8]5]M]?]I]>^2],]I]B_U]U_D]H]:c<]G]B_&]&_?_X]X_?_N_>_X]X_ I]0]S[3]0_T_5]4]+` ;[" "SfU[ P^U^#] L[U\\P]V[ Q] ]M^6\\U\\ ,^U^-\\P\\S\\B\\J]@\\P\\S\\N].]I]B]I]B]I]B]I]B]I]B]I]B^M]=]/].].].].].].].]-]G]E]N^X]B]G]D]G]D]G]D]G]D]G]@_R_A`J]D]J]A]J" "]A]J]A]J]:]6g8]K]A]M^?]M^?]M^?]M^?]M^?]M^?]M_?].].].].].].].].].]L]?]L]?]L]?]L]?]L]?]L]?]L]3^;aP]?]M^?]M^?]M^?]M^;]W]8^M];]W] H]S]T^B]J^B]J^B]J^B]J^@" "\\-]W] G^1_ :aW[V`BcW[Wc]N]<]P]7]X]8] F]KZ X]S]5[S]5\\P]R]N]K_ K]*] 0] !],]N]5]5_\"]1],]<]M]9^6^L^0] Ad Nd A\\R]O^U\\P^I^B]K^?]H[C]H^D]" ".],]G]F]H]C].].]O^=].]P^Q]H]M]X]A]I]D],]I^E]K]AZH^8]5]J]<]W]5bObJ^O^7]6_0]*]-] R]M^>^M]?^/]M^?^.]/]M^?]L]?].].]T_9].]M]M]N]L]?]L]?^M]?]M^?] ]<].]M^;" "]W]5aRaB^U^6c8_(]4](] FaSaD]P_=]M]@]P]9]L]@]-]L]9b9]O^=^N^?\\P_Q]H]T]T]?]P]=]T]T]?^L]@]L]8]4]N]@^I^?]1],^K^A`W]W`C]H]7]8]I]@^&]&^=i=^N^^P^=^P]7]X]8_ H^M[ F] 6]S]>ZQ[T^6]P]S^N^K^ K]*] 0]:] 8]0],]O^5]6_2ZI]1]-^<^O^9]4]L]0]<].] Uc Pc1]2\\Q^S`W^P]G]B]K]" ">^J\\C]I^C].],^H]F]H]C].].]N^>].]C]H]MbA^K^D],^K^D]K^B[I]7]5^L^_O]=].]O_>].].]O_?]L]?].].]S_:].]M]M]N]L]>]N]>_O]=]O_?] ]<]-" "]O_;]X^5aRaC^S^6a8_']4](] D]P^B^Ra>^N]@]Q]7]N]?^.]L]9a8]N]=^N^?]Q_Q]G]U]U]>]P]=]T]T]?_N]>]N]7]4^P^@]G]@^1]+^M^?mB]H]7]8^K^?\\%]%\\;g;\\L\\:g G]/]T[3]2n7]" "4]'^ <\\F\\ M\\S\\ J\\F\\ L^N^6\\U\\ ,\\S\\-]OhG]K]@]OhQ]LZ=]G]D]G]D]G]D]G]D]G]D]G]D^L]<^J\\C].].].].].].].]-]J_D]MbA^K^B^K^B^K^B^K^B^K^A_N_B^K]B^L^A^L^A^" "L^A^L^:]6].]K]A^O_?^O_?^O_?^O_?^O_?^O_?^Oa?].].].].]/].].].]-]N]>]L]>]N]=]N]=]N]=]N]=]N]2^;_O]=]O_>]O_>]O_>]O_:a7_O]9a E^P_>^P_>^P_>^P_>^P_>\\,a H^.]" " /[5]T[S\\8a1`<]L]=^R^<]O^8b7_ H^O\\ F] 6\\R\\=[R[U^5\\N]T]L^M` L]*] 0]:] 8]1^+]P]4]7_1[L_1]ZM];].] R` P`.]2]QfXaN]G]B]L^=^L]C]K_B].]+" "_J]F]H]C].].]M^?].]C]H]La@^M^C]+^M^C]J]B]L^7]4^N^:a4aMaK^M^8]7^.]*^.] Q]P`>`Q^=^NZ;^Q`>_LZ>].^Q`?]L]?].].]Q^;].]M]M]N]L]>^P^>`Q^=^Q`?]/ZL];]-^Q`:a4`" "P`D^Q^7a8^&]4](] S]Sb>_P^@]R^7^P^>^MZ<]L]9a9]M]=_P`XZB]Q_Q]G^V]V^>]P]=^U]U^?`P^>^P^6]4]Q^?]G]A^0]*^O^]P`>]P`>]P`>]P`>]P`>]P]X^LZN^NZ;_LZ>_LZ>_LZ>_LZ?].].].]-^P^>]L]>^P^=^P^=^P^=^P^=^P^2^:^P^=^Q`>^Q`>^Q`>^Q`:a7`Q^9a Dk],a " "H]-] /[,[._0_;]L]=j<]N]7`5a J_S^ F] 6\\R\\=^U[W_5]N^V^K_Rd L],] /]:] 8]1])^T^3]8_0^Q`0]<]Q_8^S^8^3_R_=]R^:].] O] P]+]1\\PdW`N^G^C]N_;`R`C]NaA].]*`O" "`F]H]C].].]L^@].]C]H]La?`S`B]*`S`B]J]B`Q_6]3_R_9a4aMaL^K^9]8^-])].] Q_Tb>aS^;_R\\:^Sa=`Q]>]-^Sa?]L]?].].]P^<].]M]M]N]L]=_T_=aS^;^Sa?]/^R_:]-^Sa:a3_P_" "C^P^7_8^%]4](] S_V^X^?aS^>]T^5_T_=`R]<]L]8_8]M^>`SdA]SaS]E^W]W^=]P^=_W]W_>]X]T_<_T_5^4^T^?^G^C^/])^Q^8c=]H]7]6`S` ?] ;c >c E]._W[V\\9]4^J^9]4]%] ;]L]" " IZQZ H]L] !u ,`Sd9\\U\\ ,ZQZ,]E\\E]L]?]E\\M_S^>^G^F^G^F^G^F^G^F^G^F^G^F^K]:`R`C].].].].].].].]-]ObB]La?`S`>`S`>`S`>`S`>`S`?]J]CcS`?_R_=_R_=_R_=_R_8]6" "].]V[R^?_Tb>_Tb>_Tb>_Tb>_Tb>_Tb>_T^V_Q]M_R\\:`Q]=`Q]=`Q]=`Q]?].].].],_T_=]L]=_T_;_T_;_T_;_T_;_T_1^:`T_;^Sa=^Sa=^Sa=^Sa9_6aS^7_ Bi:i:i:i:i=]+` I],] /[" ",[-].]:]L]]C]H]K`>kA])kA]J^Cm5" "]2j7_2`M`K^J]9]8tC])].] PgX]>]Xf9h9fX]],fX]?]L]?].].]O^=].]M]M]N]L]qA^U]W]U^D" "i<]O`?k=]Xg:h3a7f>uCn?]/eSe;]:]H]7]5k >] :a n?\\H\\8]4]%] 9^R^ *^R^ Xu ,q9\\U\\ /]D\\F]LfH]D\\Li>]E]F]E]F]E]F]E]F]E]F]E]F]JnIkBn?n?n?n?].].]." "]-n@]K`>ki-]]C]H]K`]Wd6f8dW]:i>]+dW]?]L]?].].]N^>].]M]M]N]L];f;]Wd7dW]?]/i7c3dV]9_2_P_E^M^8_8m4]4](] QdV`B]Xe;d1f8h<]L]8_9]K]>]XdW_@eWeBg;]O" "`=g;]Vd8f1`6d=uCn?]/eSe;]:]H]7]3g <] 9_ :_ C]+f>n>ZFZ7]4]%] 7f &f Vu ,]XdW_9\\U\\ /\\C\\F\\KfH\\C\\Kg=]E]F]E]F]E]F]E]F]E]F]E]F]JnHh@n?n?n?n?].].].]-l>" "]K`]C]H]J_9a<]$d?]I^?c0].b3_2" "_K_M^G^;]8tC](]/] M`T]>]U`2b4`U]7c;])`U]?]L]?].].]M^?].]M]M]N]L]8`8]U`3`U]?],c2a0_T]9_2^N^F^K^8]7m4]4](] O`R^B]Va8b-`3d:]L]7]9^J]?]V`T]>cUc?c9]N_:" "a8]T`3`-_4`X IX *W FW " " " " " " HX W 4Z 3VCT X W 4Z " " HX W 4Z 'VCT ;X W 3Y 2UCT KX W 3Y 0W " " " " " " @W !W 4\\ 5YET ?XHX 8] >W !W 4\\ 7XGX KW !W 4\\ 7XHX +YET :W !W 3[ 5ZFT ?XGX EW !W 3[ 7XGX 5W " " " " " " >W \"V 3\\ 7]HU ?XHX 9` ?W \"" "V 3\\ 7XGX JW \"V 3\\ 7XHX -]HU 9W \"V 3] 7]HT ?XGX DW \"V 3] 8XGX 5V " " " " " " W $V 3VNV 8XGX IW $V 3VNV 8XHX -_KV 8W $V 2] 7_KU ?XGX CW $V " "2] 8XGX 6V " " " " :W &W " "4VLV :j >XHX :VJV >W &W 4VLV 9XGX HW &W 4VLV 9XHX .j 6W &W 3VMV 9i >XGX BW &W 3VMV 9XGX 7W MW " " " " " " CV 'W 4VJV ;j >XHX ;UGV >V 'W 4VJV :XGX GV 'W 4VJV :XHX .j" " 5V 'W 3VKV :i >XGX AV 'W 3VKV :XGX 8W N[ " " " " " " DV )W 4VHU TEY ;XHX V ,V 2UEU TCU :XGX =U -V 2UCU =XGX ;V NV" "IV \"W " " " " JU /V 3VBV ETBT :U /" "V 3VBV FU /V 3VBV (U /V 2UAU DU /V 2UAU @V NVGV " " $X " " *X " " JX GTBT MX GX 7V :UEU DX GX 7V " " JX GX 7W 4X GX 6V GX GX 5V (X &X " " )X 8V " " ;X FTBT " " LX IX 7X W E\\ AW ,W ,W ,W ,W " " HY GV +Y 4Z NX @X %W " " DUDU =Y 7W KW 6Z 4XDT BTAT BW KW 6Z IW KW 6[ ,Y )XDT AW KW 5Z 4XDT " " KW KW 4Z ,W BW 8V (S W H_ AW ,W ,W ,W ,W L] GV +] ;a " " #[ F^ 8XGX +W BTEU " " *R 9a :W MW 6\\ 6ZET ?XHX W Ja AW ,W ,W ,W ,W N_ GV +_ " "?e 8] J] Jb 8[ <[ $Y FY 7XGX =Z Di 5W 8Z .Y !W FW *Y 4W)V*W)V-Y(V " " W $a MY " " EW 5W >W Kb AW ,W ,W ,W ,W !a GV +a Ch =f ^ Mf 2Z @x Mx a 5a &W 0g #\\ -_ <\\*V.\\*V0a-V\"X )Z /Z /Z /Z /Z 4WJV 1~U+d Kx Mx Mx Mx MX -X -X -X ,j" " @[3X Dc 8c 8c 8c 8c W \"W 4VNV 8]HU ?XHX " "BW \"W 3VNV 8XHX 2W ?W &XHX ^ K~\\ >S 3Q +[ @[;[ ;Q ;e HX 2VFV #VBV FS 6`1V#g GV !V 3V !T 7W 0d" " :` ;j ?k -[ Dq :g Ky Df ;d $f 1Z @o 5j Np Ex Mt :m\"X/X'X -X -X3Z%X -]0]0\\4X Gi Lm 4i Ln ;m#~W$X/X-X(X-X4Y4XCY1Y-Y.Y&~S%a >W $a N[ EV " "5W >W Lc AW ,W ,W ,W ,W \"b GV +a Dk Aj \"_ h 3Z @x Mx ?i 6X C~Q)X?X?X Ni 6V /V /" "V DX &f #W0W e >XGX %c#e +b\"i 9_ Be 9d 'V 3k %^ /c @^*V0^*V2d.V\"X )Z /Z /Z /Z /Z 3b 1~U.j Nx Mx Mx Mx MX -X -X -X ,p F\\4X Gi >i " ">i >i >i BiEV.X/X'X/X'X/X'X/X.Y.Y#X 'j ;V \"V 5VLV :_IT >XHX V \"V 5VLV 9XGX IV \"V 4VMV 9XGX ,ZHY A_IT XHX AV \"V 3VLV 9" "XHX 2V >W &XHX !_ K~[ >T 4R -_ D_?_ >S =t Fh IX 2VFV #VBV FS 7c4V#i HV \"W 3V !T 7V 0f @e >o Co 0" "\\ Dq W M" "d AW ,W ,W ,W ,W HW 1b GV +b Fm Dm #` \"j 4Z @x Mx Am 8X C~Q)X?X?X!m 9X 0V 0X EX 'h" " $W0W \"h ?XGX 'g%g 0h%i :a Cf :f *V 4m %^ 0e A^+V/^+V1f1V!X )Z /Z /Z /Z /Z 2` 1~V0o\"x Mx Mx Mx MX -X -X -X ,t J\\4X Im Bm Bm Bm Bm F" "mHV-X/X'X/X'X/X'X/X-X.X\"X (l ;V $V 4UJU :ULXLU >XHX XHX @V $V 2UJU 9XHX 3V" " =W &XHX !` K~Z >T 4S /a FaAa @T @w Hl KX 2VFV $WCV ES 8e5V$j HV \"V 1V \"T 7V 2j Eh ?q Dp 1\\ Dq >" "l Ly Hn Bj +l %e E\\ At >s$v Kx Mt >u&X/X'X -X -X5Z#X -^2^0]5X Jo q ;o r Br%~W$X/X-X(X,X6[6XAY3Y+Y0Y%~S%W 3V IW !_ FW 7W >W Md AW " ",W ,W ,W ,W HW 2[ ?V #[ Hn En #` #l 6\\ Ax Mx Cp 9X C~Q)X?X?X\"o ;Z 1V 1Z FX KS 0i #W2" "W LV ,i ?XGX *l'h 3l'i ;c Dg ;g ,W 6o %^ 1g B^,V.^,V0g3V X *\\ 1\\ 1\\ 1\\ 1\\ 2^ 0~V2s$x Mx Mx Mx MX -X -X -X ,v L]5X Jo Do Do Do Do HpKW" "-X/X'X/X'X/X'X/X-Y0Y\"X )n XHX ;UEU XHX @W &W 3VJV :XHX 4W =W &XHX " " 1\\ 1\\ 1\\ 1\\ 1\\ =XMV K~Y =S 4U 1c IdCc AU Dz In LX 2VFV $VBV ES 9g7V$k HV #W 1W #T 8W 3l Fh ?r Eq 3] Dq ?m L" "y Ip Em -n )k H\\ Au Av%x Mx Mt ?x(X/X'X -X -X6Z\"X -^2^0]5X Ls\"s ?s\"s Et%~W$X/X,X*X+X6[6X@Y5Y)Y2Y$~S%W 3W JW \"a FW 8W >W NZ 6W ,W " ",W ,W ,W HW 2X \\ 2V 2\\ GX KS 1j #" "W2W LV -j ?XGX +ZEZ)VGY 5ZDZ)i T 5V 2e KfEe CW G| Jp MX 2VFV $VBV ES 9XIX8V$l HV #V /V #T " " 8V 3n Gh ?s Fr 5^ Dq @n Lx Ir Go .o -q L^ Bv Cx&z x Mt A{)X/X'X -X -X7Z!X -^2^0^6X Mu#t Au#t Gu%~W$X/X,X*X+X6[6X?X5X'X2X#~S%W 2V JW #c FW" " 9W >W NX 4W ,W ,W ,W ,W HW 2W ;V NW IZCY Hp JY &ZDZ 9^ Bx Mx Eu W *W 2UFU ;XHX 6W ;W &XHX 7h =h =h =h =h DWJV K~X >T 5W 4g MgFg EY J~ K]FZ MX 2VFV $VBV " "ES :XGX9V%\\GX HV $W /W 3PATAP GV 3[H[ Gh ?]F] GZE^ 6^ Dq A]FX Lx I\\F\\ G\\G[ /[H] 0u N^ Bw E_D^&{!x Mt B`C_)X/X'X -X -X8Z X -_4_0_7X N^" "E^$u C^E^$u H^E\\%~W$X/X,Y,Y*W7]8X>Y7Y'Y4Y#~S%W 2V JW $e FV 9W >W NW 3W ,W ,W ,W ,W HW 2W ;V NW IY@X >X " "4[AV IX &X@X 9^ Bx Mx F^E^ =X C~Q)X?X?X&^E^ B` 4V 4` IX KS 3\\GW \"W4W KV .YBT ?XGX .V7V,P=W :W8W /VEV 3V +V /V " " 7eGU KU 3WCW ;U-V$U-V LV5V NX +^ 3^ 3^ 3^ 3^ 3^ 1~W6_D^&x Mx Mx Mx MX -X -X -X ,{\"_7X N^E^ L^E^ L^E^ L^E^ L^E^ !^Ed*X/X'X/X'X/X'X/X+Y4Y X +Y?" "X ;V *V 4UDU >TEZ TEZ T 5Y 5g MhHi G[ M~Q L\\AW MX 2VFV $VCV DS :WEW:V%ZAU HV $V -V 3RCTCR HW 4ZDZ H\\LX ?Y?[ HV>\\ 8_ DX )[?T -Y J[B" "[ I[CZ 0WAZ 2x ^ BX>^ G]=Z&X=b#X -X '];[)X/X'X -X -X:[ NX -_4_0_7X \\?\\%X@^ E\\?\\%X?] J[=X =X W X 3W 4W ,W HW 3X ;V NX KY?X Ca 9Y:R HX (X>X :VNV BZ /X '\\?\\ A^ FX0X)X?X?X'\\?\\ " " Db 5V 5b JX KS 3ZBT !W6W JV .X?R 4V4U HV ;V4V 1VCV 4V *U 0V 7fGU KU 4WAW TDX ;a 6V ,V 4UBU GV ,V 3UCU 0` 6TDX 4V ,V" " 2UDU >TDX >V ,V 1UDU :V 9W (o Do Do Do Do GWIU J~V >T 6Z 6i jIj I\\ N~R M[=U MX 2VFV %VBV H] AWCW;V%Y=R" " HV %W -V 4UETEU IV 4ZBZ IWGX ?V;[ IS9Z 9VNX DX *Z;R -X JZ>Y JZ?Y 1U>Z 5`C_#` CX;[ H[7W&X9_$X -X (\\6X)X/X'X -X -X;[ MX -_4_0`8X![;[&X" "=[ F[;[&X<[ LZ8U =X W W 2W 4W ,W HW 3W :V MW KX=W Cc " ";X7P HX (WR !X8X JV /X

W W " " 2W 4W ,W HW 3W :V MW KWU.U 4VAV &V 5U *U 2V 6gGU KU 5W?W =U/V\"U/V IU7V LX ,WNW 5WNW 5WNW 5WNW 5WNW 5WNW 4XHX H[4U&X -X -" "X -X -X -X -X -X ,X6]&`8X\"Z7Z#Z7Z#Z7Z#Z7Z#Z7Z 'Z8['X/X'X/X'X/X'X/X)Y8Y MX ,W:W 9V 0V 3U@U ?[ 1V 0V 3U@V GV 0V 3U?U 8h 1V 0V 2U@U " " CV 0V 1U@U >V 7W *`L` I`L` I`L` I`L` I`L` JV =X,X >T 6] 9k\"lKl K_ #\\ 'Y8S MX 2VFV %VBV Nk IVAV=V$X 1V %V +V " "6YHTHY -V EW 5Y>Y :X ?R5Z .Y ;VMX DX +Y DX IYW W 2W 4W ,W HW 3W :V MW KW;W De =W " " -X *W:W V$X 1V &W +W 5XITIX +V EV 4X[ JX -XNW8WNX0a9X#Y3Y(X9Y JY3Y(X9Y NX LX W W 2W 4W ,W HW " " 3W :V MW LX;W Df >W ,W +W8W >WLW @Y 2X +Z3Z!t\"X0X)X?X?X*Y3Y Kj 9V 9j AS 5X 8W:W HV /W #T)T KV " " @T(T 6U?U &V 5T +V AhGU KU 5V=V =U0V!U0V JV7V WLW 7WLW 7WLW 7WLW 7WLW 7XNX 6XGX IY.R&X -X -X -X -X -X -X -X ,X2Z'a9X#Y3Y%Y3Y%Y3Y%Y3Y%Y3" "Y )Y3Z)X/X'X/X'X/X'X/X'X:X Ki >W8V *XHZ FW ,ZW W " " 2W 4W ,W HW 3W :V MW LW:W Dg ?W ,X ,W8W >WLW ?Y 3X +Y1Y\"v#X0X)X?X?X+Y1Y MYNVNY :V :" "YNVNY BS 5X 8XU1V U1V KW7V NWLW 7WLW 7WLW 7WLW 7WLW 7WLW 6XGX JY,Q&X -X " "-X -X -X -X -X -X ,X1Z(XNX:X$Y1Y'Y1Y'Y1Y'Y1Y'Y1Y P)P$Y3[)X/X'X/X'X/X'X/X'YVKX DX -X BX IX8X NX7W KP 1P =X Y *Z W 0W MW +ZAZ 0W >W W 2W 4W ,W HW 3W :V MW LW:W DSF[ @X -X " " -X8W ?WJW ?Y 4X ,Y/Y%z%X0X)X?X?X,Y/Y YMVMY ;V ;YMVMY CS 5X 5P*Q JWU2V NU2V$_7V NXLX 9XLX 9XLX 9XLX 9XLX 8WLW 6XGX KY*P&X -X -X -X -X -X -X -X ,X0Z)XNX:X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y\"R+R&Y3]*X/X'X/X'X/X'X/X&Y>Y Jp EW:Y " " +R@Y 7Q 2W .XEVFY\"X5Y\"X5Y\"X5Y\"X5Y NV ;X/X 0V 5T 8c ^ AW4W ?Z >W6W KY " " \"Y 0X 2VFV &VCW#[LSKZ KV?V@V\"W 0V 'W )W 1XNTNX &V FW 6Y:Y X *Z NW 0W MW ,Z?Z 1W >W W 2W 4W ,W H" "W 3W :V MW LW:W DPAY ?Y .W -W6W @WJW >Y 5X ,X-X&_MXM_&X0X)X?X?X,Y/Y !YLVLY " "W FV /X 'TCfFT2i CUGfBT 9U?U &V 7U 5] >iGU KU 6V;V >U2V NU2V$]5V NWJW 9WJW 9WJW 9WJW 9WJW 9WJW 8XFX KY /X -X -X -X -X -X -X -X ,X" "/Y)XMX;X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y#T-T'Y3]*X/X'X/X'X/X'X/X%X>X Ir GW=\\ GY 9S 3W /XDVDX$X2X$X2X$X" "2X$X2X V ;X0X 0X 7T 8d X$X-WJW EX6X Y .X.Y)X -X -Y .X/X'X -X -XBZ EX -XLV:VLX0XMX;X&Y-Y+X7X NY-Y+X7X!X KX Z W FV .X (TDgFT3j CTFhDT 9U?U &V 8U 4\\ =iGU KU 6V" ";V >U3V MU3V#\\5V MWJW 9WJW 9WJW 9WJW 9WJW 9WJW 8XFX LY .X -X -X -X -X -X -X -X ,X.Y*XMX;X&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y%V/V)Y3_+X/X'X/X'X/X'X/X%Y@Y Is HW?^ " "?Z /Z /Z /Z /Z /Z /Z6Y NZ 0Z /Z /Z /Z 8Y 1Y 3Z /Z /Z /Z /Z 3ZCV 5WDX DXCVCW%X0W%X0W%X0W%X0W V :X1X 0X 7T 9f =k#~`\"h Cf " "EW4W @\\ ?X8X LX !Y /X 2VFV 'VBV#XHSET KV?VAV!W 0V (W 'W .` \"V GW 5X8X W\"W.XJX" " FX6X X -X.Y)X -X -X -X/X'X -X -XCZ DX -XLV:VLX0XLX^4WG_ 9` @WG^ 9^GW MWG\\ ;f Gm ^BV\"W:W 3X ?^ 0e AWG_ KV.X ?X Z 7X -X+X)\\HXH\\(X0X)X?X?X-X+X $YJVJY >V >YJVJY Ma =X 7V0V JW@W EV .Y *TEiET5k DTEiDT :VAV &V 9U 3_ ;W6W NiGU " "KU 6V;V >U3V MU3V#_8V NXJX ;XJX ;XJX ;XJX ;XJX ;XJX :XEX LX -X -X -X -X -X -X -X -X ,X.Y*XLXa'b 7` 5` 5` 5` AW ,W ,W ,W DY EWG_ 9` 5` 5` 5` 5` (Z <`GV W6W MW6W MW6W MW6W#W1X NWG^ HW1X NWBVBW&W.W&WJP:PJW&W4PJW&W." "W!V :X2X 0X 6S 8g >k#~`#j Fj GW4W @\\ >W8W LX X .X 2VFV 'VBV$XGSCR KV?VBV X 1V (W 'W ,\\ V GW 5X8X f CWIb =bIW MWI^ =j Im U4V LU4V\"`:V GX /WHW ;WHW ;WHW ;WHW ;WHW ;WHW :XEX MY -X -X -X -X -X -X -X -X ,X-Y+XKWf ;f ;f ;f ;f +Z >eJU NW6W MW6W MW6W MW6W\"W" "2W MWIb IW2W NWAVAW(W,W(WJRU5V KU5V GXTKW)W4TKW)W+W\"V 9X3X 2X 5T :k ?i\"~`$m Jn IW4W A^ ?X:X MW " " NY .X 2VFV 7~X2XFS VIV>X2YIY DYFY +Z JW .V NW 1Y3Y 1n DWLh Bm ChLW Gk Ll 6hLW MWKg HW ,W ,W;Y JW " ",WKfGg8WKg Cl FWLh ChLW MWK` @m Im Y =W6W JW-W&YJb }!WCWCW Hk Dx&{ W4W CWFW P JSCVAVDS :WEV $V W6W NiGU KU 6V" ";V BP>P /U5V KU5V EW=V FX 0XHX =XHX =XHX =XHX =XHX =XHX W:X MW NX -X 2VFV 7~X2WES WKX0XJX>X(Y)X,X7X!Y)X,X7X!Y LX VIV>X1YKY BXFX +Z IW .W " " W 2Y1Y 2o EWMj Dn DjMW Hn Nl 7jMW MWLi IW ,W ,WW6W NiGU KU 6V;V BQ?Q 0U6V JU6V BU>V EX 0WFW =WFW =WFW =WFW =WFW =WFW X(Y)X.Y)X.Y)X.Y)X.Y)X%Z9Z*Y6WJX,X/X'X/X'X/X'X/X!XFX EX;Z LWDX ?o Do Do Do Do Do DoKn4n Cn Cn Cn Cn HW ,W ,W ,W %l HWLi En Cn Cn Cn Cn /Z Cs LW6W MW6" "W MW6W MW6W!W4W LWMj LW4W W?V?V+W(V+WKXBXKV+W5XKV+W(V$W 8W4X 2X 5T ;n ?g!~_%p LZDZ JW4W A^ >W:W MW MX -X 2VFV 7~X2WES VJX0XIW>X(X" "'X-X7X!X'X-X7X!Y LX VIV>X1YKY AXHX +Z HW -V W 3Y/Y 3p FWMk Fo EkMW Io Nl 8kMW MWMk JW ,W ,W=Y HW ,WMjJj:WMk Gp HWMk GkMW MWMb Bo Im \\>W0X=X LW5X u 6W :V MW EkJV Wj Fn CWMk\"\\6X =Z >W6W KW+W)[Ke\"}!WCWCW Jo Hz&{ W4W DWDW ;Y ;X /X'X.YBXBY+X0X)X?X?X/X'X#T HV IT " ":V ;T3T :V CV +o BX 6ZM`MZ GXFX CV *\\ 3SFW,S:V>V 0R@R KSBV@VDS 9e #V ?W \"V ?W6W NiGU KU 6V;V BR@R 1U6V JU6V BV?V EX 1XFX ?XFX ?XFX ?XFX" " ?XFX ?XFW =XCX NX +X -X -X -X -X -X -X -X ,X+X,XIW>X(X'X/X'X/X'X/X'X/X'X%Z;Z)X5VHX-X/X'X/X'X/X'X/X XHX DX:Y LWEX >p Ep Ep Ep Ep Ep EpMp6o Do Do Do Do" " HW ,W ,W ,W 'o IWMk Gp Ep Ep Ep Ep 0Z Ds KW6W MW6W MW6W MW6W!W5X LWMk MW5X V>V?W,V'W,VKZDYKW,V5YKW,V'W%W 8X5W 2X 4T ;o @g ~^%q NY@Y KW4W B`" " ?XX -XJW@WJX0XIX?X(X'X-X7X!X'X-X8Y Y MX W/YMY @YJY +Y GW -V W 4X+X 4YE\\ FWNXG\\ H]EX F\\GXNW J\\F[ " "GW ,\\GXNW MWNXG[ JW ,W ,W?Z GW ,WNXH[KXH[:WNXG[ H]H] IWNXG\\ I\\GXNW MWNXFQ C\\CW CW ,W6W!X6X NW?\\?W.X?X JW6W 1X 6W :V MW 9X=X\"[IZKW W=Y /W @m H]DV " "CWNXG[\"\\6W =[ >W6W LW)W*ZJWKY\"}!WCWCW K\\H] J{&{ V3W DWDW :Y XCX NX +X -X -X -X -X -X -X -X ,X+X,XIX?" "X(X'X/X'X/X'X/X'X/X'X$Z=Z(X6WHX-X/X'X/X'X/X'X/X YJY DX9Y MWEW =YE\\ EYE\\ EYE\\ EYE\\ EYE\\ EYE\\ EYE]N\\G[7]EX E\\F[ F\\F[ F\\F[ F\\F[ IW ,W ,W ,W (p IWNXG[ H]H" "] G]H] G]H] G]H] G]H] 1Z E]H^ JW6W MW6W MW6W MW6W W6W KWNXG\\ MW6W NV>V>V,V&V,VJZFYIV,V6YIV,V&V%W 7W6X 3X LR:T ;q @e N~^&s!Y>Y LW4W B` >WXJX +Z GW -W !W 5X)X 5U>Z G_CZ I[>T FZC_ KZAZ HW -ZB_ " "M^BZ KW ,W ,W@Z FW ,^CZMVCZ;^BZ IZBZ I_CZ IZC_ M^ 5YY .W AXJa IZW2W EWDW 9Y =X /X'X/YAXAY,X0X)X?X?X/X'X%X JV KX Z FU>Z FU>Z FU>Z FU>Z FU>Z FU>eBZ9[>T FZAZ HZAZ HZAZ HZAZ JW ,W ,W ,W )r J^BZ IZBZ GZBZ GZBZ GZBZ" " GZBZ 1Z EZB[ JW6W MW6W MW6W MW6W W6W K_CZ MW6W V=V>V-V%V-VHZHYHV-V6YHV-V%V%W 7X7X 4X NU:T WX !Y 0Y BVDX Dk CXJc -X BX>X LX5Y MX -X Ee Le 3Z ?U=bKUCU6XDX IX9Y X +X+X+X -X /X +X/X" "'X -X -XL[ Y J]?Y KY?] M] 4X8P CW ,W6W X8X MW?\\?W-XAX IW7X 3Y 5W :V MW =_C_(YBXLV NW?Z -W CXC\\ KY ,]@Y LW8X >] ?W6W LW)W,YHWHY MW=W JWCWCW MY>Y " "L[B[ ;W >W2W FWBW 9Y >X 0X%X0X@X@X,X0X)X?X?X/X'X&Y JV KY =V >Y7Y =V CV .[HSFR BX 3t BWHW AV .WN\\ 9SFV)S;V?W 3UCU LSAV@VCS 7_ V BV LU ?W" "6W MhGU KU 5W?W AUCU 4U8V HU8V ?UAV CX 2XDX AXDX AXDX AXDX AXDX AXDX @XBX NX +X -X -X -X -X -X -X -X ,X+X,XHX@X(X'X/X'X/X'X/X'X/X'X\"ZAZ&X8WFX-X/X'" "X/X'X/X'X/X MXLX BX8X MWFW Y;Z:R GY=Y JY=Y JY=Y JY=Y KW ,W ,W ,W *]E[ J]@Y JY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y JW6W MW" "6W MW6W MW6W W7X K]?Y NW7X V=V=U-V$U-VGZJYFU-V7YFU-V$U%W 7X8X &~X/X:T =t @c L~\\'v\"W:W LW4W CXNX ?X>X MV $x EX 2~X2WES :VDW" "EV FZ :W #W 7XKTKX )V IV 4X4X >X !X 0Y BWDX Dm FXKf /Y AYBY KX5Y MX -X Gd ~X d 5Y ?V>dLUCU6WBW IX;Z Y +X+Y,X -X 0Y +X/X'X -X -XM[ ;X -XIWBWIX" "0XGW@X)Y'Y.X8X!Y'Y.X9Y M] #X aEa)X@XNW NWA[ ,W DW?[ LX +[=X KW:X =] ?W6W MW'W-XGWGX MW=W JWCWCW MXZ W2W FWBW 9Z ?X" " 0X%X0X@X@X,X0X(X@X@X/Y'Y(Y IV JY >V ?Y5Y >V CV .YFSDP BX 2q @XJX AV /WK[ :SFV)S;V@X 4VDV LSAV@VCS 6\\ MV CV KU ?W6W MhGU KU 4V?V @V" "DV 5U9V GU9V >UBV BX 2WBW AWBW AWBW AWBW AWBW AXDX @XBX Y +X -X -X -X -X -X -X -X ,X+Y-XGW@X)Y'Y1Y'Y1Y'Y1Y'Y1Y'Y\"ZCZ&Y9WEY.X/X'X/X'X/X'X/X MYNY BX8Y N" "WFW X NW $w DX $VBV#XFS :WFXEV H] ;W #W 9XITIX" " +V JW 4X4X >X \"Y 3[ BWCX Dn GXLi 1X ?ZFZ JY7Z MX -X Je M~X Me 9Y >U?gMUCV7WBW IX>\\ NX *X*X,X -X 0X *X/X'X -X -XNZ 9X -XHVBVHX0XGXAX)X%X.X9Y!X%" "X.X:Y La 'X _ @W6W MW'W.YGWFX NW=W JWCWCW NX:X NYW2W FWBW 8Z @X 0X%X0X@X@X,X0X(X@X@X" "/X%X)Y HV IY ?V @Y3Y ?V CV /YES 6X 1\\H[ JcJc LV 0WI\\ =TFV)S;WAX 5WEW MTAVAWCS 3W 4~W.W KV ?W6W LgGU KU 4WAW @WEW 6U9V GU9V ?VBV BX 2" "WBW AWBW AWBW AWBW AWBW AWBW AXAX X *X -X -X -X -X -X -X -X ,X*X-XGXAX)X%X1X%X1X%X1X%X1X%X!ZEZ%X9WCX.X/X'X/X'X/X'X/X LXNX AX7X NWFW !W ,W ,W ,W ,W ,W " ",]:X=Y .X9X LX9X LX9X LX9X LW ,W ,W ,W +Z=X K[x A` J~\\(y%W8W MW4W CXMW >W>W MV $x DX $VCV\"XFS 9XIXEV H_ X #Y ?g AVBX Do HXM" "k 3Y >l HX7Z MX -X Me J~X Je =Y >V?hNUBU8XBX Ju MX *X*X,w Lq IX *~R'X -X -c 8X -XHVBVHX0XFWAX)X%X.X9Y!X%X.X;Z Ke ,X WNV MW" "Ib +W EW;Y MW *Z;X KV:W =_ @W6W NW%W/XFWFX NW=W JWCWCW NW8X!Y:Y =W >| GW@W 8Y @X 0X%X1Y@X@Y-X0X(X@X@X/XImIX*Y GV HY @V AY1Y @V CV /XDS 6X 0YDY JdL" "d LV 1WF[ >SFV'SW6W LgGU KU 3WCW ?XFX 7U:V FU:V >UBV AX 3XBX CXBX CXBX CXBX CXBX CXBX BXAw?X *w Lw Lw Lw " "LX -X -X -X ,X*X-XFWAX)X%X1X%X1X%X1X%X1X%X ZGZ$X:WBX.X/X'X/X'X/X'X/X K` @X7X NWFW W ,W ,W ,W ,W ,W ,[8W=X -W7W LW7W LW7W LW7W LW ,W ,W ,W ,Y:X LZ;X M" "Y:Y MY:Y MY:Y MY:Y MY:Y \"Y=\\ LW6W MW6W MW6W MW6W MW:W IZ9X NW:W NVV&V 4W:X %~X2TNVW \"W ;WFTFW -V JV 3X4X >X #Y ?f AWBX Dp IXNm 4X ` @W6W NW%W/WEWEW NW=W JW" "CWCW X8X!X8X =W >| GW@W 7Y AX 0X%X1X?X?X-X0X(X@X@X/XImIX+Y FV GY AV BY/Y AV DX 1XCS 6X 0W@X KdLd LV 1VCZ ?SFV'S;WE[ 7XFX G~X .S@VBWAS @~W0W " ".P>W >W6W KfGU KU 3XEX >XFX 8U;V:W3U;VCZ9P>WCV:W/Y 3W@W CW@W CW@W CW@W CW@W CXBX CX@w?X *w Lw Lw Lw LX -X -X -X 5p9X-XFXBX)X%X1X%X1X%X1X%X1X%X N" "ZIZ#X:VAX.X/X'X/X'X/X'X/X K` @X7X NWFW W ,W ,W ,W ,W ,W ,[8X?X -X7X NX7X NX7X NX7X MW ,W ,W ,W ,X9X LY9W MX8X MX8X MX8X MX8X MX8X \"X=] LW6W MW6W MW6" "W MW6W MW:W IZ9X NW:W NVLuKU/VLuKU/VBaAU/V:YAU/V=X=U&V 4X;X %~X2RLW>T >{!z'~Z)}(W6W NW4W DXLX ?X@X MV KX ,X %VBV!YHS 8eEV" " Ic ?W !W ;UETEU ,V KW 3X4X >X $Y >c ?WAX DWD^ JbG] 5X 9d DY9[ MX -X #d D~X Dd DY a AW6W NW%W0XEWEX W=W JWCWCW W6W!X8X =W >| HX@X 7Y BX 0X%X1X?X?X-X0" "X(X@X@X/XImIX,Y EV FY BV CY-Y BV DX 1XCS 6X 1W>W KeNe LV 1VB[ ASFV'S;YI] 9YGY F~X .S@VDX@S @~W1V ,TEZ >W6W JeGU IX +U 2YIY T ?|\"}(~X)~(W6W NW4W DXKW >W@X MV KX ,X %VBV!ZIS 7cEV IYNZ8W 0W !W :RCTCR +V KW 3X4X >X %Y" " =b >V@X DS=\\ K`C[ 6Y 8b BX9[ Nd A~X Ad HY W ,X8X8W=X8X X6X MY7X\"X7Y MX 0W )W ,W6W MXXMW AW6W NW%W0XEWDW W=W JWCWCW!X6X#X6X >W >| HW>W 6Y CX 0X%X1X?X?X-X0X'XAXAX.XImIX-Y DV EY CV DY+Y CV DX 2X" "BS 6X 1Vh =W6W JeGU IX 4g :g :YFX DgEV:XhCV:X/X 3X?W EX?W EX?W EX?W EX?W EX@X EX?w?" "X *w Lw Lw Lw LX -X -X -X 5p9X-XEXCX)X%X1X%X1X%X1X%X1X%X LZMZ!XX7X NWFY !V +V +V +V +V +V +Y6W@X ,W5W NW5W NW5W NW5W MW ,W ,W" " ,W -X7X MX8X X6X X6X X6X X6X X6X $X=_ MW6W MW6W MW6W MW6W LWS >}%~R)~V(~P)W6W NW4W" " DWJX ?XAW L~^ $X ,X %VCV N\\LS 6aDVAW0XLZ9W 0W !W :PATAP +V KV 2X4X >X &Z =e BW@X DP8[ L^?Z 7X :h EY;\\ \"d >~X ?e LY ;U@W>Y" "AU:W>W Ks KX *X*X,w Lq IX6f+~R'X -X -b 7X -XGWFWGX0XDWCX)X%X.X@^ NX%X.s Bl 8X X IXDVCVDX)[ 4\\ -Z @W *V #W $W JX5W\"X -W5X W4W KW 0W5X MX7W" " MW ,W ,WIZ =W ,X8X8W=X7W W4W MX5W\"W5X MX 0X *W ,W6W LWX >XMX BW6W W#W1WD" "WDW W=W JWCWCW!W4W#X6X >W >| HW>W 7Y BX 0X%X1X?X?X-X0X'XAXAX.XImIX.Y CV DY DV EY)Y DV DX 2XBS 6X 2WY BSFV'S9bMV ;XFY D~X .S@h>S " "@~W2i >g W EW>W EW>W EW>W EW>W EW>W EX?w?X *w Lw Lw Lw LX -X -X -X 5p9X-XDWCX)X%X1X%X1X%X1X%X1X%X " "Ke X=W?X.X/X'X/X'X/X'X/X I\\ >X7X NWEY \"W ,W ,W ,W ,W ,W ,X5W@X -W4W W4W W4W W4W MW ,W ,W ,W -W6X MX7W W4W W4W W4W W4W W4W $W=VMW MW6W MW6W MW6W MW6W " "LW=X HX5W NW=X MVLuKU/VLuKU/V?[>U/V=Y>U/V=X=U&V 3X=W 7X FW@T ?~&~T*~V)~R*W5V NW4W EXJX ?XBX L~^ $X ,X &VBV Mb 4]CVC]4XJZ:W" " 0W !W +T KV KV 2X4X >X 'Z X Lu MX *X*X,w Lq IX6f+~R'X -X -c 8X -XFVFVFX0XDXDX)X%X.u MX%X.r" " ?l :X X IXDVCVDX)\\ 4Z ,Y ?W *V #W $W JX5W\"W ,W5X W3W LW 0W5X MX7W MW ,W ,WJY ;W ,X8X8W=X7W W4W MX5W\"W5X MX 0X *W ,W6W LWW 6Y 0X 9V LX 5`3R 0T?[?T/W:[ KWId DbKW HW5X NW +X7W JV>W =WLX BW6W W#W1WDWDW W=W JWCWCW!W4W#W4W >W >| IX>X 9Y AX 0X%X1X?X?X-X0X'XAXAX.XImIX/Y B" "V CY EV FY'Y EV DX 2WAS ?r CV:V =^ =V 2V=Y CSFV'S8`LV e :W6W GbGU IX 4g 8c 5XFX FgFV:YX GX>X GX>" "X GX>X GX>X GX>X FX?w?X *w Lw Lw Lw LX -X -X -X 5p9X-XDXDX)X%X1X%X1X%X1X%X1X%X Jc NX>W>X.X/X'X/X'X/X'X/X HZ =X7X NWEZ #W ,W ,W ,W ,W ,W ,X4WAW ,W3W!W3" "W!W3W!W3W NW ,W ,W ,W .X5W MX7W W4W W4W W4W W4W W4W $W>VLW MW6W MW6W MW6W MW6W KW>W GX5W MW>W LVLuKU/VLuKU/V>Z>U/V>Y=U/V=X=U&V 2W>X 8Y FW@T " " ?~P(~V*~T(~Q)V4V NW4W EXJX >WBX L~^ $X ,X &VBV Ld 4WAVD`6XHZ;W 0W !W +T KV LW 2X4X >X 'Y ;i GV>X *Z M\\;Y 9X =p HZ?^ 'd " " Id$Y 9UAWX GWEVJVEW#a >W>W 7Y 1Y 8V KY 9e8T 0T?Z>T0X:[ KWIf GdLW HW4W MW ,W6W JV?X >XKW BW6" "W W#W2XDWDX!W=W JWCWCW!W4W#W4W >W >| IWX GX>w?X *w Lw Lw Lw LX -X -X -X 5p9X-XCWDX)X%X1X%X1X%", // Start of second string. "X1X%X1X%X Ia MX?W=X.X/X'X/X'X/X'X/X GX W GX5W MW>W LVLuKU/VLuKU/V?\\?U/V?YX 8X DWBT ?~Q)~W)~R&~(V4V NW4W EWHW >WBW K~^ $X ,X &VBV Kg \"" "VEc8WFZ=W /W !W +T 4~W 5V 1X4X >X (Y -] IW>X )Y M[9X 9X >\\F\\ H[C` 'a Ca$Y 9UAV:WAU;WW )V $W 6i JX5X$X -X5X V2W LW 1W3W MW6W MW ,W ,WLY 9W ,W7W7W=W6W!X4X NX5X$X5X MW .[ .W ,W6W KW>" "W FWEVJVEW#a >W?X 8Z 4\\ 8V K[ =iW2W IWX X *X -X -X -X -X -X -X -X ,X*X-XCXEX)X%X1X%X1X%X1X%X1X%X H_ LX@Wi >i >i >i" " >i >i3WBX ,V2W!V2W!V2W!V2W NW ,W ,W ,W .W4W MW6W!X4X\"X4X\"X4X\"X4X\"X4X M~Y2X@VIW NW6W MW6W MW6W MW6W KW?X GX5X NW?X LVLuKU/VLuKU/V@^@U/V@Y;U/V=X=U&" "V 2X?W 8X CWBT ?~R*~X)~Q%}(V4W W4W FXHX ?XDX K~^ $X ,X 'WCV Ii &VEe:XEZ>W /W !W +T 4~W 5V 1X4X >X )Y )[ KW=X (Y N[9Y ;Y " "?Z@Z I]Gb '^ =^$X 9U@V:WAUXIW CW6W!W!W3WCWCW!W=W JWCWCW\"W2W%W3X ?W >W2W JW;X ~R+~Z*~P#{'V4W W4W FXHX ?XDX K~^ $X " " ,X 'VBV Gi (VFg;WCZ?W /W !W +T 4~W 6W 1X4X >X *Y &Z LW=X (Y NZ7X ;X ?Z>Z ImNX '[ 8\\%Y 9UAW:WAUX XIW CW6W!W!W3WCWCW!W=W JWCWCW\"W2W%W2W ?W >W2W JW:W =Y >X 0Y'" "X0X?X?X-X0X%XCXCX,X%X2~a GV H~a HV I~b HV DX 3W@S ?r DV8V V&V 1XAW 9" "X @WDT ?~S+~Z)}!y'W4W W4W FWFW >WDW J~^ *r ?V &VBV Eh *VEXIXX +Y $Z NWXHX DW6W!WW2W KX:X ?Y =X /X'X0Y@X@Y-X0X%YDXDY,X%X2~a GV H~a HV I~b HV DX 3W@S ?r DV8V ;X DW;V DSFV'S >XFX " " ;V .S@VFW=S (V \"W6W :UGU IX 0XFX -V;TLU MV0U!V;TLU6Y 0X:X KX:X KX:X KX:X KX:X KX:X JWV&V 1XBX :X ?WDT ?~S,~[({ x&W4W W4W FWFX ?XFX JV \"q >V &VBV Af -VEXGX=W@ZB" "W .W !W +T 4~W 5f 8V 0X4X >X ,Y \"Y W;X 'X NZ7X X -XDVJVDX0XAXGX)X%X.i" " AX%X.X>Z ,\\ ?X XGW DW6W!WW2W KW9X ?Y =X /X'X/X@X@X,X0X$YEXEY" "+X%X2~a GV H~a HV I~b HV DX 3W@S 6X 3V8V ;X DXWEW :V .TAVEW?T (V \"W6W :UGU IX /WEW .V;TKU NV/U\"V;TKU7Y /X:X KX:X KX:" "X KX:X KX:X KX:X KXWDS >~T-~\\(y" " Mw&W4W W4W GXFX ?XFX JV #r >V 'WCV X -Y Y!W;X 'Y Y5X =X @Y8Y HgKX 'a Ca%X 8UAV8" "VAU=W8W NX4X%X *X+Y,X -X 0X(X+X/X'X -X -XI[ ?X -XDWLWDX0X@WGX)X&Y.X 0X&Y.X=Y *[ @X XFX EW6W!WW2W KW8W @Y ] Jt It It It It It I~iBW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W M~Y2WCVEW NW6W MW6W MW6W MW6W IWCX EW3W L" "WCX IV=V=V.V$V.VFYKZFV.VFY7V.V$V&V 0XCW ;Y =WFT >~T-~\\'w Ku%W4W W4W GXEW >WFW IV #q =V 6~X JSN^ /VEWCW?W=ZDW .W !W :~W" " 5f 9V /X4X >X .Y MX\"W:X &X Y5X >Y @X6X FcJX &d Id%X 8UAV8VAU>X8X X4X$X +X+X+X -X /X)X+X/X'X -X -XH[ @X -XCVLVCX0X@XHX(X'X-X /X'X-XXFX EW6W!WV-V%V-VGYIZHV-VGY7V-V%V%V /WDX ;X ~T-~\\'v Is" "$W4W W4W GWDX ?XGW HV %r =V 6~X JSJ[ 0VEVAV?WX ?X6X D`IX $d Ne#X 8UAV8" "VBU=x X4X$X +X+X+X -X /X)X+X/X'X -X -XG[ AX -XCVLVCX0X?WHX(X'X-X /X'X-X;Y *Y @X WDW EW6W!WV>V,V&V,VIYGZIV,VIY6V,V&V&W /XEW N~X'VGT =~T-~\\&u Ir#W4W NV4W HXDX ?XHX HV KX ,V 6~X JSHZ 2VDVAV?W;ZGW -W !W \"V " "Lf :W .X6X =X 0Z LY#~ /X NX5X >X @X5Y AYFX !d >~X >d X 8UAV8VBU>z!X3X%X +X+X+X -X /X)X+X/X'X -X -XF[ BX -XCWNWCX0X?XIX(X'X-X /X'X-X:X )Y AX XDX FW6W!WV?W,V'W,VJYEZKW,VJY6W,V'W&W /XFX N~X'WHT =~T-~\\%s Gp\"W4W NV4V GXCW >WH" "X HW LX ,V 6~X JSGY 3VDWAW@W:ZIW ,W !W \"V Lf :W .X6X =X 1Z JX#~ /X NX5X ?Y @X4X .X Md A~X Ad LX 8UAV8VBU>z!X3X%X +X+X+" "X -X /X)X+X/X'X -X -XE[ CX -XBVNVBX0X>WIX(X'X-X /X'X-X9X *Y AX Q.X $T>Z?T0W8W HW5W\"WWCX FW6W!WXFX >V ,SBVBWCS &V \"W6W :U" "GU *m 8XFX .VWIX(X'X/X'X/X'X/X'X/X'X KZMZ XHW6X-X/X'X/X'X/X'X/X GX XIW GW LX ;~X JSFX 3VDV?V@W9ZJW +V \"W !V V -X6X =X 2Z IX#" "~ /X NX5X ?X ?X4X .X Jd D~X Dd IX 8UAV8VCV>z!X3X%Y ,X,Y+X -X /Y*X+X/X'X -X -XD[ DX -XBVNVBX0X>XJX(Y)X,X /Y)X,X9Y *X AX XBW FW6W!WXJX" "(Y)X.Y)X.Y)X.Y)X.Y)X KZKZ!YJW6X,X/X'X/X'X/X'X/X GX |\"X3X$X ,X,X*X -X .X*X+X/X'X -X -XC[ EX" " -XA\\AX0X=WJX'X)X,X .X)X,X8X *X AX XBX GW6W!WW 9X =\\KW >SEWWJX FW LX <~X JSEX 6WCV?V@W7ZMW *W #W !V !W -X6X =X 4Z GX#~ /X NX5X @X >X4X " "/X De J~X Je DX 8U@V:WDV>|\"X3X$X ,X-Y*X -X .X*X+X/X'X -X -XB[ FX -XA\\AX0X=XKX'X*Y,X .X*Y,X8Y +X AX W WJW DW MX .VCV" " :SDW 6VBV?V@W6b )W #W !V !V +X8X X4X /X Ad L~X Ld AX 8VAV:WDU=|\"X3X$Y -X-Y*X -X .Y+X+X/X'X -X -XA[ GX -XA\\AX0XWKVDVKW\"XLX 9WJW =Z #X :V MX AUEVKVDU/X:Y IW5W#WX@W GW6W!W=Y=W2WDWDW W=W JWCWCW\"X4W#W4W >W X4X 0X =d ~X" " d LUAWX2X#X3X#X -X.Y)X -X -X+X+X/X'X -X -X@[ HX -X@Z@X0XW ,W7W7W=W6W W4W MX5W\"W5X MW BX FW ,W7X FWHW >WLVBVLW#YKX :WJW =Y !W :V MW @VHXJWHV-W:Y IW5W#WY>W1WDWDW W=W JWCWCW\"X4W#W4W >W W MW7X MW7X " "MW7X MW7X EWJW AX5W GWJW AXCVCW%X0W%X0W%X0W%X0W\"V +WJX ?X 2WLT 9bKQKb)gLQMh Mi =g MW4W MV6W IX@X ?XLX CW MX 0VBV :SDW " "7VAV?V@X5_ (W #W !V \"W +X8X XLV;VLX1Y?Y >X 9Z 2W %W )W EW7X JX5W\"X -W5X X )W 0X7Y MW6W MW ,W ,WFY ?W ,W7W7W=W6W W4W MX5W\"W5X MW AW FW ,W7X FXJX" " =WMVBVMW#YJY ;WKX >Y W :V MW ?dId,W;Z IW5W#W=W DW4W!W )W6W DVKW >X>W HW6W W>Y>W1WDWDW W=W JWCWDX\"X4W#W4W >W ;V7W LX2X LY 4X *X1X%]JXJ]'X0X Hj L" "Y-Y%Y IV JY LYKVKY MY5Y MYJVJY $X 2XBS 6X 2q 9X :V #\\ 7TDgFT /XFX EV )TFV>VJT #V \"W6W :UGU +XFX *V=TCU%V1V!V=TCU=X ,X1W$X1W$X1W" "$X1W$X1W$X2X%X7X LY .X -X -X -X -X -X -X -X ,X.Y*X;XMX&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y ZAZ$_3Y*X1X%X1X%X1X%X1X FX W3W$W7X MW7X MW7X MW7X MW7X MW7X MW7Z NX -X " "-X -X -X +W ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W 5Z IWMV=W MW7X MW7X MW7X MW7X EWKX AX5W GWKX @XDVDX$X2X$X2X$X2X$X2X\"V +XKW ?X 1WMT 7`JQKa" "'fLQLf Kg W >WLW BX NY 1VBV :SDW 8V@V?V?W4] &V $W V \"V *Y:Y YGW>X0X$X4Y\"Y /X/Y(X -X ,Y-X+X/X'X -X -X>[ JX -X@Z@X0X;XMX%Y/Y*X ,Y/Y*X6Y -X AX ;Y3Y IXLX =WLV;VLW0X=Y ?X :Z 1W $V )W EW8Y JY7X\"X -X7Y X " ")W 0X7Y MW6W MW ,W ,WEY @W ,W7W7W=W6W X6X MY7X\"X7Y MW AW FW ,X8X EWJW Y NW :V MW >bGc,W;[ JW6X#W=W DX6X!W )W6W DVLX >W=X IW7" "X W>Y>W1XEWEX W=W IWDWDW!Y6X#X6X >W ;W8W MX0X MY 4X *Y3Y$^LXL^&X0X Ff IY/Y#Y JV KY JYLVLY KY7Y KYKVKY #X 2XBS 6X 3t ;X :V ![ 8TCfFT .XFX FV )U" "GV>WKT MW7X :UGU ,XFX *V=TBU&V2W!V=TBU=X -X0X&X0X&X0X&X0X&X0X&X0W%X7X KY /X -X -X -X -X -X -X -X ,X/Y)X;XMX%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y Z?Z$" "^4Y)Y3Y%Y3Y%Y3Y%Y3Y FX XEVFY\"X5Y\"X5Y\"X5Y\"X5Y!V *WLX @X /WNT 7`JQJ_&eKQKe Je :d KW4W MW8W HW>X ?XNX AX Y 1VCV 9SDW 9V?V?V?X4\\ " " &W %W V \"V )X:X ;X 9Z CX 4X (Y KW7X AX W BW6W W )W6W DWMX ?X=X IX8X W?[?W0WEWEW NW=W IWDWDW!Y6W!W6W =W ;W8W MX0X NY 3X )Y5Y\"z%X0X C` FY/Y\"X JV " "KX HYMVMY IX7X IYLVLY \"X 1XCS 6X 4v X ?XNX AY Y4P VBV 9SDW 9V?V?V?Y4Z %W %W V #W )X:X ;X :Z CY 4X (Y KX9Y AX ;X6X 1Y 1e /e @U@XB[JXW BX8X W )W6W CVNX >W;W IX8X X@[@X0XFWEW " "NW=W IWDWEX!Z8X!X8X =W :W:W LX0X Y 2X (Y7Y Nv#X0X ?X AY1Y V IV JV FYNVNY GV5V GYMVMY !X 1XCS 6X 5x =X :V MZ 8T?ZBT *VDV FV 'T&T KX" "8X :UGU ,VDV )VWNX @Y !Z6Q VBV KP>SEW 9V>WAW>X3Z &W %W V " " #V 'XU?ZH^MZ\\ JX8X\"W?W AX9Y X *W6W CVNX ?X;X JX9Y NW@[@W/XFWFX NW=W IXEWEX!Z8X!X8W ;W ;W;X MX.X\"Y 1X 'Y9Y Lt\"X0X ?X @Y3Y MT HV IT Dj ET3T EYNVN" "Y X 0XDS 6X 6ZM`LY >X :V LY 7T)T (UCU ET(T JX9Y :UGU ,UCU )V;m.V3V NV;mCY7P HX.X(X.X(X.X(X.X(X.X(X.X(X6X IY.R&X -X -X -X -" "X -X -X -X ,X2Z'X9a$Z3Y&Z3Y&Z3Y&Z3Y&Z3Y!Z9Z&Z3Y&Y5Y#Y5Y#Y5Y#Y5Y EX `" " >Y !Y8S MX +VBV KQ?SFX 9V=VAV=Y6] &V &W NV BX 1X 1V 'Y>Y :X X:W JY;Z NXB]BX.XGWGX MW=W H" "XFWFX [:X NX:X ;W :WX HXX 9X =Z 1P2Z 3X GQ5Z GX=Y @X 9Y:Y KP8Z GX -X 4^ 1^ +X 5U?gM_9W,W%X7Z L[4U&X6]%X -X )[2X+X/X'X -X -X9[ X -X&X0X8`\"Z7Z'X )Z7Z'X3X%T2Y ?X 9Z9Z E` :" "_9_3Y7Y BX >Z -W #W +W DX=\\ J\\=Y LY7P HY=\\ LY5R JW -Y?] MW6W MW ,W ,W@Y EW ,W7W7W=W6W MYX LX.X#Y 0X %Y=Z Gl MX0X ?X ?Z7Z JP FV GP @f AP/P Ah MX " "/YFSDP BX 8ZFVEY @X :V JX 7V.U %SAS CU.U HZ\\=Y B^ 7r Gr Gr Gr Gr KV (_ BX )Y S 8RBSCR <] 2\\ GW4W KZBZ HX;W >_ <[ " " $[=U MX ,VBV JUCSHY :V;WCW<[Z 0R5Z 2X GT9[ GY?Z AY 9[>[ KR;Z FX -X 1[ 1[ (X 5V>dL^9X,X&X9[ J[7W&X9_$X " "-X (\\6Z+X/X'X -X -X8[!X -X&X0X8`![;[&X ([;[&X3Y&W7[ ?X 8Z;Z D` :^7^3X5Y CX ?Z ,W #W +W DY?] J]?Y KZ:R GY?] LZ8T JW -ZA^ MW6W MW ,W ,W?Y FW ,W7W7" "W=W6W LY>Y J]?Y KY?] MW /T9X DX ,Y@] CWNW 9]>]'Y@Y =^ AY IW :V MW HYCXNW L\\>Y VAX >Y>Y LY ,W6W B] >X9X K[>[ MXDVMVDX,YIWIY LW=W GYHWHY N]>Y LY" ">Y :X :X@X LX,X%Y /X $ZAZ Ch KX0X ?X >[;[ ?V 6d >f LX /[HSFR BX 9Z3Y AX :V IX 7V1V #R@R BU0U G[>[ :UGU ,R@R 'V(U)V6W" " LV(UU IX,X*X,X*X,X*X,X*X,X*X,X*W4X G[7W&X -X -X -X -X -X -X -X ,X9_%X8`![;[![;[![;[![;[![;[\"Z3Z(];[\"Z;Z NZ;Z NZ;Z NZ;Z CX Y JW6W LY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y HY@] KY@] KY@] KY@] B^ >]?Y A^ 6o Do Do Do " "Do IV (_ CX (Y S (S ,[ 0[ GW4W J\\H\\ GW:W >^ :\\ %[@W MX ,VBV JXFSIZ :V:WEW:\\@e (V 'V MV BX 1X 2V $ZDZ 8X ?Z /U;] 2X GV=" "\\ EZC[ @X 7[@[ JT?[ EX -X /Y 1Y &X 5V=bK\\7X,X&X<^ I]=Z&X=b#X -X ']:\\+X/X'X -X -X7[\"X -X&X0X7_ \\?\\%X '\\?\\%X2X&Z<\\ >X 7[?[ B^ 9^7^4Y5Y CX ?Y +W \"V +W " " DZB_ J_CZ I[>T G[C_ K[=W JW ,\\GXNW MW6W MW ,W ,W>Y GW ,W7W7W=W6W KZBZ I_CZ J[C_ MW /W>Z DZ .ZB^ C` 8\\>\\&X>Y =\\ AY HW :V MW GZFYNY N]AZ N" "WCX _ FX0X ?X =\\?\\ >V 5b W;[>T F[=W J[=W J[=W J[=W LW ,W ,W ,W *ZBZ IW6W KZBZ GZBZ " "GZBZ GZBZ GZBZ 1Z F[BZ GZB^ KZB^ KZB^ KZB^ A\\ =_CZ ?\\ 3l Al Al Al Al HV (^ BX (X NS (S ,Z .Y FW4W In GX:X ?^ 9_ (]FZ MX " ",VBV J[ISL\\ :V9XGX9^Fi )W )W MV BX 1X 3W #[H[ Et Mx MZC_ 1X GZD^ C[G\\ @Y 7^F] IXF] DX -X ,V 1V #X 4V<^IY5X*X'y G_D^&{!y NX &`B`+X/X'X -X -X6[#" "w LX&X0X7_ N^E^$X &^E^$X2Y'^C^ =X 7^E^ B^ 8]7]4Y3Y DX @~U&W \"W ,W C\\HYNW JWNXG\\ H]EX F\\GXNW J]D[ JW +kMW MW6W MW ,W ,W=Y HW ,W7W7W=W6W K]H] IWNX" "G\\ I\\GXNW MW /[E\\ Be 9[GXNW B^ 7\\>\\'XP @W8W 3~W :_GaKP @UGU ,P>P 'V&U+V6V KV&" "U;]GZ JX*X,X*X,X*X,X*X,X*X,Y,Y,X4y7_D^&y Ny Ny Ny NX -X -X -X ,{\"X7_ N^E^ L^E^ L^E^ L^E^ L^E^ MV/V(dE^ N^E^ L^E^ L^E^ L^E^ BX \\ Av 6W :V MW FkL]$u LXGX 9p Hp EW6W A[ ?X6X LpN\\#" "hKh)s JW<] Lu LWNm Hp 6` Bl K~W'x MX 1iEi HX CX0X ?X ;u X :V HW 3X=X )X\\ /c 8c 8c 8c 8c CV '\\ ?T %W U *T *W ,V DW4W Gj EW8W " ">\\ 5~P In LX -VBV Is 9V7g6qJZ *V )V LV BX 1X 3V !l Dt Mx Mt /X Gr ?m ?X 4r Hm BX -X &P 1P LX 3V 3X*X'w Cv%x My NX #x(X/X'X" " -X -X4[%w LX&X0X5] Ls\"X $s\"X1Y(w ;X 5s ?\\ 7\\5\\5Y1Y EX @~U&W !V ,W BjLW JWMj Dn DjMW Hr JW )hLW MW6W MW ,W ,W;Y JW ,W7W7W=W6W In GWMj EjMW MW /p" " ?d 8iLW B^ 6Z<[)Y:Y >Z @v 6W :V MW EiK]$t JYLZ 7n Fo EW6W A[ ?X5W LWNfM\\\"gKg'q IW<] Ks KWMk Fn 5` Aj J~W'x MX 1iEi HX CX0X ?X :s ;V 2\\ 6" "^ HX +n Lz MR,R =X :V HW 1ZEZ %ZDZ 0~W :WNfM\\ @UGU !V%U,V6i/V%U9n JX*X,X*X,X*X,X*X,X*X,X*X-X3y5v%y Ny Ny Ny NX -X -X -X ," "x NX5] Ls Hs Hs Hs Hs IR+R(WMs Js Hs Hs Hs @X R $V NU *U *U *U DW4W Fh DW8X ?\\ 4~ Hl KX -VBV Hp 8V5e4nGZ +W +W LV BX" " 1X 3V j Ct Mx Mr -X Gq =j >Y 3p Gl AX -X 2X 3W 5X(X(u ?s$v Ky NX \"v'X/X'X -X -X3[&w LX&X0X5] Kq!X #p X0X(v :X 4p =\\ 7\\5\\6Y/Y FX @~U&W !V ,W " " AhKW JWLh Bm ChLW Gq JW (eJW MW6W MW ,W ,W:Y KW ,W7W7W=W6W Hl FWLh ChLW MW /o >d 7gKW A\\ 5ZZ @v 6W :V MW DgI\\$s He 5l Dn EW6W @Y " ">W4X MWMeM\\!eIe%o HW<] Jq JWLi Dk 2_ @h J~Y(x MX 1iEi HX CX0X ?X 9q :V 1Z 4\\ GX *m Lz LP*P X X ?v 6W :V MW CeG[$r Fc 2h Am EW6W @Y ?X3W MWMdL\\ cGc#m GW;\\ Hm HWKg Ah /] ?f I~Y(x MX 1iEi HX CX0X ?X 7m 8V 0" "X 2Z FX (j Kz AX :V HW -g Lh ,~W :WMdL\\ @UGU \"V$U-V5i0V$U7i HX(X.X(X.X(X.X(X.X(X.X(X/X2y1o\"y Ny Ny Ny NX -X -X -X ,t" " JX4\\ Im Bm Bm Bm Bm %VHm Dm Bm Bm Bm =X eJW GeJW" " GeJW GeJW ?X ;WJe 9X MW &Z =U W ,W *R &Q BW4W B` AW6W >[ /y Dd GX -VCV Af 5V2a.gBZ ,W -W KV CX 0X 4V " " Kd @t Mx Km *X Ek 6d ;X .h Bh >X .X 1X 1W 7X(X(q 7j Np Ey NX Mm\"X/X'X -X -X1[(w LX&X0X4\\ Gi LX Ni LX/X$n 7X 0i 9Z 5[5[6Y-Y GX @~U&W V -W " " >cIW JWIb k EW6W @Y ?" "W2W MWK`I[ NaEa i EW;\\ Fi FWIc >e ,\\ =b G~Y(x MX 1iEi HX CX0X ?X 5i 6V /V 0X EX &f Iz AX :V /P;W *c Gb )~W :WK`I[ @UGU " " #V#U.V4i1V#U6f FX(X.X(X.X(X.X(X.X(X.X(X/X2y/j Ny Ny Ny Ny NX -X -X -X ,p FX4\\ Gi >i >i >i >i $VEi @i >i >i >i ;X i0g ;i >i >i >i HW ,W ,W ,W #d BW6W Ef ;f ;f ;f ;f JUJe ;cIW FcIW FcIW FcIW ?X ;WIb 7X MW %Y =T X -X )P %P AW4W ?Z" " >W6X ?Z ,w B` EX .VBV <] 1V0]*b?[ -W -W KV CW /X 4V I` >t Mx Hg 'X Bf 2` :X +d =b ;X .W 0X 1X 9X&X)m 0d Kj ?y NX Jg " "NX/X'X -X -X0[)w LX&X0X3[ Dc IX Kf LX/Y!g 4X .e 7Z 5Z3Z7Y+Y HX @~U&W V -W =`GW JWG^ 7b 9^GW Ad CW \"YDW MW6W MW ,W ,W7Y NW ,W7W7W=W6W B` @WG^ 9" "^GW MW (c 2] 3_GW @Z 3X:X*Y4Y @X ?v 6W :V MW ?_AW$WKb @^ +` 9g CW6W ?W ?X2X NWJ^GY K]B^ Ke CW:[ Dd CWG_ 9` 'Y ;^ F~[)x MX 1iEi HX CX0X ?X 2c " "3V .T .V DX $b Gz AX :V /R>X &[ ?Z %~W :WJ^GY ?UGU #V +V +V 1b EX&X0X&X0X&X0X&X0X&X0Y'X1X1y,d Ky Ny Ny Ny NX -X -X " "-X ,j @X3[ Dc 8c 8c 8c 8c !VBc ;e :e :e :e 9X Y BS .V,W#Z ;V -V 7W ;W EX ;\\ 6] " "+Z 5\\ 5Z WGXBU FX=X E` \"W >] @WDY 3Z 2X C[ >T :[ KV /TAY " " EWGXBU =UGU BT 6V +V +V ,Y ?\\ +[ 0[ 0[ 0[ 0[ KT=[ 2[ 0[ 0[ 0[ 7Z ;Y .Y .Y .Y .Y .Y -" "Y2\\\"Z /\\ 1\\ 1\\ 1\\ CZ 3Z /Z /Z /Z /Z FVCZ 1Y .Y .Y .Y ,W :WDX 2W LW 7R #S" " >W /W 8W :V \"W 5X )X &Z CW NV .W :W %W" " @W :W -X -W :V MW LW FW ?W >W NW 0W =W 3S GV /XGZ " " DW HUGU AT %T 'R JT " " #T (X :W NX LW 7S =V /V 7W :V \"W" " 4X'Q &Y %Z DW NV .W :W %W @W :W -W ,W :V MW " " LW FW ?W >W NW 0W =W 3S GV /j CW HUGU @T " " %T 'P HT \"Q 'W 9W NW KW " " 7S =W 1W 7V :W \"V 2X)R &X #Z " " EW NW /W :W %W @W :W -W ,X ;V NX LW FW ?W >W NW 0W =W " " 3S GV /j CW HUGU @U &U " " U \"P 'W 9W NW KV 6S " " W NW 0W =W 3S GV /h " " AW HUGU ?T %T NT " " )X 9W X KV 6S W NW 0W =W 3S GV .f @W HUGU ?U &" "U U *W 8W W JV " " 6S ;V 3V 6V :W \"V .[5[ *Y Z " " Ha (W :a W NW 0W =W " " 3S GV +a >W HUGU >T %T " " NT +X 8W !X (VIV 6S :V 5V 5U" " 9W \"U +\\;] )X MZ Ia (W :a =Y %W ?W :W " " /W )[ ?V #[ KW FW ?W >W NW 0W =W 3S GV 'Z ;W " " HUGU >U &U U ,W 7W !" "W 'VIV 6S :V 6W 6V 4V *_C` " " )Y LZ Ja :a (P7Y $W ?W :W 0X (b GV +b JW FW ?W >W " " NW 0W =W 3S GV 7W HUGU >U &U " " U -X 7W \"X 'VJW " " 6S 9V 7V 5U 3U 'x (Z KZ Ka :a " " (R:Z $W ?W :W 0X (b GV +b JW FW ?W >W NW 0W =W 3S " " GV 7W #U &U U " " -X 7W \"X &UJW 6S 9W 9W " " Bu ([ IZ La :a (T>[ $X ?W :W 1X &a GV +a " " IW FW ?W >W NW 0W =W 3S GV 7W $V " " 'V !V .X 6W #X %VLW " " 5S 2p -a " " 8XE] %Y >W :W 3Z $_ GV +_ GW FW ?W >W NW 0W =W " " 3S GV 7W /QGW 2QGW ,QG" "W 0Z 6W %Z %a 5S " " 0l +a 8p +_ >W :W ;a !] G" "V +] EW FW ?W >W NW 0W =W 3S GV 7W /` " " 1` +` 7a 5W -a #` " " >e '` " " 7o *^ =W :W ;` KY GV +Y AW FW ?W >W NW 0W =W " " 3S GV 7W /` 1` +` " " 7` 4W -` \"_ " " 8\\ #_ \"} 3n )^ =W :W ;` 9V " " BW FW ?W >W NW 0W =W 'V 7W /_ " " 0_ *_ 6` 4W -` !] " " -] " " } 3l '] W NW 0W =W " " 'V 7W /^ /^ )^ " " 5_ 3W -_ N[ " " ,[ M} 2j &\\ ;W :W ;^ 7V BW " " FW ?W >W NW 0W =W 7W -Y *Y " " $Y 2^ 2W -^ LX " " *X J} " " /d #Z 9W :W ;\\ 5V BW FW ?W >W NW 0W =W " " 7W " " /\\ 0W HT " " I} *[ NW 6W :W ;Z 3V BW FW ?W >W" " NW 0W =W 7W " " /Z .W " " =} " " " " D" }; // Define a 40x38 'danger' color logo (used by cimg::dialog()). static const unsigned char logo40x38[4576] = { 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200, 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0, 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200, 1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0, 2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255, 255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189, 189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189, 189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123, 22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200, 1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0, 0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1, 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189, 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255, 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189, 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255, 255,0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2, 123,123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0, 1,189,189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11, 255,255,0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0, 1,189,189,189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11, 255,255,0,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123, 123,0,26,255,255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0, 0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25, 123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 }; //! Get/set default output stream for the \CImg library messages. /** \param file Desired output stream. Set to \c 0 to get the currently used output stream only. \return Currently used output stream. **/ inline std::FILE* output(std::FILE *file) { cimg::mutex(1); static std::FILE *res = stderr; if (file) res = file; cimg::mutex(1,0); return res; } // Return number of available CPU cores. inline unsigned int nb_cpus() { unsigned int res = 1; #if cimg_OS==2 SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); res = (unsigned int)sysinfo.dwNumberOfProcessors; #else res = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN); #endif return res?res:1U; } // Lock/unlock mutex for CImg multi-thread programming. inline int mutex(const unsigned int n, const int lock_mode) { switch (lock_mode) { case 0 : cimg::Mutex_attr().unlock(n); return 0; case 1 : cimg::Mutex_attr().lock(n); return 0; default : return cimg::Mutex_attr().trylock(n); } } //! Display a warning message on the default output stream. /** \param format C-string containing the format of the message, as with std::printf(). \note If configuration macro \c cimg_strict_warnings is set, this function throws a \c CImgWarningException instead. \warning As the first argument is a format string, it is highly recommended to write \code cimg::warn("%s",warning_message); \endcode instead of \code cimg::warn(warning_message); \endcode if \c warning_message can be arbitrary, to prevent nasty memory access. **/ inline void warn(const char *const format, ...) { if (cimg::exception_mode()>=1) { char *const message = new char[16384]; std::va_list ap; va_start(ap,format); cimg_vsnprintf(message,16384,format,ap); va_end(ap); #ifdef cimg_strict_warnings throw CImgWarningException(message); #else std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s%s\n",cimg::t_red,cimg::t_normal,message); #endif delete[] message; } } // Execute an external system command. /** \param command C-string containing the command line to execute. \param module_name Module name. \return Status value of the executed command, whose meaning is OS-dependent. \note This function is similar to std::system() but it does not open an extra console windows on Windows-based systems. **/ inline int system(const char *const command, const char *const module_name=0) { cimg::unused(module_name); #ifdef cimg_no_system_calls return -1; #else #if cimg_OS==1 const unsigned int l = (unsigned int)std::strlen(command); if (l) { char *const ncommand = new char[l + 16]; std::strncpy(ncommand,command,l); std::strcpy(ncommand + l," 2> /dev/null"); // Make command silent. const int out_val = std::system(ncommand); delete[] ncommand; return out_val; } else return -1; #elif cimg_OS==2 PROCESS_INFORMATION pi; STARTUPINFO si; std::memset(&pi,0,sizeof(PROCESS_INFORMATION)); std::memset(&si,0,sizeof(STARTUPINFO)); GetStartupInfo(&si); si.cb = sizeof(si); si.wShowWindow = SW_HIDE; si.dwFlags |= SW_HIDE | STARTF_USESHOWWINDOW; const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi); if (res) { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return 0; } else return std::system(command); #endif #endif } //! Return a reference to a temporary variable of type T. template inline T& temporary(const T&) { static T temp; return temp; } //! Exchange values of variables \c a and \c b. template inline void swap(T& a, T& b) { T t = a; a = b; b = t; } //! Exchange values of variables (\c a1,\c a2) and (\c b1,\c b2). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) { cimg::swap(a1,b1); cimg::swap(a2,b2); } //! Exchange values of variables (\c a1,\c a2,\c a3) and (\c b1,\c b2,\c b3). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) { cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); } //! Exchange values of variables (\c a1,\c a2,...,\c a4) and (\c b1,\c b2,...,\c b4). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) { cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); } //! Exchange values of variables (\c a1,\c a2,...,\c a5) and (\c b1,\c b2,...,\c b5). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); } //! Exchange values of variables (\c a1,\c a2,...,\c a6) and (\c b1,\c b2,...,\c b6). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6); } //! Exchange values of variables (\c a1,\c a2,...,\c a7) and (\c b1,\c b2,...,\c b7). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, T7& a7, T7& b7) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7); } //! Exchange values of variables (\c a1,\c a2,...,\c a8) and (\c b1,\c b2,...,\c b8). template inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, T7& a7, T7& b7, T8& a8, T8& b8) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8); } //! Return the endianness of the current architecture. /** \return \c false for Little Endian or \c true for Big Endian. **/ inline bool endianness() { const int x = 1; return ((unsigned char*)&x)[0]?false:true; } //! Reverse endianness of all elements in a memory buffer. /** \param[in,out] buffer Memory buffer whose endianness must be reversed. \param size Number of buffer elements to reverse. **/ template inline void invert_endianness(T* const buffer, const cimg_ulong size) { if (size) switch (sizeof(T)) { case 1 : break; case 2 : { for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) { const unsigned short val = *(--ptr); *ptr = (unsigned short)((val>>8)|((val<<8))); } } break; case 4 : { for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) { const unsigned int val = *(--ptr); *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24); } } break; default : { for (T* ptr = buffer + size; ptr>buffer; ) { unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T); for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe)); } } } } //! Reverse endianness of a single variable. /** \param[in,out] a Variable to reverse. \return Reference to reversed variable. **/ template inline T& invert_endianness(T& a) { invert_endianness(&a,1); return a; } // Conversion functions to get more precision when trying to store unsigned ints values as floats. inline unsigned int float2uint(const float f) { int tmp = 0; std::memcpy(&tmp,&f,sizeof(float)); if (tmp>=0) return (unsigned int)f; unsigned int u; // use memcpy instead of assignment to avoid undesired optimizations by C++-compiler. std::memcpy(&u,&f,sizeof(float)); return ((u)<<1)>>1; // set sign bit to 0. } inline float uint2float(const unsigned int u) { if (u<(1U<<19)) return (float)u; // Consider safe storage of unsigned int as floats until 19bits (i.e 524287). float f; const unsigned int v = u|(1U<<(8*sizeof(unsigned int)-1)); // set sign bit to 1. // use memcpy instead of simple assignment to avoid undesired optimizations by C++-compiler. std::memcpy(&f,&v,sizeof(float)); return f; } //! Return the value of a system timer, with a millisecond precision. /** \note The timer does not necessarily starts from \c 0. **/ inline cimg_ulong time() { #if cimg_OS==1 struct timeval st_time; gettimeofday(&st_time,0); return (cimg_ulong)(st_time.tv_usec/1000 + st_time.tv_sec*1000); #elif cimg_OS==2 SYSTEMTIME st_time; GetLocalTime(&st_time); return (cimg_ulong)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour))); #else return 0; #endif } // Implement a tic/toc mechanism to display elapsed time of algorithms. inline cimg_ulong tictoc(const bool is_tic); //! Start tic/toc timer for time measurement between code instructions. /** \return Current value of the timer (same value as time()). **/ inline cimg_ulong tic() { return cimg::tictoc(true); } //! End tic/toc timer and displays elapsed time from last call to tic(). /** \return Time elapsed (in ms) since last call to tic(). **/ inline cimg_ulong toc() { return cimg::tictoc(false); } //! Sleep for a given numbers of milliseconds. /** \param milliseconds Number of milliseconds to wait for. \note This function frees the CPU ressources during the sleeping time. It can be used to temporize your program properly, without wasting CPU time. **/ inline void sleep(const unsigned int milliseconds) { #if cimg_OS==1 struct timespec tv; tv.tv_sec = milliseconds/1000; tv.tv_nsec = (milliseconds%1000)*1000000; nanosleep(&tv,0); #elif cimg_OS==2 Sleep(milliseconds); #endif } inline unsigned int _wait(const unsigned int milliseconds, cimg_ulong& timer) { if (!timer) timer = cimg::time(); const cimg_ulong current_time = cimg::time(); if (current_time>=timer + milliseconds) { timer = current_time; return 0; } const unsigned int time_diff = (unsigned int)(timer + milliseconds - current_time); timer = current_time + time_diff; cimg::sleep(time_diff); return time_diff; } //! Wait for a given number of milliseconds since the last call to wait(). /** \param milliseconds Number of milliseconds to wait for. \return Number of milliseconds elapsed since the last call to wait(). \note Same as sleep() with a waiting time computed with regard to the last call of wait(). It may be used to temporize your program properly, without wasting CPU time. **/ inline cimg_long wait(const unsigned int milliseconds) { cimg::mutex(3); static cimg_ulong timer = 0; if (!timer) timer = cimg::time(); cimg::mutex(3,0); return _wait(milliseconds,timer); } // Random number generators. // CImg may use its own Random Number Generator (RNG) if configuration macro 'cimg_use_rng' is set. // Use it for instance when you have to deal with concurrent threads trying to call std::srand() // at the same time! #ifdef cimg_use_rng #include // Use a custom RNG. inline unsigned int _rand(const unsigned int seed=0, const bool set_seed=false) { static cimg_ulong next = 0xB16B00B5; cimg::mutex(4); if (set_seed) next = (cimg_ulong)seed; next = next*1103515245 + 12345U; cimg::mutex(4,0); return (unsigned int)(next&0xFFFFFFU); } inline void srand() { const unsigned int t = (unsigned int)cimg::time(); #if cimg_OS==1 cimg::_rand(t + (unsigned int)getpid(),true); #elif cimg_OS==2 cimg::_rand(t + (unsigned int)_getpid(),true); #else cimg::_rand(t,true); #endif } inline void srand(const unsigned int seed) { _rand(seed,true); } inline double rand(const double val_min, const double val_max) { const double val = cimg::_rand()/16777215.; return val_min + (val_max - val_min)*val; } #else // Use the system RNG. inline void srand() { const unsigned int t = (unsigned int)cimg::time(); #if cimg_OS==1 std::srand(t + (unsigned int)getpid()); #elif cimg_OS==2 std::srand(t + (unsigned int)_getpid()); #else std::srand(t); #endif } inline void srand(const unsigned int seed) { std::srand(seed); } //! Return a random variable uniformely distributed between [val_min,val_max]. /** **/ inline double rand(const double val_min, const double val_max) { const double val = (double)std::rand()/RAND_MAX; return val_min + (val_max - val_min)*val; } #endif //! Return a random variable uniformely distributed between [0,val_max]. /** **/ inline double rand(const double val_max=1) { return cimg::rand(0,val_max); } //! Return a random variable following a gaussian distribution and a standard deviation of 1. /** **/ inline double grand() { double x1, w; do { const double x2 = cimg::rand(-1,1); x1 = cimg::rand(-1,1); w = x1*x1 + x2*x2; } while (w<=0 || w>=1.0); return x1*std::sqrt((-2*std::log(w))/w); } //! Return a random variable following a Poisson distribution of parameter z. /** **/ inline unsigned int prand(const double z) { if (z<=1.0e-10) return 0; if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z); unsigned int k = 0; const double y = std::exp(-z); for (double s = 1.0; s>=y; ++k) s*=cimg::rand(); return k - 1; } //! Bitwise-rotate value on the left. template inline T rol(const T& a, const unsigned int n=1) { return n?(T)((a<>((sizeof(T)<<3) - n))):a; } inline float rol(const float a, const unsigned int n=1) { return (float)rol((int)a,n); } inline double rol(const double a, const unsigned int n=1) { return (double)rol((cimg_long)a,n); } inline double rol(const long double a, const unsigned int n=1) { return (double)rol((cimg_long)a,n); } //! Bitwise-rotate value on the right. template inline T ror(const T& a, const unsigned int n=1) { return n?(T)((a>>n)|(a<<((sizeof(T)<<3) - n))):a; } inline float ror(const float a, const unsigned int n=1) { return (float)ror((int)a,n); } inline double ror(const double a, const unsigned int n=1) { return (double)ror((cimg_long)a,n); } inline double ror(const long double a, const unsigned int n=1) { return (double)ror((cimg_long)a,n); } //! Return absolute value of a value. template inline T abs(const T& a) { return a>=0?a:-a; } inline bool abs(const bool a) { return a; } inline int abs(const unsigned char a) { return (int)a; } inline int abs(const unsigned short a) { return (int)a; } inline int abs(const unsigned int a) { return (int)a; } inline int abs(const int a) { return std::abs(a); } inline cimg_int64 abs(const cimg_uint64 a) { return (cimg_int64)a; } inline double abs(const double a) { return std::fabs(a); } inline float abs(const float a) { return (float)std::fabs((double)a); } //! Return square of a value. template inline T sqr(const T& val) { return val*val; } //! Return 1 + log_10(x) of a value \c x. inline int xln(const int x) { return x>0?(int)(1 + std::log10((double)x)):1; } //! Return the minimum between two values. template inline typename cimg::superset::type min(const t1& a, const t2& b) { typedef typename cimg::superset::type t1t2; return (t1t2)(a<=b?a:b); } //! Return the minimum between three values. template inline typename cimg::superset2::type min(const t1& a, const t2& b, const t3& c) { typedef typename cimg::superset2::type t1t2t3; return (t1t2t3)cimg::min(cimg::min(a,b),c); } //! Return the minimum between four values. template inline typename cimg::superset3::type min(const t1& a, const t2& b, const t3& c, const t4& d) { typedef typename cimg::superset3::type t1t2t3t4; return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d); } //! Return the maximum between two values. template inline typename cimg::superset::type max(const t1& a, const t2& b) { typedef typename cimg::superset::type t1t2; return (t1t2)(a>=b?a:b); } //! Return the maximum between three values. template inline typename cimg::superset2::type max(const t1& a, const t2& b, const t3& c) { typedef typename cimg::superset2::type t1t2t3; return (t1t2t3)cimg::max(cimg::max(a,b),c); } //! Return the maximum between four values. template inline typename cimg::superset3::type max(const t1& a, const t2& b, const t3& c, const t4& d) { typedef typename cimg::superset3::type t1t2t3t4; return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d); } //! Return the sign of a value. template inline T sign(const T& x) { return (x<0)?(T)(-1):(x==0?(T)0:(T)1); } //! Return the nearest power of 2 higher than given value. template inline cimg_ulong nearest_pow2(const T& x) { cimg_ulong i = 1; while (x>i) i<<=1; return i; } //! Return the sinc of a given value. inline double sinc(const double x) { return x?std::sin(x)/x:1; } //! Return the modulo of a value. /** \param x Input value. \param m Modulo value. \note This modulo function accepts negative and floating-points modulo numbers, as well as variables of any type. **/ template inline T mod(const T& x, const T& m) { const double dx = (double)x, dm = (double)m; return (T)(dx - dm * std::floor(dx / dm)); } inline int mod(const bool x, const bool m) { return m?(x?1:0):0; } inline int mod(const unsigned char x, const unsigned char m) { return x%m; } inline int mod(const char x, const char m) { #if defined(CHAR_MAX) && CHAR_MAX==255 return x%m; #else return x>=0?x%m:(x%m?m + x%m:0); #endif } inline int mod(const unsigned short x, const unsigned short m) { return x%m; } inline int mod(const short x, const short m) { return x>=0?x%m:(x%m?m + x%m:0); } inline int mod(const unsigned int x, const unsigned int m) { return (int)(x%m); } inline int mod(const int x, const int m) { return x>=0?x%m:(x%m?m + x%m:0); } inline cimg_int64 mod(const cimg_uint64 x, const cimg_uint64 m) { return x%m; } inline cimg_int64 mod(const cimg_int64 x, const cimg_int64 m) { return x>=0?x%m:(x%m?m + x%m:0); } //! Return the min-mod of two values. /** \note minmod(\p a,\p b) is defined to be: - minmod(\p a,\p b) = min(\p a,\p b), if \p a and \p b have the same sign. - minmod(\p a,\p b) = 0, if \p a and \p b have different signs. **/ template inline T minmod(const T& a, const T& b) { return a*b<=0?0:(a>0?(a inline T round(const T& x, const double y=1, const int rounding_type=0) { if (y<=0) return x; const double sx = (double)x/y, floor = std::floor(sx), delta = sx - floor; return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx))); } inline double _pythagore(double a, double b) { const double absa = cimg::abs(a), absb = cimg::abs(b); if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0 + tmp*tmp); } else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); } } //! Return sqrt(x^2 + y^2). inline double hypot(const double x, const double y) { double nx = cimg::abs(x), ny = cimg::abs(y), t; if (nx0) { t/=nx; return nx*std::sqrt(1+t*t); } return 0; } //! Convert ascii character to lower case. inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a'); } //! Convert C-string to lower case. inline void uncase(char *const str) { if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = uncase(*ptr); } //! Read value in a C-string. /** \param str C-string containing the float value to read. \return Read value. \note Same as std::atof() extended to manage the retrieval of fractions from C-strings, as in "1/2". **/ inline double atof(const char *const str) { double x = 0, y = 1; return str && cimg_sscanf(str,"%lf/%lf",&x,&y)>0?x/y:0; } //! Compare the first \p l characters of two C-strings, ignoring the case. /** \param str1 C-string. \param str2 C-string. \param l Number of characters to compare. \return \c 0 if the two strings are equal, something else otherwise. \note This function has to be defined since it is not provided by all C++-compilers (not ANSI). **/ inline int strncasecmp(const char *const str1, const char *const str2, const int l) { if (!l) return 0; if (!str1) return str2?-1:0; const char *nstr1 = str1, *nstr2 = str2; int k, diff = 0; for (k = 0; kp && str[q]==delimiter; ) { --q; if (!is_iterative) break; } } const int n = q - p + 1; if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; } return false; } //! Replace reserved characters (for Windows filename) by another character. /** \param[in,out] str C-string to work with (modified at output). \param[in] c Replacement character. **/ inline void strwindows_reserved(char *const str, const char c='_') { for (char *s = str; *s; ++s) { const char i = *s; if (i=='<' || i=='>' || i==':' || i=='\"' || i=='/' || i=='\\' || i=='|' || i=='?' || i=='*') *s = c; } } //! Replace escape sequences in C-strings by their binary ascii values. /** \param[in,out] str C-string to work with (modified at output). **/ inline void strunescape(char *const str) { #define cimg_strunescape(ci,co) case ci : *nd = co; ++ns; break; unsigned int val = 0; for (char *ns = str, *nd = str; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) { cimg_strunescape('a','\a'); cimg_strunescape('b','\b'); cimg_strunescape('e',0x1B); cimg_strunescape('f','\f'); cimg_strunescape('n','\n'); cimg_strunescape('r','\r'); cimg_strunescape('t','\t'); cimg_strunescape('v','\v'); cimg_strunescape('\\','\\'); cimg_strunescape('\'','\''); cimg_strunescape('\"','\"'); cimg_strunescape('\?','\?'); case 0 : *nd = 0; break; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : cimg_sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns; *nd = (char)val; break; case 'x' : cimg_sscanf(++ns,"%x",&val); while ((*ns>='0' && *ns<='9') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; *nd = (char)val; break; default : *nd = *(ns++); } else *nd = *(ns++); } // Return a temporary string describing the size of a memory buffer. inline const char *strbuffersize(const cimg_ulong size); // Return string that identifies the running OS. inline const char *stros() { #if defined(linux) || defined(__linux) || defined(__linux__) static const char *const str = "Linux"; #elif defined(sun) || defined(__sun) static const char *const str = "Sun OS"; #elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__) static const char *const str = "BSD"; #elif defined(sgi) || defined(__sgi) static const char *const str = "Irix"; #elif defined(__MACOSX__) || defined(__APPLE__) static const char *const str = "Mac OS"; #elif defined(unix) || defined(__unix) || defined(__unix__) static const char *const str = "Generic Unix"; #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ defined(WIN64) || defined(_WIN64) || defined(__WIN64__) static const char *const str = "Windows"; #else const char *const _str1 = std::getenv("OSTYPE"), *const _str2 = _str1?_str1:std::getenv("OS"), *const str = _str2?_str2:"Unknown OS"; #endif return str; } //! Return the basename of a filename. inline const char* basename(const char *const s, const char separator=cimg_file_separator) { const char *p = 0, *np = s; while (np>=s && (p=np)) np = std::strchr(np,separator) + 1; return p; } // Return a random filename. inline const char* filenamerand() { cimg::mutex(6); static char randomid[9]; cimg::srand(); for (unsigned int k = 0; k<8; ++k) { const int v = (int)cimg::rand(65535)%3; randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)): (v==1?('a' + ((int)cimg::rand(65535)%26)):('A' + ((int)cimg::rand(65535)%26)))); } cimg::mutex(6,0); return randomid; } // Convert filename as a Windows-style filename (short path name). inline void winformat_string(char *const str) { if (str && *str) { #if cimg_OS==2 char *const nstr = new char[MAX_PATH]; if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr); delete[] nstr; #endif } } //! Open a file. /** \param path Path of the filename to open. \param mode C-string describing the opening mode. \return Opened file. \note Same as std::fopen() but throw a \c CImgIOException when the specified file cannot be opened, instead of returning \c 0. **/ inline std::FILE *fopen(const char *const path, const char *const mode) { if (!path) throw CImgArgumentException("cimg::fopen(): Specified file path is (null)."); if (!mode) throw CImgArgumentException("cimg::fopen(): File '%s', specified mode is (null).", path); std::FILE *res = 0; if (*path=='-' && (!path[1] || path[1]=='.')) { res = (*mode=='r')?stdin:stdout; #if cimg_OS==2 if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode. if (_setmode(_fileno(res),0x8000)==-1) res = 0; } #endif } else res = std::fopen(path,mode); if (!res) throw CImgIOException("cimg::fopen(): Failed to open file '%s' with mode '%s'.", path,mode); return res; } //! Close a file. /** \param file File to close. \return \c 0 if file has been closed properly, something else otherwise. \note Same as std::fclose() but display a warning message if the file has not been closed properly. **/ inline int fclose(std::FILE *file) { if (!file) warn("cimg::fclose(): Specified file is (null)."); if (!file || file==stdin || file==stdout) return 0; const int errn = std::fclose(file); if (errn!=0) warn("cimg::fclose(): Error code %d returned during file closing.", errn); return errn; } //! Version of 'fseek()' that supports >=64bits offsets everywhere (for Windows). inline int fseek(FILE *stream, cimg_long offset, int origin) { #if cimg_OS==2 return _fseeki64(stream,(__int64)offset,origin); #else return std::fseek(stream,offset,origin); #endif } //! Version of 'ftell()' that supports >=64bits offsets everywhere (for Windows). inline cimg_long ftell(FILE *stream) { #if cimg_OS==2 return (cimg_long)_ftelli64(stream); #else return (cimg_long)std::ftell(stream); #endif } //! Check if a path is a directory. /** \param path Specified path to test. **/ inline bool is_directory(const char *const path) { if (!path || !*path) return false; #if cimg_OS==1 struct stat st_buf; return (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode)); #elif cimg_OS==2 const unsigned int res = (unsigned int)GetFileAttributesA(path); return res==INVALID_FILE_ATTRIBUTES?false:(res&16); #endif } //! Check if a path is a file. /** \param path Specified path to test. **/ inline bool is_file(const char *const path) { if (!path || !*path) return false; std::FILE *const file = std::fopen(path,"rb"); if (!file) return false; std::fclose(file); return !is_directory(path); } //! Get last write time of a given file or directory. /** \param path Specified path to get attributes from. \param attr Type of requested time attribute. Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } \return -1 if requested attribute could not be read. **/ inline int fdate(const char *const path, const unsigned int attr) { int res = -1; if (!path || !*path || attr>6) return -1; cimg::mutex(6); #if cimg_OS==2 HANDLE file = CreateFileA(path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (file!=INVALID_HANDLE_VALUE) { FILETIME _ft; SYSTEMTIME ft; if (GetFileTime(file,0,0,&_ft) && FileTimeToSystemTime(&_ft,&ft)) res = (int)(attr==0?ft.wYear:attr==1?ft.wMonth:attr==2?ft.wDay:attr==3?ft.wDayOfWeek: attr==4?ft.wHour:attr==5?ft.wMinute:ft.wSecond); CloseHandle(file); } #else struct stat st_buf; if (!stat(path,&st_buf)) { const time_t _ft = st_buf.st_mtime; const struct tm& ft = *std::localtime(&_ft); res = (int)(attr==0?ft.tm_year + 1900:attr==1?ft.tm_mon + 1:attr==2?ft.tm_mday:attr==3?ft.tm_wday: attr==4?ft.tm_hour:attr==5?ft.tm_min:ft.tm_sec); } #endif cimg::mutex(6,0); return res; } //! Get current local time. /** \param attr Type of requested time attribute. Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } **/ inline int date(const unsigned int attr) { int res; cimg::mutex(6); #if cimg_OS==2 SYSTEMTIME st; GetLocalTime(&st); res = (int)(attr==0?st.wYear:attr==1?st.wMonth:attr==2?st.wDay:attr==3?st.wDayOfWeek: attr==4?st.wHour:attr==5?st.wMinute:st.wSecond); #else time_t _st; std::time(&_st); struct tm *st = std::localtime(&_st); res = (int)(attr==0?st->tm_year + 1900:attr==1?st->tm_mon + 1:attr==2?st->tm_mday:attr==3?st->tm_wday: attr==4?st->tm_hour:attr==5?st->tm_min:st->tm_sec); #endif cimg::mutex(6,0); return res; } // Get/set path to store temporary files. inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the Program Files/ directory (Windows only). #if cimg_OS==2 inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false); #endif // Get/set path to the ImageMagick's \c convert binary. inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the GraphicsMagick's \c gm binary. inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the XMedcon's \c medcon binary. inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the FFMPEG's \c ffmpeg binary. inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the \c gzip binary. inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the \c gunzip binary. inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the \c dcraw binary. inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the \c wget binary. inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false); // Get/set path to the \c curl binary. inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false); //! Split filename into two C-strings \c body and \c extension. /** filename and body must not overlap! **/ inline const char *split_filename(const char *const filename, char *const body=0) { if (!filename) { if (body) *body = 0; return 0; } const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.') + 1) {} if (p==filename) { if (body) std::strcpy(body,filename); return filename + std::strlen(filename); } const unsigned int l = (unsigned int)(p - filename - 1); if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; } return p; } //! Generate a numbered version of a filename. inline char* number_filename(const char *const filename, const int number, const unsigned int digits, char *const str) { if (!filename) { if (str) *str = 0; return 0; } char *const format = new char[1024], *const body = new char[1024]; const char *const ext = cimg::split_filename(filename,body); if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits); else cimg_snprintf(format,1024,"%%s_%%.%ud",digits); cimg_sprintf(str,format,body,number,ext); delete[] format; delete[] body; return str; } //! Read data from file. /** \param[out] ptr Pointer to memory buffer that will contain the binary data read from file. \param nmemb Number of elements to read. \param stream File to read data from. \return Number of read elements. \note Same as std::fread() but may display warning message if all elements could not be read. **/ template inline size_t fread(T *const ptr, const size_t nmemb, std::FILE *stream) { if (!ptr || !stream) throw CImgArgumentException("cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.", nmemb,cimg::type::string(),nmemb>1?"s":"",stream,ptr); if (!nmemb) return 0; const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); size_t to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0; do { l_to_read = (to_read*sizeof(T))0); if (to_read>0) warn("cimg::fread(): Only %lu/%lu elements could be read from file.", (unsigned long)al_read,(unsigned long)nmemb); return al_read; } //! Write data to file. /** \param ptr Pointer to memory buffer containing the binary data to write on file. \param nmemb Number of elements to write. \param[out] stream File to write data on. \return Number of written elements. \note Similar to std::fwrite but may display warning messages if all elements could not be written. **/ template inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) { if (!ptr || !stream) throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.", nmemb,cimg::type::string(),nmemb>1?"s":"",ptr,stream); if (!nmemb) return 0; const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); size_t to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0; do { l_to_write = (to_write*sizeof(T))0); if (to_write>0) warn("cimg::fwrite(): Only %lu/%lu elements could be written in file.", (unsigned long)al_write,(unsigned long)nmemb); return al_write; } //! Create an empty file. /** \param file Input file (can be \c 0 if \c filename is set). \param filename Filename, as a C-string (can be \c 0 if \c file is set). **/ inline void fempty(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException("cimg::fempty(): Specified filename is (null)."); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); if (!file) cimg::fclose(nfile); } // Try to guess format from an image file. inline const char *ftype(std::FILE *const file, const char *const filename); // Load file from network as a local temporary file. inline char *load_network(const char *const url, char *const filename_local, const unsigned int timeout=0, const bool try_fallback=false, const char *const referer=0); //! Return options specified on the command line. inline const char* option(const char *const name, const int argc, const char *const *const argv, const char *const defaut, const char *const usage, const bool reset_static) { static bool first = true, visu = false; if (reset_static) { first = true; return 0; } const char *res = 0; if (first) { first = false; visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0; visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0; visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0; } if (!name && visu) { if (usage) { std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal); std::fprintf(cimg::output(),": %s",usage); std::fprintf(cimg::output()," (%s, %s)\n\n",__DATE__,__TIME__); } if (defaut) std::fprintf(cimg::output(),"%s\n",defaut); } if (name) { if (argc>0) { int k = 0; while (k Operating System: %s%-13s%s %s('cimg_OS'=%d)%s\n", cimg::t_bold, cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"), cimg::t_normal,cimg::t_green, cimg_OS, cimg::t_normal); std::fprintf(cimg::output()," > CPU endianness: %s%s Endian%s\n", cimg::t_bold, cimg::endianness()?"Big":"Little", cimg::t_normal); std::fprintf(cimg::output()," > Verbosity mode: %s%-13s%s %s('cimg_verbosity'=%d)%s\n", cimg::t_bold, cimg_verbosity==0?"Quiet": cimg_verbosity==1?"Console": cimg_verbosity==2?"Dialog": cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings", cimg::t_normal,cimg::t_green, cimg_verbosity, cimg::t_normal); std::fprintf(cimg::output()," > Stricts warnings: %s%-13s%s %s('cimg_strict_warnings' %s)%s\n", cimg::t_bold, #ifdef cimg_strict_warnings "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using VT100 messages: %s%-13s%s %s('cimg_use_vt100' %s)%s\n", cimg::t_bold, #ifdef cimg_use_vt100 "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Display type: %s%-13s%s %s('cimg_display'=%d)%s\n", cimg::t_bold, cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown", cimg::t_normal,cimg::t_green, cimg_display, cimg::t_normal); #if cimg_display==1 std::fprintf(cimg::output()," > Using XShm for X11: %s%-13s%s %s('cimg_use_xshm' %s)%s\n", cimg::t_bold, #ifdef cimg_use_xshm "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using XRand for X11: %s%-13s%s %s('cimg_use_xrandr' %s)%s\n", cimg::t_bold, #ifdef cimg_use_xrandr "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); #endif std::fprintf(cimg::output()," > Using OpenMP: %s%-13s%s %s('cimg_use_openmp' %s)%s\n", cimg::t_bold, #ifdef cimg_use_openmp "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using PNG library: %s%-13s%s %s('cimg_use_png' %s)%s\n", cimg::t_bold, #ifdef cimg_use_png "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using JPEG library: %s%-13s%s %s('cimg_use_jpeg' %s)%s\n", cimg::t_bold, #ifdef cimg_use_jpeg "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using TIFF library: %s%-13s%s %s('cimg_use_tiff' %s)%s\n", cimg::t_bold, #ifdef cimg_use_tiff "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using Magick++ library: %s%-13s%s %s('cimg_use_magick' %s)%s\n", cimg::t_bold, #ifdef cimg_use_magick "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using FFTW3 library: %s%-13s%s %s('cimg_use_fftw3' %s)%s\n", cimg::t_bold, #ifdef cimg_use_fftw3 "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); std::fprintf(cimg::output()," > Using LAPACK library: %s%-13s%s %s('cimg_use_lapack' %s)%s\n", cimg::t_bold, #ifdef cimg_use_lapack "Yes",cimg::t_normal,cimg::t_green,"defined", #else "No",cimg::t_normal,cimg::t_green,"undefined", #endif cimg::t_normal); char *const tmp = new char[1024]; cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::imagemagick_path()); std::fprintf(cimg::output()," > Path of ImageMagick: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::graphicsmagick_path()); std::fprintf(cimg::output()," > Path of GraphicsMagick: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::medcon_path()); std::fprintf(cimg::output()," > Path of 'medcon': %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::temporary_path()); std::fprintf(cimg::output()," > Temporary path: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); std::fprintf(cimg::output(),"\n"); delete[] tmp; } // Declare LAPACK function signatures if LAPACK support is enabled. #ifdef cimg_use_lapack template inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) { dgetrf_(&N,&N,lapA,&N,IPIV,&INFO); } inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) { sgetrf_(&N,&N,lapA,&N,IPIV,&INFO); } template inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) { dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); } inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) { sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); } template inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN, T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) { dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); } inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN, float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) { sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); } template inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) { int one = 1; dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); } inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) { int one = 1; sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); } template inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) { dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); } inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) { ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); } template inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA, T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){ dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); } inline void sgels(char & TRANS, int &M, int &N, int &NRHS, float* lapA, int &LDA, float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO){ sgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); } #endif // End of the 'cimg' namespace } /*------------------------------------------------ # # # Definition of mathematical operators and # external functions. # # -------------------------------------------------*/ #define _cimg_create_ext_operators(typ) \ template \ inline CImg::type> operator+(const typ val, const CImg& img) { \ return img + val; \ } \ template \ inline CImg::type> operator-(const typ val, const CImg& img) { \ typedef typename cimg::superset::type Tt; \ return CImg(img._width,img._height,img._depth,img._spectrum,val)-=img; \ } \ template \ inline CImg::type> operator*(const typ val, const CImg& img) { \ return img*val; \ } \ template \ inline CImg::type> operator/(const typ val, const CImg& img) { \ return val*img.get_invert(); \ } \ template \ inline CImg::type> operator&(const typ val, const CImg& img) { \ return img & val; \ } \ template \ inline CImg::type> operator|(const typ val, const CImg& img) { \ return img | val; \ } \ template \ inline CImg::type> operator^(const typ val, const CImg& img) { \ return img ^ val; \ } \ template \ inline bool operator==(const typ val, const CImg& img) { \ return img == val; \ } \ template \ inline bool operator!=(const typ val, const CImg& img) { \ return img != val; \ } _cimg_create_ext_operators(bool) _cimg_create_ext_operators(unsigned char) _cimg_create_ext_operators(char) _cimg_create_ext_operators(signed char) _cimg_create_ext_operators(unsigned short) _cimg_create_ext_operators(short) _cimg_create_ext_operators(unsigned int) _cimg_create_ext_operators(int) _cimg_create_ext_operators(cimg_uint64) _cimg_create_ext_operators(cimg_int64) _cimg_create_ext_operators(float) _cimg_create_ext_operators(double) _cimg_create_ext_operators(long double) template inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg& img) { return img + expression; } template inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg& img) { return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img; } template inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg& img) { return img*expression; } template inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg& img) { return expression*img.get_invert(); } template inline CImg operator&(const char *const expression, const CImg& img) { return img & expression; } template inline CImg operator|(const char *const expression, const CImg& img) { return img | expression; } template inline CImg operator^(const char *const expression, const CImg& img) { return img ^ expression; } template inline bool operator==(const char *const expression, const CImg& img) { return img==expression; } template inline bool operator!=(const char *const expression, const CImg& img) { return img!=expression; } template inline CImg<_cimg_Tfloat> sqr(const CImg& instance) { return instance.get_sqr(); } template inline CImg<_cimg_Tfloat> sqrt(const CImg& instance) { return instance.get_sqrt(); } template inline CImg<_cimg_Tfloat> exp(const CImg& instance) { return instance.get_exp(); } template inline CImg<_cimg_Tfloat> log(const CImg& instance) { return instance.get_log(); } template inline CImg<_cimg_Tfloat> log2(const CImg& instance) { return instance.get_log2(); } template inline CImg<_cimg_Tfloat> log10(const CImg& instance) { return instance.get_log10(); } template inline CImg<_cimg_Tfloat> abs(const CImg& instance) { return instance.get_abs(); } template inline CImg<_cimg_Tfloat> sign(const CImg& instance) { return instance.get_sign(); } template inline CImg<_cimg_Tfloat> cos(const CImg& instance) { return instance.get_cos(); } template inline CImg<_cimg_Tfloat> sin(const CImg& instance) { return instance.get_sin(); } template inline CImg<_cimg_Tfloat> sinc(const CImg& instance) { return instance.get_sinc(); } template inline CImg<_cimg_Tfloat> tan(const CImg& instance) { return instance.get_tan(); } template inline CImg<_cimg_Tfloat> acos(const CImg& instance) { return instance.get_acos(); } template inline CImg<_cimg_Tfloat> asin(const CImg& instance) { return instance.get_asin(); } template inline CImg<_cimg_Tfloat> atan(const CImg& instance) { return instance.get_atan(); } template inline CImg<_cimg_Tfloat> cosh(const CImg& instance) { return instance.get_cosh(); } template inline CImg<_cimg_Tfloat> sinh(const CImg& instance) { return instance.get_sinh(); } template inline CImg<_cimg_Tfloat> tanh(const CImg& instance) { return instance.get_tanh(); } template inline CImg transpose(const CImg& instance) { return instance.get_transpose(); } template inline CImg<_cimg_Tfloat> invert(const CImg& instance) { return instance.get_invert(); } template inline CImg<_cimg_Tfloat> pseudoinvert(const CImg& instance) { return instance.get_pseudoinvert(); } /*----------------------------------- # # Define the CImgDisplay structure # ----------------------------------*/ //! Allow the creation of windows, display images on them and manage user events (keyboard, mouse and windows events). /** CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems). If both libraries are missing, CImgDisplay will not be able to display images on screen, and will enter a minimal mode where warning messages will be outputed each time the program is trying to call one of the CImgDisplay method. The configuration variable \c cimg_display tells about the graphic library used. It is set automatically by \CImg when one of these graphic libraries has been detected. But, you can override its value if necessary. Valid choices are: - 0: Disable display capabilities. - 1: Use \b X-Window (X11) library. - 2: Use \b GDI32 library. Remember to link your program against \b X11 or \b GDI32 libraries if you use CImgDisplay. **/ struct CImgDisplay { cimg_ulong _timer, _fps_frames, _fps_timer; unsigned int _width, _height, _normalization; float _fps_fps, _min, _max; bool _is_fullscreen; char *_title; unsigned int _window_width, _window_height, _button, *_keys, *_released_keys; int _window_x, _window_y, _mouse_x, _mouse_y, _wheel; bool _is_closed, _is_resized, _is_moved, _is_event, _is_keyESC, _is_keyF1, _is_keyF2, _is_keyF3, _is_keyF4, _is_keyF5, _is_keyF6, _is_keyF7, _is_keyF8, _is_keyF9, _is_keyF10, _is_keyF11, _is_keyF12, _is_keyPAUSE, _is_key1, _is_key2, _is_key3, _is_key4, _is_key5, _is_key6, _is_key7, _is_key8, _is_key9, _is_key0, _is_keyBACKSPACE, _is_keyINSERT, _is_keyHOME, _is_keyPAGEUP, _is_keyTAB, _is_keyQ, _is_keyW, _is_keyE, _is_keyR, _is_keyT, _is_keyY, _is_keyU, _is_keyI, _is_keyO, _is_keyP, _is_keyDELETE, _is_keyEND, _is_keyPAGEDOWN, _is_keyCAPSLOCK, _is_keyA, _is_keyS, _is_keyD, _is_keyF, _is_keyG, _is_keyH, _is_keyJ, _is_keyK, _is_keyL, _is_keyENTER, _is_keySHIFTLEFT, _is_keyZ, _is_keyX, _is_keyC, _is_keyV, _is_keyB, _is_keyN, _is_keyM, _is_keySHIFTRIGHT, _is_keyARROWUP, _is_keyCTRLLEFT, _is_keyAPPLEFT, _is_keyALT, _is_keySPACE, _is_keyALTGR, _is_keyAPPRIGHT, _is_keyMENU, _is_keyCTRLRIGHT, _is_keyARROWLEFT, _is_keyARROWDOWN, _is_keyARROWRIGHT, _is_keyPAD0, _is_keyPAD1, _is_keyPAD2, _is_keyPAD3, _is_keyPAD4, _is_keyPAD5, _is_keyPAD6, _is_keyPAD7, _is_keyPAD8, _is_keyPAD9, _is_keyPADADD, _is_keyPADSUB, _is_keyPADMUL, _is_keyPADDIV; //@} //--------------------------- // //! \name Plugins //@{ //--------------------------- #ifdef cimgdisplay_plugin #include cimgdisplay_plugin #endif #ifdef cimgdisplay_plugin1 #include cimgdisplay_plugin1 #endif #ifdef cimgdisplay_plugin2 #include cimgdisplay_plugin2 #endif #ifdef cimgdisplay_plugin3 #include cimgdisplay_plugin3 #endif #ifdef cimgdisplay_plugin4 #include cimgdisplay_plugin4 #endif #ifdef cimgdisplay_plugin5 #include cimgdisplay_plugin5 #endif #ifdef cimgdisplay_plugin6 #include cimgdisplay_plugin6 #endif #ifdef cimgdisplay_plugin7 #include cimgdisplay_plugin7 #endif #ifdef cimgdisplay_plugin8 #include cimgdisplay_plugin8 #endif //@} //-------------------------------------------------------- // //! \name Constructors / Destructor / Instance Management //@{ //-------------------------------------------------------- //! Destructor. /** \note If the associated window is visible on the screen, it is closed by the call to the destructor. **/ ~CImgDisplay() { assign(); delete[] _keys; delete[] _released_keys; } //! Construct an empty display. /** \note Constructing an empty CImgDisplay instance does not make a window appearing on the screen, until display of valid data is performed. \par Example \code CImgDisplay disp; // Does actually nothing. ... disp.display(img); // Construct new window and display image in it. \endcode **/ CImgDisplay(): _width(0),_height(0),_normalization(0), _min(0),_max(0), _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(); } //! Construct a display with specified dimensions. /** \param width Window width. \param height Window height. \param title Window title. \param normalization Normalization type (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). \param is_fullscreen Tells if fullscreen mode is enabled. \param is_closed Tells if associated window is initially visible or not. \note A black background is initially displayed on the associated window. **/ CImgDisplay(const unsigned int width, const unsigned int height, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false): _width(0),_height(0),_normalization(0), _min(0),_max(0), _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(width,height,title,normalization,is_fullscreen,is_closed); } //! Construct a display from an image. /** \param img Image used as a model to create the window. \param title Window title. \param normalization Normalization type (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). \param is_fullscreen Tells if fullscreen mode is enabled. \param is_closed Tells if associated window is initially visible or not. \note The pixels of the input image are initially displayed on the associated window. **/ template explicit CImgDisplay(const CImg& img, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false): _width(0),_height(0),_normalization(0), _min(0),_max(0), _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(img,title,normalization,is_fullscreen,is_closed); } //! Construct a display from an image list. /** \param list The images list to display. \param title Window title. \param normalization Normalization type (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). \param is_fullscreen Tells if fullscreen mode is enabled. \param is_closed Tells if associated window is initially visible or not. \note All images of the list, appended along the X-axis, are initially displayed on the associated window. **/ template explicit CImgDisplay(const CImgList& list, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false): _width(0),_height(0),_normalization(0), _min(0),_max(0), _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(list,title,normalization,is_fullscreen,is_closed); } //! Construct a display as a copy of an existing one. /** \param disp Display instance to copy. \note The pixel buffer of the input window is initially displayed on the associated window. **/ CImgDisplay(const CImgDisplay& disp): _width(0),_height(0),_normalization(0), _min(0),_max(0), _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(disp); } #if cimg_display==0 static void _no_display_exception() { throw CImgDisplayException("CImgDisplay(): No display available."); } //! Destructor - Empty constructor \inplace. /** \note Replace the current instance by an empty display. **/ CImgDisplay& assign() { return flush(); } //! Construct a display with specified dimensions \inplace. /** **/ CImgDisplay& assign(const unsigned int width, const unsigned int height, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false) { cimg::unused(width,height,title,normalization,is_fullscreen,is_closed); _no_display_exception(); return assign(); } //! Construct a display from an image \inplace. /** **/ template CImgDisplay& assign(const CImg& img, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false) { _no_display_exception(); return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed); } //! Construct a display from an image list \inplace. /** **/ template CImgDisplay& assign(const CImgList& list, const char *const title=0, const unsigned int normalization=3, const bool is_fullscreen=false, const bool is_closed=false) { _no_display_exception(); return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed); } //! Construct a display as a copy of another one \inplace. /** **/ CImgDisplay& assign(const CImgDisplay &disp) { _no_display_exception(); return assign(disp._width,disp._height); } #endif //! Return a reference to an empty display. /** \note Can be useful for writing function prototypes where one of the argument (of type CImgDisplay&) must have a default value. \par Example \code void foo(CImgDisplay& disp=CImgDisplay::empty()); \endcode **/ static CImgDisplay& empty() { static CImgDisplay _empty; return _empty.assign(); } //! Return a reference to an empty display \const. static const CImgDisplay& const_empty() { static const CImgDisplay _empty; return _empty; } #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \ CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true) static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz, const int dmin, const int dmax,const bool return_y) { const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0); unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1; const unsigned int sw = (unsigned int)CImgDisplay::screen_width(), sh = (unsigned int)CImgDisplay::screen_height(), mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin, mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin, Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax, Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax; if (nwMw) { nh = nh*Mw/nw; nh+=(nh==0?1:0); nw = Mw; } if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0?1:0); nh = Mh; } if (nwdisp = img is equivalent to disp.display(img). **/ template CImgDisplay& operator=(const CImg& img) { return display(img); } //! Display list of images on associated window. /** \note disp = list is equivalent to disp.display(list). **/ template CImgDisplay& operator=(const CImgList& list) { return display(list); } //! Construct a display as a copy of another one \inplace. /** \note Equivalent to assign(const CImgDisplay&). **/ CImgDisplay& operator=(const CImgDisplay& disp) { return assign(disp); } //! Return \c false if display is empty, \c true otherwise. /** \note if (disp) { ... } is equivalent to if (!disp.is_empty()) { ... }. **/ operator bool() const { return !is_empty(); } //@} //------------------------------------------ // //! \name Instance Checking //@{ //------------------------------------------ //! Return \c true if display is empty, \c false otherwise. /** **/ bool is_empty() const { return !(_width && _height); } //! Return \c true if display is closed (i.e. not visible on the screen), \c false otherwise. /** \note - When a user physically closes the associated window, the display is set to closed. - A closed display is not destroyed. Its associated window can be show again on the screen using show(). **/ bool is_closed() const { return _is_closed; } //! Return \c true if associated window has been resized on the screen, \c false otherwise. /** **/ bool is_resized() const { return _is_resized; } //! Return \c true if associated window has been moved on the screen, \c false otherwise. /** **/ bool is_moved() const { return _is_moved; } //! Return \c true if any event has occured on the associated window, \c false otherwise. /** **/ bool is_event() const { return _is_event; } //! Return \c true if current display is in fullscreen mode, \c false otherwise. /** **/ bool is_fullscreen() const { return _is_fullscreen; } //! Return \c true if any key is being pressed on the associated window, \c false otherwise. /** \note The methods below do the same only for specific keys. **/ bool is_key() const { return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 || _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 || _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 || _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 || _is_key3 || _is_key4 || _is_key5 || _is_key6 || _is_key7 || _is_key8 || _is_key9 || _is_key0 || _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME || _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW || _is_keyE || _is_keyR || _is_keyT || _is_keyY || _is_keyU || _is_keyI || _is_keyO || _is_keyP || _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN || _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD || _is_keyF || _is_keyG || _is_keyH || _is_keyJ || _is_keyK || _is_keyL || _is_keyENTER || _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC || _is_keyV || _is_keyB || _is_keyN || _is_keyM || _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT || _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR || _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT || _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT || _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 || _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 || _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 || _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB || _is_keyPADMUL || _is_keyPADDIV; } //! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise. /** \param keycode Keycode to test. \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). \par Example \code CImgDisplay disp(400,400); while (!disp.is_closed()) { if (disp.key(cimg::keyTAB)) { ... } // Equivalent to 'if (disp.is_keyTAB())'. disp.wait(); } \endcode **/ bool is_key(const unsigned int keycode) const { #define _cimg_iskey_test(k) if (keycode==cimg::key##k) return _is_key##k; _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3); _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7); _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11); _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2); _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6); _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0); _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME); _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W); _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y); _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P); _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN); _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D); _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J); _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER); _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C); _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M); _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT); _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR); _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT); _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT); _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2); _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5); _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8); _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB); _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV); return false; } //! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise. /** \param keycode C-string containing the keycode label of the key to test. \note Use it when the key you want to test can be dynamically set by the user. \par Example \code CImgDisplay disp(400,400); const char *const keycode = "TAB"; while (!disp.is_closed()) { if (disp.is_key(keycode)) { ... } // Equivalent to 'if (disp.is_keyTAB())'. disp.wait(); } \endcode **/ bool& is_key(const char *const keycode) { static bool f = false; f = false; #define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k; _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3); _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7); _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11); _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2); _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6); _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0); _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME); _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W); _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y); _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P); _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN); _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D); _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J); _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER); _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C); _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M); _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT); _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR); _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT); _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT); _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2); _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5); _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8); _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB); _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV); return f; } //! Return \c true if specified key sequence has been typed on the associated window, \c false otherwise. /** \param keycodes_sequence Buffer of keycodes to test. \param length Number of keys in the \c keycodes_sequence buffer. \param remove_sequence Tells if the key sequence must be removed from the key history, if found. \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). \par Example \code CImgDisplay disp(400,400); const unsigned int key_seq[] = { cimg::keyCTRLLEFT, cimg::keyD }; while (!disp.is_closed()) { if (disp.is_key_sequence(key_seq,2)) { ... } // Test for the 'CTRL+D' keyboard event. disp.wait(); } \endcode **/ bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length, const bool remove_sequence=false) { if (keycodes_sequence && length) { const unsigned int *const ps_end = keycodes_sequence + length - 1, *const pk_end = (unsigned int*)_keys + 1 + 128 - length, k = *ps_end; for (unsigned int *pk = (unsigned int*)_keys; pk[0,255]. If the range of values of the data to display is different, a normalization may be required for displaying the data in a correct way. The normalization type can be one of: - \c 0: Value normalization is disabled. It is then assumed that all input data to be displayed by the CImgDisplay instance have values in range [0,255]. - \c 1: Value normalization is always performed (this is the default behavior). Before displaying an input image, its values will be (virtually) stretched in range [0,255], so that the contrast of the displayed pixels will be maximum. Use this mode for images whose minimum and maximum values are not prescribed to known values (e.g. float-valued images). Note that when normalized versions of images are computed for display purposes, the actual values of these images are not modified. - \c 2: Value normalization is performed once (on the first image display), then the same normalization coefficients are kept for next displayed frames. - \c 3: Value normalization depends on the pixel type of the data to display. For integer pixel types, the normalization is done regarding the minimum/maximum values of the type (no normalization occurs then for unsigned char). For float-valued pixel types, the normalization is done regarding the minimum/maximum value of the image data instead. **/ unsigned int normalization() const { return _normalization; } //! Return title of the associated window as a C-string. /** \note Window title may be not visible, depending on the used window manager or if the current display is in fullscreen mode. **/ const char *title() const { return _title?_title:""; } //! Return width of the associated window. /** \note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance) may be different from the actual width of the associated window. **/ int window_width() const { return (int)_window_width; } //! Return height of the associated window. /** \note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance) may be different from the actual height of the associated window. **/ int window_height() const { return (int)_window_height; } //! Return X-coordinate of the associated window. /** \note The returned coordinate corresponds to the location of the upper-left corner of the associated window. **/ int window_x() const { return _window_x; } //! Return Y-coordinate of the associated window. /** \note The returned coordinate corresponds to the location of the upper-left corner of the associated window. **/ int window_y() const { return _window_y; } //! Return X-coordinate of the mouse pointer. /** \note - If the mouse pointer is outside window area, \c -1 is returned. - Otherwise, the returned value is in the range [0,width()-1]. **/ int mouse_x() const { return _mouse_x; } //! Return Y-coordinate of the mouse pointer. /** \note - If the mouse pointer is outside window area, \c -1 is returned. - Otherwise, the returned value is in the range [0,height()-1]. **/ int mouse_y() const { return _mouse_y; } //! Return current state of the mouse buttons. /** \note Three mouse buttons can be managed. If one button is pressed, its corresponding bit in the returned value is set: - bit \c 0 (value \c 0x1): State of the left mouse button. - bit \c 1 (value \c 0x2): State of the right mouse button. - bit \c 2 (value \c 0x4): State of the middle mouse button. Several bits can be activated if more than one button are pressed at the same time. \par Example \code CImgDisplay disp(400,400); while (!disp.is_closed()) { if (disp.button()&1) { // Left button clicked. ... } if (disp.button()&2) { // Right button clicked. ... } if (disp.button()&4) { // Middle button clicked. ... } disp.wait(); } \endcode **/ unsigned int button() const { return _button; } //! Return current state of the mouse wheel. /** \note - The returned value can be positive or negative depending on whether the mouse wheel has been scrolled forward or backward. - Scrolling the wheel forward add \c 1 to the wheel value. - Scrolling the wheel backward substract \c 1 to the wheel value. - The returned value cumulates the number of forward of backward scrolls since the creation of the display, or since the last reset of the wheel value (using set_wheel()). It is strongly recommended to quickly reset the wheel counter when an action has been performed regarding the current wheel value. Otherwise, the returned wheel value may be for instance \c 0 despite the fact that many scrolls have been done (as many in forward as in backward directions). \par Example \code CImgDisplay disp(400,400); while (!disp.is_closed()) { if (disp.wheel()) { int counter = disp.wheel(); // Read the state of the mouse wheel. ... // Do what you want with 'counter'. disp.set_wheel(); // Reset the wheel value to 0. } disp.wait(); } \endcode **/ int wheel() const { return _wheel; } //! Return one entry from the pressed keys history. /** \param pos Indice to read from the pressed keys history (indice \c 0 corresponds to latest entry). \return Keycode of a pressed key or \c 0 for a released key. \note - Each CImgDisplay stores a history of the pressed keys in a buffer of size \c 128. When a new key is pressed, its keycode is stored in the pressed keys history. When a key is released, \c 0 is put instead. This means that up to the 64 last pressed keys may be read from the pressed keys history. When a new value is stored, the pressed keys history is shifted so that the latest entry is always stored at position \c 0. - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). **/ unsigned int key(const unsigned int pos=0) const { return pos<128?_keys[pos]:0; } //! Return one entry from the released keys history. /** \param pos Indice to read from the released keys history (indice \c 0 corresponds to latest entry). \return Keycode of a released key or \c 0 for a pressed key. \note - Each CImgDisplay stores a history of the released keys in a buffer of size \c 128. When a new key is released, its keycode is stored in the pressed keys history. When a key is pressed, \c 0 is put instead. This means that up to the 64 last released keys may be read from the released keys history. When a new value is stored, the released keys history is shifted so that the latest entry is always stored at position \c 0. - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). **/ unsigned int released_key(const unsigned int pos=0) const { return pos<128?_released_keys[pos]:0; } //! Return keycode corresponding to the specified string. /** \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). \par Example \code const unsigned int keyTAB = CImgDisplay::keycode("TAB"); // Return cimg::keyTAB. \endcode **/ static unsigned int keycode(const char *const keycode) { #define _cimg_keycode(k) if (!cimg::strcasecmp(keycode,#k)) return cimg::key##k; _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3); _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7); _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11); _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2); _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6); _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0); _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME); _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W); _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y); _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P); _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN); _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D); _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J); _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER); _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C); _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M); _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT); _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR); _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT); _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT); _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2); _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5); _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8); _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB); _cimg_keycode(PADMUL); _cimg_keycode(PADDIV); return 0; } //! Return the current refresh rate, in frames per second. /** \note Returns a significant value when the current instance is used to display successive frames. It measures the delay between successive calls to frames_per_second(). **/ float frames_per_second() { if (!_fps_timer) _fps_timer = cimg::time(); const float delta = (cimg::time() - _fps_timer)/1000.0f; ++_fps_frames; if (delta>=1) { _fps_fps = _fps_frames/delta; _fps_frames = 0; _fps_timer = cimg::time(); } return _fps_fps; } //@} //--------------------------------------- // //! \name Window Manipulation //@{ //--------------------------------------- #if cimg_display==0 //! Display image on associated window. /** \param img Input image to display. \note This method returns immediately. **/ template CImgDisplay& display(const CImg& img) { return assign(img); } #endif //! Display list of images on associated window. /** \param list List of images to display. \param axis Axis used to append the images along, for the visualization (can be \c x, \c y, \c z or \c c). \param align Relative position of aligned images when displaying lists with images of different sizes (\c 0 for upper-left, \c 0.5 for centering and \c 1 for lower-right). \note This method returns immediately. **/ template CImgDisplay& display(const CImgList& list, const char axis='x', const float align=0) { if (list._width==1) { const CImg& img = list[0]; if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img); } CImgList::ucharT> visu(list._width); unsigned int dims = 0; cimglist_for(list,l) { const CImg& img = list._data[l]; img.__get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2, (img._depth - 1)/2).move_to(visu[l]); dims = cimg::max(dims,visu[l]._spectrum); } cimglist_for(list,l) if (visu[l]._spectrumimg.width() become equal, as well as height() and img.height(). - The associated window is also resized to specified dimensions. **/ template CImgDisplay& resize(const CImg& img, const bool force_redraw=true) { return resize(img._width,img._height,force_redraw); } //! Resize display to the size of another CImgDisplay instance. /** \param disp Input display to take size from. \param force_redraw Tells if the previous window content must be resized and updated as well. \note - Calling this method ensures that width() and disp.width() become equal, as well as height() and disp.height(). - The associated window is also resized to specified dimensions. **/ CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) { return resize(disp.width(),disp.height(),force_redraw); } // [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs). template static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, t *ptrd, const unsigned int wd, const unsigned int hd) { unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy; float s, curr, old; s = (float)ws/wd; poffx = offx; curr = 0; for (unsigned int x = 0; xstd::printf(). \warning As the first argument is a format string, it is highly recommended to write \code disp.set_title("%s",window_title); \endcode instead of \code disp.set_title(window_title); \endcode if \c window_title can be arbitrary, to prevent nasty memory access. **/ CImgDisplay& set_title(const char *const format, ...) { return assign(0,0,format); } #endif //! Enable or disable fullscreen mode. /** \param is_fullscreen Tells is the fullscreen mode must be activated or not. \param force_redraw Tells if the previous window content must be displayed as well. \note - When the fullscreen mode is enabled, the associated window fills the entire screen but the size of the current display is not modified. - The screen resolution may be switched to fit the associated window size and ensure it appears the largest as possible. For X-Window (X11) users, the configuration flag \c cimg_use_xrandr has to be set to allow the screen resolution change (requires the X11 extensions to be enabled). **/ CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool force_redraw=true) { if (is_empty() || _is_fullscreen==is_fullscreen) return *this; return toggle_fullscreen(force_redraw); } #if cimg_display==0 //! Toggle fullscreen mode. /** \param force_redraw Tells if the previous window content must be displayed as well. \note Enable fullscreen mode if it was not enabled, and disable it otherwise. **/ CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { return assign(_width,_height,0,3,force_redraw); } //! Show mouse pointer. /** \note Depending on the window manager behavior, this method may not succeed (no exceptions are thrown nevertheless). **/ CImgDisplay& show_mouse() { return assign(); } //! Hide mouse pointer. /** \note Depending on the window manager behavior, this method may not succeed (no exceptions are thrown nevertheless). **/ CImgDisplay& hide_mouse() { return assign(); } //! Move mouse pointer to a specified location. /** \note Depending on the window manager behavior, this method may not succeed (no exceptions are thrown nevertheless). **/ CImgDisplay& set_mouse(const int pos_x, const int pos_y) { return assign(pos_x,pos_y); } #endif //! Simulate a mouse button release event. /** \note All mouse buttons are considered released at the same time. **/ CImgDisplay& set_button() { _button = 0; _is_event = true; #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif return *this; } //! Simulate a mouse button press or release event. /** \param button Buttons event code, where each button is associated to a single bit. \param is_pressed Tells if the mouse button is considered as pressed or released. **/ CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) { const unsigned int buttoncode = button==1U?1U:button==2U?2U:button==3U?4U:0U; if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode; _is_event = buttoncode?true:false; if (buttoncode) { #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif } return *this; } //! Flush all mouse wheel events. /** \note Make wheel() to return \c 0, if called afterwards. **/ CImgDisplay& set_wheel() { _wheel = 0; _is_event = true; #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif return *this; } //! Simulate a wheel event. /** \param amplitude Amplitude of the wheel scrolling to simulate. \note Make wheel() to return \c amplitude, if called afterwards. **/ CImgDisplay& set_wheel(const int amplitude) { _wheel+=amplitude; _is_event = amplitude?true:false; if (amplitude) { #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif } return *this; } //! Flush all key events. /** \note Make key() to return \c 0, if called afterwards. **/ CImgDisplay& set_key() { std::memset((void*)_keys,0,128*sizeof(unsigned int)); std::memset((void*)_released_keys,0,128*sizeof(unsigned int)); _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 = _is_keyF9 = _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 = _is_key5 = _is_key6 = _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT = _is_keyHOME = _is_keyPAGEUP = _is_keyTAB = _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY = _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE = _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK = _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ = _is_keyK = _is_keyL = _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN = _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE = _is_keyALTGR = _is_keyAPPRIGHT = _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN = _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 = _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 = _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB = _is_keyPADMUL = _is_keyPADDIV = false; _is_event = true; #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif return *this; } //! Simulate a keyboard press/release event. /** \param keycode Keycode of the associated key. \param is_pressed Tells if the key is considered as pressed or released. \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure your code stay portable (see cimg::keyESC). **/ CImgDisplay& set_key(const unsigned int keycode, const bool is_pressed=true) { #define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = is_pressed; _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3); _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7); _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11); _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2); _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6); _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0); _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME); _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W); _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y); _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P); _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN); _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D); _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J); _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER); _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C); _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M); _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT); _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR); _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT); _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT); _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2); _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5); _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8); _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB); _cimg_set_key(PADMUL); _cimg_set_key(PADDIV); if (is_pressed) { if (*_keys) std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int)); *_keys = keycode; if (*_released_keys) { std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int)); *_released_keys = 0; } } else { if (*_keys) { std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int)); *_keys = 0; } if (*_released_keys) std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int)); *_released_keys = keycode; } _is_event = keycode?true:false; if (keycode) { #if cimg_display==1 pthread_cond_broadcast(&cimg::X11_attr().wait_event); #elif cimg_display==2 SetEvent(cimg::Win32_attr().wait_event); #endif } return *this; } //! Flush all display events. /** \note Remove all passed events from the current display. **/ CImgDisplay& flush() { set_key().set_button().set_wheel(); _is_resized = _is_moved = _is_event = false; _fps_timer = _fps_frames = _timer = 0; _fps_fps = 0; return *this; } //! Wait for any user event occuring on the current display. CImgDisplay& wait() { wait(*this); return *this; } //! Wait for a given number of milliseconds since the last call to wait(). /** \param milliseconds Number of milliseconds to wait for. \note Similar to cimg::wait(). **/ CImgDisplay& wait(const unsigned int milliseconds) { cimg::_wait(milliseconds,_timer); return *this; } //! Wait for any event occuring on the display \c disp1. static void wait(CImgDisplay& disp1) { disp1._is_event = false; while (!disp1._is_closed && !disp1._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1 or \c disp2. static void wait(CImgDisplay& disp1, CImgDisplay& disp2) { disp1._is_event = disp2._is_event = false; while ((!disp1._is_closed || !disp2._is_closed) && !disp1._is_event && !disp2._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) { disp1._is_event = disp2._is_event = disp3._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4 or \c disp5. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp6. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, CImgDisplay& disp6) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = disp6._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || !disp6._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && !disp6._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp7. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, CImgDisplay& disp6, CImgDisplay& disp7) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = disp6._is_event = disp7._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || !disp6._is_closed || !disp7._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && !disp6._is_event && !disp7._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp8. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = disp6._is_event = disp7._is_event = disp8._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || !disp6._is_closed || !disp7._is_closed || !disp8._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp9. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp10. static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9, CImgDisplay& disp10) { disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = false; while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed || !disp10._is_closed) && !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event) wait_all(); } #if cimg_display==0 //! Wait for any window event occuring in any opened CImgDisplay. static void wait_all() { return _no_display_exception(); } //! Render image into internal display buffer. /** \param img Input image data to render. \note - Convert image data representation into the internal display buffer (architecture-dependent structure). - The content of the associated window is not modified, until paint() is called. - Should not be used for common CImgDisplay uses, since display() is more useful. **/ template CImgDisplay& render(const CImg& img) { return assign(img); } //! Paint internal display buffer on associated window. /** \note - Update the content of the associated window with the internal display buffer, e.g. after a render() call. - Should not be used for common CImgDisplay uses, since display() is more useful. **/ CImgDisplay& paint() { return assign(); } //! Take a snapshot of the associated window content. /** \param[out] img Output snapshot. Can be empty on input. **/ template const CImgDisplay& snapshot(CImg& img) const { cimg::unused(img); _no_display_exception(); return *this; } #endif // X11-based implementation //-------------------------- #if cimg_display==1 Atom _wm_window_atom, _wm_protocol_atom; Window _window, _background_window; Colormap _colormap; XImage *_image; void *_data; #ifdef cimg_use_xshm XShmSegmentInfo *_shminfo; #endif static int screen_width() { Display *const dpy = cimg::X11_attr().display; int res = 0; if (!dpy) { Display *const _dpy = XOpenDisplay(0); if (!_dpy) throw CImgDisplayException("CImgDisplay::screen_width(): Failed to open X11 display."); res = DisplayWidth(_dpy,DefaultScreen(_dpy)); XCloseDisplay(_dpy); } else { #ifdef cimg_use_xrandr if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width; else res = DisplayWidth(dpy,DefaultScreen(dpy)); #else res = DisplayWidth(dpy,DefaultScreen(dpy)); #endif } return res; } static int screen_height() { Display *const dpy = cimg::X11_attr().display; int res = 0; if (!dpy) { Display *const _dpy = XOpenDisplay(0); if (!_dpy) throw CImgDisplayException("CImgDisplay::screen_height(): Failed to open X11 display."); res = DisplayHeight(_dpy,DefaultScreen(_dpy)); XCloseDisplay(_dpy); } else { #ifdef cimg_use_xrandr if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height; else res = DisplayHeight(dpy,DefaultScreen(dpy)); #else res = DisplayHeight(dpy,DefaultScreen(dpy)); #endif } return res; } static void wait_all() { if (!cimg::X11_attr().display) return; pthread_mutex_lock(&cimg::X11_attr().wait_event_mutex); pthread_cond_wait(&cimg::X11_attr().wait_event,&cimg::X11_attr().wait_event_mutex); pthread_mutex_unlock(&cimg::X11_attr().wait_event_mutex); } void _handle_events(const XEvent *const pevent) { Display *const dpy = cimg::X11_attr().display; XEvent event = *pevent; switch (event.type) { case ClientMessage : { if ((int)event.xclient.message_type==(int)_wm_protocol_atom && (int)event.xclient.data.l[0]==(int)_wm_window_atom) { XUnmapWindow(cimg::X11_attr().display,_window); _is_closed = _is_event = true; pthread_cond_broadcast(&cimg::X11_attr().wait_event); } } break; case ConfigureNotify : { while (XCheckWindowEvent(dpy,_window,StructureNotifyMask,&event)) {} const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height; const int nx = event.xconfigure.x, ny = event.xconfigure.y; if (nw && nh && (nw!=_window_width || nh!=_window_height)) { _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1; XResizeWindow(dpy,_window,_window_width,_window_height); _is_resized = _is_event = true; pthread_cond_broadcast(&cimg::X11_attr().wait_event); } if (nx!=_window_x || ny!=_window_y) { _window_x = nx; _window_y = ny; _is_moved = _is_event = true; pthread_cond_broadcast(&cimg::X11_attr().wait_event); } } break; case Expose : { while (XCheckWindowEvent(dpy,_window,ExposureMask,&event)) {} _paint(false); if (_is_fullscreen) { XWindowAttributes attr; XGetWindowAttributes(dpy,_window,&attr); while (attr.map_state!=IsViewable) XSync(dpy,0); XSetInputFocus(dpy,_window,RevertToParent,CurrentTime); } } break; case ButtonPress : { do { _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; switch (event.xbutton.button) { case 1 : set_button(1); break; case 3 : set_button(2); break; case 2 : set_button(3); break; } } while (XCheckWindowEvent(dpy,_window,ButtonPressMask,&event)); } break; case ButtonRelease : { do { _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; switch (event.xbutton.button) { case 1 : set_button(1,false); break; case 3 : set_button(2,false); break; case 2 : set_button(3,false); break; case 4 : set_wheel(1); break; case 5 : set_wheel(-1); break; } } while (XCheckWindowEvent(dpy,_window,ButtonReleaseMask,&event)); } break; case KeyPress : { char tmp = 0; KeySym ksym; XLookupString(&event.xkey,&tmp,1,&ksym,0); set_key((unsigned int)ksym,true); } break; case KeyRelease : { char keys_return[32]; // Check that the key has been physically unpressed. XQueryKeymap(dpy,keys_return); const unsigned int kc = event.xkey.keycode, kc1 = kc/8, kc2 = kc%8; const bool is_key_pressed = kc1>=32?false:(keys_return[kc1]>>kc2)&1; if (!is_key_pressed) { char tmp = 0; KeySym ksym; XLookupString(&event.xkey,&tmp,1,&ksym,0); set_key((unsigned int)ksym,false); } } break; case EnterNotify: { while (XCheckWindowEvent(dpy,_window,EnterWindowMask,&event)) {} _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; } break; case LeaveNotify : { while (XCheckWindowEvent(dpy,_window,LeaveWindowMask,&event)) {} _mouse_x = _mouse_y = -1; _is_event = true; pthread_cond_broadcast(&cimg::X11_attr().wait_event); } break; case MotionNotify : { while (XCheckWindowEvent(dpy,_window,PointerMotionMask,&event)) {} _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; _is_event = true; pthread_cond_broadcast(&cimg::X11_attr().wait_event); } break; } } static void* _events_thread(void *arg) { // Thread to manage events for all opened display windows. Display *const dpy = cimg::X11_attr().display; XEvent event; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); if (!arg) for ( ; ; ) { cimg_lock_display(); bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event); if (!event_flag) event_flag = XCheckMaskEvent(dpy, ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask,&event); if (event_flag) for (unsigned int i = 0; i_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) cimg::X11_attr().wins[i]->_handle_events(&event); cimg_unlock_display(); pthread_testcancel(); cimg::sleep(8); } return 0; } void _set_colormap(Colormap& _colormap, const unsigned int dim) { XColor *const colormap = new XColor[256]; switch (dim) { case 1 : { // colormap for greyscale images for (unsigned int index = 0; index<256; ++index) { colormap[index].pixel = index; colormap[index].red = colormap[index].green = colormap[index].blue = (unsigned short)(index<<8); colormap[index].flags = DoRed | DoGreen | DoBlue; } } break; case 2 : { // colormap for RG images for (unsigned int index = 0, r = 8; r<256; r+=16) for (unsigned int g = 8; g<256; g+=16) { colormap[index].pixel = index; colormap[index].red = colormap[index].blue = (unsigned short)(r<<8); colormap[index].green = (unsigned short)(g<<8); colormap[index++].flags = DoRed | DoGreen | DoBlue; } } break; default : { // colormap for RGB images for (unsigned int index = 0, r = 16; r<256; r+=32) for (unsigned int g = 16; g<256; g+=32) for (unsigned int b = 32; b<256; b+=64) { colormap[index].pixel = index; colormap[index].red = (unsigned short)(r<<8); colormap[index].green = (unsigned short)(g<<8); colormap[index].blue = (unsigned short)(b<<8); colormap[index++].flags = DoRed | DoGreen | DoBlue; } } } XStoreColors(cimg::X11_attr().display,_colormap,colormap,256); delete[] colormap; } void _map_window() { Display *const dpy = cimg::X11_attr().display; bool is_exposed = false, is_mapped = false; XWindowAttributes attr; XEvent event; XMapRaised(dpy,_window); do { // Wait for the window to be mapped. XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event); switch (event.type) { case MapNotify : is_mapped = true; break; case Expose : is_exposed = true; break; } } while (!is_exposed || !is_mapped); do { // Wait for the window to be visible. XGetWindowAttributes(dpy,_window,&attr); if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); } } while (attr.map_state!=IsViewable); _window_x = attr.x; _window_y = attr.y; } void _paint(const bool wait_expose=true) { if (_is_closed || !_image) return; Display *const dpy = cimg::X11_attr().display; if (wait_expose) { // Send an expose event sticked to display window to force repaint. XEvent event; event.xexpose.type = Expose; event.xexpose.serial = 0; event.xexpose.send_event = 1; event.xexpose.display = dpy; event.xexpose.window = _window; event.xexpose.x = 0; event.xexpose.y = 0; event.xexpose.width = width(); event.xexpose.height = height(); event.xexpose.count = 0; XSendEvent(dpy,_window,0,0,&event); } else { // Repaint directly (may be called from the expose event). GC gc = DefaultGC(dpy,DefaultScreen(dpy)); #ifdef cimg_use_xshm if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1); else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height); #else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height); #endif } } template void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) { Display *const dpy = cimg::X11_attr().display; cimg::unused(pixel_type); #ifdef cimg_use_xshm if (_shminfo) { XShmSegmentInfo *const nshminfo = new XShmSegmentInfo; XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy); if (!nimage) { delete nshminfo; return; } else { nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777); if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; } else { nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0); if (nshminfo->shmaddr==(char*)-1) { shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; } else { nshminfo->readOnly = 0; cimg::X11_attr().is_shm_enabled = true; XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); XShmAttach(dpy,nshminfo); XFlush(dpy); XSetErrorHandler(oldXErrorHandler); if (!cimg::X11_attr().is_shm_enabled) { shmdt(nshminfo->shmaddr); shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; } else { T *const ndata = (T*)nimage->data; if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); XShmDetach(dpy,_shminfo); XDestroyImage(_image); shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); delete _shminfo; _shminfo = nshminfo; _image = nimage; _data = (void*)ndata; } } } } } else #endif { T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T)); if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); _data = (void*)ndata; XDestroyImage(_image); _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0); } } void _init_fullscreen() { if (!_is_fullscreen || _is_closed) return; Display *const dpy = cimg::X11_attr().display; _background_window = 0; #ifdef cimg_use_xrandr int foo; if (XRRQueryExtension(dpy,&foo,&foo)) { XRRRotations(dpy,DefaultScreen(dpy),&cimg::X11_attr().curr_rotation); if (!cimg::X11_attr().resolutions) { cimg::X11_attr().resolutions = XRRSizes(dpy,DefaultScreen(dpy),&foo); cimg::X11_attr().nb_resolutions = (unsigned int)foo; } if (cimg::X11_attr().resolutions) { cimg::X11_attr().curr_resolution = 0; for (unsigned int i = 0; i=_width && nh>=_height && nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) && nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height)) cimg::X11_attr().curr_resolution = i; } if (cimg::X11_attr().curr_resolution>0) { XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy)); XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy), cimg::X11_attr().curr_resolution,cimg::X11_attr().curr_rotation,CurrentTime); XRRFreeScreenConfigInfo(config); XSync(dpy,0); } } } if (!cimg::X11_attr().resolutions) cimg::warn(_cimgdisplay_instance "init_fullscreen(): Xrandr extension not supported by the X server.", cimgdisplay_instance); #endif const unsigned int sx = screen_width(), sy = screen_height(); if (sx==_width && sy==_height) return; XSetWindowAttributes winattr; winattr.override_redirect = 1; _background_window = XCreateWindow(dpy,DefaultRootWindow(dpy),0,0,sx,sy,0,0, InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); const cimg_ulong buf_size = (cimg_ulong)sx*sy*(cimg::X11_attr().nb_bits==8?1: (cimg::X11_attr().nb_bits==16?2:4)); void *background_data = std::malloc(buf_size); std::memset(background_data,0,buf_size); XImage *background_image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits, ZPixmap,0,(char*)background_data,sx,sy,8,0); XEvent event; XSelectInput(dpy,_background_window,StructureNotifyMask); XMapRaised(dpy,_background_window); do XWindowEvent(dpy,_background_window,StructureNotifyMask,&event); while (event.type!=MapNotify); GC gc = DefaultGC(dpy,DefaultScreen(dpy)); #ifdef cimg_use_xshm if (_shminfo) XShmPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy,0); else XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy); #else XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy); #endif XWindowAttributes attr; XGetWindowAttributes(dpy,_background_window,&attr); while (attr.map_state!=IsViewable) XSync(dpy,0); XDestroyImage(background_image); } void _desinit_fullscreen() { if (!_is_fullscreen) return; Display *const dpy = cimg::X11_attr().display; XUngrabKeyboard(dpy,CurrentTime); #ifdef cimg_use_xrandr if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) { XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy)); XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),0,cimg::X11_attr().curr_rotation,CurrentTime); XRRFreeScreenConfigInfo(config); XSync(dpy,0); cimg::X11_attr().curr_resolution = 0; } #endif if (_background_window) XDestroyWindow(dpy,_background_window); _background_window = 0; _is_fullscreen = false; } static int _assign_xshm(Display *dpy, XErrorEvent *error) { cimg::unused(dpy,error); cimg::X11_attr().is_shm_enabled = false; return 0; } void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { cimg::mutex(14); // Allocate space for window title const char *const nptitle = ptitle?ptitle:""; const unsigned int s = (unsigned int)std::strlen(nptitle) + 1; char *const tmp_title = s?new char[s]:0; if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); // Destroy previous display window if existing if (!is_empty()) assign(); // Open X11 display and retrieve graphical properties. Display* &dpy = cimg::X11_attr().display; if (!dpy) { dpy = XOpenDisplay(0); if (!dpy) throw CImgDisplayException(_cimgdisplay_instance "assign(): Failed to open X11 display.", cimgdisplay_instance); cimg::X11_attr().nb_bits = DefaultDepth(dpy,DefaultScreen(dpy)); if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 && cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32) throw CImgDisplayException(_cimgdisplay_instance "assign(): Invalid %u bits screen mode detected " "(only 8, 16, 24 and 32 bits modes are managed).", cimgdisplay_instance, cimg::X11_attr().nb_bits); XVisualInfo vtemplate; vtemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy,DefaultScreen(dpy))); int nb_visuals; XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals); if (vinfo && vinfo->red_maskblue_mask) cimg::X11_attr().is_blue_first = true; cimg::X11_attr().byte_order = ImageByteOrder(dpy); XFree(vinfo); cimg_lock_display(); cimg::X11_attr().events_thread = new pthread_t; pthread_create(cimg::X11_attr().events_thread,0,_events_thread,0); } else cimg_lock_display(); // Set display variables. _width = cimg::min(dimw,(unsigned int)screen_width()); _height = cimg::min(dimh,(unsigned int)screen_height()); _normalization = normalization_type<4?normalization_type:3; _is_fullscreen = fullscreen_flag; _window_x = _window_y = 0; _is_closed = closed_flag; _title = tmp_title; flush(); // Create X11 window (and LUT, if 8bits display) if (_is_fullscreen) { if (!_is_closed) _init_fullscreen(); const unsigned int sx = screen_width(), sy = screen_height(); XSetWindowAttributes winattr; winattr.override_redirect = 1; _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx - _width)/2,(sy - _height)/2,_width,_height,0,0, InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); } else _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L); XSelectInput(dpy,_window, ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask); XStoreName(dpy,_window,_title?_title:" "); if (cimg::X11_attr().nb_bits==8) { _colormap = XCreateColormap(dpy,_window,DefaultVisual(dpy,DefaultScreen(dpy)),AllocAll); _set_colormap(_colormap,3); XSetWindowColormap(dpy,_window,_colormap); } static const char *const _window_class = cimg_appname; XClassHint *const window_class = XAllocClassHint(); window_class->res_name = (char*)_window_class; window_class->res_class = (char*)_window_class; XSetClassHint(dpy,_window,window_class); XFree(window_class); _window_width = _width; _window_height = _height; // Create XImage #ifdef cimg_use_xshm _shminfo = 0; if (XShmQueryExtension(dpy)) { _shminfo = new XShmSegmentInfo; _image = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits, ZPixmap,0,_shminfo,_width,_height); if (!_image) { delete _shminfo; _shminfo = 0; } else { _shminfo->shmid = shmget(IPC_PRIVATE,_image->bytes_per_line*_image->height,IPC_CREAT|0777); if (_shminfo->shmid==-1) { XDestroyImage(_image); delete _shminfo; _shminfo = 0; } else { _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0)); if (_shminfo->shmaddr==(char*)-1) { shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0; } else { _shminfo->readOnly = 0; cimg::X11_attr().is_shm_enabled = true; XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); XShmAttach(dpy,_shminfo); XSync(dpy,0); XSetErrorHandler(oldXErrorHandler); if (!cimg::X11_attr().is_shm_enabled) { shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0; } } } } } if (!_shminfo) #endif { const cimg_ulong buf_size = (cimg_ulong)_width*_height*(cimg::X11_attr().nb_bits==8?1: (cimg::X11_attr().nb_bits==16?2:4)); _data = std::malloc(buf_size); _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits, ZPixmap,0,(char*)_data,_width,_height,8,0); } _wm_window_atom = XInternAtom(dpy,"WM_DELETE_WINDOW",0); _wm_protocol_atom = XInternAtom(dpy,"WM_PROTOCOLS",0); XSetWMProtocols(dpy,_window,&_wm_window_atom,1); if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime); cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this; if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type::min(); } cimg_unlock_display(); cimg::mutex(14,0); } CImgDisplay& assign() { if (is_empty()) return flush(); Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); // Remove display window from event thread list. unsigned int i; for (i = 0; ishmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); delete _shminfo; _shminfo = 0; } else #endif XDestroyImage(_image); _data = 0; _image = 0; if (cimg::X11_attr().nb_bits==8) XFreeColormap(dpy,_colormap); _colormap = 0; XSync(dpy,0); // Reset display variables. delete[] _title; _width = _height = _normalization = _window_width = _window_height = 0; _window_x = _window_y = 0; _is_fullscreen = false; _is_closed = true; _min = _max = 0; _title = 0; flush(); cimg_unlock_display(); return *this; } CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!dimw || !dimh) return assign(); _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); _min = _max = 0; std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))* (size_t)_width*_height); return paint(); } template CImgDisplay& assign(const CImg& img, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!img) return assign(); CImg tmp; const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, (img._height - 1)/2, (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return render(nimg).paint(); } template CImgDisplay& assign(const CImgList& list, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, (img._height - 1)/2, (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return render(nimg).paint(); } CImgDisplay& assign(const CImgDisplay& disp) { if (!disp) return assign(); _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): cimg::X11_attr().nb_bits==16?sizeof(unsigned short): sizeof(unsigned int))*(size_t)_width*_height); return paint(); } CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) { if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); if (is_empty()) return assign(nwidth,nheight); Display *const dpy = cimg::X11_attr().display; const unsigned int tmpdimx = (nwidth>0)?nwidth:(-nwidth*width()/100), tmpdimy = (nheight>0)?nheight:(-nheight*height()/100), dimx = tmpdimx?tmpdimx:1, dimy = tmpdimy?tmpdimy:1; if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { show(); cimg_lock_display(); if (_window_width!=dimx || _window_height!=dimy) { XWindowAttributes attr; for (unsigned int i = 0; i<10; ++i) { XResizeWindow(dpy,_window,dimx,dimy); XGetWindowAttributes(dpy,_window,&attr); if (attr.width==(int)dimx && attr.height==(int)dimy) break; cimg::wait(5); } } if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) { case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } } _window_width = _width = dimx; _window_height = _height = dimy; cimg_unlock_display(); } _is_resized = false; if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2); if (force_redraw) return paint(); return *this; } CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { if (is_empty()) return *this; if (force_redraw) { const cimg_ulong buf_size = (cimg_ulong)_width*_height* (cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4)); void *image_data = std::malloc(buf_size); std::memcpy(image_data,_data,buf_size); assign(_width,_height,_title,_normalization,!_is_fullscreen,false); std::memcpy(_data,image_data,buf_size); std::free(image_data); return paint(); } return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); } CImgDisplay& show() { if (is_empty() || !_is_closed) return *this; cimg_lock_display(); if (_is_fullscreen) _init_fullscreen(); _map_window(); _is_closed = false; cimg_unlock_display(); return paint(); } CImgDisplay& close() { if (is_empty() || _is_closed) return *this; Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); if (_is_fullscreen) _desinit_fullscreen(); XUnmapWindow(dpy,_window); _window_x = _window_y = -1; _is_closed = true; cimg_unlock_display(); return *this; } CImgDisplay& move(const int posx, const int posy) { if (is_empty()) return *this; if (_window_x!=posx || _window_y!=posy) { show(); Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); XMoveWindow(dpy,_window,posx,posy); _window_x = posx; _window_y = posy; cimg_unlock_display(); } _is_moved = false; return paint(); } CImgDisplay& show_mouse() { if (is_empty()) return *this; Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); XUndefineCursor(dpy,_window); cimg_unlock_display(); return *this; } CImgDisplay& hide_mouse() { if (is_empty()) return *this; Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); static const char pix_data[8] = { 0 }; XColor col; col.red = col.green = col.blue = 0; Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8); Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0); XFreePixmap(dpy,pix); XDefineCursor(dpy,_window,cur); cimg_unlock_display(); return *this; } CImgDisplay& set_mouse(const int posx, const int posy) { if (is_empty() || _is_closed) return *this; Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy); _mouse_x = posx; _mouse_y = posy; _is_moved = false; XSync(dpy,0); cimg_unlock_display(); return *this; } CImgDisplay& set_title(const char *const format, ...) { if (is_empty()) return *this; char *const tmp = new char[1024]; va_list ap; va_start(ap, format); cimg_vsnprintf(tmp,1024,format,ap); va_end(ap); if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } delete[] _title; const unsigned int s = (unsigned int)std::strlen(tmp) + 1; _title = new char[s]; std::memcpy(_title,tmp,s*sizeof(char)); Display *const dpy = cimg::X11_attr().display; cimg_lock_display(); XStoreName(dpy,_window,tmp); cimg_unlock_display(); delete[] tmp; return *this; } template CImgDisplay& display(const CImg& img) { if (!img) throw CImgArgumentException(_cimgdisplay_instance "display(): Empty specified image.", cimgdisplay_instance); if (is_empty()) return assign(img); return render(img).paint(false); } CImgDisplay& paint(const bool wait_expose=true) { if (is_empty()) return *this; cimg_lock_display(); _paint(wait_expose); cimg_unlock_display(); return *this; } template CImgDisplay& render(const CImg& img, const bool flag8=false) { if (!img) throw CImgArgumentException(_cimgdisplay_instance "render(): Empty specified image.", cimgdisplay_instance); if (is_empty()) return *this; if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, (img._depth - 1)/2)); if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height)) return render(img.get_resize(_width,_height,1,-100,1)); if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) { static const CImg::ucharT> default_colormap = CImg::ucharT>::default_LUT256(); return render(img.get_index(default_colormap,1,false)); } const T *data1 = img._data, *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1, *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1; if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3); cimg_lock_display(); if (!_normalization || (_normalization==3 && cimg::type::string()==cimg::type::string())) { _min = _max = 0; switch (cimg::X11_attr().nb_bits) { case 8 : { // 256 colormap, no normalization _set_colormap(_colormap,img._spectrum); unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: new unsigned char[(size_t)img._width*img._height], *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++); break; case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); (*ptrd++) = (R&0xf0) | (G>>4); } break; default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++); (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } } break; case 16 : { // 16 bits colors, no normalization unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: new unsigned short[(size_t)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++), G = val>>2; *(ptrd++) = (val&M) | (G>>3); *(ptrd++) = (G<<5) | (G>>1); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++), G = val>>2; *(ptrd++) = (G<<5) | (G>>1); *(ptrd++) = (val&M) | (G>>3); } break; case 2 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)*(data2++)>>2; *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); *(ptrd++) = (G<<5); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)*(data2++)>>2; *(ptrd++) = (G<<5); *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); } break; default : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)*(data2++)>>2; *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)*(data2++)>>2; *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } } break; default : { // 24 bits colors, no normalization unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: new unsigned int[(size_t)img._width*img._height]; if (sizeof(int)==4) { // 32 bits int uses optimized version unsigned int *ptrd = ndata; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++); *(ptrd++) = (val<<16) | (val<<8) | val; } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++); *(ptrd++) = (val<<16) | (val<<8) | val; } break; case 2 : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8); else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); break; default : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); } } else { unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(ptrd++) = 0; *(ptrd++) = (unsigned char)*(data1++); *(ptrd++) = 0; *(ptrd++) = 0; } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(ptrd++) = 0; *(ptrd++) = 0; *(ptrd++) = (unsigned char)*(data1++); *(ptrd++) = 0; } break; case 2 : if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(ptrd++) = 0; *(ptrd++) = (unsigned char)*(data2++); *(ptrd++) = (unsigned char)*(data1++); *(ptrd++) = 0; } break; default : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(ptrd++) = 0; *(ptrd++) = (unsigned char)*(data1++); *(ptrd++) = (unsigned char)*(data2++); *(ptrd++) = (unsigned char)*(data3++); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(ptrd++) = (unsigned char)*(data3++); *(ptrd++) = (unsigned char)*(data2++); *(ptrd++) = (unsigned char)*(data1++); *(ptrd++) = 0; } } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; } } } } else { if (_normalization==3) { if (cimg::type::is_float()) _min = (float)img.min_max(_max); else { _min = (float)cimg::type::min(); _max = (float)cimg::type::max(); } } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); const float delta = _max - _min, mm = 255/(delta?delta:1.0f); switch (cimg::X11_attr().nb_bits) { case 8 : { // 256 colormap, with normalization _set_colormap(_colormap,img._spectrum); unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: new unsigned char[(size_t)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = R; } break; case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)((*(data1++) - _min)*mm), G = (unsigned char)((*(data2++) - _min)*mm); (*ptrd++) = (R&0xf0) | (G>>4); } break; default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)((*(data1++) - _min)*mm), G = (unsigned char)((*(data2++) - _min)*mm), B = (unsigned char)((*(data3++) - _min)*mm); *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } } break; case 16 : { // 16 bits colors, with normalization unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: new unsigned short[(size_t)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; *(ptrd++) = (val&M) | (G>>3); *(ptrd++) = (G<<5) | (val>>3); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; *(ptrd++) = (G<<5) | (val>>3); *(ptrd++) = (val&M) | (G>>3); } break; case 2 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); *(ptrd++) = (G<<5); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; *(ptrd++) = (G<<5); *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); } break; default : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } } break; default : { // 24 bits colors, with normalization unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: new unsigned int[(size_t)img._width*img._height]; if (sizeof(int)==4) { // 32 bits int uses optimized version unsigned int *ptrd = ndata; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = (val<<16) | (val<<8) | val; } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = (val<<24) | (val<<16) | (val<<8); } break; case 2 : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)<<16) | ((unsigned char)((*(data2++) - _min)*mm)<<8); else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)((*(data2++) - _min)*mm)<<16) | ((unsigned char)((*(data1++) - _min)*mm)<<8); break; default : if (cimg::X11_attr().byte_order==cimg::endianness()) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)<<16) | ((unsigned char)((*(data2++) - _min)*mm)<<8) | (unsigned char)((*(data3++) - _min)*mm); else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) *(ptrd++) = ((unsigned char)((*(data3++) - _min)*mm)<<24) | ((unsigned char)((*(data2++) - _min)*mm)<<16) | ((unsigned char)((*(data1++) - _min)*mm)<<8); } } else { unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = 0; (*ptrd++) = val; (*ptrd++) = val; (*ptrd++) = val; } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = val; (*ptrd++) = val; (*ptrd++) = val; (*ptrd++) = 0; } break; case 2 : if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { (*ptrd++) = 0; (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = 0; } break; default : if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { (*ptrd++) = 0; (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm); (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = 0; } } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; } } } } cimg_unlock_display(); return *this; } template const CImgDisplay& snapshot(CImg& img) const { if (is_empty()) { img.assign(); return *this; } const unsigned char *ptrs = (unsigned char*)_data; img.assign(_width,_height,1,3); T *data1 = img.data(0,0,0,0), *data2 = img.data(0,0,0,1), *data3 = img.data(0,0,0,2); if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3); switch (cimg::X11_attr().nb_bits) { case 8 : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = *(ptrs++); *(data1++) = (T)(val&0xe0); *(data2++) = (T)((val&0x1c)<<3); *(data3++) = (T)(val<<6); } } break; case 16 : { if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val0 = *(ptrs++), val1 = *(ptrs++); *(data1++) = (T)(val0&0xf8); *(data2++) = (T)((val0<<5) | ((val1&0xe0)>>5)); *(data3++) = (T)(val1<<3); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned short val0 = *(ptrs++), val1 = *(ptrs++); *(data1++) = (T)(val1&0xf8); *(data2++) = (T)((val1<<5) | ((val0&0xe0)>>5)); *(data3++) = (T)(val0<<3); } } break; default : { if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { ++ptrs; *(data1++) = (T)*(ptrs++); *(data2++) = (T)*(ptrs++); *(data3++) = (T)*(ptrs++); } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { *(data3++) = (T)*(ptrs++); *(data2++) = (T)*(ptrs++); *(data1++) = (T)*(ptrs++); ++ptrs; } } } return *this; } // Windows-based implementation. //------------------------------- #elif cimg_display==2 bool _is_mouse_tracked, _is_cursor_visible; HANDLE _thread, _is_created, _mutex; HWND _window, _background_window; CLIENTCREATESTRUCT _ccs; unsigned int *_data; DEVMODE _curr_mode; BITMAPINFO _bmi; HDC _hdc; static int screen_width() { DEVMODE mode; mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); return (int)mode.dmPelsWidth; } static int screen_height() { DEVMODE mode; mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); return (int)mode.dmPelsHeight; } static void wait_all() { WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE); } static LRESULT APIENTRY _handle_events(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) { #ifdef _WIN64 CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA); #else CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA); #endif MSG st_msg; switch (msg) { case WM_CLOSE : disp->_mouse_x = disp->_mouse_y = -1; disp->_window_x = disp->_window_y = 0; disp->set_button().set_key(0).set_key(0,false)._is_closed = true; ReleaseMutex(disp->_mutex); ShowWindow(disp->_window,SW_HIDE); disp->_is_event = true; SetEvent(cimg::Win32_attr().wait_event); return 0; case WM_SIZE : { while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} WaitForSingleObject(disp->_mutex,INFINITE); const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam); if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) { disp->_window_width = nw; disp->_window_height = nh; disp->_mouse_x = disp->_mouse_y = -1; disp->_is_resized = disp->_is_event = true; SetEvent(cimg::Win32_attr().wait_event); } ReleaseMutex(disp->_mutex); } break; case WM_MOVE : { while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} WaitForSingleObject(disp->_mutex,INFINITE); const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam)); if (nx!=disp->_window_x || ny!=disp->_window_y) { disp->_window_x = nx; disp->_window_y = ny; disp->_is_moved = disp->_is_event = true; SetEvent(cimg::Win32_attr().wait_event); } ReleaseMutex(disp->_mutex); } break; case WM_PAINT : disp->paint(); cimg::mutex(15); if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); cimg::mutex(15,0); break; case WM_ERASEBKGND : // return 0; break; case WM_KEYDOWN : disp->set_key((unsigned int)wParam); SetEvent(cimg::Win32_attr().wait_event); break; case WM_KEYUP : disp->set_key((unsigned int)wParam,false); SetEvent(cimg::Win32_attr().wait_event); break; case WM_MOUSEMOVE : { while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {} disp->_mouse_x = LOWORD(lParam); disp->_mouse_y = HIWORD(lParam); #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT) if (!disp->_is_mouse_tracked) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = disp->_window; if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true; } #endif if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height()) disp->_mouse_x = disp->_mouse_y = -1; disp->_is_event = true; SetEvent(cimg::Win32_attr().wait_event); cimg::mutex(15); if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); cimg::mutex(15,0); } break; case WM_MOUSELEAVE : { disp->_mouse_x = disp->_mouse_y = -1; disp->_is_mouse_tracked = false; cimg::mutex(15); while (ShowCursor(TRUE)<0); cimg::mutex(15,0); } break; case WM_LBUTTONDOWN : disp->set_button(1); SetEvent(cimg::Win32_attr().wait_event); break; case WM_RBUTTONDOWN : disp->set_button(2); SetEvent(cimg::Win32_attr().wait_event); break; case WM_MBUTTONDOWN : disp->set_button(3); SetEvent(cimg::Win32_attr().wait_event); break; case WM_LBUTTONUP : disp->set_button(1,false); SetEvent(cimg::Win32_attr().wait_event); break; case WM_RBUTTONUP : disp->set_button(2,false); SetEvent(cimg::Win32_attr().wait_event); break; case WM_MBUTTONUP : disp->set_button(3,false); SetEvent(cimg::Win32_attr().wait_event); break; case 0x020A : // WM_MOUSEWHEEL: disp->set_wheel((int)((short)HIWORD(wParam))/120); SetEvent(cimg::Win32_attr().wait_event); } return DefWindowProc(window,msg,wParam,lParam); } static DWORD WINAPI _events_thread(void* arg) { CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]); const char *const title = (const char*)(((void**)arg)[1]); MSG msg; delete[] (void**)arg; disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); disp->_bmi.bmiHeader.biWidth = disp->width(); disp->_bmi.bmiHeader.biHeight = -disp->height(); disp->_bmi.bmiHeader.biPlanes = 1; disp->_bmi.bmiHeader.biBitCount = 32; disp->_bmi.bmiHeader.biCompression = BI_RGB; disp->_bmi.bmiHeader.biSizeImage = 0; disp->_bmi.bmiHeader.biXPelsPerMeter = 1; disp->_bmi.bmiHeader.biYPelsPerMeter = 1; disp->_bmi.bmiHeader.biClrUsed = 0; disp->_bmi.bmiHeader.biClrImportant = 0; disp->_data = new unsigned int[(size_t)disp->_width*disp->_height]; if (!disp->_is_fullscreen) { // Normal window RECT rect; rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2), border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1); disp->_window = CreateWindowA("MDICLIENT",title?title:" ", WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT, disp->_width + 2*border1, disp->_height + border1 + border2, 0,0,0,&(disp->_ccs)); if (!disp->_is_closed) { GetWindowRect(disp->_window,&rect); disp->_window_x = rect.left + border1; disp->_window_y = rect.top + border2; } else disp->_window_x = disp->_window_y = 0; } else { // Fullscreen window const unsigned int sx = (unsigned int)screen_width(), sy = (unsigned int)screen_height(); disp->_window = CreateWindowA("MDICLIENT",title?title:" ", WS_POPUP | (disp->_is_closed?0:WS_VISIBLE), (sx - disp->_width)/2, (sy - disp->_height)/2, disp->_width,disp->_height,0,0,0,&(disp->_ccs)); disp->_window_x = disp->_window_y = 0; } SetForegroundWindow(disp->_window); disp->_hdc = GetDC(disp->_window); disp->_window_width = disp->_width; disp->_window_height = disp->_height; disp->flush(); #ifdef _WIN64 SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp); SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events); #else SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp); SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events); #endif SetEvent(disp->_is_created); while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg); return 0; } CImgDisplay& _update_window_pos() { if (_is_closed) _window_x = _window_y = -1; else { RECT rect; rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (int)((rect.right - rect.left + 1 - _width)/2), border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); GetWindowRect(_window,&rect); _window_x = rect.left + border1; _window_y = rect.top + border2; } return *this; } void _init_fullscreen() { _background_window = 0; if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0; else { DEVMODE mode; unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U; for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) { const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight; if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) { bestbpp = mode.dmBitsPerPel; ibest = imode; bw = nw; bh = nh; } } if (bestbpp) { _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode); EnumDisplaySettings(0,ibest,&mode); ChangeDisplaySettings(&mode,0); } else _curr_mode.dmSize = 0; const unsigned int sx = (unsigned int)screen_width(), sy = (unsigned int)screen_height(); if (sx!=_width || sy!=_height) { CLIENTCREATESTRUCT background_ccs; _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs); SetForegroundWindow(_background_window); } } } void _desinit_fullscreen() { if (!_is_fullscreen) return; if (_background_window) DestroyWindow(_background_window); _background_window = 0; if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0); _is_fullscreen = false; } CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { // Allocate space for window title const char *const nptitle = ptitle?ptitle:""; const unsigned int s = (unsigned int)std::strlen(nptitle) + 1; char *const tmp_title = s?new char[s]:0; if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); // Destroy previous window if existing if (!is_empty()) assign(); // Set display variables _width = cimg::min(dimw,(unsigned int)screen_width()); _height = cimg::min(dimh,(unsigned int)screen_height()); _normalization = normalization_type<4?normalization_type:3; _is_fullscreen = fullscreen_flag; _window_x = _window_y = 0; _is_closed = closed_flag; _is_cursor_visible = true; _is_mouse_tracked = false; _title = tmp_title; flush(); if (_is_fullscreen) _init_fullscreen(); // Create event thread void *const arg = (void*)(new void*[2]); ((void**)arg)[0] = (void*)this; ((void**)arg)[1] = (void*)_title; _mutex = CreateMutex(0,FALSE,0); _is_created = CreateEvent(0,FALSE,FALSE,0); _thread = CreateThread(0,0,_events_thread,arg,0,0); WaitForSingleObject(_is_created,INFINITE); return *this; } CImgDisplay& assign() { if (is_empty()) return flush(); DestroyWindow(_window); TerminateThread(_thread,0); delete[] _data; delete[] _title; _data = 0; _title = 0; if (_is_fullscreen) _desinit_fullscreen(); _width = _height = _normalization = _window_width = _window_height = 0; _window_x = _window_y = 0; _is_fullscreen = false; _is_closed = true; _min = _max = 0; _title = 0; flush(); return *this; } CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!dimw || !dimh) return assign(); _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); _min = _max = 0; std::memset(_data,0,sizeof(unsigned int)*_width*_height); return paint(); } template CImgDisplay& assign(const CImg& img, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!img) return assign(); CImg tmp; const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, (img._height - 1)/2, (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return display(nimg); } template CImgDisplay& assign(const CImgList& list, const char *const title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, (img._height - 1)/2, (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return display(nimg); } CImgDisplay& assign(const CImgDisplay& disp) { if (!disp) return assign(); _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height); return paint(); } CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) { if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); if (is_empty()) return assign(nwidth,nheight); const unsigned int tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100), tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), dimx = tmpdimx?tmpdimx:1, dimy = tmpdimy?tmpdimy:1; if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { if (_window_width!=dimx || _window_height!=dimy) { RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); } if (_width!=dimx || _height!=dimy) { unsigned int *const ndata = new unsigned int[dimx*dimy]; if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy); else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); delete[] _data; _data = ndata; _bmi.bmiHeader.biWidth = (LONG)dimx; _bmi.bmiHeader.biHeight = -(int)dimy; _width = dimx; _height = dimy; } _window_width = dimx; _window_height = dimy; show(); } _is_resized = false; if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2); if (force_redraw) return paint(); return *this; } CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { if (is_empty()) return *this; if (force_redraw) { const cimg_ulong buf_size = (cimg_ulong)_width*_height*4; void *odata = std::malloc(buf_size); if (odata) { std::memcpy(odata,_data,buf_size); assign(_width,_height,_title,_normalization,!_is_fullscreen,false); std::memcpy(_data,odata,buf_size); std::free(odata); } return paint(); } return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); } CImgDisplay& show() { if (is_empty() || !_is_closed) return *this; _is_closed = false; if (_is_fullscreen) _init_fullscreen(); ShowWindow(_window,SW_SHOW); _update_window_pos(); return paint(); } CImgDisplay& close() { if (is_empty() || _is_closed) return *this; _is_closed = true; if (_is_fullscreen) _desinit_fullscreen(); ShowWindow(_window,SW_HIDE); _window_x = _window_y = 0; return *this; } CImgDisplay& move(const int posx, const int posy) { if (is_empty()) return *this; if (_window_x!=posx || _window_y!=posy) { if (!_is_fullscreen) { RECT rect; rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (int)((rect.right - rect.left + 1 -_width)/2), border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER); } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); _window_x = posx; _window_y = posy; show(); } _is_moved = false; return *this; } CImgDisplay& show_mouse() { if (is_empty()) return *this; _is_cursor_visible = true; return *this; } CImgDisplay& hide_mouse() { if (is_empty()) return *this; _is_cursor_visible = false; return *this; } CImgDisplay& set_mouse(const int posx, const int posy) { if (is_empty() || _is_closed || posx<0 || posy<0) return *this; _update_window_pos(); const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy); if (res) { _mouse_x = posx; _mouse_y = posy; } return *this; } CImgDisplay& set_title(const char *const format, ...) { if (is_empty()) return *this; char *const tmp = new char[1024]; va_list ap; va_start(ap, format); cimg_vsnprintf(tmp,1024,format,ap); va_end(ap); if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } delete[] _title; const unsigned int s = (unsigned int)std::strlen(tmp) + 1; _title = new char[s]; std::memcpy(_title,tmp,s*sizeof(char)); SetWindowTextA(_window, tmp); delete[] tmp; return *this; } template CImgDisplay& display(const CImg& img) { if (!img) throw CImgArgumentException(_cimgdisplay_instance "display(): Empty specified image.", cimgdisplay_instance); if (is_empty()) return assign(img); return render(img).paint(); } CImgDisplay& paint() { if (_is_closed) return *this; WaitForSingleObject(_mutex,INFINITE); SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS); ReleaseMutex(_mutex); return *this; } template CImgDisplay& render(const CImg& img) { if (!img) throw CImgArgumentException(_cimgdisplay_instance "render(): Empty specified image.", cimgdisplay_instance); if (is_empty()) return *this; if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, (img._depth - 1)/2)); const T *data1 = img._data, *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1, *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1; WaitForSingleObject(_mutex,INFINITE); unsigned int *const ndata = (img._width==_width && img._height==_height)?_data: new unsigned int[(size_t)img._width*img._height], *ptrd = ndata; if (!_normalization || (_normalization==3 && cimg::type::string()==cimg::type::string())) { _min = _max = 0; switch (img._spectrum) { case 1 : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++); *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); } } break; case 2 : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); } } break; default : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++); *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); } } } } else { if (_normalization==3) { if (cimg::type::is_float()) _min = (float)img.min_max(_max); else { _min = (float)cimg::type::min(); _max = (float)cimg::type::max(); } } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); const float delta = _max - _min, mm = 255/(delta?delta:1.0f); switch (img._spectrum) { case 1 : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); } } break; case 2 : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)((*(data1++) - _min)*mm), G = (unsigned char)((*(data2++) - _min)*mm); *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); } } break; default : { for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned char R = (unsigned char)((*(data1++) - _min)*mm), G = (unsigned char)((*(data2++) - _min)*mm), B = (unsigned char)((*(data3++) - _min)*mm); *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); } } } } if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; } ReleaseMutex(_mutex); return *this; } template const CImgDisplay& snapshot(CImg& img) const { if (is_empty()) { img.assign(); return *this; } const unsigned int *ptrs = _data; img.assign(_width,_height,1,3); T *data1 = img.data(0,0,0,0), *data2 = img.data(0,0,0,1), *data3 = img.data(0,0,0,2); for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { const unsigned int val = *(ptrs++); *(data1++) = (T)(unsigned char)(val>>16); *(data2++) = (T)(unsigned char)((val>>8)&0xFF); *(data3++) = (T)(unsigned char)(val&0xFF); } return *this; } #endif //@} }; /* #-------------------------------------- # # # # Definition of the CImg structure # # # #-------------------------------------- */ //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T. /** This is the main class of the %CImg Library. It declares and constructs an image, allows access to its pixel values, and is able to perform various image operations. \par Image representation A %CImg image is defined as an instance of the container \c CImg, which contains a regular grid of pixels, each pixel value being of type \c T. The image grid can have up to 4 dimensions: width, height, depth and number of channels. Usually, the three first dimensions are used to describe spatial coordinates (x,y,z), while the number of channels is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance). If you need a fifth dimension, you can use image lists \c CImgList rather than simple images \c CImg. Thus, the \c CImg class is able to represent volumetric images of vector-valued pixels, as well as images with less dimensions (1d scalar signal, 2d color images, ...). Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions. Concerning the pixel value type \c T: fully supported template types are the basic C++ types: unsigned char, char, short, unsigned int, int, unsigned long, long, float, double, ... . Typically, fast image display can be done using CImg images, while complex image processing algorithms may be rather coded using CImg or CImg images that have floating-point pixel values. The default value for the template T is \c float. Using your own template types may be possible. However, you will certainly have to define the complete set of arithmetic and logical operators for your class. \par Image structure The \c CImg structure contains \e six fields: - \c _width defines the number of \a columns of the image (size along the X-axis). - \c _height defines the number of \a rows of the image (size along the Y-axis). - \c _depth defines the number of \a slices of the image (size along the Z-axis). - \c _spectrum defines the number of \a channels of the image (size along the C-axis). - \c _data defines a \a pointer to the \a pixel \a data (of type \c T). - \c _is_shared is a boolean that tells if the memory buffer \c data is shared with another image. You can access these fields publicly although it is recommended to use the dedicated functions width(), height(), depth(), spectrum() and ptr() to do so. Image dimensions are not limited to a specific range (as long as you got enough available memory). A value of \e 1 usually means that the corresponding dimension is \a flat. If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty. Empty images should not contain any pixel data and thus, will not be processed by CImg member functions (a CImgInstanceException will be thrown instead). Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage). \par Image declaration and construction Declaring an image can be done by using one of the several available constructors. Here is a list of the most used: - Construct images from arbitrary dimensions: - CImg img; declares an empty image. - CImg img(128,128); declares a 128x128 greyscale image with \c unsigned \c char pixel values. - CImg img(3,3); declares a 3x3 matrix with \c double coefficients. - CImg img(256,256,1,3); declares a 256x256x1x3 (color) image (colors are stored as an image with three channels). - CImg img(128,128,128); declares a 128x128x128 volumetric and greyscale image (with \c double pixel values). - CImg<> img(128,128,128,3); declares a 128x128x128 volumetric color image (with \c float pixels, which is the default value of the template parameter \c T). - \b Note: images pixels are not automatically initialized to 0. You may use the function \c fill() to do it, or use the specific constructor taking 5 parameters like this: CImg<> img(128,128,128,3,0); declares a 128x128x128 volumetric color image with all pixel values to 0. - Construct images from filenames: - CImg img("image.jpg"); reads a JPEG color image from the file "image.jpg". - CImg img("analyze.hdr"); reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr". - \b Note: You need to install ImageMagick to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io). - Construct images from C-style arrays: - CImg img(data_buffer,256,256); constructs a 256x256 greyscale image from a \c int* buffer \c data_buffer (of size 256x256=65536). - CImg img(data_buffer,256,256,1,3); constructs a 256x256 color image from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). The complete list of constructors can be found here. \par Most useful functions The \c CImg class contains a lot of functions that operates on images. Some of the most useful are: - operator()(): Read or write pixel values. - display(): displays the image in a new window. **/ template struct CImg { unsigned int _width, _height, _depth, _spectrum; bool _is_shared; T *_data; //! Simple iterator type, to loop through each pixel value of an image instance. /** \note - The \c CImg::iterator type is defined to be a T*. - You will seldom have to use iterators in %CImg, most classical operations being achieved (often in a faster way) using methods of \c CImg. \par Example \code CImg img("reference.jpg"); // Load image from file. for (CImg::iterator it = img.begin(), it::const_iterator type is defined to be a \c const \c T*. - You will seldom have to use iterators in %CImg, most classical operations being achieved (often in a faster way) using methods of \c CImg. \par Example \code const CImg img("reference.jpg"); // Load image from file. float sum = 0; for (CImg::iterator it = img.begin(), it::value_type type of a \c CImg is defined to be a \c T. - \c CImg::value_type is actually not used in %CImg methods. It has been mainly defined for compatibility with STL naming conventions. **/ typedef T value_type; // Define common types related to template type T. typedef typename cimg::superset::type Tbool; typedef typename cimg::superset::type Tuchar; typedef typename cimg::superset::type Tchar; typedef typename cimg::superset::type Tushort; typedef typename cimg::superset::type Tshort; typedef typename cimg::superset::type Tuint; typedef typename cimg::superset::type Tint; typedef typename cimg::superset::type Tulong; typedef typename cimg::superset::type Tlong; typedef typename cimg::superset::type Tfloat; typedef typename cimg::superset::type Tdouble; typedef typename cimg::last::type boolT; typedef typename cimg::last::type ucharT; typedef typename cimg::last::type charT; typedef typename cimg::last::type ushortT; typedef typename cimg::last::type shortT; typedef typename cimg::last::type uintT; typedef typename cimg::last::type intT; typedef typename cimg::last::type ulongT; typedef typename cimg::last::type longT; typedef typename cimg::last::type uint64T; typedef typename cimg::last::type int64T; typedef typename cimg::last::type floatT; typedef typename cimg::last::type doubleT; //@} //--------------------------- // //! \name Plugins //@{ //--------------------------- #ifdef cimg_plugin #include cimg_plugin #endif #ifdef cimg_plugin1 #include cimg_plugin1 #endif #ifdef cimg_plugin2 #include cimg_plugin2 #endif #ifdef cimg_plugin3 #include cimg_plugin3 #endif #ifdef cimg_plugin4 #include cimg_plugin4 #endif #ifdef cimg_plugin5 #include cimg_plugin5 #endif #ifdef cimg_plugin6 #include cimg_plugin6 #endif #ifdef cimg_plugin7 #include cimg_plugin7 #endif #ifdef cimg_plugin8 #include cimg_plugin8 #endif //@} //--------------------------------------------------------- // //! \name Constructors / Destructor / Instance Management //@{ //--------------------------------------------------------- //! Destroy image. /** \note - The pixel buffer data() is deallocated if necessary, e.g. for non-empty and non-shared image instances. - Destroying an empty or shared image does nothing actually. \warning - When destroying a non-shared image, make sure that you will \e not operate on a remaining shared image that shares its buffer with the destroyed instance, in order to avoid further invalid memory access (to a deallocated buffer). **/ ~CImg() { if (!_is_shared) delete[] _data; } //! Construct empty image. /** \note - An empty image has no pixel data and all of its dimensions width(), height(), depth(), spectrum() are set to \c 0, as well as its pixel buffer pointer data(). - An empty image may be re-assigned afterwards, e.g. with the family of assign(unsigned int,unsigned int,unsigned int,unsigned int) methods, or by operator=(const CImg&). In all cases, the type of pixels stays \c T. - An empty image is never shared. \par Example \code CImg img1, img2; // Construct two empty images. img1.assign(256,256,1,3); // Re-assign 'img1' to be a 256x256x1x3 (color) image. img2 = img1.get_rand(0,255); // Re-assign 'img2' to be a random-valued version of 'img1'. img2.assign(); // Re-assign 'img2' to be an empty image again. \endcode **/ CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {} //! Construct image with specified size. /** \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \note - It is able to create only \e non-shared images, and allocates thus a pixel buffer data() for each constructed image instance. - Setting one dimension \c size_x,\c size_y,\c size_z or \c size_c to \c 0 leads to the construction of an \e empty image. - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. when requested size is too big for available memory). \warning - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values. In order to initialize pixel values during construction (e.g. with \c 0), use constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) instead. \par Example \code CImg img1(256,256,1,3); // Construct a 256x256x1x3 (color) image, filled with garbage values. CImg img2(256,256,1,3,0); // Construct a 256x256x1x3 (color) image, filled with value '0'. \endcode **/ explicit CImg(const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1): _is_shared(false) { size_t siz = (size_t)size_x*size_y*size_z*size_c; if (siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Construct image with specified size and initialize pixel values. /** \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param value Initialization value. \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills the pixel buffer with the specified \c value. \warning - It cannot be used to construct a vector-valued image and initialize it with \e vector-valued pixels (e.g. RGB vector, for color images). For this task, you may use fillC() after construction. **/ CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const T& value): _is_shared(false) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } fill(value); } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Construct image with specified size and initialize pixel values from a sequence of integers. /** Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initialize pixel values from the specified sequence of integers \c value0,\c value1,\c ... \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param value0 First value of the initialization sequence (must be an \e integer). \param value1 Second value of the initialization sequence (must be an \e integer). \param ... \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills the pixel buffer with a sequence of specified integer values. \warning - You must specify \e exactly \c size_x*\c size_y*\c size_z*\c size_c integers in the initialization sequence. Otherwise, the constructor may crash or fill your image pixels with garbage. \par Example \code const CImg img(2,2,1,3, // Construct a 2x2 color (RGB) image. 0,255,0,255, // Set the 4 values for the red component. 0,0,255,255, // Set the 4 values for the green component. 64,64,64,64); // Set the 4 values for the blue component. img.resize(150,150).display(); \endcode \image html ref_constructor1.jpg **/ CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const int value0, const int value1, ...): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { #define _CImg_stdarg(img,a0,a1,N,t) { \ size_t _siz = (size_t)N; \ if (_siz--) { \ va_list ap; \ va_start(ap,a1); \ T *ptrd = (img)._data; \ *(ptrd++) = (T)a0; \ if (_siz--) { \ *(ptrd++) = (T)a1; \ for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ } \ va_end(ap); \ } \ } assign(size_x,size_y,size_z,size_c); _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int); } #if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 //! Construct image with specified size and initialize pixel values from an initializer list of integers. /** Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initialize pixel values from the specified initializer list of integers { \c value0,\c value1,\c ... } \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param { value0, value1, ... } Initialization list \param repeat_values Tells if the value filling process is repeated over the image. \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills the pixel buffer with a sequence of specified integer values. \par Example \code const CImg img(2,2,1,3, // Construct a 2x2 color (RGB) image. { 0,255,0,255, // Set the 4 values for the red component. 0,0,255,255, // Set the 4 values for the green component. 64,64,64,64 }); // Set the 4 values for the blue component. img.resize(150,150).display(); \endcode \image html ref_constructor1.jpg **/ template CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const std::initializer_list values, const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { #define _cimg_constructor_cpp11(repeat_values) \ auto it = values.begin(); \ size_t siz = size(); \ if (repeat_values) for (T *ptrd = _data; siz--; ) { \ *(ptrd++) = (T)(*(it++)); if (it==values.end()) it = values.begin(); } \ else { siz = cimg::min(siz,values.size()); for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); } assign(size_x,size_y,size_z,size_c); _cimg_constructor_cpp11(repeat_values); } template CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, std::initializer_list values, const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x,size_y,size_z); _cimg_constructor_cpp11(repeat_values); } template CImg(const unsigned int size_x, const unsigned int size_y, std::initializer_list values, const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x,size_y); _cimg_constructor_cpp11(repeat_values); } template CImg(const unsigned int size_x, std::initializer_list values, const bool repeat_values=true):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x); _cimg_constructor_cpp11(repeat_values); } //! Construct single channel 1D image with pixel values and width obtained from an initializer list of integers. /** Construct a new image instance of size \c width x \c 1 x \c 1 x \c 1, with pixels of type \c T, and initialize pixel values from the specified initializer list of integers { \c value0,\c value1,\c ... }. Image width is given by the size of the initializer list. \param { value0, value1, ... } Initialization list \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int) with height=1, depth=1, and spectrum=1, but it also fills the pixel buffer with a sequence of specified integer values. \par Example \code const CImg img = {10,20,30,20,10 }; // Construct a 5x1 image with one channel, and set its pixel values. img.resize(150,150).display(); \endcode \image html ref_constructor1.jpg **/ template CImg(const std::initializer_list values): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(values.size(),1,1,1); auto it = values.begin(); unsigned int siz = _width; for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); } template CImg & operator=(std::initializer_list values) { _cimg_constructor_cpp11(siz>values.size()); return *this; } #endif //! Construct image with specified size and initialize pixel values from a sequence of doubles. /** Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initialize pixel values from the specified sequence of doubles \c value0,\c value1,\c ... \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param value0 First value of the initialization sequence (must be a \e double). \param value1 Second value of the initialization sequence (must be a \e double). \param ... \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...), but takes a sequence of double values instead of integers. \warning - You must specify \e exactly \c dx*\c dy*\c dz*\c dc doubles in the initialization sequence. Otherwise, the constructor may crash or fill your image with garbage. For instance, the code below will probably crash on most platforms: \code const CImg img(2,2,1,1, 0.5,0.5,255,255); // FAIL: The two last arguments are 'int', not 'double'! \endcode **/ CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const double value0, const double value1, ...): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x,size_y,size_z,size_c); _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double); } //! Construct image with specified size and initialize pixel values from a value string. /** Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initializes pixel values from the specified string \c values. \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param values Value string describing the way pixel values are set. \param repeat_values Tells if the value filling process is repeated over the image. \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills the pixel buffer with values described in the value string \c values. - Value string \c values may describe two different filling processes: - Either \c values is a sequences of values assigned to the image pixels, as in "1,2,3,7,8,2". In this case, set \c repeat_values to \c true to periodically fill the image with the value sequence. - Either, \c values is a formula, as in "cos(x/10)*sin(y/20)". In this case, parameter \c repeat_values is pointless. - For both cases, specifying \c repeat_values is mandatory. It disambiguates the possible overloading of constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) with \c T being a const char*. - A \c CImgArgumentException is thrown when an invalid value string \c values is specified. \par Example \code const CImg img1(129,129,1,3,"0,64,128,192,255",true), // Construct image filled from a value sequence. img2(129,129,1,3,"if(c==0,255*abs(cos(x/10)),1.8*y)",false); // Construct image filled from a formula. (img1,img2).display(); \endcode \image html ref_constructor2.jpg **/ CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const char *const values, const bool repeat_values):_is_shared(false) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } fill(values,repeat_values); } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Construct image with specified size and initialize pixel values from a memory buffer. /** Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initializes pixel values from the specified \c t* memory buffer. \param values Pointer to the input memory buffer. \param size_x Image width(). \param size_y Image height(). \param size_z Image depth(). \param size_c Image spectrum() (number of channels). \param is_shared Tells if input memory buffer must be shared by the current instance. \note - If \c is_shared is \c false, the image instance allocates its own pixel buffer, and values from the specified input buffer are copied to the instance buffer. If buffer types \c T and \c t are different, a regular static cast is performed during buffer copy. - Otherwise, the image instance does \e not allocate a new buffer, and uses the input memory buffer as its own pixel buffer. This case requires that types \c T and \c t are the same. Later, destroying such a shared image will not deallocate the pixel buffer, this task being obviously charged to the initial buffer allocator. - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. when requested size is too big for available memory). \warning - You must take care when operating on a shared image, since it may have an invalid pixel buffer pointer data() (e.g. already deallocated). \par Example \code unsigned char tab[256*256] = { 0 }; CImg img1(tab,256,256,1,1,false), // Construct new non-shared image from buffer 'tab'. img2(tab,256,256,1,1,true); // Construct new shared-image from buffer 'tab'. tab[1024] = 255; // Here, 'img2' is indirectly modified, but not 'img1'. \endcode **/ template CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) { if (is_shared) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgArgumentException(_cimg_instance "CImg(): Invalid construction request of a (%u,%u,%u,%u) shared instance " "from a (%s*) buffer (pixel types are different).", cimg_instance, size_x,size_y,size_z,size_c,CImg::pixel_type()); } const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (values && siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Construct image with specified size and initialize pixel values from a memory buffer \specialization. CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (values && siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared; if (_is_shared) _data = const_cast(values); else { try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } std::memcpy(_data,values,siz*sizeof(T)); } } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } } //! Construct image from reading an image file. /** Construct a new image instance with pixels of type \c T, and initialize pixel values with the data read from an image file. \param filename Filename, as a C-string. \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it reads the image dimensions and pixel values from the specified image file. - The recognition of the image file format by %CImg higly depends on the tools installed on your system and on the external libraries you used to link your code against. - Considered pixel type \c T should better fit the file format specification, or data loss may occur during file load (e.g. constructing a \c CImg from a float-valued image file). - A \c CImgIOException is thrown when the specified \c filename cannot be read, or if the file format is not recognized. \par Example \code const CImg img("reference.jpg"); img.display(); \endcode \image html ref_image.jpg **/ explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(filename); } //! Construct image copy. /** Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg instance. \param img Input image to copy. \note - Constructed copy has the same size width() x height() x depth() x spectrum() and pixel values as the input image \c img. - If input image \c img is \e shared and if types \c T and \c t are the same, the constructed copy is also \e shared, and shares its pixel buffer with \c img. Modifying a pixel value in the constructed copy will thus also modifies it in the input image \c img. This behavior is needful to allow functions to return shared images. - Otherwise, the constructed copy allocates its own pixel buffer, and copies pixel values from the input image \c img into its buffer. The copied pixel values may be eventually statically casted if types \c T and \c t are different. - Constructing a copy from an image \c img when types \c t and \c T are the same is significantly faster than with different types. - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. not enough available memory). **/ template CImg(const CImg& img):_is_shared(false) { const size_t siz = (size_t)img.size(); if (img._data && siz) { _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), img._width,img._height,img._depth,img._spectrum); } const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Construct image copy \specialization. CImg(const CImg& img) { const size_t siz = (size_t)img.size(); if (img._data && siz) { _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = img._is_shared; if (_is_shared) _data = const_cast(img._data); else { try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), img._width,img._height,img._depth,img._spectrum); } std::memcpy(_data,img._data,siz*sizeof(T)); } } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } } //! Advanced copy constructor. /** Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg instance, while forcing the shared state of the constructed copy. \param img Input image to copy. \param is_shared Tells about the shared state of the constructed copy. \note - Similar to CImg(const CImg&), except that it allows to decide the shared state of the constructed image, which does not depend anymore on the shared state of the input image \c img: - If \c is_shared is \c true, the constructed copy will share its pixel buffer with the input image \c img. For that case, the pixel types \c T and \c t \e must be the same. - If \c is_shared is \c false, the constructed copy will allocate its own pixel buffer, whether the input image \c img is shared or not. - A \c CImgArgumentException is thrown when a shared copy is requested with different pixel types \c T and \c t. **/ template CImg(const CImg& img, const bool is_shared):_is_shared(false) { if (is_shared) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgArgumentException(_cimg_instance "CImg(): Invalid construction request of a shared instance from a " "CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).", cimg_instance, CImg::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data); } const size_t siz = (size_t)img.size(); if (img._data && siz) { _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), img._width,img._height,img._depth,img._spectrum); } const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); } else { _width = _height = _depth = _spectrum = 0; _data = 0; } } //! Advanced copy constructor \specialization. CImg(const CImg& img, const bool is_shared) { const size_t siz = (size_t)img.size(); if (img._data && siz) { _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = is_shared; if (_is_shared) _data = const_cast(img._data); else { try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), img._width,img._height,img._depth,img._spectrum); } std::memcpy(_data,img._data,siz*sizeof(T)); } } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } } //! Construct image with dimensions borrowed from another image. /** Construct a new image instance with pixels of type \c T, and size get from some dimensions of an existing \c CImg instance. \param img Input image from which dimensions are borrowed. \param dimensions C-string describing the image size along the X,Y,Z and C-dimensions. \note - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it takes the image dimensions (\e not its pixel values) from an existing \c CImg instance. - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values. In order to initialize pixel values (e.g. with \c 0), use constructor CImg(const CImg&,const char*,T) instead. \par Example \code const CImg img1(256,128,1,3), // 'img1' is a 256x128x1x3 image. img2(img1,"xyzc"), // 'img2' is a 256x128x1x3 image. img3(img1,"y,x,z,c"), // 'img3' is a 128x256x1x3 image. img4(img1,"c,x,y,3",0), // 'img4' is a 3x128x256x3 image (with pixels initialized to '0'). \endcode **/ template CImg(const CImg& img, const char *const dimensions): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(img,dimensions); } //! Construct image with dimensions borrowed from another image and initialize pixel values. /** Construct a new image instance with pixels of type \c T, and size get from the dimensions of an existing \c CImg instance, and set all pixel values to specified \c value. \param img Input image from which dimensions are borrowed. \param dimensions String describing the image size along the X,Y,Z and V-dimensions. \param value Value used for initialization. \note - Similar to CImg(const CImg&,const char*), but it also fills the pixel buffer with the specified \c value. **/ template CImg(const CImg& img, const char *const dimensions, const T& value): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(img,dimensions).fill(value); } //! Construct image from a display window. /** Construct a new image instance with pixels of type \c T, as a snapshot of an existing \c CImgDisplay instance. \param disp Input display window. \note - The width() and height() of the constructed image instance are the same as the specified \c CImgDisplay. - The depth() and spectrum() of the constructed image instance are respectively set to \c 1 and \c 3 (i.e. a 2d color image). - The image pixels are read as 8-bits RGB values. **/ explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { disp.snapshot(*this); } // Constructor and assignment operator for rvalue references (c++11). // This avoids an additional image copy for methods returning new images. Can save RAM for big images ! #if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 CImg(CImg&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { swap(img); } CImg& operator=(CImg&& img) { if (_is_shared) return assign(img); return img.swap(*this); } #endif //! Construct empty image \inplace. /** In-place version of the default constructor CImg(). It simply resets the instance to an empty image. **/ CImg& assign() { if (!_is_shared) delete[] _data; _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; return *this; } //! Construct image with specified size \inplace. /** In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (!siz) return assign(); const size_t curr_siz = (size_t)size(); if (siz!=curr_siz) { if (_is_shared) throw CImgArgumentException(_cimg_instance "assign(): Invalid assignement request of shared instance from specified " "image (%u,%u,%u,%u).", cimg_instance, size_x,size_y,size_z,size_c); else { delete[] _data; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } } } _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; return *this; } //! Construct image with specified size and initialize pixel values \inplace. /** In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const T& value) { return assign(size_x,size_y,size_z,size_c).fill(value); } //! Construct image with specified size and initialize pixel values from a sequence of integers \inplace. /** In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const int value0, const int value1, ...) { assign(size_x,size_y,size_z,size_c); _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int); return *this; } //! Construct image with specified size and initialize pixel values from a sequence of doubles \inplace. /** In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const double value0, const double value1, ...) { assign(size_x,size_y,size_z,size_c); _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double); return *this; } //! Construct image with specified size and initialize pixel values from a value string \inplace. /** In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const char *const values, const bool repeat_values) { return assign(size_x,size_y,size_z,size_c).fill(values,repeat_values); } //! Construct image with specified size and initialize pixel values from a memory buffer \inplace. /** In-place version of the constructor CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int). **/ template CImg& assign(const t *const values, const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (!values || !siz) return assign(); assign(size_x,size_y,size_z,size_c); const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); return *this; } //! Construct image with specified size and initialize pixel values from a memory buffer \specialization. CImg& assign(const T *const values, const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (!values || !siz) return assign(); const size_t curr_siz = (size_t)size(); if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c); if (_is_shared || values + siz<_data || values>=_data + size()) { assign(size_x,size_y,size_z,size_c); if (_is_shared) std::memmove(_data,values,siz*sizeof(T)); else std::memcpy(_data,values,siz*sizeof(T)); } else { T *new_data = 0; try { new_data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; throw CImgInstanceException(_cimg_instance "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", cimg_instance, cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), size_x,size_y,size_z,size_c); } std::memcpy(new_data,values,siz*sizeof(T)); delete[] _data; _data = new_data; _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; } return *this; } //! Construct image with specified size and initialize pixel values from a memory buffer \overloading. template CImg& assign(const t *const values, const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const bool is_shared) { if (is_shared) throw CImgArgumentException(_cimg_instance "assign(): Invalid assignment request of shared instance from (%s*) buffer" "(pixel types are different).", cimg_instance, CImg::pixel_type()); return assign(values,size_x,size_y,size_z,size_c); } //! Construct image with specified size and initialize pixel values from a memory buffer \overloading. CImg& assign(const T *const values, const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const bool is_shared) { const size_t siz = (size_t)size_x*size_y*size_z*size_c; if (!values || !siz) return assign(); if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); } else { if (!_is_shared) { if (values + siz<_data || values>=_data + size()) assign(); else cimg::warn(_cimg_instance "assign(): Shared image instance has overlapping memory.", cimg_instance); } _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true; _data = const_cast(values); } return *this; } //! Construct image from reading an image file \inplace. /** In-place version of the constructor CImg(const char*). **/ CImg& assign(const char *const filename) { return load(filename); } //! Construct image copy \inplace. /** In-place version of the constructor CImg(const CImg&). **/ template CImg& assign(const CImg& img) { return assign(img._data,img._width,img._height,img._depth,img._spectrum); } //! In-place version of the advanced copy constructor. /** In-place version of the constructor CImg(const CImg&,bool). **/ template CImg& assign(const CImg& img, const bool is_shared) { return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared); } //! Construct image with dimensions borrowed from another image \inplace. /** In-place version of the constructor CImg(const CImg&,const char*). **/ template CImg& assign(const CImg& img, const char *const dimensions) { if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum); unsigned int siz[4] = { 0,1,1,1 }, k = 0; CImg item(256); for (const char *s = dimensions; *s && k<4; ++k) { if (cimg_sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item._data)>0) s+=std::strlen(item); if (*s) { unsigned int val = 0; char sep = 0; if (cimg_sscanf(s,"%u%c",&val,&sep)>0) { if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100; else siz[k] = val; while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s; } else switch (cimg::uncase(*s)) { case 'x' : case 'w' : siz[k] = img._width; ++s; break; case 'y' : case 'h' : siz[k] = img._height; ++s; break; case 'z' : case 'd' : siz[k] = img._depth; ++s; break; case 'c' : case 's' : siz[k] = img._spectrum; ++s; break; default : throw CImgArgumentException(_cimg_instance "assign(): Invalid character '%c' detected in specified dimension string '%s'.", cimg_instance, *s,dimensions); } } } return assign(siz[0],siz[1],siz[2],siz[3]); } //! Construct image with dimensions borrowed from another image and initialize pixel values \inplace. /** In-place version of the constructor CImg(const CImg&,const char*,T). **/ template CImg& assign(const CImg& img, const char *const dimensions, const T& value) { return assign(img,dimensions).fill(value); } //! Construct image from a display window \inplace. /** In-place version of the constructor CImg(const CImgDisplay&). **/ CImg& assign(const CImgDisplay &disp) { disp.snapshot(*this); return *this; } //! Construct empty image \inplace. /** Equivalent to assign(). \note - It has been defined for compatibility with STL naming conventions. **/ CImg& clear() { return assign(); } //! Transfer content of an image instance into another one. /** Transfer the dimensions and the pixel buffer content of an image instance into another one, and replace instance by an empty image. It avoids the copy of the pixel buffer when possible. \param img Destination image. \note - Pixel types \c T and \c t of source and destination images can be different, though the process is designed to be instantaneous when \c T and \c t are the same. \par Example \code CImg src(256,256,1,3,0), // Construct a 256x256x1x3 (color) image filled with value '0'. dest(16,16); // Construct a 16x16x1x1 (scalar) image. src.move_to(dest); // Now, 'src' is empty and 'dest' is the 256x256x1x3 image. \endcode **/ template CImg& move_to(CImg& img) { img.assign(*this); assign(); return img; } //! Transfer content of an image instance into another one \specialization. CImg& move_to(CImg& img) { if (_is_shared || img._is_shared) img.assign(*this); else swap(img); assign(); return img; } //! Transfer content of an image instance into a new image in an image list. /** Transfer the dimensions and the pixel buffer content of an image instance into a newly inserted image at position \c pos in specified \c CImgList instance. \param list Destination list. \param pos Position of the newly inserted image in the list. \note - When optionnal parameter \c pos is ommited, the image instance is transfered as a new image at the end of the specified \c list. - It is convenient to sequentially insert new images into image lists, with no additional copies of memory buffer. \par Example \code CImgList list; // Construct an empty image list. CImg img("reference.jpg"); // Read image from filename. img.move_to(list); // Transfer image content as a new item in the list (no buffer copy). \endcode **/ template CImgList& move_to(CImgList& list, const unsigned int pos=~0U) { const unsigned int npos = pos>list._width?list._width:pos; move_to(list.insert(1,npos)[npos]); return list; } //! Swap fields of two image instances. /** \param img Image to swap fields with. \note - It can be used to interchange the content of two images in a very fast way. Can be convenient when dealing with algorithms requiring two swapping buffers. \par Example \code CImg img1("lena.jpg"), img2("milla.jpg"); img1.swap(img2); // Now, 'img1' is 'milla' and 'img2' is 'lena'. \endcode **/ CImg& swap(CImg& img) { cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum); cimg::swap(_data,img._data); cimg::swap(_is_shared,img._is_shared); return img; } //! Return a reference to an empty image. /** \note This function is useful mainly to declare optional parameters having type \c CImg in functions prototypes, e.g. \code void f(const int x=0, const int y=0, const CImg& img=CImg::empty()); \endcode **/ static CImg& empty() { static CImg _empty; return _empty.assign(); } //! Return a reference to an empty image \const. static const CImg& const_empty() { static const CImg _empty; return _empty; } //@} //------------------------------------------ // //! \name Overloaded Operators //@{ //------------------------------------------ //! Access to a pixel value. /** Return a reference to a located pixel value of the image instance, being possibly \e const, whether the image instance is \e const or not. This is the standard method to get/set pixel values in \c CImg images. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Range of pixel coordinates start from (0,0,0,0) to (width() - 1,height() - 1,depth() - 1,spectrum() - 1). - Due to the particular arrangement of the pixel buffers defined in %CImg, you can omit one coordinate if the corresponding dimension is equal to \c 1. For instance, pixels of a 2d image (depth() equal to \c 1) can be accessed by img(x,y,c) instead of img(x,y,0,c). \warning - There is \e no boundary checking done in this operator, to make it as fast as possible. You \e must take care of out-of-bounds access by yourself, if necessary. For debuging purposes, you may want to define macro \c 'cimg_verbosity'>=3 to enable additional boundary checking operations in this operator. In that case, warning messages will be printed on the error output when accessing out-of-bounds pixels. \par Example \code CImg img(100,100,1,3,0); // Construct a 100x100x1x3 (color) image with pixels set to '0'. const float valR = img(10,10,0,0), // Read red value at coordinates (10,10). valG = img(10,10,0,1), // Read green value at coordinates (10,10) valB = img(10,10,2), // Read blue value at coordinates (10,10) (Z-coordinate can be omitted). avg = (valR + valG + valB)/3; // Compute average pixel value. img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the color pixel (10,10) by the average grey value. \endcode **/ #if cimg_verbosity>=3 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { const ulongT off = (ulongT)offset(x,y,z,c); if (!_data || off>=size()) { cimg::warn(_cimg_instance "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].", cimg_instance, (int)x,(int)y,(int)z,(int)c,off); return *_data; } else return _data[off]; } //! Access to a pixel value \const. const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { return const_cast*>(this)->operator()(x,y,z,c); } //! Access to a pixel value. /** \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param wh Precomputed offset, must be equal to width()*\ref height(). \param whd Precomputed offset, must be equal to width()*\ref height()*\ref depth(). \note - Similar to (but faster than) operator()(). It uses precomputed offsets to optimize memory access. You may use it to optimize the reading/writing of several pixel values in the same image (e.g. in a loop). **/ T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, const ulongT wh, const ulongT whd=0) { cimg::unused(wh,whd); return (*this)(x,y,z,c); } //! Access to a pixel value \const. const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, const ulongT wh, const ulongT whd=0) const { cimg::unused(wh,whd); return (*this)(x,y,z,c); } #else T& operator()(const unsigned int x) { return _data[x]; } const T& operator()(const unsigned int x) const { return _data[x]; } T& operator()(const unsigned int x, const unsigned int y) { return _data[x + y*_width]; } const T& operator()(const unsigned int x, const unsigned int y) const { return _data[x + y*_width]; } T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) { return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height]; } const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const { return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height]; } T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) { return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth]; } const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const { return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth]; } T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int, const ulongT wh) { return _data[x + y*_width + z*wh]; } const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int, const ulongT wh) const { return _data[x + y*_width + z*wh]; } T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, const ulongT wh, const ulongT whd) { return _data[x + y*_width + z*wh + c*whd]; } const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, const ulongT wh, const ulongT whd) const { return _data[x + y*_width + z*wh + c*whd]; } #endif //! Implicitely cast an image into a \c T*. /** Implicitely cast a \c CImg instance into a \c T* or \c const \c T* pointer, whether the image instance is \e const or not. The returned pointer points on the first value of the image pixel buffer. \note - It simply returns the pointer data() to the pixel buffer. - This implicit conversion is convenient to test the empty state of images (data() being \c 0 in this case), e.g. \code CImg img1(100,100), img2; // 'img1' is a 100x100 image, 'img2' is an empty image. if (img1) { // Test succeeds, 'img1' is not an empty image. if (!img2) { // Test succeeds, 'img2' is an empty image. std::printf("'img1' is not empty, 'img2' is empty."); } } \endcode - It also allows to use brackets to access pixel values, without need for a \c CImg::operator[](), e.g. \code CImg img(100,100); const float value = img[99]; // Access to value of the last pixel on the first row. img[510] = 255; // Set pixel value at (10,5). \endcode **/ operator T*() { return _data; } //! Implicitely cast an image into a \c T* \const. operator const T*() const { return _data; } //! Assign a value to all image pixels. /** Assign specified \c value to each pixel value of the image instance. \param value Value that will be assigned to image pixels. \note - The image size is never modified. - The \c value may be casted to pixel type \c T if necessary. \par Example \code CImg img(100,100); // Declare image (with garbage values). img = 0; // Set all pixel values to '0'. img = 1.2; // Set all pixel values to '1' (cast of '1.2' as a 'char'). \endcode **/ CImg& operator=(const T& value) { return fill(value); } //! Assign pixels values from a specified expression. /** Initialize all pixel values from the specified string \c expression. \param expression Value string describing the way pixel values are set. \note - String parameter \c expression may describe different things: - If \c expression is a list of values (as in \c "1,2,3,8,3,2"), or a formula (as in \c "(x*y)%255"), the pixel values are set from specified \c expression and the image size is not modified. - If \c expression is a filename (as in \c "reference.jpg"), the corresponding image file is loaded and replace the image instance. The image size is modified if necessary. \par Example \code CImg img1(100,100), img2(img1), img3(img1); // Declare three 100x100 scalar images with unitialized pixel values. img1 = "0,50,100,150,200,250,200,150,100,50"; // Set pixel values of 'img1' from a value sequence. img2 = "10*((x*y)%25)"; // Set pixel values of 'img2' from a formula. img3 = "reference.jpg"; // Set pixel values of 'img3' from a file (image size is modified). (img1,img2,img3).display(); \endcode \image html ref_operator_eq.jpg **/ CImg& operator=(const char *const expression) { const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { _fill(expression,true,true,0,0,"operator=",0); } catch (CImgException&) { cimg::exception_mode(omode); load(expression); } cimg::exception_mode(omode); return *this; } //! Copy an image into the current image instance. /** Similar to the in-place copy constructor assign(const CImg&). **/ template CImg& operator=(const CImg& img) { return assign(img); } //! Copy an image into the current image instance \specialization. CImg& operator=(const CImg& img) { return assign(img); } //! Copy the content of a display window to the current image instance. /** Similar to assign(const CImgDisplay&). **/ CImg& operator=(const CImgDisplay& disp) { disp.snapshot(*this); return *this; } //! In-place addition operator. /** Add specified \c value to all pixels of an image instance. \param value Value to add. \note - Resulting pixel values are casted to fit the pixel type \c T. For instance, adding \c 0.2 to a \c CImg is possible but does nothing indeed. - Overflow values are treated as with standard C++ numeric types. For instance, \code CImg img(100,100,1,1,255); // Construct a 100x100 image with pixel values '255'. img+=1; // Add '1' to each pixels -> Overflow. // here all pixels of image 'img' are equal to '0'. \endcode - To prevent value overflow, you may want to consider pixel type \c T as \c float or \c double, and use cut() after addition. \par Example \code CImg img1("reference.jpg"); // Load a 8-bits RGB image (values in [0,255]). CImg img2(img1); // Construct a float-valued copy of 'img1'. img2+=100; // Add '100' to pixel values -> goes out of [0,255] but no problems with floats. img2.cut(0,255); // Cut values in [0,255] to fit the 'unsigned char' constraint. img1 = img2; // Rewrite safe result in 'unsigned char' version 'img1'. const CImg img3 = (img1 + 100).cut(0,255); // Do the same in a more simple and elegant way. (img1,img2,img3).display(); \endcode \image html ref_operator_plus.jpg **/ template CImg& operator+=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value); return *this; } //! In-place addition operator. /** Add values to image pixels, according to the specified string \c expression. \param expression Value string describing the way pixel values are added. \note - Similar to operator=(const char*), except that it adds values to the pixels of the current image instance, instead of assigning them. **/ CImg& operator+=(const char *const expression) { return *this+=(+*this)._fill(expression,true,true,0,0,"operator+=",this); } //! In-place addition operator. /** Add values to image pixels, according to the values of the input image \c img. \param img Input image to add. \note - The size of the image instance is never modified. - It is not mandatory that input image \c img has the same size as the image instance. If less values are available in \c img, then the values are added periodically. For instance, adding one WxH scalar image (spectrum() equal to \c 1) to one WxH color image (spectrum() equal to \c 3) means each color channel will be incremented with the same values at the same locations. \par Example \code CImg img1("reference.jpg"); // Load a RGB color image (img1.spectrum()==3) const CImg img2(img1.width(),img.height(),1,1,"255*(x/w)^2"); // Construct a scalar shading (img2.spectrum()==1). img1+=img2; // Add shading to each channel of 'img1'. img1.cut(0,255); // Prevent [0,255] overflow. (img2,img1).display(); \endcode \image html ref_operator_plus1.jpg **/ template CImg& operator+=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this+=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs& operator++() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) ++*ptrd; return *this; } //! In-place increment operator (postfix). /** Add \c 1 to all image pixels, and return a new copy of the initial (pre-incremented) image instance. \note - Use the prefixed version operator++() if you don't need a copy of the initial (pre-incremented) image instance, since a useless image copy may be expensive in terms of memory usage. **/ CImg operator++(int) { const CImg copy(*this,false); ++*this; return copy; } //! Return a non-shared copy of the image instance. /** \note - Use this operator to ensure you get a non-shared copy of an image instance with same pixel type \c T. Indeed, the usual copy constructor CImg(const CImg&) returns a shared copy of a shared input image, and it may be not desirable to work on a regular copy (e.g. for a resize operation) if you have no information about the shared state of the input image. - Writing \c (+img) is equivalent to \c CImg(img,false). **/ CImg operator+() const { return CImg(*this,false); } //! Addition operator. /** Similar to operator+=(const t), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator+(const t value) const { return CImg<_cimg_Tt>(*this,false)+=value; } //! Addition operator. /** Similar to operator+=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ CImg operator+(const char *const expression) const { return CImg(*this,false)+=expression; } //! Addition operator. /** Similar to operator+=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator+(const CImg& img) const { return CImg<_cimg_Tt>(*this,false)+=img; } //! In-place substraction operator. /** Similar to operator+=(const t), except that it performs a substraction instead of an addition. **/ template CImg& operator-=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value); return *this; } //! In-place substraction operator. /** Similar to operator+=(const char*), except that it performs a substraction instead of an addition. **/ CImg& operator-=(const char *const expression) { return *this-=(+*this)._fill(expression,true,true,0,0,"operator-=",this); } //! In-place substraction operator. /** Similar to operator+=(const CImg&), except that it performs a substraction instead of an addition. **/ template CImg& operator-=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this-=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs& operator--() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1; return *this; } //! In-place decrement operator (postfix). /** Similar to operator++(int), except that it performs a decrement instead of an increment. **/ CImg operator--(int) { const CImg copy(*this,false); --*this; return copy; } //! Replace each pixel by its opposite value. /** \note - If the computed opposite values are out-of-range, they are treated as with standard C++ numeric types. For instance, the \c unsigned \c char opposite of \c 1 is \c 255. \par Example \code const CImg img1("reference.jpg"), // Load a RGB color image. img2 = -img1; // Compute its opposite (in 'unsigned char'). (img1,img2).display(); \endcode \image html ref_operator_minus.jpg **/ CImg operator-() const { return CImg(_width,_height,_depth,_spectrum,(T)0)-=*this; } //! Substraction operator. /** Similar to operator-=(const t), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator-(const t value) const { return CImg<_cimg_Tt>(*this,false)-=value; } //! Substraction operator. /** Similar to operator-=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ CImg operator-(const char *const expression) const { return CImg(*this,false)-=expression; } //! Substraction operator. /** Similar to operator-=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator-(const CImg& img) const { return CImg<_cimg_Tt>(*this,false)-=img; } //! In-place multiplication operator. /** Similar to operator+=(const t), except that it performs a multiplication instead of an addition. **/ template CImg& operator*=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=262144) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value); return *this; } //! In-place multiplication operator. /** Similar to operator+=(const char*), except that it performs a multiplication instead of an addition. **/ CImg& operator*=(const char *const expression) { return mul((+*this)._fill(expression,true,true,0,0,"operator*=",this)); } //! In-place multiplication operator. /** Replace the image instance by the matrix multiplication between the image instance and the specified matrix \c img. \param img Second operand of the matrix multiplication. \note - It does \e not compute a pointwise multiplication between two images. For this purpose, use mul(const CImg&) instead. - The size of the image instance can be modified by this operator. \par Example \code CImg A(2,2,1,1, 1,2,3,4); // Construct 2x2 matrix A = [1,2;3,4]. const CImg X(1,2,1,1, 1,2); // Construct 1x2 vector X = [1;2]. A*=X; // Assign matrix multiplication A*X to 'A'. // 'A' is now a 1x2 vector whose values are [5;11]. \endcode **/ template CImg& operator*=(const CImg& img) { return ((*this)*img).move_to(*this); } //! Multiplication operator. /** Similar to operator*=(const t), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator*(const t value) const { return CImg<_cimg_Tt>(*this,false)*=value; } //! Multiplication operator. /** Similar to operator*=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ CImg operator*(const char *const expression) const { return CImg(*this,false)*=expression; } //! Multiplication operator. /** Similar to operator*=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator*(const CImg& img) const { if (_width!=img._height || _depth!=1 || _spectrum!=1) throw CImgArgumentException(_cimg_instance "operator*(): Invalid multiplication of instance by specified " "matrix (%u,%u,%u,%u,%p)", cimg_instance, img._width,img._height,img._depth,img._spectrum,img._data); CImg<_cimg_Tt> res(img._width,_height); #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024) cimg_forXY(res,i,j) { _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value; } #else _cimg_Tt *ptrd = res._data; cimg_forXY(res,i,j) { _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = (_cimg_Tt)value; } #endif return res; } //! In-place division operator. /** Similar to operator+=(const t), except that it performs a division instead of an addition. **/ template CImg& operator/=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value); return *this; } //! In-place division operator. /** Similar to operator+=(const char*), except that it performs a division instead of an addition. **/ CImg& operator/=(const char *const expression) { return div((+*this)._fill(expression,true,true,0,0,"operator/=",this)); } //! In-place division operator. /** Replace the image instance by the (right) matrix division between the image instance and the specified matrix \c img. \param img Second operand of the matrix division. \note - It does \e not compute a pointwise division between two images. For this purpose, use div(const CImg&) instead. - It returns the matrix operation \c A*inverse(img). - The size of the image instance can be modified by this operator. **/ template CImg& operator/=(const CImg& img) { return (*this*img.get_invert()).move_to(*this); } //! Division operator. /** Similar to operator/=(const t), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator/(const t value) const { return CImg<_cimg_Tt>(*this,false)/=value; } //! Division operator. /** Similar to operator/=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ CImg operator/(const char *const expression) const { return CImg(*this,false)/=expression; } //! Division operator. /** Similar to operator/=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator/(const CImg& img) const { return (*this)*img.get_invert(); } //! In-place modulo operator. /** Similar to operator+=(const t), except that it performs a modulo operation instead of an addition. **/ template CImg& operator%=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=16384) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value); return *this; } //! In-place modulo operator. /** Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition. **/ CImg& operator%=(const char *const expression) { return *this%=(+*this)._fill(expression,true,true,0,0,"operator%=",this); } //! In-place modulo operator. /** Similar to operator+=(const CImg&), except that it performs a modulo operation instead of an addition. **/ template CImg& operator%=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this%=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg<_cimg_Tt> operator%(const t value) const { return CImg<_cimg_Tt>(*this,false)%=value; } //! Modulo operator. /** Similar to operator%=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ CImg operator%(const char *const expression) const { return CImg(*this,false)%=expression; } //! Modulo operator. /** Similar to operator%=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. **/ template CImg<_cimg_Tt> operator%(const CImg& img) const { return CImg<_cimg_Tt>(*this,false)%=img; } //! In-place bitwise AND operator. /** Similar to operator+=(const t), except that it performs a bitwise AND operation instead of an addition. **/ template CImg& operator&=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd & (ulongT)value); return *this; } //! In-place bitwise AND operator. /** Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition. **/ CImg& operator&=(const char *const expression) { return *this&=(+*this)._fill(expression,true,true,0,0,"operator&=",this); } //! In-place bitwise AND operator. /** Similar to operator+=(const CImg&), except that it performs a bitwise AND operation instead of an addition. **/ template CImg& operator&=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this&=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg operator&(const t value) const { return (+*this)&=value; } //! Bitwise AND operator. /** Similar to operator&=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ CImg operator&(const char *const expression) const { return (+*this)&=expression; } //! Bitwise AND operator. /** Similar to operator&=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator&(const CImg& img) const { return (+*this)&=img; } //! In-place bitwise OR operator. /** Similar to operator+=(const t), except that it performs a bitwise OR operation instead of an addition. **/ template CImg& operator|=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd | (ulongT)value); return *this; } //! In-place bitwise OR operator. /** Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition. **/ CImg& operator|=(const char *const expression) { return *this|=(+*this)._fill(expression,true,true,0,0,"operator|=",this); } //! In-place bitwise OR operator. /** Similar to operator+=(const CImg&), except that it performs a bitwise OR operation instead of an addition. **/ template CImg& operator|=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this|=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg operator|(const t value) const { return (+*this)|=value; } //! Bitwise OR operator. /** Similar to operator|=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ CImg operator|(const char *const expression) const { return (+*this)|=expression; } //! Bitwise OR operator. /** Similar to operator|=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator|(const CImg& img) const { return (+*this)|=img; } //! In-place bitwise XOR operator. /** Similar to operator+=(const t), except that it performs a bitwise XOR operation instead of an addition. \warning - It does \e not compute the \e power of pixel values. For this purpose, use pow(const t) instead. **/ template CImg& operator^=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)value); return *this; } //! In-place bitwise XOR operator. /** Similar to operator+=(const char*), except that it performs a bitwise XOR operation instead of an addition. \warning - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead. **/ CImg& operator^=(const char *const expression) { return *this^=(+*this)._fill(expression,true,true,0,0,"operator^=",this); } //! In-place bitwise XOR operator. /** Similar to operator+=(const CImg&), except that it performs a bitwise XOR operation instead of an addition. \warning - It does \e not compute the \e power of pixel values. For this purpose, use pow(const CImg&) instead. **/ template CImg& operator^=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this^=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg operator^(const t value) const { return (+*this)^=value; } //! Bitwise XOR operator. /** Similar to operator^=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ CImg operator^(const char *const expression) const { return (+*this)^=expression; } //! Bitwise XOR operator. /** Similar to operator^=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator^(const CImg& img) const { return (+*this)^=img; } //! In-place bitwise left shift operator. /** Similar to operator+=(const t), except that it performs a bitwise left shift instead of an addition. **/ template CImg& operator<<=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) << (int)value); return *this; } //! In-place bitwise left shift operator. /** Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition. **/ CImg& operator<<=(const char *const expression) { return *this<<=(+*this)._fill(expression,true,true,0,0,"operator<<=",this); } //! In-place bitwise left shift operator. /** Similar to operator+=(const CImg&), except that it performs a bitwise left shift instead of an addition. **/ template CImg& operator<<=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this^=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg operator<<(const t value) const { return (+*this)<<=value; } //! Bitwise left shift operator. /** Similar to operator<<=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ CImg operator<<(const char *const expression) const { return (+*this)<<=expression; } //! Bitwise left shift operator. /** Similar to operator<<=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator<<(const CImg& img) const { return (+*this)<<=img; } //! In-place bitwise right shift operator. /** Similar to operator+=(const t), except that it performs a bitwise right shift instead of an addition. **/ template CImg& operator>>=(const t value) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) >> (int)value); return *this; } //! In-place bitwise right shift operator. /** Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition. **/ CImg& operator>>=(const char *const expression) { return *this>>=(+*this)._fill(expression,true,true,0,0,"operator>>=",this); } //! In-place bitwise right shift operator. /** Similar to operator+=(const CImg&), except that it performs a bitwise right shift instead of an addition. **/ template CImg& operator>>=(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return *this^=+img; T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs> (int)*(ptrs++)); for (const t *ptrs = img._data; ptrd> (int)*(ptrs++)); } return *this; } //! Bitwise right shift operator. /** Similar to operator>>=(const t), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator>>(const t value) const { return (+*this)>>=value; } //! Bitwise right shift operator. /** Similar to operator>>=(const char*), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ CImg operator>>(const char *const expression) const { return (+*this)>>=expression; } //! Bitwise right shift operator. /** Similar to operator>>=(const CImg&), except that it returns a new image instance instead of operating in-place. The pixel type of the returned image is \c T. **/ template CImg operator>>(const CImg& img) const { return (+*this)>>=img; } //! Bitwise inversion operator. /** Similar to operator-(), except that it compute the bitwise inverse instead of the opposite value. **/ CImg operator~() const { CImg res(_width,_height,_depth,_spectrum); const T *ptrs = _data; cimg_for(res,ptrd,T) { const ulongT value = (ulongT)*(ptrs++); *ptrd = (T)~value; } return res; } //! Test if all pixels of an image have the same value. /** Return \c true is all pixels of the image instance are equal to the specified \c value. \param value Reference value to compare with. **/ template bool operator==(const t value) const { if (is_empty()) return false; typedef _cimg_Tt Tt; bool is_equal = true; for (T *ptrd = _data + size(); is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)value)) {} return is_equal; } //! Test if all pixel values of an image follow a specified expression. /** Return \c true is all pixels of the image instance are equal to the specified \c expression. \param expression Value string describing the way pixel values are compared. **/ bool operator==(const char *const expression) const { return *this==(+*this)._fill(expression,true,true,0,0,"operator==",this); } //! Test if two images have the same size and values. /** Return \c true if the image instance and the input image \c img have the same dimensions and pixel values, and \c false otherwise. \param img Input image to compare with. \note - The pixel buffer pointers data() of the two compared images do not have to be the same for operator==() to return \c true. Only the dimensions and the pixel values matter. Thus, the comparison can be \c true even for different pixel types \c T and \c t. \par Example \code const CImg img1(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'float' pixel values). const CImg img2(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'char' pixel values). if (img1==img2) { // Test succeeds, image dimensions and values are the same. std::printf("'img1' and 'img2' have same dimensions and values."); } \endcode **/ template bool operator==(const CImg& img) const { typedef _cimg_Tt Tt; const ulongT siz = size(); bool is_equal = true; if (siz!=img.size()) return false; t *ptrs = img._data + siz; for (T *ptrd = _data + siz; is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)*(--ptrs))) {} return is_equal; } //! Test if pixels of an image are all different from a value. /** Return \c true is all pixels of the image instance are different than the specified \c value. \param value Reference value to compare with. **/ template bool operator!=(const t value) const { return !((*this)==value); } //! Test if all pixel values of an image are different from a specified expression. /** Return \c true is all pixels of the image instance are different to the specified \c expression. \param expression Value string describing the way pixel values are compared. **/ bool operator!=(const char *const expression) const { return !((*this)==expression); } //! Test if two images have different sizes or values. /** Return \c true if the image instance and the input image \c img have different dimensions or pixel values, and \c false otherwise. \param img Input image to compare with. \note - Writing \c img1!=img2 is equivalent to \c !(img1==img2). **/ template bool operator!=(const CImg& img) const { return !((*this)==img); } //! Construct an image list from two images. /** Return a new list of image (\c CImgList instance) containing exactly two elements: - A copy of the image instance, at position [\c 0]. - A copy of the specified image \c img, at position [\c 1]. \param img Input image that will be the second image of the resulting list. \note - The family of operator,() is convenient to easily create list of images, but it is also \e quite \e slow in practice (see warning below). - Constructed lists contain no shared images. If image instance or input image \c img are shared, they are inserted as new non-shared copies in the resulting list. - The pixel type of the returned list may be a superset of the initial pixel type \c T, if necessary. \warning - Pipelining operator,() \c N times will perform \c N copies of the entire content of a (growing) image list. This may become very expensive in terms of speed and used memory. You should avoid using this technique to build a new CImgList instance from several images, if you are seeking for performance. Fast insertions of images in an image list are possible with CImgList::insert(const CImg&,unsigned int,bool) or move_to(CImgList&,unsigned int). \par Example \code const CImg img1("reference.jpg"), img2 = img1.get_mirror('x'), img3 = img2.get_blur(5); const CImgList list = (img1,img2); // Create list of two elements from 'img1' and 'img2'. (list,img3).display(); // Display image list containing copies of 'img1','img2' and 'img3'. \endcode \image html ref_operator_comma.jpg **/ template CImgList<_cimg_Tt> operator,(const CImg& img) const { return CImgList<_cimg_Tt>(*this,img); } //! Construct an image list from image instance and an input image list. /** Return a new list of images (\c CImgList instance) containing exactly \c list.size() \c + \c 1 elements: - A copy of the image instance, at position [\c 0]. - A copy of the specified image list \c list, from positions [\c 1] to [\c list.size()]. \param list Input image list that will be appended to the image instance. \note - Similar to operator,(const CImg&) const, except that it takes an image list as an argument. **/ template CImgList<_cimg_Tt> operator,(const CImgList& list) const { return CImgList<_cimg_Tt>(list,false).insert(*this,0); } //! Split image along specified axis. /** Return a new list of images (\c CImgList instance) containing the splitted components of the instance image along the specified axis. \param axis Splitting axis (can be '\c x','\c y','\c z' or '\c c') \note - Similar to get_split(char,int) const, with default second argument. \par Example \code const CImg img("reference.jpg"); // Load a RGB color image. const CImgList list = (img<'c'); // Get a list of its three R,G,B channels. (img,list).display(); \endcode \image html ref_operator_less.jpg **/ CImgList operator<(const char axis) const { return get_split(axis); } //@} //------------------------------------- // //! \name Instance Characteristics //@{ //------------------------------------- //! Return the type of image pixel values as a C string. /** Return a \c char* string containing the usual type name of the image pixel values (i.e. a stringified version of the template parameter \c T). \note - The returned string may contain spaces (as in \c "unsigned char"). - If the pixel type \c T does not correspond to a registered type, the string "unknown" is returned. **/ static const char* pixel_type() { return cimg::type::string(); } //! Return the number of image columns. /** Return the image width, i.e. the image dimension along the X-axis. \note - The width() of an empty image is equal to \c 0. - width() is typically equal to \c 1 when considering images as \e vectors for matrix calculations. - width() returns an \c int, although the image width is internally stored as an \c unsigned \c int. Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving \c unsigned \c int variables. Access to the initial \c unsigned \c int variable is possible (though not recommended) by (*this)._width. **/ int width() const { return (int)_width; } //! Return the number of image rows. /** Return the image height, i.e. the image dimension along the Y-axis. \note - The height() of an empty image is equal to \c 0. - height() returns an \c int, although the image height is internally stored as an \c unsigned \c int. Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving \c unsigned \c int variables. Access to the initial \c unsigned \c int variable is possible (though not recommended) by (*this)._height. **/ int height() const { return (int)_height; } //! Return the number of image slices. /** Return the image depth, i.e. the image dimension along the Z-axis. \note - The depth() of an empty image is equal to \c 0. - depth() is typically equal to \c 1 when considering usual 2d images. When depth()\c > \c 1, the image is said to be \e volumetric. - depth() returns an \c int, although the image depth is internally stored as an \c unsigned \c int. Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving \c unsigned \c int variables. Access to the initial \c unsigned \c int variable is possible (though not recommended) by (*this)._depth. **/ int depth() const { return (int)_depth; } //! Return the number of image channels. /** Return the number of image channels, i.e. the image dimension along the C-axis. \note - The spectrum() of an empty image is equal to \c 0. - spectrum() is typically equal to \c 1 when considering scalar-valued images, to \c 3 for RGB-coded color images, and to \c 4 for RGBA-coded color images (with alpha-channel). The number of channels of an image instance is not limited. The meaning of the pixel values is not linked up to the number of channels (e.g. a 4-channel image may indifferently stands for a RGBA or CMYK color image). - spectrum() returns an \c int, although the image spectrum is internally stored as an \c unsigned \c int. Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving \c unsigned \c int variables. Access to the initial \c unsigned \c int variable is possible (though not recommended) by (*this)._spectrum. **/ int spectrum() const { return (int)_spectrum; } //! Return the total number of pixel values. /** Return width()*\ref height()*\ref depth()*\ref spectrum(), i.e. the total number of values of type \c T in the pixel buffer of the image instance. \note - The size() of an empty image is equal to \c 0. - The allocated memory size for a pixel buffer of a non-shared \c CImg instance is equal to size()*sizeof(T). \par Example \code const CImg img(100,100,1,3); // Construct new 100x100 color image. if (img.size()==30000) // Test succeeds. std::printf("Pixel buffer uses %lu bytes", img.size()*sizeof(float)); \endcode **/ ulongT size() const { return (ulongT)_width*_height*_depth*_spectrum; } //! Return a pointer to the first pixel value. /** Return a \c T*, or a \c const \c T* pointer to the first value in the pixel buffer of the image instance, whether the instance is \c const or not. \note - The data() of an empty image is equal to \c 0 (null pointer). - The allocated pixel buffer for the image instance starts from \c data() and goes to data()+\ref size() - 1 (included). - To get the pointer to one particular location of the pixel buffer, use data(unsigned int,unsigned int,unsigned int,unsigned int) instead. **/ T* data() { return _data; } //! Return a pointer to the first pixel value \const. const T* data() const { return _data; } //! Return a pointer to a located pixel value. /** Return a \c T*, or a \c const \c T* pointer to the value located at (\c x,\c y,\c z,\c c) in the pixel buffer of the image instance, whether the instance is \c const or not. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Writing \c img.data(x,y,z,c) is equivalent to &(img(x,y,z,c)). Thus, this method has the same properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int). **/ #if cimg_verbosity>=3 T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { const ulongT off = (ulongT)offset(x,y,z,c); if (off>=size()) cimg::warn(_cimg_instance "data(): Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].", cimg_instance, x,y,z,c,off); return _data + off; } //! Return a pointer to a located pixel value \const. const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { return const_cast*>(this)->data(x,y,z,c); } #else T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth; } const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth; } #endif //! Return the offset to a located pixel value, with respect to the beginning of the pixel buffer. /** \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Writing \c img.data(x,y,z,c) is equivalent to &(img(x,y,z,c)) - img.data(). Thus, this method has the same properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int). \par Example \code const CImg img(100,100,1,3); // Define a 100x100 RGB-color image. const long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10). const float val = img[off]; // Get the blue value of this pixel. \endcode **/ longT offset(const int x, const int y=0, const int z=0, const int c=0) const { return x + (longT)y*_width + (longT)z*_width*_height + (longT)c*_width*_height*_depth; } //! Return a CImg::iterator pointing to the first pixel value. /** \note - Equivalent to data(). - It has been mainly defined for compatibility with STL naming conventions. **/ iterator begin() { return _data; } //! Return a CImg::iterator pointing to the first value of the pixel buffer \const. const_iterator begin() const { return _data; } //! Return a CImg::iterator pointing next to the last pixel value. /** \note - Writing \c img.end() is equivalent to img.data() + img.size(). - It has been mainly defined for compatibility with STL naming conventions. \warning - The returned iterator actually points to a value located \e outside the acceptable bounds of the pixel buffer. Trying to read or write the content of the returned iterator will probably result in a crash. Use it mainly as a strict upper bound for a CImg::iterator. \par Example \code CImg img(100,100,1,3); // Define a 100x100 RGB color image. for (CImg::iterator it = img.begin(); it::iterator pointing next to the last pixel value \const. const_iterator end() const { return _data + size(); } //! Return a reference to the first pixel value. /** \note - Writing \c img.front() is equivalent to img[0], or img(0,0,0,0). - It has been mainly defined for compatibility with STL naming conventions. **/ T& front() { return *_data; } //! Return a reference to the first pixel value \const. const T& front() const { return *_data; } //! Return a reference to the last pixel value. /** \note - Writing \c img.end() is equivalent to img[img.size() - 1], or img(img.width() - 1,img.height() - 1,img.depth() - 1,img.spectrum() - 1). - It has been mainly defined for compatibility with STL naming conventions. **/ T& back() { return *(_data + size() - 1); } //! Return a reference to the last pixel value \const. const T& back() const { return *(_data + size() - 1); } //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions. /** Return a reference to the pixel value of the image instance located at a specified \c offset, or to a specified default value in case of out-of-bounds access. \param offset Offset to the desired pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note - Writing \c img.at(offset,out_value) is similar to img[offset], except that if \c offset is outside bounds (e.g. \c offset<0 or \c offset>=img.size()), a reference to a value \c out_value is safely returned instead. - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel offset. **/ T& at(const int offset, const T& out_value) { return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset]; } //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions \const. T at(const int offset, const T& out_value) const { return (offset<0 || offset>=(int)size())?out_value:(*this)[offset]; } //! Access to a pixel value at a specified offset, using Neumann boundary conditions. /** Return a reference to the pixel value of the image instance located at a specified \c offset, or to the nearest pixel location in the image instance in case of out-of-bounds access. \param offset Offset to the desired pixel value. \note - Similar to at(int,const T), except that an out-of-bounds access returns the value of the nearest pixel in the image instance, regarding the specified offset, i.e. - If \c offset<0, then \c img[0] is returned. - If \c offset>=img.size(), then \c img[img.size() - 1] is returned. - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel offset. - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int). **/ T& at(const int offset) { if (is_empty()) throw CImgInstanceException(_cimg_instance "at(): Empty instance.", cimg_instance); return _at(offset); } T& _at(const int offset) { const unsigned int siz = (unsigned int)size(); return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; } //! Access to a pixel value at a specified offset, using Neumann boundary conditions \const. const T& at(const int offset) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "at(): Empty instance.", cimg_instance); return _at(offset); } const T& _at(const int offset) const { const unsigned int siz = (unsigned int)size(); return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; } //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate. /** Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c), or to a specified default value in case of out-of-bounds access along the X-axis. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c (\c x,\c y,\c z,\c c) is outside image bounds. \note - Similar to operator()(), except that an out-of-bounds access along the X-axis returns the specified value \c out_value. - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel coordinates. \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ T& atX(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \const. T atX(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || x>=width())?out_value:(*this)(x,y,z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate. /** Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c), or to the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Similar to at(int,int,int,int,const T), except that an out-of-bounds access returns the value of the nearest pixel in the image instance, regarding the specified X-coordinate. - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel coordinates. - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int,int,int,int). \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ T& atX(const int x, const int y=0, const int z=0, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimg_instance "atX(): Empty instance.", cimg_instance); return _atX(x,y,z,c); } T& _atX(const int x, const int y=0, const int z=0, const int c=0) { return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate \const. const T& atX(const int x, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atX(): Empty instance.", cimg_instance); return _atX(x,y,z,c); } const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const { return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y-coordinates. /** Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X and Y-coordinates. **/ T& atXY(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y coordinates \const. T atXY(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates. /** Similar to atX(int,int,int,int), except that boundary checking is performed both on X and Y-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXY(int,int,int,int). **/ T& atXY(const int x, const int y, const int z=0, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXY(): Empty instance.", cimg_instance); return _atXY(x,y,z,c); } T& _atXY(const int x, const int y, const int z=0, const int c=0) { return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates \const. const T& atXY(const int x, const int y, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXY(): Empty instance.", cimg_instance); return _atXY(x,y,z,c); } const T& _atXY(const int x, const int y, const int z=0, const int c=0) const { return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates. /** Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X,Y and Z-coordinates. **/ T& atXYZ(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())? (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates \const. T atXYZ(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates. /** Similar to atX(int,int,int,int), except that boundary checking is performed both on X,Y and Z-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXYZ(int,int,int,int). **/ T& atXYZ(const int x, const int y, const int z, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZ(): Empty instance.", cimg_instance); return _atXYZ(x,y,z,c); } T& _atXYZ(const int x, const int y, const int z, const int c=0) { return (*this)(x<0?0:x>=width()?width() - 1:x,y<0?0:y>=height()?height() - 1:y, z<0?0:z>=depth()?depth() - 1:z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates \const. const T& atXYZ(const int x, const int y, const int z, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZ(): Empty instance.", cimg_instance); return _atXYZ(x,y,z,c); } const T& _atXYZ(const int x, const int y, const int z, const int c=0) const { return (*this)(x<0?0:(x>=width()?width() - 1:x),y<0?0:(y>=height()?height() - 1:y), z<0?0:(z>=depth()?depth() - 1:z),c); } //! Access to a pixel value, using Dirichlet boundary conditions. /** Similar to atX(int,int,int,int,const T), except that boundary checking is performed on all X,Y,Z and C-coordinates. **/ T& atXYZC(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())? (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions \const. T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value: (*this)(x,y,z,c); } //! Access to a pixel value, using Neumann boundary conditions. /** Similar to atX(int,int,int,int), except that boundary checking is performed on all X,Y,Z and C-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXYZC(int,int,int,int). **/ T& atXYZC(const int x, const int y, const int z, const int c) { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZC(): Empty instance.", cimg_instance); return _atXYZC(x,y,z,c); } T& _atXYZC(const int x, const int y, const int z, const int c) { return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y), z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c)); } //! Access to a pixel value, using Neumann boundary conditions \const. const T& atXYZC(const int x, const int y, const int z, const int c) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZC(): Empty instance.", cimg_instance); return _atXYZC(x,y,z,c); } const T& _atXYZC(const int x, const int y, const int z, const int c) const { return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y), z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c)); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X-coordinate. /** Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), or a specified default value in case of out-of-bounds access along the X-axis. \param fx X-coordinate of the pixel value (float-valued). \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds. \note - Similar to atX(int,int,int,int,const T), except that the returned pixel value is approximated by a linear interpolation along the X-axis, if corresponding coordinates are not integers. - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued. \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1; const float dx = fx - x; const Tfloat Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value); return Ic + dx*(In - Ic); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X-coordinate. /** Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), or the value of the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis. \param fx X-coordinate of the pixel value (float-valued). \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Similar to linear_atX(float,int,int,int,const T) const, except that an out-of-bounds access returns the value of the nearest pixel in the image instance, regarding the specified X-coordinate. - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atX(float,int,int,int). \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "linear_atX(): Empty instance.", cimg_instance); return _linear_atX(fx,y,z,c); } Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx); const unsigned int x = (unsigned int)nfx; const float dx = nfx - x; const unsigned int nx = dx>0?x + 1:x; const Tfloat Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c); return Ic + dx*(In - Ic); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X and Y-coordinates. /** Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved both for X and Y-coordinates. **/ Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1; const float dx = fx - x, dy = fy - y; const Tfloat Icc = (Tfloat)atXY(x,y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value); return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X and Y-coordinates. /** Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking are achieved both for X and Y-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXY(float,float,int,int). **/ Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "linear_atXY(): Empty instance.", cimg_instance); return _linear_atXY(fx,fy,z,c); } Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), nfy = fy<0?0:(fy>_height - 1?_height - 1:fy); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy; const float dx = nfx - x, dy = nfy - y; const unsigned int nx = dx>0?x + 1:x, ny = dy>0?y + 1:y; const Tfloat Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c); return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates. /** Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved both for X,Y and Z-coordinates. **/ Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1, z = (int)fz - (fz>=0?0:1), nz = z + 1; const float dx = fx - x, dy = fy - y, dz = fz - z; const Tfloat Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value); return Iccc + dx*(Incc - Iccc + dy*(Iccc + Innc - Icnc - Incc + dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) + dz*(Iccc + Incn - Iccn - Incc)) + dy*(Icnc - Iccc + dz*(Iccc + Icnn - Iccn - Icnc)) + dz*(Iccn - Iccc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. /** Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking are achieved both for X,Y and Z-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXYZ(float,float,float,int). **/ Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "linear_atXYZ(): Empty instance.", cimg_instance); return _linear_atXYZ(fx,fy,fz,c); } Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy, z = (unsigned int)nfz; const float dx = nfx - x, dy = nfy - y, dz = nfz - z; const unsigned int nx = dx>0?x + 1:x, ny = dy>0?y + 1:y, nz = dz>0?z + 1:z; const Tfloat Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c); return Iccc + dx*(Incc - Iccc + dy*(Iccc + Innc - Icnc - Incc + dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) + dz*(Iccc + Incn - Iccn - Incc)) + dy*(Icnc - Iccc + dz*(Iccc + Icnn - Iccn - Icnc)) + dz*(Iccn - Iccc); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for all X,Y,Z,C-coordinates. /** Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved for all X,Y,Z and C-coordinates. **/ Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1, z = (int)fz - (fz>=0?0:1), nz = z + 1, c = (int)fc - (fc>=0?0:1), nc = c + 1; const float dx = fx - x, dy = fy - y, dz = fz - z, dc = fc - c; const Tfloat Icccc = (Tfloat)atXYZC(x,y,z,c,out_value), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_value), Icncc = (Tfloat)atXYZC(x,ny,z,c,out_value), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_value), Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_value), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_value), Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_value), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_value), Icccn = (Tfloat)atXYZC(x,y,z,nc,out_value), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_value), Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_value), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_value), Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value), Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value); return Icccc + dx*(Inccc - Icccc + dy*(Icccc + Inncc - Icncc - Inccc + dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + dz*(Icccc + Incnc - Iccnc - Inccc + dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + dc*(Icccc + Inccn - Inccc - Icccn)) + dy*(Icncc - Icccc + dz*(Icccc + Icnnc - Iccnc - Icncc + dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + dc*(Icccc + Icncn - Icncc - Icccn)) + dz*(Iccnc - Icccc + dc*(Icccc + Iccnn - Iccnc - Icccn)) + dc*(Icccn -Icccc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for all X,Y,Z and C-coordinates. /** Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking are achieved for all X,Y,Z and C-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXYZC(float,float,float,float). **/ Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "linear_atXYZC(): Empty instance.", cimg_instance); return _linear_atXYZC(fx,fy,fz,fc); } Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz), nfc = fc<0?0:(fc>_spectrum - 1?_spectrum - 1:fc); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy, z = (unsigned int)nfz, c = (unsigned int)nfc; const float dx = nfx - x, dy = nfy - y, dz = nfz - z, dc = nfc - c; const unsigned int nx = dx>0?x + 1:x, ny = dy>0?y + 1:y, nz = dz>0?z + 1:z, nc = dc>0?c + 1:c; const Tfloat Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c), Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c), Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c), Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c), Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc), Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc), Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc), Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc); return Icccc + dx*(Inccc - Icccc + dy*(Icccc + Inncc - Icncc - Inccc + dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + dz*(Icccc + Incnc - Iccnc - Inccc + dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + dc*(Icccc + Inccn - Inccc - Icccn)) + dy*(Icncc - Icccc + dz*(Icccc + Icnnc - Iccnc - Icncc + dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + dc*(Icccc + Icncn - Icncc - Icccn)) + dz*(Iccnc - Icccc + dc*(Icccc + Iccnn - Iccnc - Icccn)) + dc*(Icccn - Icccc); } //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. /** Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), or a specified default value in case of out-of-bounds access along the X-axis. The cubic interpolation uses Hermite splines. \param fx d X-coordinate of the pixel value (float-valued). \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds. \note - Similar to linear_atX(float,int,int,int,const T) const, except that the returned pixel value is approximated by a \e cubic interpolation along the X-axis. - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued. \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2; const float dx = fx - x; const Tfloat Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value); return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. /** Similar to cubic_atX(float,int,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atX(fx,y,z,c,out_value); return valmax_value?max_value:val; } //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate. /** Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), or the value of the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis. The cubic interpolation uses Hermite splines. \param fx X-coordinate of the pixel value (float-valued). \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Similar to cubic_atX(float,int,int,int,const T) const, except that the returned pixel value is approximated by a cubic interpolation along the X-axis. - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atX(float,int,int,int). \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "cubic_atX(): Empty instance.", cimg_instance); return _cubic_atX(fx,y,z,c); } Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx); const int x = (int)nfx; const float dx = nfx - x; const int px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2; const Tfloat Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c); return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate. /** Similar to cubic_atX(float,int,int,int) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atX(fx,y,z,c); return valmax_value?max_value:val; } Tfloat _cubic_atX(const float fx, const int y, const int z, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = _cubic_atX(fx,y,z,c); return valmax_value?max_value:val; } //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X and Y-coordinates. /** Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking are achieved both for X and Y-coordinates. **/ Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2; const float dx = fx - x, dy = fy - y; const Tfloat Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value), Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value), Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), Ipc = (Tfloat)atXY(px,y,z,c,out_value), Icc = (Tfloat)atXY(x, y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value), Iac = (Tfloat)atXY(ax,y,z,c,out_value), Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value), In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value), Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value), Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y-coordinates. /** Similar to cubic_atXY(float,float,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXY(fx,fy,z,c,out_value); return valmax_value?max_value:val; } //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X and Y-coordinates. /** Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking are achieved for both X and Y-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atXY(float,float,int,int). **/ Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "cubic_atXY(): Empty instance.", cimg_instance); return _cubic_atXY(fx,fy,z,c); } Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), nfy = fy<0?0:(fy>_height - 1?_height - 1:fy); const int x = (int)nfx, y = (int)nfy; const float dx = nfx - x, dy = nfy - y; const int px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2, py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2; const Tfloat Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), Iap = (Tfloat)(*this)(ax,py,z,c), Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), Iac = (Tfloat)(*this)(ax,y,z,c), Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), Ian = (Tfloat)(*this)(ax,ny,z,c), In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), Iaa = (Tfloat)(*this)(ax,ay,z,c), Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y-coordinates. /** Similar to cubic_atXY(float,float,int,int) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXY(fx,fy,z,c); return valmax_value?max_value:val; } Tfloat _cubic_atXY(const float fx, const float fy, const int z, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = _cubic_atXY(fx,fy,z,c); return valmax_value?max_value:val; } //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates. /** Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking are achieved both for X,Y and Z-coordinates. **/ Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2, z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2; const float dx = fx - x, dy = fy - y, dz = fz - z; const Tfloat Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value), Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value), Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value), Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value), Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value), Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value), Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value), Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value), Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value), Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value), Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value), Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value), Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value), Iccc = (Tfloat)atXYZ(x, y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value), Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value), Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value), Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value), Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value), Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value), Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value), Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value), Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value), Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value), Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value), Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value), Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value), Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), Ipca = (Tfloat)atXYZ(px,y,az,c,out_value), Icca = (Tfloat)atXYZ(x, y,az,c,out_value), Inca = (Tfloat)atXYZ(nx,y,az,c,out_value), Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value), Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value), Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value), Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value), Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value), Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the XYZ-coordinates. /** Similar to cubic_atXYZ(float,float,float,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXYZ(fx,fy,fz,c,out_value); return valmax_value?max_value:val; } //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. /** Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking are achieved both for X,Y and Z-coordinates. \note - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atXYZ(float,float,float,int). **/ Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "cubic_atXYZ(): Empty instance.", cimg_instance); return _cubic_atXYZ(fx,fy,fz,c); } Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { const float nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz); const int x = (int)nfx, y = (int)nfy, z = (int)nfz; const float dx = nfx - x, dy = nfy - y, dz = nfz - z; const int px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2, py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2, pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2; const Tfloat Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c), Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c), Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c), Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c), Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c), Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c), Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c), Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c), Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c), Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c), Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c), Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c), Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c), Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c), Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c), Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c), Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c), Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c), Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c), Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c), Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c), Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c), Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c), Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c), Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c), Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c), Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c), Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c), Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the XYZ-coordinates. /** Similar to cubic_atXYZ(float,float,float,int) const, except that you can specify the authorized minimum and maximum of the returned value. **/ Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXYZ(fx,fy,fz,c); return valmax_value?max_value:val; } Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = _cubic_atXYZ(fx,fy,fz,c); return valmax_value?max_value:val; } //! Set pixel value, using linear interpolation for the X-coordinates. /** Set pixel value at specified coordinates (\c fx,\c y,\c z,\c c) in the image instance, in a way that the value is spread amongst several neighbors if the pixel coordinates are float-valued. \param value Pixel value to set. \param fx X-coordinate of the pixel value (float-valued). \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param is_added Tells if the pixel value is added to (\c true), or simply replace (\c false) the current image pixel(s). \return A reference to the current image instance. \note - Calling this method with out-of-bounds coordinates does nothing. **/ CImg& set_linear_atX(const T& value, const float fx, const int y=0, const int z=0, const int c=0, const bool is_added=false) { const int x = (int)fx - (fx>=0?0:1), nx = x + 1; const float dx = fx - x; if (y>=0 && y=0 && z=0 && c=0 && x=0 && nx& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0, const bool is_added=false) { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1; const float dx = fx - x, dy = fy - y; if (z>=0 && z=0 && c=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0, const bool is_added=false) { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1, z = (int)fz - (fz>=0?0:1), nz = z + 1; const float dx = fx - x, dy = fy - y, dz = fz - z; if (c>=0 && c=0 && z=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx=0 && nz=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx image whose buffer data() is a \c char* string describing the list of all pixel values of the image instance (written in base 10), separated by specified \c separator character. \param separator A \c char character which specifies the separator between values in the returned C-string. \param max_size Maximum size of the returned image. \param format For float-values, tell the printf format used to generate the ascii representation of the numbers. (or \c 0 for default representation). \note - The returned image is never empty. - For an empty image instance, the returned string is "". - If \c max_size is equal to \c 0, there are no limits on the size of the returned string. - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off and terminated by character \c '\0'. In that case, the returned image size is max_size + 1. **/ CImg value_string(const char separator=',', const unsigned int max_size=0, const char *const format=0) const { if (is_empty()) return CImg::string(""); CImgList items; CImg s_item(256); *s_item = 0; const T *ptrs = _data; unsigned int string_size = 0; const char *const _format = format?format:cimg::type::format(); for (ulongT off = 0, siz = size(); off::format(*(ptrs++))); CImg item(s_item._data,printed_size); item[printed_size - 1] = separator; item.move_to(items); if (max_size) string_size+=printed_size; } CImg res; (items>'x').move_to(res); if (max_size && res._width>max_size) res.crop(0,max_size); res.back() = 0; return res; } //@} //------------------------------------- // //! \name Instance Checking //@{ //------------------------------------- //! Test shared state of the pixel buffer. /** Return \c true if image instance has a shared memory buffer, and \c false otherwise. \note - A shared image do not own his pixel buffer data() and will not deallocate it on destruction. - Most of the time, a \c CImg image instance will \e not be shared. - A shared image can only be obtained by a limited set of constructors and methods (see list below). **/ bool is_shared() const { return _is_shared; } //! Test if image instance is empty. /** Return \c true, if image instance is empty, i.e. does \e not contain any pixel values, has dimensions \c 0 x \c 0 x \c 0 x \c 0 and a pixel buffer pointer set to \c 0 (null pointer), and \c false otherwise. **/ bool is_empty() const { return !(_data && _width && _height && _depth && _spectrum); } //! Test if image instance contains a 'inf' value. /** Return \c true, if image instance contains a 'inf' value, and \c false otherwise. **/ bool is_inf() const { if (cimg::type::is_float()) cimg_for(*this,p,T) if (cimg::type::is_inf((float)*p)) return true; return false; } //! Test if image instance contains a NaN value. /** Return \c true, if image instance contains a NaN value, and \c false otherwise. **/ bool is_nan() const { if (cimg::type::is_float()) cimg_for(*this,p,T) if (cimg::type::is_nan((float)*p)) return true; return false; } //! Test if image width is equal to specified value. bool is_sameX(const unsigned int size_x) const { return _width==size_x; } //! Test if image width is equal to specified value. template bool is_sameX(const CImg& img) const { return is_sameX(img._width); } //! Test if image width is equal to specified value. bool is_sameX(const CImgDisplay& disp) const { return is_sameX(disp._width); } //! Test if image height is equal to specified value. bool is_sameY(const unsigned int size_y) const { return _height==size_y; } //! Test if image height is equal to specified value. template bool is_sameY(const CImg& img) const { return is_sameY(img._height); } //! Test if image height is equal to specified value. bool is_sameY(const CImgDisplay& disp) const { return is_sameY(disp._height); } //! Test if image depth is equal to specified value. bool is_sameZ(const unsigned int size_z) const { return _depth==size_z; } //! Test if image depth is equal to specified value. template bool is_sameZ(const CImg& img) const { return is_sameZ(img._depth); } //! Test if image spectrum is equal to specified value. bool is_sameC(const unsigned int size_c) const { return _spectrum==size_c; } //! Test if image spectrum is equal to specified value. template bool is_sameC(const CImg& img) const { return is_sameC(img._spectrum); } //! Test if image width and height are equal to specified values. /** Test if is_sameX(unsigned int) const and is_sameY(unsigned int) const are both verified. **/ bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const { return _width==size_x && _height==size_y; } //! Test if image width and height are the same as that of another image. /** Test if is_sameX(const CImg&) const and is_sameY(const CImg&) const are both verified. **/ template bool is_sameXY(const CImg& img) const { return is_sameXY(img._width,img._height); } //! Test if image width and height are the same as that of an existing display window. /** Test if is_sameX(const CImgDisplay&) const and is_sameY(const CImgDisplay&) const are both verified. **/ bool is_sameXY(const CImgDisplay& disp) const { return is_sameXY(disp._width,disp._height); } //! Test if image width and depth are equal to specified values. /** Test if is_sameX(unsigned int) const and is_sameZ(unsigned int) const are both verified. **/ bool is_sameXZ(const unsigned int size_x, const unsigned int size_z) const { return _width==size_x && _depth==size_z; } //! Test if image width and depth are the same as that of another image. /** Test if is_sameX(const CImg&) const and is_sameZ(const CImg&) const are both verified. **/ template bool is_sameXZ(const CImg& img) const { return is_sameXZ(img._width,img._depth); } //! Test if image width and spectrum are equal to specified values. /** Test if is_sameX(unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameXC(const unsigned int size_x, const unsigned int size_c) const { return _width==size_x && _spectrum==size_c; } //! Test if image width and spectrum are the same as that of another image. /** Test if is_sameX(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameXC(const CImg& img) const { return is_sameXC(img._width,img._spectrum); } //! Test if image height and depth are equal to specified values. /** Test if is_sameY(unsigned int) const and is_sameZ(unsigned int) const are both verified. **/ bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const { return _height==size_y && _depth==size_z; } //! Test if image height and depth are the same as that of another image. /** Test if is_sameY(const CImg&) const and is_sameZ(const CImg&) const are both verified. **/ template bool is_sameYZ(const CImg& img) const { return is_sameYZ(img._height,img._depth); } //! Test if image height and spectrum are equal to specified values. /** Test if is_sameY(unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const { return _height==size_y && _spectrum==size_c; } //! Test if image height and spectrum are the same as that of another image. /** Test if is_sameY(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameYC(const CImg& img) const { return is_sameYC(img._height,img._spectrum); } //! Test if image depth and spectrum are equal to specified values. /** Test if is_sameZ(unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameZC(const unsigned int size_z, const unsigned int size_c) const { return _depth==size_z && _spectrum==size_c; } //! Test if image depth and spectrum are the same as that of another image. /** Test if is_sameZ(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameZC(const CImg& img) const { return is_sameZC(img._depth,img._spectrum); } //! Test if image width, height and depth are equal to specified values. /** Test if is_sameXY(unsigned int,unsigned int) const and is_sameZ(unsigned int) const are both verified. **/ bool is_sameXYZ(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z) const { return is_sameXY(size_x,size_y) && _depth==size_z; } //! Test if image width, height and depth are the same as that of another image. /** Test if is_sameXY(const CImg&) const and is_sameZ(const CImg&) const are both verified. **/ template bool is_sameXYZ(const CImg& img) const { return is_sameXYZ(img._width,img._height,img._depth); } //! Test if image width, height and spectrum are equal to specified values. /** Test if is_sameXY(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const { return is_sameXY(size_x,size_y) && _spectrum==size_c; } //! Test if image width, height and spectrum are the same as that of another image. /** Test if is_sameXY(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameXYC(const CImg& img) const { return is_sameXYC(img._width,img._height,img._spectrum); } //! Test if image width, depth and spectrum are equal to specified values. /** Test if is_sameXZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const { return is_sameXZ(size_x,size_z) && _spectrum==size_c; } //! Test if image width, depth and spectrum are the same as that of another image. /** Test if is_sameXZ(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameXZC(const CImg& img) const { return is_sameXZC(img._width,img._depth,img._spectrum); } //! Test if image height, depth and spectrum are equal to specified values. /** Test if is_sameYZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const { return is_sameYZ(size_y,size_z) && _spectrum==size_c; } //! Test if image height, depth and spectrum are the same as that of another image. /** Test if is_sameYZ(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameYZC(const CImg& img) const { return is_sameYZC(img._height,img._depth,img._spectrum); } //! Test if image width, height, depth and spectrum are equal to specified values. /** Test if is_sameXYZ(unsigned int,unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. **/ bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const { return is_sameXYZ(size_x,size_y,size_z) && _spectrum==size_c; } //! Test if image width, height, depth and spectrum are the same as that of another image. /** Test if is_sameXYZ(const CImg&) const and is_sameC(const CImg&) const are both verified. **/ template bool is_sameXYZC(const CImg& img) const { return is_sameXYZC(img._width,img._height,img._depth,img._spectrum); } //! Test if specified coordinates are inside image bounds. /** Return \c true if pixel located at (\c x,\c y,\c z,\c c) is inside bounds of the image instance, and \c false otherwise. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note - Return \c true only if all these conditions are verified: - The image instance is \e not empty. - 0<=x<=\ref width() - 1. - 0<=y<=\ref height() - 1. - 0<=z<=\ref depth() - 1. - 0<=c<=\ref spectrum() - 1. **/ bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const { return !is_empty() && x>=0 && x=0 && y=0 && z=0 && c img(100,100,1,3); // Construct a 100x100 RGB color image. const unsigned long offset = 1249; // Offset to the pixel (49,12,0,0). unsigned int x,y,z,c; if (img.contains(img[offset],x,y,z,c)) { // Convert offset to (x,y,z,c) coordinates. std::printf("Offset %u refers to pixel located at (%u,%u,%u,%u).\n", offset,x,y,z,c); } \endcode **/ template bool contains(const T& pixel, t& x, t& y, t& z, t& c) const { const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum; const T *const ppixel = &pixel; if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; ulongT off = (ulongT)(ppixel - _data); const ulongT nc = off/whd; off%=whd; const ulongT nz = off/wh; off%=wh; const ulongT ny = off/_width, nx = off%_width; x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc; return true; } //! Test if pixel value is inside image bounds and get its X,Y and Z-coordinates. /** Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X,Y and Z-coordinates are set. **/ template bool contains(const T& pixel, t& x, t& y, t& z) const { const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum; const T *const ppixel = &pixel; if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; ulongT off = ((ulongT)(ppixel - _data))%whd; const ulongT nz = off/wh; off%=wh; const ulongT ny = off/_width, nx = off%_width; x = (t)nx; y = (t)ny; z = (t)nz; return true; } //! Test if pixel value is inside image bounds and get its X and Y-coordinates. /** Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X and Y-coordinates are set. **/ template bool contains(const T& pixel, t& x, t& y) const { const ulongT wh = (ulongT)_width*_height, siz = wh*_depth*_spectrum; const T *const ppixel = &pixel; if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; ulongT off = ((unsigned int)(ppixel - _data))%wh; const ulongT ny = off/_width, nx = off%_width; x = (t)nx; y = (t)ny; return true; } //! Test if pixel value is inside image bounds and get its X-coordinate. /** Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X-coordinate is set. **/ template bool contains(const T& pixel, t& x) const { const T *const ppixel = &pixel; if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false; x = (t)(((ulongT)(ppixel - _data))%_width); return true; } //! Test if pixel value is inside image bounds. /** Similar to contains(const T&,t&,t&,t&,t&) const, except that no pixel coordinates are set. **/ bool contains(const T& pixel) const { const T *const ppixel = &pixel; return !is_empty() && ppixel>=_data && ppixel<_data + size(); } //! Test if pixel buffers of instance and input images overlap. /** Return \c true, if pixel buffers attached to image instance and input image \c img overlap, and \c false otherwise. \param img Input image to compare with. \note - Buffer overlapping may happen when manipulating \e shared images. - If two image buffers overlap, operating on one of the image will probably modify the other one. - Most of the time, \c CImg instances are \e non-shared and do not overlap between each others. \par Example \code const CImg img1("reference.jpg"), // Load RGB-color image. img2 = img1.get_shared_channel(1); // Get shared version of the green channel. if (img1.is_overlapped(img2)) { // Test succeeds, 'img1' and 'img2' overlaps. std::printf("Buffers overlap!\n"); } \endcode **/ template bool is_overlapped(const CImg& img) const { const ulongT csiz = size(), isiz = img.size(); return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz)); } //! Test if the set {\c *this,\c primitives,\c colors,\c opacities} defines a valid 3d object. /** Return \c true is the 3d object represented by the set {\c *this,\c primitives,\c colors,\c opacities} defines a valid 3d object, and \c false otherwise. The vertex coordinates are defined by the instance image. \param primitives List of primitives of the 3d object. \param colors List of colors of the 3d object. \param opacities List (or image) of opacities of the 3d object. \param full_check Tells if full checking of the 3d object must be performed. \param[out] error_message C-string to contain the error message, if the test does not succeed. \note - Set \c full_checking to \c false to speed-up the 3d object checking. In this case, only the size of each 3d object component is checked. - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message. **/ template bool is_object3d(const CImgList& primitives, const CImgList& colors, const to& opacities, const bool full_check=true, char *const error_message=0) const { if (error_message) *error_message = 0; // Check consistency for the particular case of an empty 3d object. if (is_empty()) { if (primitives || colors || opacities) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines no vertices but %u primitives, " "%u colors and %lu opacities", _width,primitives._width,primitives._width, colors._width,(unsigned long)opacities.size()); return false; } return true; } // Check consistency of vertices. if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions. if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)", _width,primitives._width,_width,_height,_depth,_spectrum); return false; } if (colors._width>primitives._width + 1) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines %u colors", _width,primitives._width,colors._width); return false; } if (opacities.size()>primitives._width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines %lu opacities", _width,primitives._width,(unsigned long)opacities.size()); return false; } if (!full_check) return true; // Check consistency of primitives. cimglist_for(primitives,l) { const CImg& primitive = primitives[l]; const unsigned int psiz = primitive.size(); switch (psiz) { case 1 : { // Point. const unsigned int i0 = (unsigned int)primitive(0); if (i0>=_width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) refers to invalid vertex indice %u in " "point primitive [%u]", _width,primitives._width,i0,l); return false; } } break; case 5 : { // Sphere. const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1); if (i0>=_width || i1>=_width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " "sphere primitive [%u]", _width,primitives._width,i0,i1,l); return false; } } break; case 2 : // Segment. case 6 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1); if (i0>=_width || i1>=_width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " "segment primitive [%u]", _width,primitives._width,i0,i1,l); return false; } } break; case 3 : // Triangle. case 9 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2); if (i0>=_width || i1>=_width || i2>=_width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " "triangle primitive [%u]", _width,primitives._width,i0,i1,i2,l); return false; } } break; case 4 : // Quadrangle. case 12 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2), i3 = (unsigned int)primitive(3); if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " "quadrangle primitive [%u]", _width,primitives._width,i0,i1,i2,i3,l); return false; } } break; default : if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines an invalid primitive [%u] of size %u", _width,primitives._width,l,(unsigned int)psiz); return false; } } // Check consistency of colors. cimglist_for(colors,c) { const CImg& color = colors[c]; if (!color) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines no color for primitive [%u]", _width,primitives._width,c); return false; } } // Check consistency of light texture. if (colors._width>primitives._width) { const CImg &light = colors.back(); if (!light || light._depth>1) { if (error_message) cimg_sprintf(error_message, "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)", _width,primitives._width,light._width, light._height,light._depth,light._spectrum); return false; } } return true; } //! Test if image instance represents a valid serialization of a 3d object. /** Return \c true if the image instance represents a valid serialization of a 3d object, and \c false otherwise. \param full_check Tells if full checking of the instance must be performed. \param[out] error_message C-string to contain the error message, if the test does not succeed. \note - Set \c full_check to \c false to speed-up the 3d object checking. In this case, only the size of each 3d object component is checked. - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message. **/ bool is_CImg3d(const bool full_check=true, char *const error_message=0) const { if (error_message) *error_message = 0; // Check instance dimension and header. if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) { if (error_message) cimg_sprintf(error_message, "CImg3d has invalid dimensions (%u,%u,%u,%u)", _width,_height,_depth,_spectrum); return false; } const T *ptrs = _data, *const ptre = end(); if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') || !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) { if (error_message) cimg_sprintf(error_message, "CImg3d header not found"); return false; } const unsigned int nb_points = cimg::float2uint((float)*(ptrs++)), nb_primitives = cimg::float2uint((float)*(ptrs++)); // Check consistency of number of vertices / primitives. if (!full_check) { const ulongT minimal_size = 8UL + 3*nb_points + 6*nb_primitives; if (_data + minimal_size>ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected", nb_points,nb_primitives,size(),minimal_size); return false; } } // Check consistency of vertex data. if (!nb_points) { if (nb_primitives) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines no vertices but %u primitives", nb_points,nb_primitives,nb_primitives); return false; } if (ptrs!=ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) is an empty object but contains %u value%s " "more than expected", nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); return false; } return true; } if (ptrs + 3*nb_points>ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines only %u vertices data", nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3); return false; } ptrs+=3*nb_points; // Check consistency of primitive data. if (ptrs==ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines %u vertices but no primitive", nb_points,nb_primitives,nb_points); return false; } if (!full_check) return true; for (unsigned int p = 0; p=nb_points) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]", nb_points,nb_primitives,i0,p); return false; } } break; case 5 : { // Sphere. const unsigned int i0 = cimg::float2uint((float)*(ptrs++)), i1 = cimg::float2uint((float)*(ptrs++)); ptrs+=3; if (i0>=nb_points || i1>=nb_points) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " "sphere primitive [%u]", nb_points,nb_primitives,i0,i1,p); return false; } } break; case 2 : case 6 : { // Segment. const unsigned int i0 = cimg::float2uint((float)*(ptrs++)), i1 = cimg::float2uint((float)*(ptrs++)); if (nb_inds==6) ptrs+=4; if (i0>=nb_points || i1>=nb_points) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " "segment primitive [%u]", nb_points,nb_primitives,i0,i1,p); return false; } } break; case 3 : case 9 : { // Triangle. const unsigned int i0 = cimg::float2uint((float)*(ptrs++)), i1 = cimg::float2uint((float)*(ptrs++)), i2 = cimg::float2uint((float)*(ptrs++)); if (nb_inds==9) ptrs+=6; if (i0>=nb_points || i1>=nb_points || i2>=nb_points) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " "triangle primitive [%u]", nb_points,nb_primitives,i0,i1,i2,p); return false; } } break; case 4 : case 12 : { // Quadrangle. const unsigned int i0 = cimg::float2uint((float)*(ptrs++)), i1 = cimg::float2uint((float)*(ptrs++)), i2 = cimg::float2uint((float)*(ptrs++)), i3 = cimg::float2uint((float)*(ptrs++)); if (nb_inds==12) ptrs+=8; if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " "quadrangle primitive [%u]", nb_points,nb_primitives,i0,i1,i2,i3,p); return false; } } break; default : if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u", nb_points,nb_primitives,p,nb_inds); return false; } if (ptrs>ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], " "%u values missing", nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre)); return false; } } // Check consistency of color data. if (ptrs==ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines no color/texture data", nb_points,nb_primitives); return false; } for (unsigned int c = 0; c=c) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u " "for primitive [%u]", nb_points,nb_primitives,w,c); return false; } } else ptrs+=w*h*s; } if (ptrs>ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], " "%u values missing", nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre)); return false; } } // Check consistency of opacity data. if (ptrs==ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) defines no opacity data", nb_points,nb_primitives); return false; } for (unsigned int o = 0; o=o) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) refers to invalid shared opacity indice %u " "for primitive [%u]", nb_points,nb_primitives,w,o); return false; } } else ptrs+=w*h*s; } if (ptrs>ptre) { if (error_message) cimg_sprintf(error_message, "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]", nb_points,nb_primitives,o); return false; } } // Check end of data. if (ptrs1?"s":""); return false; } return true; } static bool _is_CImg3d(const T val, const char c) { return val>=(T)c && val<(T)(c + 1); } //@} //------------------------------------- // //! \name Mathematical Functions //@{ //------------------------------------- // Define the math formula parser/compiler and expression evaluator. struct _cimg_math_parser { CImg mem; CImg memtype; CImgList _code, &code; CImg opcode; const CImg *p_code_begin, *p_code_end, *p_code; CImg expr, pexpr; const CImg& imgin; const CImgList& listin; CImg &imgout; CImgList& listout; CImg _img_stats, &img_stats; CImgList _list_stats, &list_stats, _list_median, &list_median; CImg mem_img_stats; CImg level, variable_pos, reserved_label; CImgList variable_def, function_def, function_body; char *user_function; unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim; bool is_parallelizable, need_input_copy; double *result; const char *const calling_function, *s_op, *ss_op; typedef double (*mp_func)(_cimg_math_parser&); #define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant? #define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar? #define _cimg_mp_is_temp(arg) (!memtype[arg]) // Is temporary scalar? #define _cimg_mp_is_variable(arg) (memtype[arg]==-1) // Is scalar variable? #define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector? #define _cimg_mp_vector_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Vector size #define _cimg_mp_calling_function calling_function_s()._data #define _cimg_mp_op(s) s_op = s; ss_op = ss #define _cimg_mp_check_type(arg,n_arg,mode,N) check_type(arg,n_arg,mode,N,ss,se,saved_char) #define _cimg_mp_check_constant(arg,n_arg,is_strict) check_constant(arg,n_arg,is_strict,ss,se,saved_char) #define _cimg_mp_check_matrix_square(arg,n_arg) check_matrix_square(arg,n_arg,ss,se,saved_char) #define _cimg_mp_check_vector0(dim) check_vector0(dim,ss,se,saved_char) #define _cimg_mp_check_list(is_out) check_list(is_out,ss,se,saved_char) #define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp) #define _cimg_mp_return(x) { *se = saved_char; s_op = previous_s_op; ss_op = previous_ss_op; return x; } #define _cimg_mp_constant(val) _cimg_mp_return(constant((double)(val))) #define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op)) #define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1)) #define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2)) #define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3)) #define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6)) #define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7)) #define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1)) #define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2)) #define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2)) #define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2)) #define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3)) // Constructors. _cimg_math_parser(const char *const expression, const char *const funcname=0, const CImg& img_input=CImg::const_empty(), CImg *const img_output=0, const CImgList *const list_input=0, CImgList *const list_output=0): code(_code),imgin(img_input),listin(list_input?*list_input:CImgList::const_empty()), imgout(img_output?*img_output:CImg::empty()),listout(list_output?*list_output:CImgList::empty()), img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_function(0), mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),is_parallelizable(true), need_input_copy(false),calling_function(funcname?funcname:"cimg_math_parser") { if (!expression || !*expression) throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Empty expression.", pixel_type(),_cimg_mp_calling_function); const char *_expression = expression; while (*_expression && (*_expression<=' ' || *_expression==';')) ++_expression; CImg::string(_expression).move_to(expr); char *ps = &expr.back() - 1; while (ps>expr._data && (*ps==' ' || *ps==';')) --ps; *(++ps) = 0; expr._width = (unsigned int)(ps - expr._data + 1); // Ease the retrieval of previous non-space characters afterwards. pexpr.assign(expr._width); char c, *pe = pexpr._data; for (ps = expr._data, c = ' '; *ps; ++ps) { if (*ps!=' ') c = *ps; *(pe++) = c; } *pe = 0; // Count parentheses/brackets level of expression. level.assign(expr._width - 1); int lv = 0; unsigned int *pd = level._data; for (ps = expr._data; *ps && lv>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv); if (lv!=0) { cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.", pixel_type(),_cimg_mp_calling_function, expr._data); } // Init constant values. mem.assign(96); memtype.assign(96); double *p_mem = mem._data; for (unsigned int i = 0; i<=10; ++i) *(p_mem++) = (double)i; // mem[0-10] for (unsigned int i = 1; i<=5; ++i) *(p_mem++) = -(double)i; // mem[11-15] *(p_mem++) = 0.5; // mem[16] *(p_mem++) = 0; // mem[17] = thread_id *(p_mem++) = (double)imgin._width; // mem[18] *(p_mem++) = (double)imgin._height; // mem[19] *(p_mem++) = (double)imgin._depth; // mem[20] *(p_mem++) = (double)imgin._spectrum; // mem[21] *(p_mem++) = (double)imgin._is_shared; // mem[22] *(p_mem++) = (double)imgin._width*imgin._height; // mem[23] *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth; // mem[24] *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // mem[25] *(p_mem++) = cimg::PI; // mem[26] *(p_mem++) = std::exp(1.0); // mem[27] *(p_mem++) = cimg::type::nan(); // mem[28] // Then, [29] = x, [30] = y, [31] = z and [32] = c. #define _cimg_mp_x 29 #define _cimg_mp_y 30 #define _cimg_mp_z 31 #define _cimg_mp_c 32 // Set value property : // { -1 = variable | 0 = regular value | 1 = compile time constant | N>1 = constant ptr to vector[N-1] }. std::memset(memtype._data,0,sizeof(int)*memtype._width); int *p_memtype = memtype._data; for (unsigned int i = 0; i<_cimg_mp_x; ++i) *(p_memtype++) = 1; memtype[17] = 0; mempos = _cimg_mp_c + 1; variable_pos.assign(8); reserved_label.assign(128,1,1,1,~0U); reserved_label['t'] = 17; reserved_label['w'] = 18; reserved_label['h'] = 19; reserved_label['d'] = 20; reserved_label['s'] = 21; reserved_label['r'] = 22; reserved_label[0] = 23; // wh reserved_label[1] = 24; // whd reserved_label[2] = 25; // whds reserved_label[3] = 26; // pi reserved_label['e'] = 27; reserved_label[29] = 0; // interpolation reserved_label[30] = 0; // boundary reserved_label['x'] = _cimg_mp_x; reserved_label['y'] = _cimg_mp_y; reserved_label['z'] = _cimg_mp_z; reserved_label['c'] = _cimg_mp_c; // reserved_label[4-28] store also two-char variables: // [4] = im, [5] = iM, [6] = ia, [7] = iv, [8] = is, [9] = ip, [10] = ic, // [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM, [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9, // Compile expression into a serie of opcodes. s_op = ""; ss_op = expr._data; const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0); p_code_end = code.end(); // Free resources used for parsing and prepare for evaluation. if (_cimg_mp_is_vector(ind_result)) result_dim = _cimg_mp_vector_size(ind_result); mem.resize(mempos,1,1,1,-1); result = mem._data + ind_result; memtype.assign(); level.assign(); variable_pos.assign(); reserved_label.assign(); expr.assign(); pexpr.assign(); opcode.assign(); opcode._width = opcode._depth = opcode._spectrum = 1; opcode._is_shared = true; // Execute init() function if any specified. p_code_begin = code._data + init_size; if (init_size) { mem[_cimg_mp_x] = mem[_cimg_mp_y] = mem[_cimg_mp_z] = mem[_cimg_mp_c] = 0; for (p_code = code._data; p_code &op = *p_code; opcode._data = op._data; opcode._height = op._height; const ulongT target = opcode[1]; mem[target] = _cimg_mp_defunc(*this); } } } _cimg_math_parser(): code(_code),p_code_begin(0),p_code_end(0), imgin(CImg::const_empty()),listin(CImgList::const_empty()), imgout(CImg::empty()),listout(CImgList::empty()), img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0), result_dim(0),is_parallelizable(true),need_input_copy(false),calling_function(0) { mem.assign(1 + _cimg_mp_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()() result = mem._data; } _cimg_math_parser(const _cimg_math_parser& mp): mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end), imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats), list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim), is_parallelizable(mp.is_parallelizable), need_input_copy(mp.need_input_copy), result(mem._data + (mp.result - mp.mem._data)),calling_function(0) { #ifdef cimg_use_openmp mem[17] = omp_get_thread_num(); #endif opcode._width = opcode._depth = opcode._spectrum = 1; opcode._is_shared = true; } // Compilation procedure. unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref) { if (depth>256) { cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Call stack overflow (infinite recursion?), " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } const char *const ss0 = ss; char c1, c2, c3, c4; if (ssss && (c1=*(se - 1))>0 && (c1<=' ' || c1==';')) --se; } if (se>ss && *(se - 1)==';') --se; while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Detect simple content around parentheses. ++ss; --se; } if (se<=ss || !*ss) { cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s%s Missing %s, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", *s_op=='F'?"argument":"item", (ss_op - 4)>expr._data?"...":"", (ss_op - 4)>expr._data?ss_op - 4:expr._data, ss_op + std::strlen(ss_op)<&expr.back()?"...":""); } const char *const previous_s_op = s_op, *const previous_ss_op = ss_op; const unsigned int depth1 = depth + 1; unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6; char *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4, *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8, *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0; double val, val1, val2; mp_func op; // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value // linked to the returned memory slot (reference that cannot be determined at compile time). // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) | // 3 = image value (coordinates) | 4 = image value as a vector (offsets) | // 5 = image value as a vector (coordinates) }. // Depending on p_ref[0], the remaining p_ref[k] have the following meaning: // When p_ref[0]==0, p_ref is actually unlinked. // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ]. // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ]. // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ]. // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ]. // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ]. if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; } const char saved_char = *se; *se = 0; const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1; bool is_sth, is_relative; CImg ref; CImgList _opcode; CImg variable_name; // Look for a single value or a pre-defined variable. int nb = cimg_sscanf(ss,"%lf%c%c",&val,&(sep=0),&(end=0)); #if cimg_OS==2 // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able // to read those particular values. if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) { is_sth = true; s = ss; if (*s=='+') ++s; else if (*s=='-') { ++s; is_sth = false; } if (!cimg::strcasecmp(s,"inf")) { val = cimg::type::inf(); nb = 1; } else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type::nan(); nb = 1; } if (nb==1 && !is_sth) val = -val; } #endif if (nb==1) _cimg_mp_constant(val); if (nb==2 && sep=='%') _cimg_mp_constant(val/100); if (ss1==se) switch (*ss) { // One-char variable case 't' : case 'w' : case 'h' : case 'd' : case 's' : case 'r' : case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : _cimg_mp_return(reserved_label[*ss]); case 'u' : if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']); _cimg_mp_scalar2(mp_u,0,1); case 'g' : if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']); _cimg_mp_scalar0(mp_g); case 'i' : if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']); _cimg_mp_scalar0(mp_i); case 'I' : _cimg_mp_op("Variable 'I'"); if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']); _cimg_mp_check_vector0(imgin._spectrum); need_input_copy = true; pos = vector(imgin._spectrum); CImg::vector((ulongT)mp_Joff,pos,0,0).move_to(code); _cimg_mp_return(pos); case 'R' : if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']); need_input_copy = true; _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,0,0); case 'G' : if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']); need_input_copy = true; _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,0,0); case 'B' : if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']); need_input_copy = true; _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,0,0); case 'A' : if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']); need_input_copy = true; _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,0,0); } else if (ss2==se) { // Two-chars variable arg1 = arg2 = ~0U; if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi if (*ss=='i') { if (*ss1>='0' && *ss1<='9') { // i0...i9 pos = 19 + *ss1 - '0'; if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]); need_input_copy = true; _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,pos - 19,0,0); } switch (*ss1) { case 'm' : arg1 = 4; arg2 = 0; break; // im case 'M' : arg1 = 5; arg2 = 1; break; // iM case 'a' : arg1 = 6; arg2 = 2; break; // ia case 'v' : arg1 = 7; arg2 = 3; break; // iv case 's' : arg1 = 8; arg2 = 12; break; // is case 'p' : arg1 = 9; arg2 = 13; break; // is case 'c' : // ic if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]); if (mem_img_median==~0U) mem_img_median = imgin?constant(imgin.median()):0; _cimg_mp_return(mem_img_median); break; } } else if (*ss1=='m') switch (*ss) { case 'x' : arg1 = 11; arg2 = 4; break; // xm case 'y' : arg1 = 12; arg2 = 5; break; // ym case 'z' : arg1 = 13; arg2 = 6; break; // zm case 'c' : arg1 = 14; arg2 = 7; break; // cm } else if (*ss1=='M') switch (*ss) { case 'x' : arg1 = 15; arg2 = 8; break; // xM case 'y' : arg1 = 16; arg2 = 9; break; // yM case 'z' : arg1 = 17; arg2 = 10; break; // zM case 'c' : arg1 = 18; arg2 = 11; break; // cM } if (arg1!=~0U) { if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]); if (!img_stats) { img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false); mem_img_stats.assign(1,14,1,1,~0U); } if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = constant(img_stats[arg2]); _cimg_mp_return(mem_img_stats[arg2]); } } else if (ss3==se) { // Three-chars variable if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd } else if (ss4==se) { // Four-chars variable if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds } pos = ~0U; for (s0 = ss, s = ss1; s='i'?1:3,p2); if (p_ref) { *p_ref = _cimg_mp_is_vector(arg2)?4:2; p_ref[1] = p1; p_ref[2] = (unsigned int)is_relative; p_ref[3] = arg1; if (_cimg_mp_is_vector(arg2)) set_variable_vector(arg2); // Prevent from being used in further optimization else if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; } if (p1!=~0U) { if (!listout) _cimg_mp_return(arg2); if (*ss>='i') CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), arg2,p1,arg1).move_to(code); else if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), arg2,p1,arg1).move_to(code); else CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), arg2,p1,arg1).move_to(code); } else { if (!imgout) _cimg_mp_return(arg2); if (*ss>='i') CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), arg2,arg1).move_to(code); if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), arg2,arg1).move_to(code); else CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), arg2,arg1).move_to(code); } _cimg_mp_return(arg2); } if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value is_parallelizable = false; if (*ss2=='#') { // Index specified s0 = ss3; while (s01) { arg2 = arg1 + 1; if (p2>2) { arg3 = arg2 + 1; if (p2>3) arg4 = arg3 + 1; } } } else if (s1='i'?1:3,p2); if (p_ref) { *p_ref = _cimg_mp_is_vector(arg5)?5:3; p_ref[1] = p1; p_ref[2] = (unsigned int)is_relative; p_ref[3] = arg1; p_ref[4] = arg2; p_ref[5] = arg3; p_ref[6] = arg4; if (_cimg_mp_is_vector(arg5)) set_variable_vector(arg5); // Prevent from being used in further optimization else if (_cimg_mp_is_temp(arg5)) memtype[arg5] = -1; if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1; } if (p1!=~0U) { if (!listout) _cimg_mp_return(arg5); if (*ss>='i') CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), arg5,p1,arg1,arg2,arg3,arg4).move_to(code); else if (_cimg_mp_is_scalar(arg5)) CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), arg5,p1,arg1,arg2,arg3).move_to(code); else CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), arg5,p1,arg1,arg2,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg5); if (*ss>='i') CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), arg5,arg1,arg2,arg3,arg4).move_to(code); else if (_cimg_mp_is_scalar(arg5)) CImg::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), arg5,arg1,arg2,arg3).move_to(code); else CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), arg5,arg1,arg2,arg3).move_to(code); } _cimg_mp_return(arg5); } } // Assign vector value (direct). if (l_variable_name>3 && *ve1==']' && *ss!='[') { s0 = ve1; while (s0>ss && *s0!='[') --s0; is_sth = true; // is_valid_variable_name? if (*ss>='0' && *ss<='9') is_sth = false; else for (ns = ss; nsss) { variable_name[s0 - ss] = 0; // Remove brackets in variable name arg1 = ~0U; // Vector slot arg2 = compile(++s0,ve1,depth1,0); // Index arg3 = compile(s + 1,se,depth1,0); // Value to assign _cimg_mp_check_type(arg3,2,1,0); if (variable_name[1]) { // Multi-char variable cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; } } else arg1 = reserved_label[*variable_name]; // Single-char variable if (arg1==~0U) compile(ss,s0 - 1,depth1,0); // Variable does not exist -> error else { // Variable already exists if (_cimg_mp_is_scalar(arg1)) compile(ss,s,depth1,0); // Variable is not a vector -> error if (_cimg_mp_is_constant(arg2)) { // Constant index -> return corresponding variable slot directly nb = (int)mem[arg2]; if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) { arg1+=nb + 1; CImg::vector((ulongT)mp_copy,arg1,arg3).move_to(code); _cimg_mp_return(arg1); } compile(ss,s,depth1,0); // Out-of-bounds reference -> error } // Case of non-constant index -> return assigned value + linked reference if (p_ref) { *p_ref = 1; p_ref[1] = arg1; p_ref[2] = arg2; if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; // Prevent from being used in further optimization if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; } CImg::vector((ulongT)mp_vector_set_off,arg3,arg1,_cimg_mp_vector_size(arg1),arg2,arg3). move_to(code); _cimg_mp_return(arg3); } } } // Assign user-defined macro. if (l_variable_name>2 && *ve1==')' && *ss!='(') { s0 = ve1; while (s0>ss && *s0!='(') --s0; is_sth = std::strncmp(variable_name,"debug(",6) && std::strncmp(variable_name,"print(",6); // is_valid_function_name? if (*ss>='0' && *ss<='9') is_sth = false; else for (ns = ss; nsss) { // Looks like a valid function declaration s0 = variable_name._data + (s0 - ss); *s0 = 0; s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis CImg(variable_name._data,(unsigned int)(s0 - variable_name._data + 1)).move_to(function_def,0); ++s; while (*s && *s<=' ') ++s; CImg(s,(unsigned int)(se - s + 1)).move_to(function_body,0); p1 = 1; // Indice of current parsed argument for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments if (p1>24) { *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Too much specified arguments (>24) when defining " "function '%s()', in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } while (*s && *s<=' ') ++s; if (*s==')' && p1==1) break; // Function has no arguments s2 = s; // Start of the argument name is_sth = true; // is_valid_argument_name? if (*s>='0' && *s<='9') is_sth = false; else for (ns = s; ns' '; ++ns) if (!is_varchar(*ns)) { is_sth = false; break; } s3 = ns; // End of the argument name while (*ns && *ns<=' ') ++ns; if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) { *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: %s name specified for argument %u when defining " "function '%s()', in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, is_sth?"Empty":"Invalid",p1, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } if (ns==s1 || *ns==',') { // New argument found *s3 = 0; p2 = (unsigned int)(s3 - s2); // Argument length p3 = function_body[0]._width - p2 + 1; // Related to copy length for (ps = std::strstr(function_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number if (!((ps>function_body[0]._data && is_varchar(*(ps - 1))) || (ps + p21) { std::memmove(ps,ps + p2 - 1,function_body[0]._data + p3 - ps); function_body[0]._width-=p2 - 1; } } else ++ps; } } } // Store number of arguments function_def[0].resize(function_def[0]._width + 1,1,1,1,0).back() = (char)(p1 - 1); _cimg_mp_return(28); } } // Check if the variable name could be valid. If not, this is probably an lvalue assignment. is_sth = true; // is_valid_variable_name? if (*variable_name>='0' && *variable_name<='9') is_sth = false; else for (ns = variable_name._data; *ns; ++ns) if (!is_varchar(*ns)) { is_sth = false; break; } // Assign variable (direct). if (is_sth) { if (variable_name[1] && !variable_name[2]) { // Two-chars variable c1 = variable_name[0]; c2 = variable_name[1]; if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi else if (c1=='i') { if (c2>='0' && c2<='9') variable_name.fill(19 + c2 - '0',0); // i0...i9 else if (c2=='m') variable_name.fill(4,0); // im else if (c2=='M') variable_name.fill(5,0); // iM else if (c2=='a') variable_name.fill(6,0); // ia else if (c2=='v') variable_name.fill(7,0); // iv else if (c2=='s') variable_name.fill(8,0); // is else if (c2=='p') variable_name.fill(9,0); // ip else if (c2=='c') variable_name.fill(10,0); // ic } else if (c2=='m') { if (c1=='x') variable_name.fill(11,0); // xm else if (c1=='y') variable_name.fill(12,0); // ym else if (c1=='z') variable_name.fill(13,0); // zm else if (c1=='c') variable_name.fill(14,0); // cm } else if (c2=='M') { if (c1=='x') variable_name.fill(15,0); // xM else if (c1=='y') variable_name.fill(16,0); // yM else if (c1=='z') variable_name.fill(17,0); // zM else if (c1=='c') variable_name.fill(18,0); // cM } } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable c1 = variable_name[0]; c2 = variable_name[1]; c3 = variable_name[2]; if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0); // whd } else if (variable_name[1] && variable_name[2] && variable_name[3] && !variable_name[4]) { // Four-chars variable c1 = variable_name[0]; c2 = variable_name[1]; c3 = variable_name[2]; c4 = variable_name[3]; if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0); // whds } else if (!std::strcmp(variable_name,"interpolation")) variable_name.fill(29,0); else if (!std::strcmp(variable_name,"boundary")) variable_name.fill(30,0); arg1 = ~0U; arg2 = compile(s + 1,se,depth1,0); if (!variable_name[1]) // One-char variable, or variable in reserved_labels arg1 = reserved_label[*variable_name]; else // Multi-char variable name : check for existing variable with same name cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; } if (arg1==~0U || arg1<=_cimg_mp_c) { // Create new variable if (_cimg_mp_is_vector(arg2)) { // Vector variable arg1 = vector_copy(arg2); set_variable_vector(arg1); } else { // Scalar variable arg1 = scalar1(mp_copy,arg2); memtype[arg1] = -1; } if (!variable_name[1]) reserved_label[*variable_name] = arg1; else { if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); variable_pos[variable_def._width] = arg1; variable_name.move_to(variable_def); } } else { // Variable already exists -> assign a new value _cimg_mp_check_type(arg2,2,_cimg_mp_is_vector(arg1)?3:1,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1)) { // Vector if (_cimg_mp_is_vector(arg2)) // From vector CImg::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_vector_size(arg1)). move_to(code); else // From scalar CImg::vector((ulongT)mp_vector_init,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2). move_to(code); } else // Scalar CImg::vector((ulongT)mp_copy,arg1,arg2).move_to(code); } _cimg_mp_return(arg1); } // Assign lvalue (variable name was not valid). is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator? if (is_sth) break; // Do nothing and make ternary operator prioritary over assignment if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) { ref.assign(7); arg1 = compile(ss,s,depth1,ref); // Lvalue slot arg2 = compile(s + 1,se,depth1,0); // Value to assign if (*ref==1) { // Vector value (scalar): V[k] = scalar _cimg_mp_check_type(arg2,2,1,0); arg3 = ref[1]; // Vector slot arg4 = ref[2]; // Index if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)mp_vector_set_off,arg2,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg2). move_to(code); _cimg_mp_return(arg2); } if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar _cimg_mp_check_type(arg2,2,1,0); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg2); CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), arg2,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg2); CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), arg2,arg3).move_to(code); } _cimg_mp_return(arg2); } if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar _cimg_mp_check_type(arg2,2,1,0); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z arg6 = ref[6]; // C if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg2); CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), arg2,p1,arg3,arg4,arg5,arg6).move_to(code); } else { if (!imgout) _cimg_mp_return(arg2); CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), arg2,arg3,arg4,arg5,arg6).move_to(code); } _cimg_mp_return(arg2); } if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg2); if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), arg2,p1,arg3).move_to(code); else CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), arg2,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg2); if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), arg2,arg3).move_to(code); else CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), arg2,arg3).move_to(code); } _cimg_mp_return(arg2); } if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg2); if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), arg2,p1,arg3,arg4,arg5).move_to(code); else CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), arg2,p1,arg3,arg4,arg5).move_to(code); } else { if (!imgout) _cimg_mp_return(arg2); if (_cimg_mp_is_scalar(arg2)) CImg::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), arg2,arg3,arg4,arg5).move_to(code); else CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), arg2,arg3,arg4,arg5).move_to(code); } _cimg_mp_return(arg2); } if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value _cimg_mp_check_type(arg2,2,1,0); if (_cimg_mp_is_vector(arg2)) // From vector CImg::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_vector_size(arg1)). move_to(code); else // From scalar CImg::vector((ulongT)mp_vector_init,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2). move_to(code); _cimg_mp_return(arg1); } if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar _cimg_mp_check_type(arg2,2,1,0); CImg::vector((ulongT)mp_copy,arg1,arg2).move_to(code); _cimg_mp_return(arg1); } } // No assignment expressions match -> error *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Invalid left-hand operand '%s', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } // Apply unary/binary/ternary operators. The operator precedences should be roughly the same as in C++. for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps && level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=) _cimg_mp_op(*ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='"); ref.assign(7); arg1 = compile(ss,ns,depth1,ref); // Vector slot arg2 = compile(s + 1,se,depth1,0); // Right operand if (*ps!='*') { _cimg_mp_check_type(arg1,2,2,2); _cimg_mp_check_type(arg2,2,2,2); } if (_cimg_mp_is_vector(arg2)) { // Complex **= complex or Matrix **= matrix if (*ps=='*') { if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) CImg::vector((ulongT)mp_complex_mul,arg1,arg1,arg2).move_to(code); else { _cimg_mp_check_matrix_square(arg2,2); p3 = _cimg_mp_vector_size(arg1); p2 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg2)); p1 = p3/p2; if (p1*p2!=p3) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Types of left-hand and right-hand operands " "('%s' and '%s') do not match, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(arg1)._data,s_type(arg2)._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } CImg::vector((ulongT)mp_matrix_mul,arg1,arg1,arg2,p1,p2,p2).move_to(code); } } else if (*ps=='/') CImg::vector((ulongT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code); else CImg::vector((ulongT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code); } else { // Complex **= scalar if (*ps=='*') self_vector_s(arg1,mp_self_mul,arg2); else if (*ps=='/') self_vector_s(arg1,mp_self_div,arg2); else CImg::vector((ulongT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code); } // Write computed value back in image if necessary. if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), arg1,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), arg1,arg3).move_to(code); } } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), arg1,p1,arg3,arg4,arg5).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), arg1,arg3,arg4,arg5).move_to(code); } } _cimg_mp_return(arg1); } for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || *ps=='%' || *ps=='&' || *ps=='^' || *ps=='|' || (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) && level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=) switch (*ps) { case '+' : op = mp_self_add; _cimg_mp_op("Operator '+='"); break; case '-' : op = mp_self_sub; _cimg_mp_op("Operator '-='"); break; case '*' : op = mp_self_mul; _cimg_mp_op("Operator '*='"); break; case '/' : op = mp_self_div; _cimg_mp_op("Operator '/='"); break; case '%' : op = mp_self_modulo; _cimg_mp_op("Operator '%='"); break; case '<' : op = mp_self_bitwise_left_shift; _cimg_mp_op("Operator '<<='"); break; case '>' : op = mp_self_bitwise_right_shift; _cimg_mp_op("Operator '>=='"); break; case '&' : op = mp_self_bitwise_and; _cimg_mp_op("Operator '&='"); break; case '|' : op = mp_self_bitwise_or; _cimg_mp_op("Operator '|='"); break; default : op = mp_self_pow; _cimg_mp_op("Operator '^='"); break; } s1 = *ps=='>' || *ps=='<'?ns:ps; ref.assign(7); arg1 = compile(ss,s1,depth1,ref); // Variable slot arg2 = compile(s + 1,se,depth1,0); // Value to apply if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary. if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); else arg1 = scalar1(mp_copy,arg1); } if (*ref==1) { // Vector value (scalar): V[k] += scalar _cimg_mp_check_type(arg2,2,1,0); arg3 = ref[1]; // Vector slot arg4 = ref[2]; // Index if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1,arg2).move_to(code); CImg::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg1). move_to(code); _cimg_mp_return(arg1); } if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar _cimg_mp_check_type(arg2,2,1,0); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1,arg2).move_to(code); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), arg1,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), arg1,arg3).move_to(code); } _cimg_mp_return(arg1); } if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar _cimg_mp_check_type(arg2,2,1,0); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z arg6 = ref[6]; // C if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1,arg2).move_to(code); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), arg1,p1,arg3,arg4,arg5,arg6).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), arg1,arg3,arg4,arg5,arg6).move_to(code); } _cimg_mp_return(arg1); } if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), arg1,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), arg1,arg3).move_to(code); } _cimg_mp_return(arg1); } if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) += value _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2); if (p1!=~0U) { if (!listout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), arg1,p1,arg3,arg4,arg5).move_to(code); } else { if (!imgout) _cimg_mp_return(arg1); CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), arg1,arg3,arg4,arg5).move_to(code); } _cimg_mp_return(arg1); } if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg2)) self_vector_v(arg1,op,arg2); // Vector += vector else self_vector_s(arg1,op,arg2); // Vector += scalar _cimg_mp_return(arg1); } if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar _cimg_mp_check_type(arg2,2,1,0); CImg::vector((ulongT)op,arg1,arg2).move_to(code); _cimg_mp_return(arg1); } variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0; *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Invalid left-hand operand '%s', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } for (s = ss1; s::vector((ulongT)mp_if,pos,arg1,arg2,arg3, p3 - p2,code._width - p3,arg4).move_to(code,p2); _cimg_mp_return(pos); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||') _cimg_mp_op("Operator '||'"); arg1 = compile(ss,s,depth1,0); p2 = code._width; arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg1,1,1,0); _cimg_mp_check_type(arg2,2,1,0); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] || mem[arg2]); pos = scalar(); CImg::vector((ulongT)mp_logical_or,pos,arg1,arg2,code._width - p2). move_to(code,p2); _cimg_mp_return(pos); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&') _cimg_mp_op("Operator '&&'"); arg1 = compile(ss,s,depth1,0); p2 = code._width; arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg1,1,1,0); _cimg_mp_check_type(arg2,2,1,0); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] && mem[arg2]); pos = scalar(); CImg::vector((ulongT)mp_logical_and,pos,arg1,arg2,code._width - p2). move_to(code,p2); _cimg_mp_return(pos); } for (s = se2; s>ss; --s) if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|') _cimg_mp_op("Operator '|'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant((ulongT)mem[arg1] | (ulongT)mem[arg2]); _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2); } for (s = se2; s>ss; --s) if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&') _cimg_mp_op("Operator '&'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant((ulongT)mem[arg1] & (ulongT)mem[arg2]); _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=') _cimg_mp_op("Operator '!='"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_neq,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_neq,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_neq,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]!=mem[arg2]); _cimg_mp_scalar2(mp_neq,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==') _cimg_mp_op("Operator '=='"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_eq,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_eq,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_eq,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]==mem[arg2]); _cimg_mp_scalar2(mp_eq,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=') _cimg_mp_op("Operator '<='"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<=mem[arg2]); _cimg_mp_scalar2(mp_lte,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=') _cimg_mp_op("Operator '>='"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>=mem[arg2]); _cimg_mp_scalar2(mp_gte,arg1,arg2); } for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps) if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<') _cimg_mp_op("Operator '<'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]ss; --s, --ns, --ps) if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>') _cimg_mp_op("Operator '>'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>mem[arg2]); _cimg_mp_scalar2(mp_gt,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<') _cimg_mp_op("Operator '<<'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant((longT)mem[arg1]<<(unsigned int)mem[arg2]); _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>') _cimg_mp_op("Operator '>>'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant((longT)mem[arg1]>>(unsigned int)mem[arg2]); _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2); } for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && level[s - expr._data]==clevel) { // Addition ('+') _cimg_mp_op("Operator '+'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] + mem[arg2]); if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1); if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2); _cimg_mp_scalar2(mp_add,arg1,arg2); } for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && level[s - expr._data]==clevel) { // Subtraction ('-') _cimg_mp_op("Operator '-'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_sub,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] - mem[arg2]); if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1); _cimg_mp_scalar2(mp_sub,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex/matrix multiplication ('**') _cimg_mp_op("Operator '**'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) { // Complex multiplication pos = vector(2); CImg::vector((ulongT)mp_complex_mul,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } else { // Matrix multiplication p1 = _cimg_mp_vector_size(arg1); p2 = _cimg_mp_vector_size(arg2); arg4 = p1/p2; if (arg4*p2!=p1) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Types of left-hand and right-hand operands " "('%s' and '%s') do not match, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(arg1)._data,s_type(arg2)._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } pos = vector(arg4); CImg::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,p2,1).move_to(code); _cimg_mp_return(pos); } } if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]); _cimg_mp_scalar2(mp_mul,arg1,arg2); } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//') _cimg_mp_op("Operator '//'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg1,1,3,2); _cimg_mp_check_type(arg2,2,3,2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { pos = vector(2); CImg::vector((ulongT)mp_complex_div_vv,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { pos = vector(2); CImg::vector((ulongT)mp_complex_div_sv,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]); _cimg_mp_scalar2(mp_div,arg1,arg2); } for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*') _cimg_mp_op("Operator '*'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]); _cimg_mp_scalar2(mp_mul,arg1,arg2); } for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/') _cimg_mp_op("Operator '/'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]); _cimg_mp_scalar2(mp_div,arg1,arg2); } for (s = se2, ns = se1; s>ss; --s, --ns) if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%') _cimg_mp_op("Operator '%'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(cimg::mod(mem[arg1],mem[arg2])); _cimg_mp_scalar2(mp_modulo,arg1,arg2); } if (se1>ss) { if (*ss=='+' && (*ss1!='+' || (ss2='0' && *ss2<='9'))) { // Unary plus ('+') _cimg_mp_op("Operator '+'"); _cimg_mp_return(compile(ss1,se,depth1,0)); } if (*ss=='-' && (*ss1!='-' || (ss2='0' && *ss2<='9'))) { // Unary minus ('-') _cimg_mp_op("Operator '-'"); arg1 = compile(ss1,se,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]); _cimg_mp_scalar1(mp_minus,arg1); } if (*ss=='!') { // Logical not ('!') _cimg_mp_op("Operator '!'"); arg1 = compile(ss1,se,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]); _cimg_mp_scalar1(mp_logical_not,arg1); } if (*ss=='~') { // Bitwise not ('~') _cimg_mp_op("Operator '~'"); arg1 = compile(ss1,se,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(ulongT)mem[arg1]); _cimg_mp_scalar1(mp_bitwise_not,arg1); } } for (s = se3, ns = se2; s>ss; --s, --ns) if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^') _cimg_mp_op("Operator '^^'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 2,se,depth1,0); _cimg_mp_check_type(arg1,1,3,2); _cimg_mp_check_type(arg2,2,3,2); pos = (_cimg_mp_is_vector(arg1) || _cimg_mp_is_vector(arg2))?vector(2):0; if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { CImg::vector((ulongT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) { CImg::vector((ulongT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { CImg::vector((ulongT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(std::pow(mem[arg1],mem[arg2])); switch (arg2) { case 0 : _cimg_mp_return(1); case 1 : _cimg_mp_return(arg1); case 2 : _cimg_mp_scalar1(mp_sqr,arg1); case 3 : _cimg_mp_scalar1(mp_pow3,arg1); case 4 : _cimg_mp_scalar1(mp_pow4,arg1); default : _cimg_mp_scalar2(mp_pow,arg1,arg2); } } for (s = se2; s>ss; --s) if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^') _cimg_mp_op("Operator '^'"); arg1 = compile(ss,s,depth1,0); arg2 = compile(s + 1,se,depth1,0); _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1)); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2); if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2); if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2); if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(std::pow(mem[arg1],mem[arg2])); switch (arg2) { case 0 : _cimg_mp_return(1); case 1 : _cimg_mp_return(arg1); case 2 : _cimg_mp_scalar1(mp_sqr,arg1); case 3 : _cimg_mp_scalar1(mp_pow3,arg1); case 4 : _cimg_mp_scalar1(mp_pow4,arg1); default : _cimg_mp_scalar2(mp_pow,arg1,arg2); } } is_sth = ss1ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { // Pre/post-decrement and increment if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) { _cimg_mp_op("Operator '++'"); op = mp_self_increment; } else { _cimg_mp_op("Operator '--'"); op = mp_self_decrement; } ref.assign(7); arg1 = is_sth?compile(ss2,se,depth1,ref):compile(ss,se2,depth1,ref); // Variable slot if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary. if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); else arg1 = scalar1(mp_copy,arg1); } if (is_sth) pos = arg1; // Determine return indice, depending on pre/post action else { if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1); else pos = scalar1(mp_copy,arg1); } if (*ref==1) { // Vector value (scalar): V[k]++ arg3 = ref[1]; // Vector slot arg4 = ref[2]; // Index if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1,1).move_to(code); CImg::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_vector_size(arg3),arg4,arg1). move_to(code); _cimg_mp_return(pos); } if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++ is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1).move_to(code); if (p1!=~0U) { if (!listout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), arg1,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), arg1,arg3).move_to(code); } _cimg_mp_return(pos); } if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++ is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z arg6 = ref[6]; // C if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); CImg::vector((ulongT)op,arg1).move_to(code); if (p1!=~0U) { if (!listout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), arg1,p1,arg3,arg4,arg5,arg6).move_to(code); } else { if (!imgout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), arg1,arg3,arg4,arg5,arg6).move_to(code); } _cimg_mp_return(pos); } if (*ref==4) { // Image value (vector): I/J[_#ind,off]++ is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // Offset if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); if (p1!=~0U) { if (!listout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), arg1,p1,arg3).move_to(code); } else { if (!imgout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), arg1,arg3).move_to(code); } _cimg_mp_return(pos); } if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++ is_parallelizable = false; p1 = ref[1]; // Index is_relative = (bool)ref[2]; arg3 = ref[3]; // X arg4 = ref[4]; // Y arg5 = ref[5]; // Z if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); if (p1!=~0U) { if (!listout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), arg1,p1,arg3,arg4,arg5).move_to(code); } else { if (!imgout) _cimg_mp_return(pos); CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), arg1,arg3,arg4,arg5).move_to(code); } _cimg_mp_return(pos); } if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++ self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); _cimg_mp_return(pos); } if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s++ CImg::vector((ulongT)op,arg1).move_to(code); _cimg_mp_return(pos); } if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1)); else variable_name.assign(ss,(unsigned int)(se1 - ss)); variable_name.back() = 0; *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Invalid operand '%s', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } // Array-like access to vectors and image values 'i/j[_#ind,offset,_boundary]' and 'vector[offset]'. if (*se1==']' && *ss!='[') { _cimg_mp_op("Operator '[]'"); is_relative = *ss=='j' || *ss=='J'; if ((*ss=='I' || *ss=='J') && *ss1=='[' && (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector if (*ss2=='#') { // Index specified s0 = ss3; while (s0::vector((ulongT)(is_relative?mp_list_Joff:mp_list_Ioff), pos,p1,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code); } else { need_input_copy = true; CImg::vector((ulongT)(is_relative?mp_Joff:mp_Ioff), pos,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code); } _cimg_mp_return(pos); } if ((*ss=='i' || *ss=='j') && *ss1=='[' && (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a scalar if (*ss2=='#') { // Index specified s0 = ss3; while (s0ss && *s0!='[') --s0; if (s0>ss) { // Vector value arg1 = compile(ss,s0,depth1,0); s1 = s0 + 1; while (s1 sub-vector extraction arg2 = compile(++s0,s1,depth1,0); arg3 = compile(++s1,se1,depth1,0); _cimg_mp_check_constant(arg2,1,false); _cimg_mp_check_constant(arg3,2,false); p1 = (unsigned int)mem[arg2]; p2 = (unsigned int)mem[arg3]; p3 = _cimg_mp_vector_size(arg1); if (p1>=p3 || p2>=p3) { variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Out-of-bounds request for sub-vector '%s[%d,%d]' " "(vector '%s' has dimension %u), " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data,(int)mem[arg2],(int)mem[arg3], variable_name._data,p3, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } if (p1>p2) cimg::swap(p1,p2); (p2-=p1)++; pos = vector(p2); CImg::vector((ulongT)mp_vector_crop,pos,arg1,p1,p2).move_to(code); _cimg_mp_return(pos); } // One argument -> vector value reference if (_cimg_mp_is_scalar(arg1)) { variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } arg2 = compile(++s0,se1,depth1,0); if (_cimg_mp_is_constant(arg2)) { // Constant index nb = (int)mem[arg2]; if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) _cimg_mp_return(arg1 + 1 + nb); variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Out-of-bounds reference '%s[%d]' " "(vector '%s' has dimension %u), " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function, variable_name._data,nb, variable_name._data,_cimg_mp_vector_size(arg1), (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } if (p_ref) { *p_ref = 1; p_ref[1] = arg1; p_ref[2] = arg2; if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; // Prevent from being used in further optimization } _cimg_mp_scalar3(mp_vector_off,arg1,(ulongT)_cimg_mp_vector_size(arg1),arg2); } } // Look for a function call, an access to image value, or a parenthesis. if (*se1==')') { if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses is_relative = *ss=='j' || *ss=='J'; _cimg_mp_op("Operator '()'"); // I/J(_#ind,_x,_y,_z,_interpolation,_boundary) if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar if (*ss2=='#') { // Index specified s0 = ss3; while (s01) { arg2 = arg1 + 1; if (p2>2) arg3 = arg2 + 1; } if (s1::vector((ulongT)(is_relative?mp_list_Jxyz:mp_list_Ixyz), pos,p1,arg1,arg2,arg3, arg4==~0U?reserved_label[29]:arg4, arg5==~0U?reserved_label[30]:arg5).move_to(code); else { need_input_copy = true; CImg::vector((ulongT)(is_relative?mp_Jxyz:mp_Ixyz), pos,arg1,arg2,arg3, arg4==~0U?reserved_label[29]:arg4, arg5==~0U?reserved_label[30]:arg5).move_to(code); } _cimg_mp_return(pos); } // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary) if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar if (*ss2=='#') { // Index specified s0 = ss3; while (s01) { arg2 = arg1 + 1; if (p2>2) { arg3 = arg2 + 1; if (p2>3) arg4 = arg3 + 1; } } if (s1::vector((ulongT)mp_complex_conj,pos,arg1).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential _cimg_mp_op("Function 'cexp()'"); arg1 = compile(ss5,se1,depth1,0); _cimg_mp_check_type(arg1,0,2,2); pos = vector(2); CImg::vector((ulongT)mp_complex_exp,pos,arg1).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm _cimg_mp_op("Function 'clog()'"); arg1 = compile(ss5,se1,depth1,0); _cimg_mp_check_type(arg1,0,2,2); pos = vector(2); CImg::vector((ulongT)mp_complex_log,pos,arg1).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"copy(",5)) { // Memory copy _cimg_mp_op("Function 'copy()'"); ref.assign(14); s1 = ss5; while (s1(1,21).move_to(code); code.back().get_shared_rows(0,6).fill((ulongT)mp_memcopy,p1,arg1,arg2,arg3,arg4,arg5); code.back().get_shared_rows(7,20).fill(ref); _cimg_mp_return(p1); } if (!std::strncmp(ss,"cos(",4)) { // Cosine _cimg_mp_op("Function 'cos()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1])); _cimg_mp_scalar1(mp_cos,arg1); } if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine _cimg_mp_op("Function 'cosh()'"); arg1 = compile(ss5,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1])); _cimg_mp_scalar1(mp_cosh,arg1); } if (!std::strncmp(ss,"crop(",5)) { // Image crop _cimg_mp_op("Function 'crop()'"); if (*ss5=='#') { // Index specified s0 = ss6; while (s0::sequence((ulongT)_cimg_mp_vector_size(arg1),arg1 + 1, arg1 + (ulongT)_cimg_mp_vector_size(arg1)); opcode.resize(1,cimg::min(opcode._height,4U),1,1,0).move_to(_opcode); is_sth = true; } else { _cimg_mp_check_type(arg1,pos + 1,1,0); CImg::vector(arg1).move_to(_opcode); } s = ns; } (_opcode>'y').move_to(opcode); arg1 = 0; arg2 = p1!=~0U?1:0; switch (opcode._height) { case 0 : case 1 : CImg::vector(0,0,0,0,~0U,~0U,~0U,~0U,0).move_to(opcode); break; case 2 : CImg::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,reserved_label[30]).move_to(opcode); arg1 = arg2?3:2; break; case 3 : CImg::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,opcode[2]).move_to(opcode); arg1 = arg2?3:2; break; case 4 : CImg::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,reserved_label[30]). move_to(opcode); arg1 = (is_sth?2:1) + arg2; break; case 5 : CImg::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,opcode[4]). move_to(opcode); arg1 = (is_sth?2:1) + arg2; break; case 6 : CImg::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U, reserved_label[30]).move_to(opcode); arg1 = (is_sth?2:4) + arg2; break; case 7 : CImg::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U, opcode[6]).move_to(opcode); arg1 = (is_sth?2:4) + arg2; break; case 8 : CImg::vector(*opcode,opcode[1],opcode[2],opcode[3],opcode[4],opcode[5],opcode[6], opcode[7],reserved_label[30]).move_to(opcode); arg1 = (is_sth?2:5) + arg2; break; case 9 : arg1 = (is_sth?2:5) + arg2; break; default : // Error -> too much arguments throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Too much arguments specified, " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } _cimg_mp_check_type(*opcode,arg2 + 1,1,0); _cimg_mp_check_type(opcode[1],arg2 + (is_sth?0:1),1,0); _cimg_mp_check_type(opcode[2],arg2 + (is_sth?0:2),1,0); _cimg_mp_check_type(opcode[3],arg2 + (is_sth?0:3),1,0); if (opcode[4]!=(ulongT)~0U) { _cimg_mp_check_constant(opcode[4],arg1,true); opcode[4] = (ulongT)mem[opcode[4]]; } if (opcode[5]!=(ulongT)~0U) { _cimg_mp_check_constant(opcode[5],arg1 + 1,true); opcode[5] = (ulongT)mem[opcode[5]]; } if (opcode[6]!=(ulongT)~0U) { _cimg_mp_check_constant(opcode[6],arg1 + 2,true); opcode[6] = (ulongT)mem[opcode[6]]; } if (opcode[7]!=(ulongT)~0U) { _cimg_mp_check_constant(opcode[7],arg1 + 3,true); opcode[7] = (ulongT)mem[opcode[7]]; } _cimg_mp_check_type(opcode[8],arg1 + 4,1,0); if (opcode[4]==(ulongT)~0U || opcode[5]==(ulongT)~0U || opcode[6]==(ulongT)~0U || opcode[7]==(ulongT)~0U) { if (p1!=~0U) { _cimg_mp_check_constant(p1,1,false); p1 = (unsigned int)cimg::mod((int)mem[p1],listin.width()); } const CImg &img = p1!=~0U?listin[p1]:imgin; if (!img) throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Cannot crop empty image when " "some xyzc-coordinates are unspecified, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); if (opcode[4]==(ulongT)~0U) opcode[4] = (ulongT)img._width; if (opcode[5]==(ulongT)~0U) opcode[5] = (ulongT)img._height; if (opcode[6]==(ulongT)~0U) opcode[6] = (ulongT)img._depth; if (opcode[7]==(ulongT)~0U) opcode[7] = (ulongT)img._spectrum; } pos = vector(opcode[4]*opcode[5]*opcode[6]*opcode[7]); CImg::vector((ulongT)mp_crop, pos,p1, *opcode,opcode[1],opcode[2],opcode[3], opcode[4],opcode[5],opcode[6],opcode[7], opcode[8]).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"cross(",6)) { // Cross product _cimg_mp_op("Function 'cross()'"); s1 = ss6; while (s1::vector((ulongT)mp_cross,pos,arg1,arg2).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"cut(",4)) { // Cut _cimg_mp_op("Function 'cut()'"); s1 = ss4; while (s1val2?val2:val); } _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3); } break; case 'd' : if (!std::strncmp(ss,"date(",5)) { // Date and file date _cimg_mp_op("Function 'date()'"); s1 = ss5; while (s1::vector((ulongT)mp_debug,arg1,code._width - p1), CImg::string(ss6).unroll('y'))>'y').move_to(code,p1); *se1 = ')'; _cimg_mp_return(arg1); } if (!std::strncmp(ss,"det(",4)) { // Matrix determinant _cimg_mp_op("Function 'det()'"); arg1 = compile(ss4,se1,depth1,0); _cimg_mp_check_matrix_square(arg1,1); p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1)); _cimg_mp_scalar2(mp_det,arg1,p1); } if (!std::strncmp(ss,"diag(",5)) { // Diagonal matrix _cimg_mp_op("Function 'diag()'"); arg1 = compile(ss5,se1,depth1,0); _cimg_mp_check_type(arg1,1,2,0); p1 = _cimg_mp_vector_size(arg1); pos = vector(p1*p1); CImg::vector((ulongT)mp_diag,pos,arg1,p1).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"dot(",4)) { // Dot product _cimg_mp_op("Function 'dot()'"); s1 = ss4; while (s1::vector((ulongT)mp_dowhile,arg1,arg2,code._width - p1).move_to(code,p1); _cimg_mp_return(arg1); } if (!std::strncmp(ss,"draw(",5)) { // Draw image _cimg_mp_op("Function 'draw()'"); is_parallelizable = false; if (*ss5=='#') { // Index specified s0 = ss6; while (s01) { arg3 = arg2 + 1; if (p2>2) { arg4 = arg3 + 1; if (p2>3) arg5 = arg4 + 1; } } ++s0; is_sth = true; } else { if (s0::vector((ulongT)mp_draw,arg1,p1,arg2,arg3,arg4,arg5,0,0,0,0,1,(ulongT)-1,0,1). move_to(opcode); arg2 = arg3 = arg4 = arg5 = ~0U; p2 = p1!=~0U?0:1; if (s0 &img = p1!=~0U?listout[p1]:imgout; if (arg2==~0U) arg2 = img._width; if (arg3==~0U) arg3 = img._height; if (arg4==~0U) arg4 = img._depth; if (arg5==~0U) arg5 = img._spectrum; } if (arg2*arg3*arg4*arg5!=_cimg_mp_vector_size(arg1)) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Type of %s argument ('%s') and specified size " "(%u,%u,%u,%u) do not match, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, p1==~0U?"first":"second",s_type(arg1)._data, arg2,arg3,arg4,arg5, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } opcode[7] = (ulongT)arg2; opcode[8] = (ulongT)arg3; opcode[9] = (ulongT)arg4; opcode[10] = (ulongT)arg5; if (s0::%s: %s: Type of opacity mask ('%s') and specified size " "(%u,%u,%u,%u) do not match, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(p2)._data, arg2,arg3,arg4,arg5, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } opcode[12] = p2; opcode[13] = _cimg_mp_vector_size(p2)/(arg2*arg3*arg4); p3 = s0::vector((ulongT)mp_eig,pos,arg1,p1).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"exp(",4)) { // Exponential _cimg_mp_op("Function 'exp()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1])); _cimg_mp_scalar1(mp_exp,arg1); } if (!std::strncmp(ss,"eye(",4)) { // Identity matrix _cimg_mp_op("Function 'eye()'"); arg1 = compile(ss4,se1,depth1,0); _cimg_mp_check_constant(arg1,1,true); p1 = (unsigned int)mem[arg1]; pos = vector(p1*p1); CImg::vector((ulongT)mp_eye,pos,p1).move_to(code); _cimg_mp_return(pos); } break; case 'f' : if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop _cimg_mp_op("Function 'for()'"); if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace s1 = ss4; while (s1::vector((ulongT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1); _cimg_mp_return(pos); } break; case 'g' : if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function _cimg_mp_op("Function 'gauss()'"); s1 = ss6; while (s10) { val/=val1; _cimg_mp_constant(val1*std::sqrt(1+val*val)); } _cimg_mp_constant(0); } _cimg_mp_scalar2(mp_hypot,arg1,arg2); } break; case 'i' : if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.] _cimg_mp_op("Function 'if()'"); if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace s1 = ss3; while (s1::vector((ulongT)mp_if,pos,arg1,arg2,arg3, p3 - p2,code._width - p3,arg4).move_to(code,p2); _cimg_mp_return(pos); } if (!std::strncmp(ss,"init(",5)) { // Init _cimg_mp_op("Function 'init()'"); if (ss0!=expr._data || code.width()) { // (only allowed as the first instruction) *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: %s: Init invokation not done at the " "beginning of expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } arg1 = compile(ss5,se1,depth1,p_ref); init_size = code.width(); _cimg_mp_return(arg1); } if (!std::strncmp(ss,"int(",4)) { // Integer cast _cimg_mp_op("Function 'int()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((longT)mem[arg1]); _cimg_mp_scalar1(mp_int,arg1); } if (!std::strncmp(ss,"inv(",4)) { // Matrix/scalar inversion _cimg_mp_op("Function 'inv()'"); arg1 = compile(ss4,se1,depth1,0); _cimg_mp_check_matrix_square(arg1,1); p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1)); pos = vector(p1*p1); CImg::vector((ulongT)mp_inv,pos,arg1,p1).move_to(code); _cimg_mp_return(pos); } if (*ss1=='s') { // Family of 'is_?()' functions if (!std::strncmp(ss,"isbool(",7)) { // Is boolean? _cimg_mp_op("Function 'isbool()'"); if (ss7==se1) _cimg_mp_return(0); arg1 = compile(ss7,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_return(mem[arg1]==0.0 || mem[arg1]==1.0); _cimg_mp_scalar1(mp_isbool,arg1); } if (!std::strncmp(ss,"isdir(",6)) { // Is directory? _cimg_mp_op("Function 'isdir()'"); *se1 = 0; is_sth = cimg::is_directory(ss6); *se1 = ')'; _cimg_mp_return(is_sth?1U:0U); } if (!std::strncmp(ss,"isfile(",7)) { // Is file? _cimg_mp_op("Function 'isfile()'"); *se1 = 0; is_sth = cimg::is_file(ss7); *se1 = ')'; _cimg_mp_return(is_sth?1U:0U); } if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector? if (ss5>=se1) _cimg_mp_return(0); _cimg_mp_op("Function 'isin()'"); pos = scalar(); CImg::vector((ulongT)mp_isin,pos).move_to(_opcode); for (s = ss5; s::sequence((ulongT)_cimg_mp_vector_size(arg1),arg1 + 1, arg1 + (ulongT)_cimg_mp_vector_size(arg1)). move_to(_opcode); else CImg::vector(arg1).move_to(_opcode); s = ns; } (_opcode>'y').move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"isinf(",6)) { // Is infinite? _cimg_mp_op("Function 'isinf()'"); if (ss6==se1) _cimg_mp_return(0); arg1 = compile(ss6,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type::is_inf(mem[arg1])); _cimg_mp_scalar1(mp_isinf,arg1); } if (!std::strncmp(ss,"isint(",6)) { // Is integer? _cimg_mp_op("Function 'isint()'"); if (ss6==se1) _cimg_mp_return(0); arg1 = compile(ss6,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)(cimg::mod(mem[arg1],1.0)==0)); _cimg_mp_scalar1(mp_isint,arg1); } if (!std::strncmp(ss,"isnan(",6)) { // Is NaN? _cimg_mp_op("Function 'isnan()'"); if (ss6==se1) _cimg_mp_return(0); arg1 = compile(ss6,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type::is_nan(mem[arg1])); _cimg_mp_scalar1(mp_isnan,arg1); } if (!std::strncmp(ss,"isval(",6)) { // Is value? _cimg_mp_op("Function 'isval()'"); val = 0; if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); _cimg_mp_return(0); } } break; case 'l' : if (!std::strncmp(ss,"log(",4)) { // Natural logarithm _cimg_mp_op("Function 'log()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1])); _cimg_mp_scalar1(mp_log,arg1); } if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm _cimg_mp_op("Function 'log2()'"); arg1 = compile(ss5,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1])); _cimg_mp_scalar1(mp_log2,arg1); } if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm _cimg_mp_op("Function 'log10()'"); arg1 = compile(ss6,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1])); _cimg_mp_scalar1(mp_log10,arg1); } break; case 'm' : if (!std::strncmp(ss,"mul(",4)) { // Matrix multiplication _cimg_mp_op("Function 'mul()'"); s1 = ss4; while (s1::%s: %s: Types of first and second arguments ('%s' and '%s') " "do not match for third argument 'nb_colsB=%u', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(arg1)._data,s_type(arg2)._data,p3, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } pos = vector(arg4*p3); CImg::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code); _cimg_mp_return(pos); } break; case 'n' : if (!std::strncmp(ss,"narg(",5)) { // Number of arguments _cimg_mp_op("Function 'narg()'"); if (ss5>=se1) _cimg_mp_return(0); arg1 = 0; for (s = ss5; s::vector((ulongT)mp_norm0,pos).move_to(_opcode); break; case 1 : CImg::vector((ulongT)mp_norm1,pos).move_to(_opcode); break; case 2 : CImg::vector((ulongT)mp_norm2,pos).move_to(_opcode); break; case ~0U : CImg::vector((ulongT)mp_norminf,pos).move_to(_opcode); break; default : CImg::vector((ulongT)mp_normp,pos,(ulongT)(arg1==~0U?-1:(int)arg1)). move_to(_opcode); } for (s = std::strchr(ss5,'(') + 1; s::sequence((ulongT)_cimg_mp_vector_size(arg2),arg2 + 1, arg2 + (ulongT)_cimg_mp_vector_size(arg2)). move_to(_opcode); else CImg::vector(arg2).move_to(_opcode); s = ns; } (_opcode>'y').move_to(code); _cimg_mp_return(pos); } break; case 'p' : if (!std::strncmp(ss,"print(",6)) { // Print expression _cimg_mp_op("Function 'print()'"); pos = compile(ss6,se1,depth1,p_ref); *se1 = 0; if (_cimg_mp_is_vector(pos)) // Vector ((CImg::vector((ulongT)mp_vector_print,pos,(ulongT)_cimg_mp_vector_size(pos)), CImg::string(ss6).unroll('y'))>'y').move_to(code); else // Scalar ((CImg::vector((ulongT)mp_print,pos), CImg::string(ss6).unroll('y'))>'y').move_to(code); *se1 = ')'; _cimg_mp_return(pos); } break; case 'r' : if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation _cimg_mp_op(ss[2]=='l'?"Function 'rol()'":"Function 'ror()'"); s1 = ss4; while (s11) { arg2 = arg1 + 1; if (p2>2) arg3 = arg2 + 1; } arg4 = compile(++s1,se1,depth1,0); } else { s2 = s1 + 1; while (s2::vector((ulongT)mp_rot3d,pos,arg1,arg2,arg3,arg4).move_to(code); } else { // 2d rotation _cimg_mp_check_type(arg1,1,1,0); pos = vector(4); CImg::vector((ulongT)mp_rot2d,pos,arg1).move_to(code); } _cimg_mp_return(pos); } if (!std::strncmp(ss,"round(",6)) { // Value rounding _cimg_mp_op("Function 'round()'"); s1 = ss6; while (s1::vector((ulongT)mp_single,arg1,code._width - p1).move_to(code,p1); _cimg_mp_return(arg1); } if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine _cimg_mp_op("Function 'sinh()'"); arg1 = compile(ss5,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1])); _cimg_mp_scalar1(mp_sinh,arg1); } if (!std::strncmp(ss,"size(",5)) { // Vector size. _cimg_mp_op("Function 'size()'"); arg1 = compile(ss5,se1,depth1,0); _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_vector_size(arg1)); } if (!std::strncmp(ss,"solve(",6)) { // Solve linear system _cimg_mp_op("Function 'solve()'"); s1 = ss6; while (s1::%s: %s: Types of first and second arguments ('%s' and '%s') " "do not match for third argument 'nb_colsB=%u', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(arg1)._data,s_type(arg2)._data,p3, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } pos = vector(arg4*p3); CImg::vector((ulongT)mp_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"sort(",5)) { // Sort vector _cimg_mp_op("Function 'sort()'"); s1 = ss6; while (s1::%s: %s: Invalid specified chunk size (%u) for first argument " "('%s'), in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, arg3,s_type(arg1)._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } pos = vector(p1); CImg::vector((ulongT)mp_sort,pos,arg1,p1,arg2,arg3).move_to(code); _cimg_mp_return(pos); } if (!std::strncmp(ss,"sqr(",4)) { // Square _cimg_mp_op("Function 'sqr()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1])); _cimg_mp_scalar1(mp_sqr,arg1); } if (!std::strncmp(ss,"sqrt(",5)) { // Square root _cimg_mp_op("Function 'sqrt()'"); arg1 = compile(ss5,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1])); _cimg_mp_scalar1(mp_sqrt,arg1); } break; case 't' : if (!std::strncmp(ss,"tan(",4)) { // Tangent _cimg_mp_op("Function 'tan()'"); arg1 = compile(ss4,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1])); _cimg_mp_scalar1(mp_tan,arg1); } if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent _cimg_mp_op("Function 'tanh()'"); arg1 = compile(ss5,se1,depth1,0); if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1); if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1])); _cimg_mp_scalar1(mp_tanh,arg1); } if (!std::strncmp(ss,"trace(",6)) { // Matrix trace _cimg_mp_op("Function 'trace()'"); arg1 = compile(ss6,se1,depth1,0); _cimg_mp_check_matrix_square(arg1,1); p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1)); _cimg_mp_scalar2(mp_trace,arg1,p1); } if (!std::strncmp(ss,"transp(",7)) { // Matrix transpose _cimg_mp_op("Function 'transp()'"); s1 = ss7; while (s1::%s: %s: Size of first argument ('%s') does not match" "for second specified argument 'nb_cols=%u', " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op, s_type(arg1)._data,p2, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } pos = vector(p3*p2); CImg::vector((ulongT)mp_transp,pos,arg1,p2,p3).move_to(code); _cimg_mp_return(pos); } break; case 'u' : if (*ss1=='(') { // Random value with uniform distribution _cimg_mp_op("Function 'u()'"); if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1); s1 = ss2; while (s10) || !std::strncmp(ss,"vector(",7)) { // Vector _cimg_mp_op("Function 'vector()'"); arg2 = 0; // Number of specified values. s = std::strchr(ss6,'(') + 1; if (s::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(_opcode); arg2+=arg4; } else { CImg::vector(arg3).move_to(_opcode); ++arg2; } s = ns; } if (arg1==~0U) arg1 = arg2; _cimg_mp_check_vector0(arg1); pos = vector(arg1); _opcode.insert(CImg::vector((ulongT)mp_vector_init,pos,arg1),0); (_opcode>'y').move_to(code); _cimg_mp_return(pos); } break; case 'w' : if (!std::strncmp(ss,"whiledo",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do _cimg_mp_op("Function 'whiledo()'"); if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace s1 = ss8; while (s1::vector((ulongT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1); _cimg_mp_return(pos); } break; } if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) || !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) || !std::strncmp(ss,"arg(",4) || !std::strncmp(ss,"sum(",4) || !std::strncmp(ss,"std(",4) || !std::strncmp(ss,"var(",4) || !std::strncmp(ss,"prod(",5) || !std::strncmp(ss,"mean(",5) || !std::strncmp(ss,"argmin(",7) || !std::strncmp(ss,"argmax(",7)) { // Multi-argument functions _cimg_mp_op(*ss=='a'?(ss[3]=='('?"Function 'arg()'":ss[4]=='i'?"Function 'argmin()'": "Function 'argmax()'"): *ss=='s'?(ss[1]=='u'?"Function 'sum()'":"Function 'std()'"): *ss=='k'?"Function 'kth()'": *ss=='p'?"Function 'prod()'": *ss=='v'?"Function 'var()'": ss[1]=='i'?"Function 'min()'": ss[1]=='a'?"Function 'max()'": ss[2]=='a'?"Function 'mean()'":"Function 'med()'"); pos = scalar(); CImg::vector((ulongT)(*ss=='a'?(ss[3]=='('?mp_arg:ss[4]=='i'?mp_argmin:mp_argmax): *ss=='s'?(ss[1]=='u'?mp_sum:mp_std): *ss=='k'?mp_kth: *ss=='p'?mp_prod: *ss=='v'?mp_var: ss[1]=='i'?mp_min: ss[1]=='a'?mp_max: ss[2]=='a'?mp_mean: mp_med),pos). move_to(_opcode); for (s = std::strchr(ss,'(') + 1; s::sequence((ulongT)_cimg_mp_vector_size(arg2),arg2 + 1, arg2 + (ulongT)_cimg_mp_vector_size(arg2)). move_to(_opcode); else CImg::vector(arg2).move_to(_opcode); s = ns; } (_opcode>'y').move_to(code); _cimg_mp_return(pos); } // No corresponding built-in function -> Look for a user-defined macro. s0 = strchr(ss,'('); if (s0) { variable_name.assign(ss,s0 - ss + 1).back() = 0; cimglist_for(function_def,l) if (!std::strcmp(function_def[l],variable_name)) { p2 = (unsigned int)function_def[l].back(); // Number of required arguments CImg _expr = function_body[l]; // Expression to be substituted p1 = 1; // Indice of current parsed argument for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments while (*s && *s<=' ') ++s; if (*s==')' && p1==1) break; // Function has no arguments if (p1>p2) { ++p1; break; } ns = s; while (ns::%s: Function '%s()': Number of specified arguments does not " "match function declaration (%u argument%s required), " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,variable_name._data, p2,p2!=1?"s":"", (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } // Recompute 'pexpr' and 'level' for evaluating substituted expression. CImg _pexpr(_expr._width); ns = _pexpr._data; for (ps = _expr._data, c1 = ' '; *ps; ++ps) { if (*ps!=' ') c1 = *ps; *(ns++) = c1; } *ns = 0; CImg _level(_expr._width - 1); unsigned int *pd = _level._data; nb = 0; for (ps = _expr._data; *ps && nb>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('||*ps=='['?nb++:*ps==')'||*ps==']'?--nb:nb); expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level); s0 = user_function; user_function = function_def[l]; pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref); user_function = s0; expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level); _cimg_mp_return(pos); } } } // if (se1==')') // Vector specification using initializer '[ ... ]'. if (*ss=='[' && *se1==']') { _cimg_mp_op("Operator '[]'"); arg1 = 0; // Number of specified values. if (*ss1!=']') for (s = ss1; s::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(_opcode); arg1+=arg3; } else { CImg::vector(arg2).move_to(_opcode); ++arg1; } s = ns; } _cimg_mp_check_vector0(arg1); pos = vector(arg1); _opcode.insert(CImg::vector((ulongT)mp_vector_init,pos,arg1),0); (_opcode>'y').move_to(code); _cimg_mp_return(pos); } // Variables related to the input list of images. if (*ss1=='#' && ss2::vector(listin[p1].median()).move_to(list_median[p1]); _cimg_mp_constant(*list_median[p1]); } _cimg_mp_scalar1(mp_list_median,arg1); } if (*ss1>='0' && *ss1<='9') { // i0#ind...i9#ind if (!listin) _cimg_mp_return(0); _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,*ss1 - '0', reserved_label[29],reserved_label[30]); } switch (*ss1) { case 'm' : arg2 = 0; break; // im#ind case 'M' : arg2 = 1; break; // iM#ind case 'a' : arg2 = 2; break; // ia#ind case 'v' : arg2 = 3; break; // iv#ind case 's' : arg2 = 12; break; // is#ind case 'p' : arg2 = 13; break; // ip#ind } } else if (*ss1=='m') switch (*ss) { case 'x' : arg2 = 4; break; // xm#ind case 'y' : arg2 = 5; break; // ym#ind case 'z' : arg2 = 6; break; // zm#ind case 'c' : arg2 = 7; break; // cm#ind } else if (*ss1=='M') switch (*ss) { case 'x' : arg2 = 8; break; // xM#ind case 'y' : arg2 = 9; break; // yM#ind case 'z' : arg2 = 10; break; // zM#ind case 'c' : arg2 = 11; break; // cM#ind } if (arg2!=~0U) { if (!listin) _cimg_mp_return(0); if (_cimg_mp_is_constant(arg1)) { if (!list_stats) list_stats.assign(listin._width); if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(listin[p1].get_stats(),false); _cimg_mp_constant(list_stats(p1,arg2)); } _cimg_mp_scalar2(mp_list_stats,arg1,arg2); } } if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4 error. is_sth = true; // is_valid_variable_name if (*variable_name>='0' && *variable_name<='9') is_sth = false; else for (ns = variable_name._data; *ns; ++ns) if (!is_varchar(*ns)) { is_sth = false; break; } *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); if (is_sth) throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Undefined variable '%s' in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function, variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); s0 = std::strchr(ss,'('); if (s0 && *se1==')') s_op = "function call"; else s_op = "item"; throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s: Unrecognized %s '%s' in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function, s_op,variable_name._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } // Evaluation procedure. double operator()(const double x, const double y, const double z, const double c) { mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c; for (p_code = p_code_begin; p_code &op = *p_code; opcode._data = op._data; opcode._height = op._height; const ulongT target = opcode[1]; mem[target] = _cimg_mp_defunc(*this); } return *result; } // Evaluation procedure (return output values in vector 'output'). template void operator()(const double x, const double y, const double z, const double c, t *const output) { mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c; for (p_code = p_code_begin; p_code &op = *p_code; opcode._data = op._data; opcode._height = op._height; const ulongT target = opcode[1]; mem[target] = _cimg_mp_defunc(*this); } if (result_dim) { const double *ptrs = result + 1; t *ptrd = output; for (unsigned int k = 0; k s_type(const unsigned int arg) const { CImg res; if (_cimg_mp_is_vector(arg)) { // Vector CImg::string("vectorXXXXXXXXXXXXXXXX").move_to(res); std::sprintf(res._data + 6,"%u",_cimg_mp_vector_size(arg)); } else CImg::string("scalar").move_to(res); return res; } // Insert constant value in memory. unsigned int constant(const double val) { if (val==(double)(int)val) { if (val>=0 && val<=9) return (unsigned int)val; if (val<0 && val>=-5) return (unsigned int)(10 - val); } if (val==0.5) return 16; if (cimg::type::is_nan(val)) return 28; if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); } const unsigned int pos = mempos++; mem[pos] = val; memtype[pos] = 1; // Set constant property return pos; } // Insert code instructions for processing scalars. unsigned int scalar() { // Insert new scalar in memory. if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); } return mempos++; } unsigned int scalar0(const mp_func op) { const unsigned int pos = scalar(); CImg::vector((ulongT)op,pos).move_to(code); return pos; } unsigned int scalar1(const mp_func op, const unsigned int arg1) { const unsigned int pos = arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:scalar(); CImg::vector((ulongT)op,pos,arg1).move_to(code); return pos; } unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) { const unsigned int pos = arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:scalar(); CImg::vector((ulongT)op,pos,arg1,arg2).move_to(code); return pos; } unsigned int scalar3(const mp_func op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { const unsigned int pos = arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:scalar(); CImg::vector((ulongT)op,pos,arg1,arg2,arg3).move_to(code); return pos; } unsigned int scalar6(const mp_func op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) { const unsigned int pos = arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3: arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4: arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5: arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:scalar(); CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code); return pos; } unsigned int scalar7(const mp_func op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, const unsigned int arg4, const unsigned int arg5, const unsigned int arg6, const unsigned int arg7) { const unsigned int pos = arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3: arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4: arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5: arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6: arg7>_cimg_mp_c && _cimg_mp_is_temp(arg7)?arg7:scalar(); CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code); return pos; } // Return a string that defines the calling function + the user-defined function scope. CImg calling_function_s() const { CImg res; const unsigned int l1 = calling_function?(unsigned int)std::strlen(calling_function):0U, l2 = user_function?(unsigned int)std::strlen(user_function):0U; if (l2) { res.assign(l1 + l2 + 48); cimg_snprintf(res,res._width,"%s(): When substituting function '%s()'",calling_function,user_function); } else { res.assign(l1 + l2 + 4); cimg_snprintf(res,res._width,"%s()",calling_function); } return res; } // Return true if specified argument can be a part of an allowed variable name. bool is_varchar(const char c) const { return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; } // Insert code instructions for processing vectors. bool is_tmp_vector(const unsigned int arg) const { unsigned int siz = _cimg_mp_vector_size(arg); if (siz>8) return false; const int *ptr = memtype.data(arg + 1); bool is_tmp = true; while (siz-->0) if (*(ptr++)) { is_tmp = false; break; } return is_tmp; } void set_variable_vector(const unsigned int arg) { unsigned int siz = _cimg_mp_vector_size(arg); int *ptr = memtype.data(arg + 1); while (siz-->0) *(ptr++) = -1; } unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory if (mempos + siz>=mem._width) { mem.resize(2*mem._width + siz,1,1,1,0); memtype.resize(mem._width,1,1,1,0); } const unsigned int pos = mempos++; mem[pos] = cimg::type::nan(); memtype[pos] = siz + 1; mempos+=siz; return pos; } unsigned int vector(const unsigned int siz, const double value) { // Insert new initialized vector const unsigned int pos = vector(siz); double *ptr = &mem[pos] + 1; for (unsigned int i = 0; i::vector((ulongT)mp_vector_copy,pos,arg,siz).move_to(code); return pos; } void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) { const unsigned int siz = _cimg_mp_vector_size(pos); if (siz>24) CImg::vector((ulongT)mp_self_map_vector_s,pos,siz,(ulongT)op,arg1).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]); } } void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) { const unsigned int siz = _cimg_mp_vector_size(pos); if (siz>24) CImg::vector((ulongT)mp_self_map_vector_v,pos,siz,(ulongT)op,arg1).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]); } } unsigned int vector1_v(const mp_func op, const unsigned int arg1) { const unsigned int siz = _cimg_mp_vector_size(arg1), pos = is_tmp_vector(arg1)?arg1:vector(siz); if (siz>24) CImg::vector((ulongT)mp_vector_map_v,pos,siz,(ulongT)op,arg1).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]); } return pos; } unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { const unsigned int siz = _cimg_mp_vector_size(arg1), pos = is_tmp_vector(arg1)?arg1:is_tmp_vector(arg2)?arg2:vector(siz); if (siz>24) CImg::vector((ulongT)mp_vector_map_vv,pos,siz,(ulongT)op,arg1,arg2).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1 + k,arg2 + k).move_to(code[code._width - 1 - siz + k]); } return pos; } unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) { const unsigned int siz = _cimg_mp_vector_size(arg1), pos = is_tmp_vector(arg1)?arg1:vector(siz); if (siz>24) CImg::vector((ulongT)mp_vector_map_vs,pos,siz,(ulongT)op,arg1,arg2).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1 + k,arg2).move_to(code[code._width - 1 - siz + k]); } return pos; } unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { const unsigned int siz = _cimg_mp_vector_size(arg2), pos = is_tmp_vector(arg2)?arg2:vector(siz); if (siz>24) CImg::vector((ulongT)mp_vector_map_sv,pos,siz,(ulongT)op,arg1,arg2).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1,arg2 + k).move_to(code[code._width - 1 - siz + k]); } return pos; } unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { const unsigned int siz = _cimg_mp_vector_size(arg1), pos = is_tmp_vector(arg1)?arg1:vector(siz); if (siz>24) CImg::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code); else { code.insert(siz); for (unsigned int k = 1; k<=siz; ++k) CImg::vector((ulongT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]); } return pos; } // Check if a memory slot is a positive integer constant scalar value. void check_constant(const unsigned int arg, const unsigned int n_arg, const bool is_strictly_positive, const char *const ss, char *const se, const char saved_char) { _cimg_mp_check_type(arg,n_arg,1,0); if (!_cimg_mp_is_constant(arg) || mem[arg]<(is_strictly_positive?1:0) || (double)(int)mem[arg]!=mem[arg]) { const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ": n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth ": n_arg==9?"Ninth ":"One of the "; *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s %s%s (of type '%s') is not a %spositive integer constant, " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", s_arg,*s_arg?"argument":"Argument",s_type(arg)._data, is_strictly_positive?"strictly ":"", (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } } // Check a matrix is square. void check_matrix_square(const unsigned int arg, const unsigned int n_arg, const char *const ss, char *const se, const char saved_char) { _cimg_mp_check_type(arg,n_arg,2,0); const unsigned int siz = _cimg_mp_vector_size(arg), n = (unsigned int)std::sqrt((float)siz); if (n*n!=siz) { const char *s_arg; if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand "; else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One "; *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s %s%s (of type '%s') " "cannot be considered as a square matrix, in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"), s_type(arg)._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } } // Check type compatibility for one argument. // Bits of 'mode' tells what types are allowed: // { 1 = scalar | 2 = vectorN }. // If 'N' is not zero, it also restricts the vectors to be of size N only. void check_type(const unsigned int arg, const unsigned int n_arg, const unsigned int mode, const unsigned int N, const char *const ss, char *const se, const char saved_char) { const bool is_scalar = _cimg_mp_is_scalar(arg), is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_vector_size(arg)==N); bool cond = false; if (mode&1) cond|=is_scalar; if (mode&2) cond|=is_vector; if (!cond) { const char *s_arg; if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand "; else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ": n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth": n_arg==9?"Ninth":"One of the "; CImg sb_type(32); if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'"); else if (mode==2) { if (N) cimg_snprintf(sb_type,sb_type._width,"'vector%u'",N); else cimg_snprintf(sb_type,sb_type._width,"'vector'"); } else { if (N) cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector%u'",N); else cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector'"); } *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s %s%s has invalid type '%s' (should be %s), " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"), s_type(arg)._data,sb_type._data, (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } } // Check is listin is not empty. void check_list(const bool is_out, const char *const ss, char *const se, const char saved_char) { if ((!is_out && !listin) || (is_out && !listout)) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s Invalid call with an empty image list, " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } } // Check a vector is not 0-dimensional, or with unknown dimension at compile time. void check_vector0(const unsigned int dim, const char *const ss, char *const se, const char saved_char) { if (!dim) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s Invalid construction of a 0-dimensional vector, " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } else if (dim==~0U) { *se = saved_char; cimg::strellipsize(expr,64); throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): %s%s Invalid construction of a vector with dynamic size, " "in expression '%s%s%s'.", pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", (ss - 4)>expr._data?"...":"", (ss - 4)>expr._data?ss - 4:expr._data, se<&expr.back()?"...":""); } } // Evaluation functions, known by the parser. // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulongT), // so we can store pointers to them directly in the opcode vectors. #ifdef _mp_arg #undef _mp_arg #endif #define _mp_arg(x) mp.mem[mp.opcode[x]] static double mp_abs(_cimg_math_parser& mp) { return cimg::abs(_mp_arg(2)); } static double mp_add(_cimg_math_parser& mp) { return _mp_arg(2) + _mp_arg(3); } static double mp_acos(_cimg_math_parser& mp) { return std::acos(_mp_arg(2)); } static double mp_arg(_cimg_math_parser& mp) { const int _ind = (int)_mp_arg(2); const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind; if (ind>=nb_args) return 0; return _mp_arg(ind + 2); } static double mp_argmin(_cimg_math_parser& mp) { double val = _mp_arg(2); unsigned int argval = 0; for (unsigned int i = 3; ival) { val = _val; argval = i - 2; } } return (double)argval; } static double mp_asin(_cimg_math_parser& mp) { return std::asin(_mp_arg(2)); } static double mp_atan(_cimg_math_parser& mp) { return std::atan(_mp_arg(2)); } static double mp_atan2(_cimg_math_parser& mp) { return std::atan2(_mp_arg(2),_mp_arg(3)); } static double mp_bitwise_and(_cimg_math_parser& mp) { return (double)((ulongT)_mp_arg(2) & (ulongT)_mp_arg(3)); } static double mp_bitwise_left_shift(_cimg_math_parser& mp) { return (double)((longT)_mp_arg(2)<<(unsigned int)_mp_arg(3)); } static double mp_bitwise_not(_cimg_math_parser& mp) { return (double)~(ulongT)_mp_arg(2); } static double mp_bitwise_or(_cimg_math_parser& mp) { return (double)((ulongT)_mp_arg(2) | (ulongT)_mp_arg(3)); } static double mp_bitwise_right_shift(_cimg_math_parser& mp) { return (double)((longT)_mp_arg(2)>>(unsigned int)_mp_arg(3)); } static double mp_cbrt(_cimg_math_parser& mp) { return std::pow(_mp_arg(2),1.0/3); } static double mp_complex_conj(_cimg_math_parser& mp) { const double *ptrs = &_mp_arg(2) + 1; double *ptrd = &_mp_arg(1) + 1; *(ptrd++) = *(ptrs++); *ptrd = -*(ptrs); return cimg::type::nan(); } static double mp_complex_div_sv(_cimg_math_parser& mp) { const double *ptr2 = &_mp_arg(3) + 1, r1 = _mp_arg(2), r2 = *(ptr2++), i2 = *ptr2; double *ptrd = &_mp_arg(1) + 1; const double denom = r2*r2 + i2*i2; *(ptrd++) = r1*r2/denom; *ptrd = -r1*i2/denom; return cimg::type::nan(); } static double mp_complex_div_vv(_cimg_math_parser& mp) { const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, r1 = *(ptr1++), i1 = *ptr1, r2 = *(ptr2++), i2 = *ptr2; double *ptrd = &_mp_arg(1) + 1; const double denom = r2*r2 + i2*i2; *(ptrd++) = (r1*r2 + i1*i2)/denom; *ptrd = (r2*i1 - r1*i2)/denom; return cimg::type::nan(); } static double mp_complex_exp(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r); *(ptrd++) = er*std::cos(i); *(ptrd++) = er*std::sin(i); return cimg::type::nan(); } static double mp_complex_log(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs); *(ptrd++) = std::log(std::sqrt(r*r + i*i)); *(ptrd++) = std::atan2(i,r); return cimg::type::nan(); } static double mp_complex_mul(_cimg_math_parser& mp) { const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, r1 = *(ptr1++), i1 = *ptr1, r2 = *(ptr2++), i2 = *ptr2; double *ptrd = &_mp_arg(1) + 1; *(ptrd++) = r1*r2 - i1*i2; *(ptrd++) = r1*i2 + r2*i1; return cimg::type::nan(); } static void _mp_complex_pow(const double r1, const double i1, const double r2, const double i2, double *ptrd) { double ro, io; if (cimg::abs(i2)<1e-15) { // Exponent is real if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) { if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; } else ro = io = 0; } else { const double mod1_2 = r1*r1 + i1*i1, phi1 = std::atan2(i1,r1), modo = std::pow(mod1_2,0.5*r2), phio = r2*phi1; ro = modo*std::cos(phio); io = modo*std::sin(phio); } } else { // Exponent is complex if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0; const double mod1_2 = r1*r1 + i1*i1, phi1 = std::atan2(i1,r1), modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1), phio = r2*phi1 + 0.5*i2*std::log(mod1_2); ro = modo*std::cos(phio); io = modo*std::sin(phio); } *(ptrd++) = ro; *ptrd = io; } static double mp_complex_pow_sv(_cimg_math_parser& mp) { const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1; double *ptrd = &_mp_arg(1) + 1; _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd); return cimg::type::nan(); } static double mp_complex_pow_vs(_cimg_math_parser& mp) { const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3); double *ptrd = &_mp_arg(1) + 1; _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd); return cimg::type::nan(); } static double mp_complex_pow_vv(_cimg_math_parser& mp) { const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1; double *ptrd = &_mp_arg(1) + 1; _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd); return cimg::type::nan(); } static double mp_cos(_cimg_math_parser& mp) { return std::cos(_mp_arg(2)); } static double mp_cosh(_cimg_math_parser& mp) { return std::cosh(_mp_arg(2)); } static double mp_crop(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6); const unsigned int dx = (unsigned int)mp.opcode[7], dy = (unsigned int)mp.opcode[8], dz = (unsigned int)mp.opcode[9], dc = (unsigned int)mp.opcode[10]; const bool boundary_conditions = (bool)_mp_arg(11); unsigned int ind = (unsigned int)mp.opcode[2]; if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); const CImg &img = ind==~0U?mp.imgin:mp.listin[ind]; if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double)); else CImg(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c, x + dx - 1,y + dy - 1, z + dz - 1,c + dc - 1, boundary_conditions); return cimg::type::nan(); } static double mp_cross(_cimg_math_parser& mp) { CImg vout(&_mp_arg(1) + 1,1,3,1,1,true), v1(&_mp_arg(2) + 1,1,3,1,1,true), v2(&_mp_arg(3) + 1,1,3,1,1,true); (vout = v1).cross(v2); return cimg::type::nan(); } static double mp_cut(_cimg_math_parser& mp) { double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4); return valcmax?cmax:val; } static double mp_debug(_cimg_math_parser& mp) { CImg expr(mp.opcode._height - 3); const ulongT *ptrs = mp.opcode._data + 3; cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); cimg::strellipsize(expr); const ulongT g_target = mp.opcode[1]; #ifndef cimg_use_openmp const unsigned int n_thread = 0; #else const unsigned int n_thread = omp_get_thread_num(); #pragma omp critical #endif { std::fprintf(cimg::output(), "\n[_cimg_math_parser] %p[thread #%u]:%*c" "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)", (void*)&mp,n_thread,mp.debug_indent,' ', expr._data,(unsigned int)mp.opcode[2],(unsigned int)g_target,mp.mem._width); std::fflush(cimg::output()); const CImg *const p_end = (++mp.p_code) + mp.opcode[2]; CImg _op; mp.debug_indent+=3; for ( ; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; _op.assign(1,op._height - 1); const ulongT *ptrs = op._data + 1; for (ulongT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd mem[%u] = %g", (void*)&mp,n_thread,mp.debug_indent,' ', (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(), (unsigned int)target,mp.mem[target]); std::fflush(cimg::output()); } mp.debug_indent-=3; std::fprintf(cimg::output(), "\n[_cimg_math_parser] %p[thread #%u]:%*c" "End debugging expression '%s' -> mem[%u] = %g (memsize: %u)", (void*)&mp,n_thread,mp.debug_indent,' ', expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width); std::fflush(cimg::output()); --mp.p_code; } return mp.mem[g_target]; } static double mp_decrement(_cimg_math_parser& mp) { return _mp_arg(2) - 1; } static double mp_det(_cimg_math_parser& mp) { const double *ptrs = &_mp_arg(2) + 1; const unsigned int k = (unsigned int)mp.opcode(3); return CImg(ptrs,k,k,1,1,true).det(); } static double mp_diag(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptrs = &_mp_arg(2) + 1; const unsigned int k = (unsigned int)mp.opcode(3); CImg(ptrd,k,k,1,1,true) = CImg(ptrs,1,k,1,1,true).get_diagonal(); return cimg::type::nan(); } static double mp_div(_cimg_math_parser& mp) { return _mp_arg(2)/_mp_arg(3); } static double mp_dot(_cimg_math_parser& mp) { const unsigned int siz = (unsigned int)mp.opcode[4]; return CImg(&_mp_arg(2) + 1,1,siz,1,1,true). dot(CImg(&_mp_arg(3) + 1,1,siz,1,1,true)); } static double mp_dowhile(_cimg_math_parser& mp) { const ulongT mem_proc = mp.opcode[1], mem_cond = mp.opcode[2]; const CImg *const p_proc = ++mp.p_code, *const p_end = p_proc + mp.opcode[3]; do { for (mp.p_code = p_proc; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } } while (mp.mem[mem_cond]); --mp.p_code; return mp.mem[mem_proc]; } static double mp_draw(_cimg_math_parser& mp) { const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6); const unsigned int dx = (unsigned int)mp.opcode[7], dy = (unsigned int)mp.opcode[8], dz = (unsigned int)mp.opcode[9], dc = (unsigned int)mp.opcode[10]; const CImg S(&_mp_arg(1) + 1,dx,dy,dz,dc,true); const float opacity = (float)_mp_arg(11); unsigned int ind = (unsigned int)mp.opcode[2]; if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); CImg &img = ind==~0U?mp.imgout:mp.listout[ind]; if (img) { if (mp.opcode[12]!=(ulongT)-1) { const CImg M(&_mp_arg(12) + 1,dx,dy,dz,(unsigned int)mp.opcode[13],true); img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(14)); } else img.draw_image(x,y,z,c,S,opacity); } return cimg::type::nan(); } static double mp_eig(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptr1 = &_mp_arg(2) + 1; const unsigned int k = (unsigned int)mp.opcode(3); CImg val, vec; CImg(ptr1,k,k,1,1,true).symmetric_eigen(val,vec); CImg(ptrd,k,1,1,1,true) = val.unroll('x'); CImg(ptrd + k,k,k,1,1,true) = vec.get_transpose(); return cimg::type::nan(); } static double mp_eq(_cimg_math_parser& mp) { return (double)(_mp_arg(2)==_mp_arg(3)); } static double mp_exp(_cimg_math_parser& mp) { return std::exp(_mp_arg(2)); } static double mp_eye(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int k = (unsigned int)mp.opcode(2); CImg(ptrd,k,k,1,1,true).identity_matrix(); return cimg::type::nan(); } static double mp_g(_cimg_math_parser& mp) { cimg::unused(mp); return cimg::grand(); } static double mp_gauss(_cimg_math_parser& mp) { const double x = _mp_arg(2), s = _mp_arg(3); return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI); } static double mp_gt(_cimg_math_parser& mp) { return (double)(_mp_arg(2)>_mp_arg(3)); } static double mp_gte(_cimg_math_parser& mp) { return (double)(_mp_arg(2)>=_mp_arg(3)); } static double mp_hypot(_cimg_math_parser& mp) { return cimg::hypot(_mp_arg(2),_mp_arg(3)); } static double mp_i(_cimg_math_parser& mp) { return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_x],(int)mp.mem[_cimg_mp_y], (int)mp.mem[_cimg_mp_z],(int)mp.mem[_cimg_mp_c],0); } static double mp_if(_cimg_math_parser& mp) { const bool is_cond = (bool)_mp_arg(2); const ulongT mem_left = mp.opcode[3], mem_right = mp.opcode[4]; const CImg *const p_right = ++mp.p_code + mp.opcode[5], *const p_end = p_right + mp.opcode[6]; const unsigned int vtarget = mp.opcode[1], vsiz = mp.opcode[7]; if (is_cond) { for ( ; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } mp.p_code = p_end - 1; if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_left] + 1,sizeof(double)*vsiz); return mp.mem[mem_left]; } for (mp.p_code = p_right; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } --mp.p_code; if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_right] + 1,sizeof(double)*vsiz); return mp.mem[mem_right]; } static double mp_increment(_cimg_math_parser& mp) { return _mp_arg(2) + 1; } static double mp_int(_cimg_math_parser& mp) { return (double)(longT)_mp_arg(2); } static double mp_inv(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptr1 = &_mp_arg(2) + 1; const unsigned int k = (unsigned int)mp.opcode(3); CImg(ptrd,k,k,1,1,true) = CImg(ptr1,k,k,1,1,true).get_invert(); return cimg::type::nan(); } static double mp_ioff(_cimg_math_parser& mp) { const unsigned int boundary_conditions = (unsigned int)_mp_arg(3); const CImg &img = mp.imgin; const longT off = (longT)_mp_arg(2), whds = (longT)img.size(); if (off<0 || off>=whds) switch (boundary_conditions) { case 2 : // Periodic boundary if (img) return (double)img[cimg::mod(off,whds)]; return 0; case 1 : // Neumann boundary if (img) return (double)(off<0?*img:img.back()); return 0; default : // Dirichet boundary return 0; } return (double)img[off]; } static double mp_isbool(_cimg_math_parser& mp) { const double val = _mp_arg(2); return (double)(val==0.0 || val==1.0); } static double mp_isin(_cimg_math_parser& mp) { const double val = _mp_arg(2); for (unsigned int i = 3; i::is_inf(_mp_arg(2)); } static double mp_isint(_cimg_math_parser& mp) { return (double)(cimg::mod(_mp_arg(2),1.0)==0); } static double mp_isnan(_cimg_math_parser& mp) { return (double)cimg::type::is_nan(_mp_arg(2)); } static double mp_ixyzc(_cimg_math_parser& mp) { const unsigned int interpolation = (unsigned int)_mp_arg(6), boundary_conditions = (unsigned int)_mp_arg(7); const CImg &img = mp.imgin; const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4), c = _mp_arg(5); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) return (double)img.atXYZC(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), cimg::mod((int)c,img.spectrum())); if (boundary_conditions==1) return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); } else { // Linear interpolation if (boundary_conditions==2) return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()), cimg::mod((float)c,(float)img.spectrum())); if (boundary_conditions==1) return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); } } static double mp_joff(_cimg_math_parser& mp) { const unsigned int boundary_conditions = (unsigned int)_mp_arg(3); const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const CImg &img = mp.imgin; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), whds = (longT)img.size(); if (off<0 || off>=whds) switch (boundary_conditions) { case 2 : // Periodic boundary if (img) return (double)img[cimg::mod(off,whds)]; return 0; case 1 : // Neumann boundary if (img) return (double)(off<0?*img:img.back()); return 0; default : // Dirichet boundary return 0; } return (double)img[off]; } static double mp_jxyzc(_cimg_math_parser& mp) { const unsigned int interpolation = (unsigned int)_mp_arg(6), boundary_conditions = (unsigned int)_mp_arg(7); const CImg &img = mp.imgin; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c], x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4), c = oc + _mp_arg(5); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) return (double)img.atXYZC(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), cimg::mod((int)c,img.spectrum())); if (boundary_conditions==1) return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); } else { // Linear interpolation if (boundary_conditions==2) return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()), cimg::mod((float)c,(float)img.spectrum())); if (boundary_conditions==1) return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); } } static double mp_kth(_cimg_math_parser& mp) { CImg vals(mp.opcode._height - 3); double *p = vals.data(); for (unsigned int i = 3; i &img = mp.listin[ind]; const longT off = (longT)_mp_arg(3), whds = (longT)img.size(); if (off<0 || off>=whds) switch (boundary_conditions) { case 2 : // Periodic boundary if (img) return (double)img[cimg::mod(off,whds)]; return 0; case 1 : // Neumann boundary if (img) return (double)(off<0?*img:img.back()); return 0; default : // Dirichet boundary return 0; } return (double)img[off]; } static double mp_list_is_shared(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._is_shared; } static double mp_list_ixyzc(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), interpolation = (unsigned int)_mp_arg(7), boundary_conditions = (unsigned int)_mp_arg(8); const CImg &img = mp.listin[ind]; const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5), c = _mp_arg(6); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) return (double)img.atXYZC(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), cimg::mod((int)c,img.spectrum())); if (boundary_conditions==1) return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); } else { // Linear interpolation if (boundary_conditions==2) return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()), cimg::mod((float)c,(float)img.spectrum())); if (boundary_conditions==1) return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); } } static double mp_list_joff(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), boundary_conditions = (unsigned int)_mp_arg(4); const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const CImg &img = mp.listin[ind]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), whds = (longT)img.size(); if (off<0 || off>=whds) switch (boundary_conditions) { case 2 : // Periodic boundary if (img) return (double)img(ind,cimg::mod(off,whds)); return 0; case 1 : // Neumann boundary if (img) return (double)(off<0?*img:img.back()); return 0; default : // Dirichet boundary return 0; } return (double)img[off]; } static double mp_list_jxyzc(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), interpolation = (unsigned int)_mp_arg(7), boundary_conditions = (unsigned int)_mp_arg(8); const CImg &img = mp.listin[ind]; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c], x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5), c = oc + _mp_arg(6); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) return (double)img.atXYZC(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), cimg::mod((int)c,img.spectrum())); if (boundary_conditions==1) return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); } else { // Linear interpolation if (boundary_conditions==2) return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()), cimg::mod((float)c,(float)img.spectrum())); if (boundary_conditions==1) return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); } } static double mp_list_median(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); if (!mp.list_median) mp.list_median.assign(mp.listin._width); if (!mp.list_median[ind]) CImg::vector(mp.listin[ind].median()).move_to(mp.list_median[ind]); return *mp.list_median[ind]; } static double mp_list_set_ioff(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); CImg &img = mp.listout[ind]; const longT off = (longT)_mp_arg(3), whds = (longT)img.size(); const double val = _mp_arg(1); if (off>=0 && off &img = mp.listout[ind]; const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6); const double val = _mp_arg(1); if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.listout[ind]; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), whds = (longT)img.size(); const double val = _mp_arg(1); if (off>=0 && off &img = mp.listout[ind]; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c]; const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6)); const double val = _mp_arg(1); if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.listout[ind]; const longT off = (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const T val = (T)_mp_arg(1); if (off>=0 && off &img = mp.listout[ind]; const longT off = (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const double *ptrs = &_mp_arg(1) + 1; if (off>=0 && off::nan(); } static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); CImg &img = mp.listout[ind]; const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5); const T val = (T)_mp_arg(1); if (x>=0 && x=0 && y=0 && z &img = mp.listout[ind]; const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5); const double *ptrs = &_mp_arg(1) + 1; if (x>=0 && x=0 && y=0 && z::nan(); } static double mp_list_set_Joff_s(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); CImg &img = mp.listout[ind]; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const T val = (T)_mp_arg(1); if (off>=0 && off &img = mp.listout[ind]; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const double *ptrs = &_mp_arg(1) + 1; if (off>=0 && off::nan(); } static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); CImg &img = mp.listout[ind]; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5)); const T val = (T)_mp_arg(1); if (x>=0 && x=0 && y=0 && z &img = mp.listout[ind]; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5)); const double *ptrs = &_mp_arg(1) + 1; if (x>=0 && x=0 && y=0 && z::nan(); } static double mp_list_spectrum(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._spectrum; } static double mp_list_stats(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), k = (unsigned int)_mp_arg(3); if (!mp.list_stats) mp.list_stats.assign(mp.listin._width); if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false); return mp.list_stats(ind,k); } static double mp_list_wh(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._width*mp.listin[ind]._height; } static double mp_list_whd(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth; } static double mp_list_whds(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum; } static double mp_list_width(_cimg_math_parser& mp) { const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); return (double)mp.listin[ind]._width; } static double mp_list_Ioff(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), boundary_conditions = (unsigned int)_mp_arg(4); const CImg &img = mp.listin[ind]; const longT off = (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const T *ptrs; if (off<0 || off>=whd) switch (boundary_conditions) { case 2 : // Periodic boundary if (!img) { ptrs = &img[cimg::mod(off,whd)]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); case 1 : // Neumann boundary if (img) { ptrs = off<0?img._data:&img.back(); cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); default : // Dirichet boundary std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); } ptrs = &img[off]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return cimg::type::nan(); } static double mp_list_Ixyz(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), interpolation = (unsigned int)_mp_arg(6), boundary_conditions = (unsigned int)_mp_arg(7); const CImg &img = mp.listin[ind]; const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); } else { // Linear interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()),c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); } return cimg::type::nan(); } static double mp_list_Joff(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), boundary_conditions = (unsigned int)_mp_arg(4); const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z]; const CImg &img = mp.listin[ind]; const longT off = img.offset(ox,oy,oz) + (longT)_mp_arg(3), whd = (longT)img.width()*img.height()*img.depth(); const T *ptrs; if (off<0 || off>=whd) switch (boundary_conditions) { case 2 : // Periodic boundary if (!img) { ptrs = &img[cimg::mod(off,whd)]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); case 1 : // Neumann boundary if (img) { ptrs = off<0?img._data:&img.back(); cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); default : // Dirichet boundary std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); } ptrs = &img[off]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return cimg::type::nan(); } static double mp_list_Jxyz(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), interpolation = (unsigned int)_mp_arg(6), boundary_conditions = (unsigned int)_mp_arg(7); const CImg &img = mp.listin[ind]; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); } else { // Linear interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()),c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); } return cimg::type::nan(); } static double mp_log(_cimg_math_parser& mp) { return std::log(_mp_arg(2)); } static double mp_log10(_cimg_math_parser& mp) { return std::log10(_mp_arg(2)); } static double mp_log2(_cimg_math_parser& mp) { return cimg::log2(_mp_arg(2)); } static double mp_logical_and(_cimg_math_parser& mp) { const bool val_left = (bool)_mp_arg(2); const CImg *const p_end = ++mp.p_code + mp.opcode[4]; if (!val_left) { mp.p_code = p_end - 1; return 0; } const ulongT mem_right = mp.opcode[3]; for ( ; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } --mp.p_code; return (double)(bool)mp.mem[mem_right]; } static double mp_logical_not(_cimg_math_parser& mp) { return (double)!_mp_arg(2); } static double mp_logical_or(_cimg_math_parser& mp) { const bool val_left = (bool)_mp_arg(2); const CImg *const p_end = ++mp.p_code + mp.opcode[4]; if (val_left) { mp.p_code = p_end - 1; return 1; } const ulongT mem_right = mp.opcode[3]; for ( ; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } --mp.p_code; return (double)(bool)mp.mem[mem_right]; } static double mp_lt(_cimg_math_parser& mp) { return (double)(_mp_arg(2)<_mp_arg(3)); } static double mp_lte(_cimg_math_parser& mp) { return (double)(_mp_arg(2)<=_mp_arg(3)); } static double mp_matrix_mul(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1; const unsigned int k = (unsigned int)mp.opcode(4), l = (unsigned int)mp.opcode(5), m = (unsigned int)mp.opcode(6); CImg(ptrd,m,k,1,1,true) = CImg(ptr1,l,k,1,1,true)*CImg(ptr2,m,l,1,1,true); return cimg::type::nan(); } static double mp_max(_cimg_math_parser& mp) { double val = _mp_arg(2); for (unsigned int i = 3; i=mp.mem.width()) throw CImgArgumentException("[_cimg_math_parser] CImg<%s>: 'copy()': " "Out-of-bounds variable pointer " "(length: %ld, increment: %ld, offset start: %ld, " "offset end: %ld, offset max: %u).", mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1); return &mp.mem[off]; } static float* _mp_memcopy_float(_cimg_math_parser& mp, const ulongT *const p_ref, const longT siz, const long inc) { const unsigned ind = p_ref[1]; const CImg &img = ind==~0U?mp.imgin:mp.listin[cimg::mod((int)mp.mem[ind],mp.listin.width())]; const bool is_relative = (bool)p_ref[2]; int ox, oy, oz, oc; longT off = 0; if (is_relative) { ox = (int)mp.mem[_cimg_mp_x]; oy = (int)mp.mem[_cimg_mp_y]; oz = (int)mp.mem[_cimg_mp_z]; oc = (int)mp.mem[_cimg_mp_c]; off = img.offset(ox,oy,oz,oc); } if ((*p_ref)%2) { const int x = (int)mp.mem[p_ref[3]], y = (int)mp.mem[p_ref[4]], z = (int)mp.mem[p_ref[5]], c = *p_ref==5?0:(int)mp.mem[p_ref[6]]; off+=img.offset(x,y,z,c); } else off+=(longT)mp.mem[p_ref[3]]; const longT eoff = off + (siz - 1)*inc; if (off<0 || eoff>=(longT)img.size()) throw CImgArgumentException("[_cimg_math_parser] CImg<%s>: Function 'copy()': " "Out-of-bounds image pointer " "(length: %ld, increment: %ld, offset start: %ld, " "offset end: %ld, offset max: %lu).", mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1); return (float*)&img[off]; } static double mp_memcopy(_cimg_math_parser& mp) { longT siz = (longT)_mp_arg(4); const longT inc_d = (longT)_mp_arg(5), inc_s = (longT)_mp_arg(6); if (siz>0) { const bool is_doubled = mp.opcode[7]<=1, is_doubles = mp.opcode[14]<=1; if (is_doubled && is_doubles) { // (double*) <- (double*) double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d); const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s); if (inc_d==1 && inc_s==1) { if (ptrs + siz - 1ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double)); else std::memmove(ptrd,ptrs,siz*sizeof(double)); } else { if (ptrs + (siz - 1)*inc_sptrd + (siz - 1)*inc_d) while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; } else { // Overlapping buffers CImg buf(siz); cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; } ptrs = buf; while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; } } } } else if (is_doubled && !is_doubles) { // (double*) <- (float*) double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d); const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s); while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; } } else if (!is_doubled && is_doubles) { // (float*) <- (double*) float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d); const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s); while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; } } else { // (float*) <- (float*) float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d); const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s); if (inc_d==1 && inc_s==1) { if (ptrs + siz - 1ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float)); else std::memmove(ptrd,ptrs,siz*sizeof(float)); } else { if (ptrs + (siz - 1)*inc_sptrd + (siz - 1)*inc_d) while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; } else { // Overlapping buffers CImg buf(siz); cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; } ptrs = buf; while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; } } } } } return _mp_arg(1); } static double mp_min(_cimg_math_parser& mp) { double val = _mp_arg(2); for (unsigned int i = 3; i vals(mp.opcode._height - 2); double *p = vals.data(); for (unsigned int i = 2; ires) res = val; } return res; } static double mp_normp(_cimg_math_parser& mp) { const double p = (double)mp.opcode[2]; double res = 0; for (unsigned int i = 3; i0?res:0.0; } static double mp_pow(_cimg_math_parser& mp) { const double v = _mp_arg(2), p = _mp_arg(3); return std::pow(v,p); } static double mp_pow3(_cimg_math_parser& mp) { const double val = _mp_arg(2); return val*val*val; } static double mp_pow4(_cimg_math_parser& mp) { const double val = _mp_arg(2); return val*val*val*val; } static double mp_print(_cimg_math_parser& mp) { cimg::mutex(6); CImg expr(mp.opcode._height - 2); const ulongT *ptrs = mp.opcode._data + 2; cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); cimg::strellipsize(expr); const double val = _mp_arg(1); #ifdef cimg_use_openmp #pragma omp critical #endif { std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = %g",expr._data,val); std::fflush(cimg::output()); } cimg::mutex(6,0); return val; } static double mp_prod(_cimg_math_parser& mp) { double val = _mp_arg(2); for (unsigned int i = 3; i::nan(); } static double mp_rot3d(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5); CImg(ptrd,3,3,1,1,true) = CImg::rotation_matrix(x,y,z,theta); return cimg::type::nan(); } static double mp_round(_cimg_math_parser& mp) { return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4)); } static double mp_self_add(_cimg_math_parser& mp) { return _mp_arg(1)+=_mp_arg(2); } static double mp_self_bitwise_and(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = (double)((ulongT)val & (ulongT)_mp_arg(2)); } static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = (double)((longT)val<<(unsigned int)_mp_arg(2)); } static double mp_self_bitwise_or(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = (double)((ulongT)val | (ulongT)_mp_arg(2)); } static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = (double)((longT)val>>(unsigned int)_mp_arg(2)); } static double mp_self_decrement(_cimg_math_parser& mp) { return --_mp_arg(1); } static double mp_self_increment(_cimg_math_parser& mp) { return ++_mp_arg(1); } static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar unsigned int ptrd = (unsigned int)mp.opcode[1] + 1, siz = (unsigned int)mp.opcode[2]; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,3); l_opcode[2] = mp.opcode[4]; // Scalar argument. l_opcode.swap(mp.opcode); ulongT &target = mp.opcode[1]; while (siz-->0) { target = ptrd++; (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector unsigned int ptrd = (unsigned int)mp.opcode[1] + 1, siz = (unsigned int)mp.opcode[2], ptrs = (unsigned int)mp.opcode[4] + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,4); l_opcode.swap(mp.opcode); ulongT &target = mp.opcode[1], &argument = mp.opcode[2]; while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_self_mul(_cimg_math_parser& mp) { return _mp_arg(1)*=_mp_arg(2); } static double mp_self_div(_cimg_math_parser& mp) { return _mp_arg(1)/=_mp_arg(2); } static double mp_self_modulo(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = cimg::mod(val,_mp_arg(2)); } static double mp_self_pow(_cimg_math_parser& mp) { double &val = _mp_arg(1); return val = std::pow(val,_mp_arg(2)); } static double mp_self_sub(_cimg_math_parser& mp) { return _mp_arg(1)-=_mp_arg(2); } static double mp_set_ioff(_cimg_math_parser& mp) { CImg &img = mp.imgout; const longT off = (longT)_mp_arg(2), whds = (longT)img.size(); const double val = _mp_arg(1); if (off>=0 && off &img = mp.imgout; const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4), c = (int)_mp_arg(5); const double val = _mp_arg(1); if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.imgout; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), whds = (longT)img.size(); const double val = _mp_arg(1); if (off>=0 && off &img = mp.imgout; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c]; const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5)); const double val = _mp_arg(1); if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.imgout; const longT off = (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const T val = (T)_mp_arg(1); if (off>=0 && off &img = mp.imgout; const longT off = (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const double *ptrs = &_mp_arg(1) + 1; if (off>=0 && off::nan(); } static double mp_set_Ixyz_s(_cimg_math_parser& mp) { CImg &img = mp.imgout; const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4); const T val = (T)_mp_arg(1); if (x>=0 && x=0 && y=0 && z &img = mp.imgout; const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4); const double *ptrs = &_mp_arg(1) + 1; if (x>=0 && x=0 && y=0 && z::nan(); } static double mp_set_Joff_s(_cimg_math_parser& mp) { CImg &img = mp.imgout; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const T val = (T)_mp_arg(1); if (off>=0 && off &img = mp.imgout; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; const longT off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const double *ptrs = &_mp_arg(1) + 1; if (off>=0 && off::nan(); } static double mp_set_Jxyz_s(_cimg_math_parser& mp) { CImg &img = mp.imgout; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4)); const T val = (T)_mp_arg(1); if (x>=0 && x=0 && y=0 && z &img = mp.imgout; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4)); const double *ptrs = &_mp_arg(1) + 1; if (x>=0 && x=0 && y=0 && z::nan(); } static double mp_sign(_cimg_math_parser& mp) { return cimg::sign(_mp_arg(2)); } static double mp_sin(_cimg_math_parser& mp) { return std::sin(_mp_arg(2)); } static double mp_sinc(_cimg_math_parser& mp) { return cimg::sinc(_mp_arg(2)); } static double mp_single(_cimg_math_parser& mp) { const double res = _mp_arg(1); #ifdef cimg_use_openmp #pragma omp critical #endif { for (const CImg *const p_end = ++mp.p_code + mp.opcode[2]; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } } --mp.p_code; return res; } static double mp_sinh(_cimg_math_parser& mp) { return std::sinh(_mp_arg(2)); } static double mp_solve(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1; const unsigned int k = (unsigned int)mp.opcode(4), l = (unsigned int)mp.opcode(5), m = (unsigned int)mp.opcode(6); CImg(ptrd,m,k,1,1,true) = CImg(ptr2,m,l,1,1,true).get_solve(CImg(ptr1,k,l,1,1,true)); return cimg::type::nan(); } static double mp_sort(_cimg_math_parser& mp) { double *const ptrd = &_mp_arg(1) + 1; const double *const ptrs = &_mp_arg(2) + 1; const unsigned int siz = mp.opcode[3], chunk_siz = mp.opcode[5]; const bool is_increasing = (bool)_mp_arg(4); CImg(ptrd,chunk_siz,siz/chunk_siz,1,1,true) = CImg(ptrs,chunk_siz,siz/chunk_siz,1,1,true). get_sort(is_increasing,chunk_siz>1?'y':0); return cimg::type::nan(); } static double mp_sqr(_cimg_math_parser& mp) { return cimg::sqr(_mp_arg(2)); } static double mp_sqrt(_cimg_math_parser& mp) { return std::sqrt(_mp_arg(2)); } static double mp_std(_cimg_math_parser& mp) { CImg vals(mp.opcode._height - 2); double *p = vals.data(); for (unsigned int i = 2; i(ptrs,k,k,1,1,true).trace(); } static double mp_transp(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const double *ptr1 = &_mp_arg(2) + 1; const unsigned int k = (unsigned int)mp.opcode(3), l = (unsigned int)mp.opcode(4); CImg(ptrd,l,k,1,1,true) = CImg(ptr1,k,l,1,1,true).get_transpose(); return cimg::type::nan(); } static double mp_u(_cimg_math_parser& mp) { return cimg::rand(_mp_arg(2),_mp_arg(3)); } static double mp_var(_cimg_math_parser& mp) { CImg vals(mp.opcode._height - 2); double *p = vals.data(); for (unsigned int i = 2; i::nan(); } static double mp_vector_crop(_cimg_math_parser& mp) { double *const ptrd = &_mp_arg(1) + 1; const double *const ptrs = &_mp_arg(2) + 1; const unsigned int p1 = mp.opcode[3], p2 = mp.opcode[4]; std::memcpy(ptrd,ptrs + p1,p2*sizeof(double)); return cimg::type::nan(); } static double mp_vector_init(_cimg_math_parser& mp) { unsigned int ptrs = 3U, ptrd = (unsigned int)mp.opcode[1] + 1, siz = (unsigned int)mp.opcode[2]; switch (mp.opcode._height) { case 3 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given case 4 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break; default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode._height) ptrs = 3U; } } return cimg::type::nan(); } static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector) unsigned int siz = (unsigned int)mp.opcode[2], ptrs = (unsigned int)mp.opcode[5] + 1; double *ptrd = &_mp_arg(1) + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(4); l_opcode[2] = mp.opcode[4]; // Scalar argument1 l_opcode.swap(mp.opcode); ulongT &argument2 = mp.opcode[3]; while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector) unsigned int siz = (unsigned int)mp.opcode[2], ptrs = (unsigned int)mp.opcode[4] + 1; double *ptrd = &_mp_arg(1) + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,3); l_opcode.swap(mp.opcode); ulongT &argument = mp.opcode[2]; while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar) unsigned int siz = (unsigned int)mp.opcode[2], ptrs = (unsigned int)mp.opcode[4] + 1; double *ptrd = &_mp_arg(1) + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,4); l_opcode[3] = mp.opcode[5]; // Scalar argument2 l_opcode.swap(mp.opcode); ulongT &argument1 = mp.opcode[2]; while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar) unsigned int siz = (unsigned int)mp.opcode[2], ptrs = (unsigned int)mp.opcode[4] + 1; double *ptrd = &_mp_arg(1) + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,5); l_opcode[3] = mp.opcode[5]; // Scalar argument2 l_opcode[4] = mp.opcode[6]; // Scalar argument3 l_opcode.swap(mp.opcode); ulongT &argument1 = mp.opcode[2]; while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector) unsigned int siz = (unsigned int)mp.opcode[2], ptrs1 = (unsigned int)mp.opcode[4] + 1, ptrs2 = (unsigned int)mp.opcode[5] + 1; double *ptrd = &_mp_arg(1) + 1; mp_func op = (mp_func)mp.opcode[3]; CImg l_opcode(1,4); l_opcode.swap(mp.opcode); ulongT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3]; while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); } l_opcode.swap(mp.opcode); return cimg::type::nan(); } static double mp_vector_off(_cimg_math_parser& mp) { const unsigned int ptr = mp.opcode[2] + 1, siz = (int)mp.opcode[3]; const int off = (int)_mp_arg(4); return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type::nan(); } static double mp_vector_set_off(_cimg_math_parser& mp) { const unsigned int ptr = mp.opcode[2] + 1, siz = mp.opcode[3]; const int off = (int)_mp_arg(4); if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5); return _mp_arg(5); } static double mp_vector_print(_cimg_math_parser& mp) { CImg expr(mp.opcode._height - 3); const ulongT *ptrs = mp.opcode._data + 3; cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); cimg::strellipsize(expr); unsigned int ptr = mp.opcode[1] + 1, siz = mp.opcode[2]; std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = [",expr._data); while (siz-->0) std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":""); std::fputc(']',cimg::output()); std::fflush(cimg::output()); return cimg::type::nan(); } static double mp_whiledo(_cimg_math_parser& mp) { // Used also by 'for()' const ulongT mem_proc = mp.opcode[1], mem_cond = mp.opcode[2]; const CImg *const p_cond = ++mp.p_code, *const p_proc = p_cond + mp.opcode[3], *const p_end = p_proc + mp.opcode[4]; const unsigned int vsiz = mp.opcode[5]; bool is_first_iter = true, is_cond = false; do { for (mp.p_code = p_cond; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } is_cond = (bool)mp.mem[mem_cond]; if (is_cond) { // Evaluate loop iteration for ( ; mp.p_code &op = *mp.p_code; mp.opcode._data = op._data; mp.opcode._height = op._height; const ulongT target = mp.opcode[1]; mp.mem[target] = _cimg_mp_defunc(mp); } is_first_iter = false; } } while (is_cond); mp.p_code = p_end - 1; if (vsiz && is_first_iter) std::memset(&mp.mem[mem_proc] + 1,0,vsiz*sizeof(double)); return is_first_iter?0:mp.mem[mem_proc]; } static double mp_Ioff(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int boundary_conditions = (unsigned int)_mp_arg(3); const CImg &img = mp.imgin; const longT off = (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const T *ptrs; if (off<0 || off>=whd) switch (boundary_conditions) { case 2 : // Periodic boundary if (!img) { ptrs = &img[cimg::mod(off,whd)]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); case 1 : // Neumann boundary if (img) { ptrs = off<0?img._data:&img.back(); cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); default : // Dirichet boundary std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); } ptrs = &img[off]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return cimg::type::nan(); } static double mp_Ixyz(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int interpolation = (unsigned int)_mp_arg(5), boundary_conditions = (unsigned int)_mp_arg(6); const CImg &img = mp.imgin; const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); } else { // Linear interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()),c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); } return cimg::type::nan(); } static double mp_Joff(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int boundary_conditions = (unsigned int)_mp_arg(3); const CImg &img = mp.imgin; const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z]; const longT off = img.offset(ox,oy,oz) + (longT)_mp_arg(2), whd = (longT)img.width()*img.height()*img.depth(); const T *ptrs; if (off<0 || off>=whd) switch (boundary_conditions) { case 2 : // Periodic boundary if (!img) { ptrs = &img[cimg::mod(off,whd)]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); case 1 : // Neumann boundary if (img) { ptrs = off<0?img._data:&img.back(); cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } } else std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); default : // Dirichet boundary std::memset(ptrd,0,img._spectrum*sizeof(double)); return cimg::type::nan(); } ptrs = &img[off]; cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return cimg::type::nan(); } static double mp_Jxyz(_cimg_math_parser& mp) { double *ptrd = &_mp_arg(1) + 1; const unsigned int interpolation = (unsigned int)_mp_arg(5), boundary_conditions = (unsigned int)_mp_arg(6); const CImg &img = mp.imgin; const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4); if (interpolation==0) { // Nearest neighbor interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), cimg::mod((int)y,img.height()), cimg::mod((int)z,img.depth()), c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); } else { // Linear interpolation if (boundary_conditions==2) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), cimg::mod((float)y,(float)img.height()), cimg::mod((float)z,(float)img.depth()),c); else if (boundary_conditions==1) cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); else cimg_forC(img,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); } return cimg::type::nan(); } #undef _mp_arg }; // struct _cimg_math_parser {} //! Compute the square value of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square value \f$I_{(x,y,z,c)}^2\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. \par Example \code const CImg img("reference.jpg"); (img,img.get_sqr().normalize(0,255)).display(); \endcode \image html ref_sqr.jpg **/ CImg& sqr() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); }; return *this; } //! Compute the square value of each pixel value \newinstance. CImg get_sqr() const { return CImg(*this,false).sqr(); } //! Compute the square root of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square root \f$\sqrt{I_{(x,y,z,c)}}\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. \par Example \code const CImg img("reference.jpg"); (img,img.get_sqrt().normalize(0,255)).display(); \endcode \image html ref_sqrt.jpg **/ CImg& sqrt() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd); return *this; } //! Compute the square root of each pixel value \newinstance. CImg get_sqrt() const { return CImg(*this,false).sqrt(); } //! Compute the exponential of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its exponential \f$e^{I_{(x,y,z,c)}}\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& exp() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=4096) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd); return *this; } //! Compute the exponential of each pixel value \newinstance. CImg get_exp() const { return CImg(*this,false).exp(); } //! Compute the logarithm of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its logarithm \f$\mathrm{log}_{e}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& log() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=262144) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd); return *this; } //! Compute the logarithm of each pixel value \newinstance. CImg get_log() const { return CImg(*this,false).log(); } //! Compute the base-2 logarithm of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its base-2 logarithm \f$\mathrm{log}_{2}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& log2() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=4096) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd); return *this; } //! Compute the base-10 logarithm of each pixel value \newinstance. CImg get_log2() const { return CImg(*this,false).log2(); } //! Compute the base-10 logarithm of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its base-10 logarithm \f$\mathrm{log}_{10}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& log10() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=4096) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd); return *this; } //! Compute the base-10 logarithm of each pixel value \newinstance. CImg get_log10() const { return CImg(*this,false).log10(); } //! Compute the absolute value of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its absolute value \f$|I_{(x,y,z,c)}|\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& abs() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=524288) #endif cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd); return *this; } //! Compute the absolute value of each pixel value \newinstance. CImg get_abs() const { return CImg(*this,false).abs(); } //! Compute the sign of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sign \f$\mathrm{sign}(I_{(x,y,z,c)})\f$. \note - The sign is set to: - \c 1 if pixel value is strictly positive. - \c -1 if pixel value is strictly negative. - \c 0 if pixel value is equal to \c 0. - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& sign() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd); return *this; } //! Compute the sign of each pixel value \newinstance. CImg get_sign() const { return CImg(*this,false).sign(); } //! Compute the cosine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its cosine \f$\cos(I_{(x,y,z,c)})\f$. \note - Pixel values are regarded as being in \e radian. - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& cos() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd); return *this; } //! Compute the cosine of each pixel value \newinstance. CImg get_cos() const { return CImg(*this,false).cos(); } //! Compute the sine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sine \f$\sin(I_{(x,y,z,c)})\f$. \note - Pixel values are regarded as being in \e radian. - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& sin() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd); return *this; } //! Compute the sine of each pixel value \newinstance. CImg get_sin() const { return CImg(*this,false).sin(); } //! Compute the sinc of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sinc \f$\mathrm{sinc}(I_{(x,y,z,c)})\f$. \note - Pixel values are regarded as being exin \e radian. - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& sinc() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=2048) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd); return *this; } //! Compute the sinc of each pixel value \newinstance. CImg get_sinc() const { return CImg(*this,false).sinc(); } //! Compute the tangent of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its tangent \f$\tan(I_{(x,y,z,c)})\f$. \note - Pixel values are regarded as being exin \e radian. - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& tan() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=2048) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd); return *this; } //! Compute the tangent of each pixel value \newinstance. CImg get_tan() const { return CImg(*this,false).tan(); } //! Compute the hyperbolic cosine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic cosine \f$\mathrm{cosh}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& cosh() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=2048) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd); return *this; } //! Compute the hyperbolic cosine of each pixel value \newinstance. CImg get_cosh() const { return CImg(*this,false).cosh(); } //! Compute the hyperbolic sine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic sine \f$\mathrm{sinh}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& sinh() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=2048) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd); return *this; } //! Compute the hyperbolic sine of each pixel value \newinstance. CImg get_sinh() const { return CImg(*this,false).sinh(); } //! Compute the hyperbolic tangent of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic tangent \f$\mathrm{tanh}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& tanh() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=2048) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd); return *this; } //! Compute the hyperbolic tangent of each pixel value \newinstance. CImg get_tanh() const { return CImg(*this,false).tanh(); } //! Compute the arccosine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arccosine \f$\mathrm{acos}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& acos() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd); return *this; } //! Compute the arccosine of each pixel value \newinstance. CImg get_acos() const { return CImg(*this,false).acos(); } //! Compute the arcsine of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arcsine \f$\mathrm{asin}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& asin() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd); return *this; } //! Compute the arcsine of each pixel value \newinstance. CImg get_asin() const { return CImg(*this,false).asin(); } //! Compute the arctangent of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent \f$\mathrm{atan}(I_{(x,y,z,c)})\f$. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. **/ CImg& atan() { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd); return *this; } //! Compute the arctangent of each pixel value \newinstance. CImg get_atan() const { return CImg(*this,false).atan(); } //! Compute the arctangent2 of each pixel value. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent2 \f$\mathrm{atan2}(I_{(x,y,z,c)})\f$. \param img Image whose pixel values specify the second argument of the \c atan2() function. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. \par Example \code const CImg img_x(100,100,1,1,"x-w/2",false), // Define an horizontal centered gradient, from '-width/2' to 'width/2'. img_y(100,100,1,1,"y-h/2",false), // Define a vertical centered gradient, from '-height/2' to 'height/2'. img_atan2 = img_y.get_atan2(img_x); // Compute atan2(y,x) for each pixel value. (img_x,img_y,img_atan2).display(); \endcode **/ template CImg& atan2(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return atan2(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg get_atan2(const CImg& img) const { return CImg(*this,false).atan2(img); } //! In-place pointwise multiplication. /** Compute the pointwise multiplication between the image instance and the specified input image \c img. \param img Input image, as the second operand of the multiplication. \note - Similar to operator+=(const CImg&), except that it performs a pointwise multiplication instead of an addition. - It does \e not perform a \e matrix multiplication. For this purpose, use operator*=(const CImg&) instead. \par Example \code CImg img("reference.jpg"), shade(img.width,img.height(),1,1,"-(x-w/2)^2-(y-h/2)^2",false); shade.normalize(0,1); (img,shade,img.get_mul(shade)).display(); \endcode **/ template CImg& mul(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return mul(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg<_cimg_Tt> get_mul(const CImg& img) const { return CImg<_cimg_Tt>(*this,false).mul(img); } //! In-place pointwise division. /** Similar to mul(const CImg&), except that it performs a pointwise division instead of a multiplication. **/ template CImg& div(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return div(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg<_cimg_Tt> get_div(const CImg& img) const { return CImg<_cimg_Tt>(*this,false).div(img); } //! Raise each pixel value to a specified power. /** Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its power \f$I_{(x,y,z,c)}^p\f$. \param p Exponent value. \note - The \inplace of this method statically casts the computed values to the pixel type \c T. - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. \par Example \code const CImg img0("reference.jpg"), // Load reference color image. img1 = (img0/255).pow(1.8)*=255, // Compute gamma correction, with gamma = 1.8. img2 = (img0/255).pow(0.5)*=255; // Compute gamma correction, with gamma = 0.5. (img0,img1,img2).display(); \endcode **/ CImg& pow(const double p) { if (is_empty()) return *this; if (p==-4) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); } return *this; } if (p==-3) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); } return *this; } if (p==-2) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); } return *this; } if (p==-1) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); } return *this; } if (p==-0.5) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); } return *this; } if (p==0) return fill(1); if (p==0.5) return sqrt(); if (p==1) return *this; if (p==2) return sqr(); if (p==3) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=262144) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; } return *this; } if (p==4) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=131072) #endif cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; } return *this; } #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=1024) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p); return *this; } //! Raise each pixel value to a specified power \newinstance. CImg get_pow(const double p) const { return CImg(*this,false).pow(p); } //! Raise each pixel value to a power, specified from an expression. /** Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition. **/ CImg& pow(const char *const expression) { return pow((+*this)._fill(expression,true,true,0,0,"pow",this)); } //! Raise each pixel value to a power, specified from an expression \newinstance. CImg get_pow(const char *const expression) const { return CImg(*this,false).pow(expression); } //! Raise each pixel value to a power, pointwisely specified from another image. /** Similar to operator+=(const CImg& img), except that it performs an exponentiation instead of an addition. **/ template CImg& pow(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return pow(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg get_pow(const CImg& img) const { return CImg(*this,false).pow(img); } //! Compute the bitwise left rotation of each pixel value. /** Similar to operator<<=(unsigned int), except that it performs a left rotation instead of a left shift. **/ CImg& rol(const unsigned int n=1) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n); return *this; } //! Compute the bitwise left rotation of each pixel value \newinstance. CImg get_rol(const unsigned int n=1) const { return (+*this).rol(n); } //! Compute the bitwise left rotation of each pixel value. /** Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift. **/ CImg& rol(const char *const expression) { return rol((+*this)._fill(expression,true,true,0,0,"rol",this)); } //! Compute the bitwise left rotation of each pixel value \newinstance. CImg get_rol(const char *const expression) const { return (+*this).rol(expression); } //! Compute the bitwise left rotation of each pixel value. /** Similar to operator<<=(const CImg&), except that it performs a left rotation instead of a left shift. **/ template CImg& rol(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return rol(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg get_rol(const CImg& img) const { return (+*this).rol(img); } //! Compute the bitwise right rotation of each pixel value. /** Similar to operator>>=(unsigned int), except that it performs a right rotation instead of a right shift. **/ CImg& ror(const unsigned int n=1) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n); return *this; } //! Compute the bitwise right rotation of each pixel value \newinstance. CImg get_ror(const unsigned int n=1) const { return (+*this).ror(n); } //! Compute the bitwise right rotation of each pixel value. /** Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift. **/ CImg& ror(const char *const expression) { return ror((+*this)._fill(expression,true,true,0,0,"ror",this)); } //! Compute the bitwise right rotation of each pixel value \newinstance. CImg get_ror(const char *const expression) const { return (+*this).ror(expression); } //! Compute the bitwise right rotation of each pixel value. /** Similar to operator>>=(const CImg&), except that it performs a right rotation instead of a right shift. **/ template CImg& ror(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return ror(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg get_ror(const CImg& img) const { return (+*this).ror(img); } //! Pointwise min operator between instance image and a value. /** \param val Value used as the reference argument of the min operator. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{val})\f$. **/ CImg& min(const T& val) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val); return *this; } //! Pointwise min operator between instance image and a value \newinstance. CImg get_min(const T& val) const { return (+*this).min(val); } //! Pointwise min operator between two images. /** \param img Image used as the reference argument of the min operator. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. **/ template CImg& min(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return min(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg<_cimg_Tt> get_min(const CImg& img) const { return CImg<_cimg_Tt>(*this,false).min(img); } //! Pointwise min operator between an image and an expression. /** \param expression Math formula as a C-string. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. **/ CImg& min(const char *const expression) { return min((+*this)._fill(expression,true,true,0,0,"min",this)); } //! Pointwise min operator between an image and an expression \newinstance. CImg get_min(const char *const expression) const { return CImg(*this,false).min(expression); } //! Pointwise max operator between instance image and a value. /** \param val Value used as the reference argument of the max operator. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{val})\f$. **/ CImg& max(const T& val) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val); return *this; } //! Pointwise max operator between instance image and a value \newinstance. CImg get_max(const T& val) const { return (+*this).max(val); } //! Pointwise max operator between two images. /** \param img Image used as the reference argument of the max operator. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. **/ template CImg& max(const CImg& img) { const ulongT siz = size(), isiz = img.size(); if (siz && isiz) { if (is_overlapped(img)) return max(+img); T *ptrd = _data, *const ptre = _data + siz; if (siz>isiz) for (ulongT n = siz/isiz; n; --n) for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs CImg<_cimg_Tt> get_max(const CImg& img) const { return CImg<_cimg_Tt>(*this,false).max(img); } //! Pointwise max operator between an image and an expression. /** \param expression Math formula as a C-string. \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. **/ CImg& max(const char *const expression) { return max((+*this)._fill(expression,true,true,0,0,"max",this)); } //! Pointwise max operator between an image and an expression \newinstance. CImg get_max(const char *const expression) const { return CImg(*this,false).max(expression); } //! Return a reference to the minimum pixel value. /** **/ T& min() { if (is_empty()) throw CImgInstanceException(_cimg_instance "min(): Empty instance.", cimg_instance); T *ptr_min = _data; T min_value = *ptr_min; cimg_for(*this,ptrs,T) if (*ptrsmax_value) max_value = *(ptr_max=ptrs); return *ptr_max; } //! Return a reference to the maximum pixel value \const. const T& max() const { if (is_empty()) throw CImgInstanceException(_cimg_instance "max(): Empty instance.", cimg_instance); const T *ptr_max = _data; T max_value = *ptr_max; cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); return *ptr_max; } //! Return a reference to the minimum pixel value as well as the maximum pixel value. /** \param[out] max_val Maximum pixel value. **/ template T& min_max(t& max_val) { if (is_empty()) throw CImgInstanceException(_cimg_instance "min_max(): Empty instance.", cimg_instance); T *ptr_min = _data; T min_value = *ptr_min, max_value = min_value; cimg_for(*this,ptrs,T) { const T val = *ptrs; if (valmax_value) max_value = val; } max_val = (t)max_value; return *ptr_min; } //! Return a reference to the minimum pixel value as well as the maximum pixel value \const. template const T& min_max(t& max_val) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "min_max(): Empty instance.", cimg_instance); const T *ptr_min = _data; T min_value = *ptr_min, max_value = min_value; cimg_for(*this,ptrs,T) { const T val = *ptrs; if (valmax_value) max_value = val; } max_val = (t)max_value; return *ptr_min; } //! Return a reference to the maximum pixel value as well as the minimum pixel value. /** \param[out] min_val Minimum pixel value. **/ template T& max_min(t& min_val) { if (is_empty()) throw CImgInstanceException(_cimg_instance "max_min(): Empty instance.", cimg_instance); T *ptr_max = _data; T max_value = *ptr_max, min_value = max_value; cimg_for(*this,ptrs,T) { const T val = *ptrs; if (val>max_value) { max_value = val; ptr_max = ptrs; } if (val const T& max_min(t& min_val) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "max_min(): Empty instance.", cimg_instance); const T *ptr_max = _data; T max_value = *ptr_max, min_value = max_value; cimg_for(*this,ptrs,T) { const T val = *ptrs; if (val>max_value) { max_value = val; ptr_max = ptrs; } if (val arr(*this); unsigned int l = 0, ir = size() - 1; for ( ; ; ) { if (ir<=l + 1) { if (ir==l + 1 && arr[ir]>1; cimg::swap(arr[mid],arr[l + 1]); if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]); if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]); unsigned int i = l + 1, j = ir; const T pivot = arr[l + 1]; for ( ; ; ) { do ++i; while (arr[i]pivot); if (j=k) ir = j - 1; if (j<=k) l = i; } } } //! Return the median pixel value. /** **/ T median() const { if (is_empty()) throw CImgInstanceException(_cimg_instance "median(): Empty instance.", cimg_instance); const unsigned int s = size(); const T res = kth_smallest(s>>1); return (s%2)?res:((res + kth_smallest((s>>1) - 1))/2); } //! Return the product of all the pixel values. /** **/ double product() const { if (is_empty()) return 0; double res = 1; cimg_for(*this,ptrs,T) res*=(double)*ptrs; return res; } //! Return the sum of all the pixel values. /** **/ double sum() const { double res = 0; cimg_for(*this,ptrs,T) res+=(double)*ptrs; return res; } //! Return the average pixel value. /** **/ double mean() const { double res = 0; cimg_for(*this,ptrs,T) res+=(double)*ptrs; return res/size(); } //! Return the variance of the pixel values. /** \param variance_method Method used to estimate the variance. Can be: - \c 0: Second moment, computed as \f$1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2 = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right)\f$ with \f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$. - \c 1: Best unbiased estimator, computed as \f$\frac{1}{N - 1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 \f$. - \c 2: Least median of squares. - \c 3: Least trimmed of squares. **/ double variance(const unsigned int variance_method=1) const { double foo; return variance_mean(variance_method,foo); } //! Return the variance as well as the average of the pixel values. /** \param variance_method Method used to estimate the variance (see variance(const unsigned int) const). \param[out] mean Average pixel value. **/ template double variance_mean(const unsigned int variance_method, t& mean) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "variance_mean(): Empty instance.", cimg_instance); double variance = 0, average = 0; const ulongT siz = size(); switch (variance_method) { case 0 : { // Least mean square (standard definition) double S = 0, S2 = 0; cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } variance = (S2 - S*S/siz)/siz; average = S; } break; case 1 : { // Least mean square (robust definition) double S = 0, S2 = 0; cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; average = S; } break; case 2 : { // Least Median of Squares (MAD) CImg buf(*this,false); buf.sort(); const ulongT siz2 = siz>>1; const double med_i = (double)buf[siz2]; cimg_for(buf,ptrs,Tfloat) { const double val = (double)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; } buf.sort(); const double sig = (double)(1.4828*buf[siz2]); variance = sig*sig; } break; default : { // Least trimmed of Squares CImg buf(*this,false); const ulongT siz2 = siz>>1; cimg_for(buf,ptrs,Tfloat) { const double val = (double)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; } buf.sort(); double a = 0; const Tfloat *ptrs = buf._data; for (ulongT j = 0; j0?variance:0; } //! Return estimated variance of the noise. /** \param variance_method Method used to compute the variance (see variance(const unsigned int) const). \note Because of structures such as edges in images it is recommanded to use a robust variance estimation. The variance of the noise is estimated by computing the variance of the Laplacian \f$(\Delta I)^2 \f$ scaled by a factor \f$c\f$ insuring \f$ c E[(\Delta I)^2]= \sigma^2\f$ where \f$\sigma\f$ is the noise variance. **/ double variance_noise(const unsigned int variance_method=2) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "variance_noise(): Empty instance.", cimg_instance); const ulongT siz = size(); if (!siz || !_data) return 0; if (variance_method>1) { // Compute a scaled version of the Laplacian. CImg tmp(*this); if (_depth==1) { const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height>=262144 && _spectrum>=2) #endif cimg_forC(*this,c) { CImg_3x3(I,T); cimg_for3x3(*this,x,y,0,c,I,T) { tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn + (double)Icp - 4*(double)Icc); } } } else { const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=262144 && _spectrum>=2) #endif cimg_forC(*this,c) { CImg_3x3x3(I,T); cimg_for3x3x3(*this,x,y,z,c,I,T) { tmp(x,y,z,c) = cste*( (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc + (double)Iccn + (double)Iccp - 6*(double)Iccc); } } } return tmp.variance(variance_method); } // Version that doesn't need intermediate images. double variance = 0, S = 0, S2 = 0; if (_depth==1) { const double cste = 1.0/std::sqrt(20.0); CImg_3x3(I,T); cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) { const double val = cste*((double)Inc + (double)Ipc + (double)Icn + (double)Icp - 4*(double)Icc); S+=val; S2+=val*val; } } else { const double cste = 1.0/std::sqrt(42.0); CImg_3x3x3(I,T); cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) { const double val = cste * ((double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc + (double)Iccn + (double)Iccp - 6*(double)Iccc); S+=val; S2+=val*val; } } if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; else variance = (S2 - S*S/siz)/siz; return variance>0?variance:0; } //! Compute the MSE (Mean-Squared Error) between two images. /** \param img Image used as the second argument of the MSE operator. **/ template double MSE(const CImg& img) const { if (img.size()!=size()) throw CImgArgumentException(_cimg_instance "MSE(): Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.", cimg_instance, img._width,img._height,img._depth,img._spectrum,img._data); double vMSE = 0; const t* ptr2 = img._data; cimg_for(*this,ptr1,T) { const double diff = (double)*ptr1 - (double)*(ptr2++); vMSE+=diff*diff; } const ulongT siz = img.size(); if (siz) vMSE/=siz; return vMSE; } //! Compute the PSNR (Peak Signal-to-Noise Ratio) between two images. /** \param img Image used as the second argument of the PSNR operator. \param max_value Maximum theoretical value of the signal. **/ template double PSNR(const CImg& img, const double max_value=255) const { const double vMSE = (double)std::sqrt(MSE(img)); return (vMSE!=0)?(double)(20*std::log10(max_value/vMSE)):(double)(cimg::type::max()); } //! Evaluate math formula. /** \param expression Math formula, as a C-string. \param x Value of the pre-defined variable \c x. \param y Value of the pre-defined variable \c y. \param z Value of the pre-defined variable \c z. \param c Value of the pre-defined variable \c c. \param list_inputs A list of input images attached to the specified math formula. \param list_outputs A pointer to a list of output images attached to the specified math formula. **/ double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) { return _eval(this,expression,x,y,z,c,list_inputs,list_outputs); } //! Evaluate math formula \const. double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) const { return _eval(0,expression,x,y,z,c,list_inputs,list_outputs); } double _eval(CImg *const img_output, const char *const expression, const double x, const double y, const double z, const double c, const CImgList *const list_inputs, CImgList *const list_outputs) const { if (!expression) return 0; if (!expression[1]) switch (*expression) { // Single-char optimization. case 'w' : return (double)_width; case 'h' : return (double)_height; case 'd' : return (double)_depth; case 's' : return (double)_spectrum; case 'r' : return (double)_is_shared; } _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*' || *expression==':'?1:0),"eval", *this,img_output,list_inputs,list_outputs); return mp(x,y,z,c); } //! Evaluate math formula. /** \param[out] output Contains values of output vector returned by the evaluated expression (or is empty if the returned type is scalar). \param expression Math formula, as a C-string. \param x Value of the pre-defined variable \c x. \param y Value of the pre-defined variable \c y. \param z Value of the pre-defined variable \c z. \param c Value of the pre-defined variable \c c. \param list_inputs A list of input images attached to the specified math formula. \param list_outputs A pointer to a list of output images attached to the specified math formula. **/ template void eval(CImg &output, const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) { _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs); } //! Evaluate math formula \const. template void eval(CImg& output, const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) const { _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs); } template void _eval(CImg& output, CImg *const img_output, const char *const expression, const double x, const double y, const double z, const double c, const CImgList *const list_inputs, CImgList *const list_outputs) const { if (!expression) { output.assign(1); *output = 0; } if (!expression[1]) switch (*expression) { // Single-char optimization. case 'w' : output.assign(1); *output = (t)_width; case 'h' : output.assign(1); *output = (t)_height; case 'd' : output.assign(1); *output = (t)_depth; case 's' : output.assign(1); *output = (t)_spectrum; case 'r' : output.assign(1); *output = (t)_is_shared; } _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*' || *expression==':'?1:0),"eval", *this,img_output,list_inputs,list_outputs); output.assign(1,cimg::max(1U,mp.result_dim)); mp(x,y,z,c,output._data); } //! Evaluate math formula on a set of variables. /** \param expression Math formula, as a C-string. \param xyzc Set of values (x,y,z,c) used for the evaluation. **/ template CImg eval(const char *const expression, const CImg& xyzc, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) { return _eval(this,expression,xyzc,list_inputs,list_outputs); } //! Evaluate math formula on a set of variables \const. template CImg eval(const char *const expression, const CImg& xyzc, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) const { return _eval(0,expression,xyzc,list_inputs,list_outputs); } template CImg _eval(CImg *const output, const char *const expression, const CImg& xyzc, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) const { CImg res(1,xyzc.size()/4); if (!expression) return res.fill(0); _cimg_math_parser mp(expression,"eval",*this,output,list_inputs,list_outputs); #ifdef cimg_use_openmp #pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6) { _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; #pragma omp for for (unsigned int i = 0; i[min; max; mean; variance; xmin; ymin; zmin; cmin; xmax; ymax; zmax; cmax; sum; product]. **/ CImg get_stats(const unsigned int variance_method=1) const { if (is_empty()) return CImg(); const ulongT siz = size(); const T *const odata = _data; const T *pm = odata, *pM = odata; double S = 0, S2 = 0, P = _data?1:0; T m = *pm, M = m; cimg_for(*this,ptrs,T) { const T val = *ptrs; const double _val = (double)val; if (valM) { M = val; pM = ptrs; } S+=_val; S2+=_val*_val; P*=_val; } const double mean_value = S/siz, _variance_value = variance_method==0?(S2 - S*S/siz)/siz: (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0): variance(variance_method)), variance_value = _variance_value>0?_variance_value:0; int xm = 0, ym = 0, zm = 0, cm = 0, xM = 0, yM = 0, zM = 0, cM = 0; contains(*pm,xm,ym,zm,cm); contains(*pM,xM,yM,zM,cM); return CImg(1,14).fill((double)m,(double)M,mean_value,variance_value, (double)xm,(double)ym,(double)zm,(double)cm, (double)xM,(double)yM,(double)zM,(double)cM, S,P); } //! Compute statistics vector from the pixel values \inplace. CImg& stats(const unsigned int variance_method=1) { return get_stats(variance_method).move_to(*this); } //@} //------------------------------------- // //! \name Vector / Matrix Operations //@{ //------------------------------------- //! Compute norm of the image, viewed as a matrix. /** \param magnitude_type Norm type. Can be: - \c -1: Linf-norm - \c 0: L2-norm - \c 1: L1-norm **/ double magnitude(const int magnitude_type=2) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "magnitude(): Empty instance.", cimg_instance); double res = 0; switch (magnitude_type) { case -1 : { cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; } } break; case 1 : { cimg_for(*this,ptrs,T) res+=(double)cimg::abs(*ptrs); } break; default : { cimg_for(*this,ptrs,T) res+=(double)cimg::sqr(*ptrs); res = (double)std::sqrt(res); } } return res; } //! Compute the trace of the image, viewed as a matrix. /** **/ double trace() const { if (is_empty()) throw CImgInstanceException(_cimg_instance "trace(): Empty instance.", cimg_instance); double res = 0; cimg_forX(*this,k) res+=(double)(*this)(k,k); return res; } //! Compute the determinant of the image, viewed as a matrix. /** **/ double det() const { if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1) throw CImgInstanceException(_cimg_instance "det(): Instance is not a square matrix.", cimg_instance); switch (_width) { case 1 : return (double)((*this)(0,0)); case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0)); case 3 : { const double a = (double)_data[0], d = (double)_data[1], g = (double)_data[2], b = (double)_data[3], e = (double)_data[4], h = (double)_data[5], c = (double)_data[6], f = (double)_data[7], i = (double)_data[8]; return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e; } default : { CImg lu(*this); CImg indx; bool d; lu._LU(indx,d); double res = d?(double)1:(double)-1; cimg_forX(lu,i) res*=lu(i,i); return res; } } } //! Compute the dot product between instance and argument, viewed as matrices. /** \param img Image used as a second argument of the dot product. **/ template double dot(const CImg& img) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "dot(): Empty instance.", cimg_instance); if (!img) throw CImgArgumentException(_cimg_instance "dot(): Empty specified image.", cimg_instance); const ulongT nb = cimg::min(size(),img.size()); double res = 0; for (ulongT off = 0; off get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { CImg res; if (res._height!=_spectrum) res.assign(1,_spectrum); const ulongT whd = (ulongT)_width*_height*_depth; const T *ptrs = data(x,y,z); T *ptrd = res._data; cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return res; } //! Get (square) matrix-valued pixel located at specified position. /** \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \note - The spectrum() of the image must be a square. **/ CImg get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const { const int n = (int)std::sqrt((double)_spectrum); const T *ptrs = data(x,y,z,0); const ulongT whd = (ulongT)_width*_height*_depth; CImg res(n,n); T *ptrd = res._data; cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } return res; } //! Get tensor-valued pixel located at specified position. /** \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. **/ CImg get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { const T *ptrs = data(x,y,z,0); const ulongT whd = (ulongT)_width*_height*_depth; if (_spectrum==6) return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd)); if (_spectrum==3) return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd)); return tensor(*ptrs); } //! Set vector-valued pixel at specified position. /** \param vec Vector to put on the instance image. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. **/ template CImg& set_vector_at(const CImg& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) { if (x<_width && y<_height && z<_depth) { const t *ptrs = vec._data; const ulongT whd = (ulongT)_width*_height*_depth; T *ptrd = data(x,y,z); for (unsigned int k = cimg::min((unsigned int)vec.size(),_spectrum); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whd; } } return *this; } //! Set (square) matrix-valued pixel at specified position. /** \param mat Matrix to put on the instance image. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. **/ template CImg& set_matrix_at(const CImg& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { return set_vector_at(mat,x,y,z); } //! Set tensor-valued pixel at specified position. /** \param ten Tensor to put on the instance image. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. **/ template CImg& set_tensor_at(const CImg& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { T *ptrd = data(x,y,z,0); const ulongT siz = (ulongT)_width*_height*_depth; if (ten._height==2) { *ptrd = (T)ten[0]; ptrd+=siz; *ptrd = (T)ten[1]; ptrd+=siz; *ptrd = (T)ten[3]; } else { *ptrd = (T)ten[0]; ptrd+=siz; *ptrd = (T)ten[1]; ptrd+=siz; *ptrd = (T)ten[2]; ptrd+=siz; *ptrd = (T)ten[4]; ptrd+=siz; *ptrd = (T)ten[5]; ptrd+=siz; *ptrd = (T)ten[8]; } return *this; } //! Unroll pixel values along axis \c y. /** \note Equivalent to \code unroll('y'); \endcode. **/ CImg& vector() { return unroll('y'); } //! Unroll pixel values along axis \c y \newinstance. CImg get_vector() const { return get_unroll('y'); } //! Resize image to become a scalar square matrix. /** **/ CImg& matrix() { const ulongT siz = size(); switch (siz) { case 1 : break; case 4 : _width = _height = 2; break; case 9 : _width = _height = 3; break; case 16 : _width = _height = 4; break; case 25 : _width = _height = 5; break; case 36 : _width = _height = 6; break; case 49 : _width = _height = 7; break; case 64 : _width = _height = 8; break; case 81 : _width = _height = 9; break; case 100 : _width = _height = 10; break; default : { ulongT i = 11, i2 = i*i; while (i2 get_matrix() const { return (+*this).matrix(); } //! Resize image to become a symmetric tensor. /** **/ CImg& tensor() { return get_tensor().move_to(*this); } //! Resize image to become a symmetric tensor \newinstance. CImg get_tensor() const { CImg res; const ulongT siz = size(); switch (siz) { case 1 : break; case 3 : res.assign(2,2); res(0,0) = (*this)(0); res(1,0) = res(0,1) = (*this)(1); res(1,1) = (*this)(2); break; case 6 : res.assign(3,3); res(0,0) = (*this)(0); res(1,0) = res(0,1) = (*this)(1); res(2,0) = res(0,2) = (*this)(2); res(1,1) = (*this)(3); res(2,1) = res(1,2) = (*this)(4); res(2,2) = (*this)(5); break; default : throw CImgInstanceException(_cimg_instance "tensor(): Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).", cimg_instance); } return res; } //! Resize image to become a diagonal matrix. /** \note Transform the image as a diagonal matrix so that each of its initial value becomes a diagonal coefficient. **/ CImg& diagonal() { return get_diagonal().move_to(*this); } //! Resize image to become a diagonal matrix \newinstance. CImg get_diagonal() const { if (is_empty()) return *this; CImg res(size(),size(),1,1,0); cimg_foroff(*this,off) res(off,off) = (*this)(off); return res; } //! Replace the image by an identity matrix. /** \note If the instance image is not square, it is resized to a square matrix using its maximum dimension as a reference. **/ CImg& identity_matrix() { return identity_matrix(cimg::max(_width,_height)).move_to(*this); } //! Replace the image by an identity matrix \newinstance. CImg get_identity_matrix() const { return identity_matrix(cimg::max(_width,_height)); } //! Fill image with a linear sequence of values. /** \param a0 Starting value of the sequence. \param a1 Ending value of the sequence. **/ CImg& sequence(const T& a0, const T& a1) { if (is_empty()) return *this; const unsigned int siz = size() - 1; T* ptr = _data; if (siz) { const double delta = (double)a1 - (double)a0; cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz); } else *ptr = a0; return *this; } //! Fill image with a linear sequence of values \newinstance. CImg get_sequence(const T& a0, const T& a1) const { return (+*this).sequence(a0,a1); } //! Transpose the image, viewed as a matrix. /** \note Equivalent to \code permute_axes("yxzc"); \endcode **/ CImg& transpose() { if (_width==1) { _width = _height; _height = 1; return *this; } if (_height==1) { _height = _width; _width = 1; return *this; } if (_width==_height) { cimg_forYZC(*this,y,z,c) for (int x = y; x get_transpose() const { return get_permute_axes("yxzc"); } //! Compute the cross product between two \c 1x3 images, viewed as 3d vectors. /** \param img Image used as the second argument of the cross product. \note The first argument of the cross product is \c *this. **/ template CImg& cross(const CImg& img) { if (_width!=1 || _height<3 || img._width!=1 || img._height<3) throw CImgInstanceException(_cimg_instance "cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.", cimg_instance, img._width,img._height,img._depth,img._spectrum,img._data); const T x = (*this)[0], y = (*this)[1], z = (*this)[2]; (*this)[0] = (T)(y*img[2] - z*img[1]); (*this)[1] = (T)(z*img[0] - x*img[2]); (*this)[2] = (T)(x*img[1] - y*img[0]); return *this; } //! Compute the cross product between two \c 1x3 images, viewed as 3d vectors \newinstance. template CImg<_cimg_Tt> get_cross(const CImg& img) const { return CImg<_cimg_Tt>(*this).cross(img); } //! Invert the instance image, viewed as a matrix. /** \param use_LU Choose the inverting algorithm. Can be: - \c true: LU-based matrix inversion. - \c false: SVD-based matrix inversion. **/ CImg& invert(const bool use_LU=true) { if (_width!=_height || _depth!=1 || _spectrum!=1) throw CImgInstanceException(_cimg_instance "invert(): Instance is not a square matrix.", cimg_instance); #ifdef cimg_use_lapack int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N]; Tfloat *const lapA = new Tfloat[N*N], *const WORK = new Tfloat[LWORK]; cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); cimg::getrf(N,lapA,IPIV,INFO); if (INFO) cimg::warn(_cimg_instance "invert(): LAPACK function dgetrf_() returned error code %d.", cimg_instance, INFO); else { cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO); if (INFO) cimg::warn(_cimg_instance "invert(): LAPACK function dgetri_() returned error code %d.", cimg_instance, INFO); } if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0); delete[] IPIV; delete[] lapA; delete[] WORK; #else const double dete = _width>3?-1.0:det(); if (dete!=0.0 && _width==2) { const double a = _data[0], c = _data[1], b = _data[2], d = _data[3]; _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete); _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete); } else if (dete!=0.0 && _width==3) { const double a = _data[0], d = _data[1], g = _data[2], b = _data[3], e = _data[4], h = _data[5], c = _data[6], f = _data[7], i = _data[8]; _data[0] = (T)((i*e-f*h)/dete), _data[1] = (T)((g*f-i*d)/dete), _data[2] = (T)((d*h-g*e)/dete); _data[3] = (T)((h*c-i*b)/dete), _data[4] = (T)((i*a-c*g)/dete), _data[5] = (T)((g*b-a*h)/dete); _data[6] = (T)((b*f-e*c)/dete), _data[7] = (T)((d*c-a*f)/dete), _data[8] = (T)((a*e-d*b)/dete); } else { if (use_LU) { // LU-based inverse computation CImg A(*this), indx, col(1,_width); bool d; A._LU(indx,d); cimg_forX(*this,j) { col.fill(0); col(j) = 1; col._solve(A,indx); cimg_forX(*this,i) (*this)(j,i) = (T)col(i); } } else { // SVD-based inverse computation CImg U(_width,_width), S(1,_width), V(_width,_width); SVD(U,S,V,false); U.transpose(); cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k]; S.diagonal(); *this = V*S*U; } } #endif return *this; } //! Invert the instance image, viewed as a matrix \newinstance. CImg get_invert(const bool use_LU=true) const { return CImg(*this,false).invert(use_LU); } //! Compute the Moore-Penrose pseudo-inverse of the instance image, viewed as a matrix. /** **/ CImg& pseudoinvert() { return get_pseudoinvert().move_to(*this); } //! Compute the Moore-Penrose pseudo-inverse of the instance image, viewed as a matrix \newinstance. CImg get_pseudoinvert() const { CImg U, S, V; SVD(U,S,V); const Tfloat tolerance = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*cimg::max(_width,_height)*S.max(); cimg_forX(V,x) { const Tfloat s = S(x), invs = s>tolerance?1/s:(Tfloat)0; cimg_forY(V,y) V(x,y)*=invs; } return V*U.transpose(); } //! Solve a system of linear equations. /** \param A Matrix of the linear system. \note Solve \c AX=B where \c B=*this. **/ template CImg& solve(const CImg& A) { if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1) throw CImgArgumentException(_cimg_instance "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have " "incompatible dimensions.", cimg_instance, A._width,A._height,A._depth,A._spectrum,A._data); typedef _cimg_Ttfloat Ttfloat; if (A._width==A._height) { // Classical linear system if (_width!=1) { CImg res(_width,A._width); cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A)); return res.move_to(*this); } #ifdef cimg_use_lapack char TRANS = 'N'; int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N]; Ttfloat *const lapA = new Ttfloat[N*N], *const lapB = new Ttfloat[N], *const WORK = new Ttfloat[LWORK]; cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l)); cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i)); cimg::getrf(N,lapA,IPIV,INFO); if (INFO) cimg::warn(_cimg_instance "solve(): LAPACK library function dgetrf_() returned error code %d.", cimg_instance, INFO); if (!INFO) { cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO); if (INFO) cimg::warn(_cimg_instance "solve(): LAPACK library function dgetrs_() returned error code %d.", cimg_instance, INFO); } if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0); delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK; #else CImg lu(A,false); CImg indx; bool d; lu._LU(indx,d); _solve(lu,indx); #endif } else { // Least-square solution for non-square systems. #ifdef cimg_use_lapack if (_width!=1) { CImg res(_width,A._width); cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A)); return res.move_to(*this); } char TRANS = 'N'; int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width; Ttfloat WORK_QUERY; Ttfloat * const lapA = new Ttfloat[M*N], * const lapB = new Ttfloat[M*NRHS]; cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO); LWORK = (int) WORK_QUERY; Ttfloat *const WORK = new Ttfloat[LWORK]; cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l)); cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l)); cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO); if (INFO != 0) cimg::warn(_cimg_instance "solve(): LAPACK library function sgels() returned error code %d.", cimg_instance, INFO); assign(NRHS, N); if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l]; else assign(A.get_pseudoinvert()*(*this)); delete[] lapA; delete[] lapB; delete[] WORK; #else assign(A.get_pseudoinvert()*(*this)); #endif } return *this; } //! Solve a system of linear equations \newinstance. template CImg<_cimg_Ttfloat> get_solve(const CImg& A) const { return CImg<_cimg_Ttfloat>(*this,false).solve(A); } template CImg& _solve(const CImg& A, const CImg& indx) { typedef _cimg_Ttfloat Ttfloat; const int N = (int)size(); int ii = -1; Ttfloat sum; for (int i = 0; i=0) for (int j = ii; j<=i - 1; ++j) sum-=A(j,i)*(*this)(j); else if (sum!=0) ii = i; (*this)(i) = (T)sum; } for (int i = N - 1; i>=0; --i) { sum = (*this)(i); for (int j = i + 1; j CImg& solve_tridiagonal(const CImg& A) { const unsigned int siz = (unsigned int)size(); if (A._width!=3 || A._height!=siz) throw CImgArgumentException(_cimg_instance "solve_tridiagonal(): Instance and tridiagonal matrix " "(%u,%u,%u,%u,%p) have incompatible dimensions.", cimg_instance, A._width,A._height,A._depth,A._spectrum,A._data); typedef _cimg_Ttfloat Ttfloat; const Ttfloat epsilon = 1e-4f; CImg B = A.get_column(1), V(*this,false); for (int i = 1; i<(int)siz; ++i) { const Ttfloat m = A(0,i)/(B[i - 1]?B[i - 1]:epsilon); B[i] -= m*A(2,i - 1); V[i] -= m*V[i - 1]; } (*this)[siz - 1] = (T)(V[siz - 1]/(B[siz - 1]?B[siz - 1]:epsilon)); for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i + 1])/(B[i]?B[i]:epsilon)); return *this; } //! Solve a tridiagonal system of linear equations \newinstance. template CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg& A) const { return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(A); } //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix. /** \param[out] val Vector of the estimated eigenvalues, in decreasing order. \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. **/ template const CImg& eigen(CImg& val, CImg &vec) const { if (is_empty()) { val.assign(); vec.assign(); } else { if (_width!=_height || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "eigen(): Instance is not a square matrix.", cimg_instance); if (val.size()<(ulongT)_width) val.assign(1,_width); if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width); switch (_width) { case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break; case 2 : { const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d; double f = e*e - 4*(a*d - b*c); if (f<0) cimg::warn(_cimg_instance "eigen(): Complex eigenvalues found.", cimg_instance); f = std::sqrt(f); const double l1 = 0.5*(e-f), l2 = 0.5*(e+f); const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b); val[0] = (t)l2; val[1] = (t)l1; vec(0,0) = (t)std::cos(theta1); vec(0,1) = (t)std::sin(theta1); vec(1,0) = (t)std::cos(theta2); vec(1,1) = (t)std::sin(theta2); } break; default : throw CImgInstanceException(_cimg_instance "eigen(): Eigenvalues computation of general matrices is limited " "to 2x2 matrices.", cimg_instance); } } return *this; } //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix. /** \return A list of two images [val; vec], whose meaning is similar as in eigen(CImg&,CImg&) const. **/ CImgList get_eigen() const { CImgList res(2); eigen(res[0],res[1]); return res; } //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix. /** \param[out] val Vector of the estimated eigenvalues, in decreasing order. \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. **/ template const CImg& symmetric_eigen(CImg& val, CImg& vec) const { if (is_empty()) { val.assign(); vec.assign(); } else { #ifdef cimg_use_lapack char JOB = 'V', UPLO = 'U'; int N = _width, LWORK = 4*N, INFO; Tfloat *const lapA = new Tfloat[N*N], *const lapW = new Tfloat[N], *const WORK = new Tfloat[LWORK]; cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO); if (INFO) cimg::warn(_cimg_instance "symmetric_eigen(): LAPACK library function dsyev_() returned error code %d.", cimg_instance, INFO); val.assign(1,N); vec.assign(N,N); if (!INFO) { cimg_forY(val,i) val(i) = (T)lapW[N - 1 -i]; cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N - 1 - k)*N + l]); } else { val.fill(0); vec.fill(0); } delete[] lapA; delete[] lapW; delete[] WORK; #else if (_width!=_height || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "eigen(): Instance is not a square matrix.", cimg_instance); val.assign(1,_width); if (vec._data) vec.assign(_width,_width); if (_width<3) { eigen(val,vec); if (_width==2) { vec[1] = -vec[2]; vec[3] = vec[0]; } // Force orthogonality for 2x2 matrices. return *this; } CImg V(_width,_width); Tfloat M = 0, m = (Tfloat)min_max(M), maxabs = cimg::max((Tfloat)1.0f,cimg::abs(m),cimg::abs(M)); (CImg(*this,false)/=maxabs).SVD(vec,val,V,false); if (maxabs!=1) val*=maxabs; bool is_ambiguous = false; float eig = 0; cimg_forY(val,p) { // check for ambiguous cases. if (val[p]>eig) eig = (float)val[p]; t scal = 0; cimg_forY(vec,y) scal+=vec(p,y)*V(p,y); if (cimg::abs(scal)<0.9f) is_ambiguous = true; if (scal<0) val[p] = -val[p]; } if (is_ambiguous) { ++(eig*=2); SVD(vec,val,V,false,40,eig); val-=eig; } CImg permutations; // sort eigenvalues in decreasing order CImg tmp(_width); val.sort(permutations,false); cimg_forY(vec,k) { cimg_forY(permutations,y) tmp(y) = vec(permutations(y),k); std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width); } #endif } return *this; } //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix. /** \return A list of two images [val; vec], whose meaning are similar as in symmetric_eigen(CImg&,CImg&) const. **/ CImgList get_symmetric_eigen() const { CImgList res(2); symmetric_eigen(res[0],res[1]); return res; } //! Sort pixel values and get sorting permutations. /** \param[out] permutations Permutation map used for the sorting. \param is_increasing Tells if pixel values are sorted in an increasing (\c true) or decreasing (\c false) way. **/ template CImg& sort(CImg& permutations, const bool is_increasing=true) { permutations.assign(_width,_height,_depth,_spectrum); if (is_empty()) return *this; cimg_foroff(permutations,off) permutations[off] = (t)off; return _quicksort(0,size() - 1,permutations,is_increasing,true); } //! Sort pixel values and get sorting permutations \newinstance. template CImg get_sort(CImg& permutations, const bool is_increasing=true) const { return (+*this).sort(permutations,is_increasing); } //! Sort pixel values. /** \param is_increasing Tells if pixel values are sorted in an increasing (\c true) or decreasing (\c false) way. \param axis Tells if the value sorting must be done along a specific axis. Can be: - \c 0: All pixel values are sorted, independently on their initial position. - \c 'x': Image columns are sorted, according to the first value in each column. - \c 'y': Image rows are sorted, according to the first value in each row. - \c 'z': Image slices are sorted, according to the first value in each slice. - \c 'c': Image channels are sorted, according to the first value in each channel. **/ CImg& sort(const bool is_increasing=true, const char axis=0) { if (is_empty()) return *this; CImg perm; switch (cimg::uncase(axis)) { case 0 : _quicksort(0,size() - 1,perm,is_increasing,false); break; case 'x' : { perm.assign(_width); get_crop(0,0,0,0,_width - 1,0,0,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c); } break; case 'y' : { perm.assign(_height); get_crop(0,0,0,0,0,_height - 1,0,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c); } break; case 'z' : { perm.assign(_depth); get_crop(0,0,0,0,0,0,_depth - 1,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c); } break; case 'c' : { perm.assign(_spectrum); get_crop(0,0,0,0,0,0,0,_spectrum - 1).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]); } break; default : throw CImgArgumentException(_cimg_instance "sort(): Invalid specified axis '%c' " "(should be { x | y | z | c }).", cimg_instance,axis); } return *this; } //! Sort pixel values \newinstance. CImg get_sort(const bool is_increasing=true, const char axis=0) const { return (+*this).sort(is_increasing,axis); } template CImg& _quicksort(const int indm, const int indM, CImg& permutations, const bool is_increasing, const bool is_permutations) { if (indm(*this)[mid]) { cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); } if ((*this)[mid]>(*this)[indM]) { cimg::swap((*this)[indM],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indM],permutations[mid]); } if ((*this)[indm]>(*this)[mid]) { cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); } } else { if ((*this)[indm]<(*this)[mid]) { cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); } if ((*this)[mid]<(*this)[indM]) { cimg::swap((*this)[indM],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indM],permutations[mid]); } if ((*this)[indm]<(*this)[mid]) { cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); } } if (indM - indm>=3) { const T pivot = (*this)[mid]; int i = indm, j = indM; if (is_increasing) { do { while ((*this)[i]pivot) --j; if (i<=j) { if (is_permutations) cimg::swap(permutations[i],permutations[j]); cimg::swap((*this)[i++],(*this)[j--]); } } while (i<=j); } else { do { while ((*this)[i]>pivot) ++i; while ((*this)[j] A; // Input matrix (assumed to contain some values). CImg<> U,S,V; A.SVD(U,S,V) \endcode **/ template const CImg& SVD(CImg& U, CImg& S, CImg& V, const bool sorting=true, const unsigned int max_iteration=40, const float lambda=0) const { if (is_empty()) { U.assign(); S.assign(); V.assign(); } else { U = *this; if (lambda!=0) { const unsigned int delta = cimg::min(U._width,U._height); for (unsigned int i = 0; i rv1(_width); t anorm = 0, c, f, g = 0, h, s, scale = 0; int l = 0, nm = 0; cimg_forX(U,i) { l = i + 1; rv1[i] = scale*g; g = s = scale = 0; if (i=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g; for (int j = l; j=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; for (int k = l; k=0; --i) { if (i=0; --i) { l = i + 1; g = S[i]; for (int j = l; j=0; --k) { for (unsigned int its = 0; its=1; --l) { nm = l - 1; if ((cimg::abs(rv1[l]) + anorm)==anorm) { flag = false; break; } if ((cimg::abs(S[nm]) + anorm)==anorm) break; } if (flag) { c = 0; s = 1; for (int i = l; i<=k; ++i) { f = s*rv1[i]; rv1[i] = c*rv1[i]; if ((cimg::abs(f) + anorm)==anorm) break; g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h; cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c + z*s; U(i,j) = z*c - y*s; } } } const t z = S[k]; if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; } nm = k - 1; t x = S[l], y = S[nm]; g = rv1[nm]; h = rv1[k]; f = ((y - z)*(y + z)+(g - h)*(g + h))/cimg::max((t)1e-25,2*h*y); g = (t)cimg::_pythagore(f,1.0); f = ((x - z)*(x + z)+h*((y/(f + (f>=0?g:-g))) - h))/cimg::max((t)1e-25,x); c = s = 1; for (int j = l; j<=nm; ++j) { const int i = j + 1; g = rv1[i]; h = s*g; g = c*g; t y = S[i]; t z = (t)cimg::_pythagore(f,h); rv1[j] = z; c = f/cimg::max((t)1e-25,z); s = h/cimg::max((t)1e-25,z); f = x*c + g*s; g = g*c - x*s; h = y*s; y*=c; cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c + z*s; V(i,jj) = z*c - x*s; } z = (t)cimg::_pythagore(f,h); S[j] = z; if (z) { z = 1/cimg::max((t)1e-25,z); c = f*z; s = h*z; } f = c*g + s*y; x = c*y - s*g; cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c + z*s; U(i,jj) = z*c - y*s; } } rv1[l] = 0; rv1[k]=f; S[k]=x; } } if (sorting) { CImg permutations; CImg tmp(_width); S.sort(permutations,false); cimg_forY(U,k) { cimg_forY(permutations,y) tmp(y) = U(permutations(y),k); std::memcpy(U.data(0,k),tmp._data,sizeof(t)*_width); } cimg_forY(V,k) { cimg_forY(permutations,y) tmp(y) = V(permutations(y),k); std::memcpy(V.data(0,k),tmp._data,sizeof(t)*_width); } } } return *this; } //! Compute the SVD of the instance image, viewed as a general matrix. /** \return A list of three images [U; S; V], whose meaning is similar as in SVD(CImg&,CImg&,CImg&,bool,unsigned int,float) const. **/ CImgList get_SVD(const bool sorting=true, const unsigned int max_iteration=40, const float lambda=0) const { CImgList res(3); SVD(res[0],res[1],res[2],sorting,max_iteration,lambda); return res; } // [internal] Compute the LU decomposition of a permuted matrix. template CImg& _LU(CImg& indx, bool& d) { const int N = width(); int imax = 0; CImg vv(N); indx.assign(N); d = true; cimg_forX(*this,i) { Tfloat vmax = 0; cimg_forX(*this,j) { const Tfloat tmp = cimg::abs((*this)(j,i)); if (tmp>vmax) vmax = tmp; } if (vmax==0) { indx.fill(0); return fill(0); } vv[i] = 1/vmax; } cimg_forX(*this,j) { for (int i = 0; i=vmax) { vmax=tmp; imax=i; } } if (j!=imax) { cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j)); d =!d; vv[imax] = vv[j]; } indx[j] = (t)imax; if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20; if (j static CImg dijkstra(const tf& distance, const unsigned int nb_nodes, const unsigned int starting_node, const unsigned int ending_node, CImg& previous_node) { if (starting_node>=nb_nodes) throw CImgArgumentException("CImg<%s>::dijkstra(): Specified indice of starting node %u is higher " "than number of nodes %u.", pixel_type(),starting_node,nb_nodes); CImg dist(1,nb_nodes,1,1,cimg::type::max()); dist(starting_node) = 0; previous_node.assign(1,nb_nodes,1,1,(t)-1); previous_node(starting_node) = (t)starting_node; CImg Q(nb_nodes); cimg_forX(Q,u) Q(u) = (unsigned int)u; cimg::swap(Q(starting_node),Q(0)); unsigned int sizeQ = nb_nodes; while (sizeQ) { // Update neighbors from minimal vertex const unsigned int umin = Q(0); if (umin==ending_node) sizeQ = 0; else { const T dmin = dist(umin); const T infty = cimg::type::max(); for (unsigned int q = 1; qdist(Q(left))) || (rightdist(Q(right)));) { if (right static CImg dijkstra(const tf& distance, const unsigned int nb_nodes, const unsigned int starting_node, const unsigned int ending_node=~0U) { CImg foo; return dijkstra(distance,nb_nodes,starting_node,ending_node,foo); } //! Return minimal path in a graph, using the Dijkstra algorithm. /** \param starting_node Indice of the starting node. \param ending_node Indice of the ending node. \param previous_node Array that gives the previous node indice in the path to the starting node (optional parameter). \return Array of distances of each node to the starting node. \note image instance corresponds to the adjacency matrix of the graph. **/ template CImg& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg& previous_node) { return get_dijkstra(starting_node,ending_node,previous_node).move_to(*this); } //! Return minimal path in a graph, using the Dijkstra algorithm \newinstance. template CImg get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg& previous_node) const { if (_width!=_height || _depth!=1 || _spectrum!=1) throw CImgInstanceException(_cimg_instance "dijkstra(): Instance is not a graph adjacency matrix.", cimg_instance); return dijkstra(*this,_width,starting_node,ending_node,previous_node); } //! Return minimal path in a graph, using the Dijkstra algorithm. CImg& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) { return get_dijkstra(starting_node,ending_node).move_to(*this); } //! Return minimal path in a graph, using the Dijkstra algorithm \newinstance. CImg get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const { CImg foo; return get_dijkstra(starting_node,ending_node,foo); } //! Return an image containing the ascii codes of the specified string. /** \param str input C-string to encode as an image. \param is_last_zero Tells if the ending \c '0' character appear in the resulting image. **/ static CImg string(const char *const str, const bool is_last_zero=true, const bool is_shared=false) { if (!str) return CImg(); return CImg(str,(unsigned int)std::strlen(str) + (is_last_zero?1:0),1,1,1,is_shared); } //! Return a \c 1x1 image containing specified value. /** \param a0 First vector value. **/ static CImg vector(const T& a0) { CImg r(1,1); r[0] = a0; return r; } //! Return a \c 1x2 image containing specified values. /** \param a0 First vector value. \param a1 Second vector value. **/ static CImg vector(const T& a0, const T& a1) { CImg r(1,2); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; return r; } //! Return a \c 1x3 image containing specified values. /** \param a0 First vector value. \param a1 Second vector value. \param a2 Third vector value. **/ static CImg vector(const T& a0, const T& a1, const T& a2) { CImg r(1,3); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; return r; } //! Return a \c 1x4 image containing specified values. /** \param a0 First vector value. \param a1 Second vector value. \param a2 Third vector value. \param a3 Fourth vector value. **/ static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3) { CImg r(1,4); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; return r; } //! Return a \c 1x5 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { CImg r(1,5); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; return r; } //! Return a \c 1x6 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { CImg r(1,6); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; return r; } //! Return a \c 1x7 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) { CImg r(1,7); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; return r; } //! Return a \c 1x8 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7) { CImg r(1,8); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; return r; } //! Return a \c 1x9 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8) { CImg r(1,9); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; return r; } //! Return a \c 1x10 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9) { CImg r(1,10); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; return r; } //! Return a \c 1x11 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10) { CImg r(1,11); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; return r; } //! Return a \c 1x12 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11) { CImg r(1,12); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; return r; } //! Return a \c 1x13 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12) { CImg r(1,13); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; return r; } //! Return a \c 1x14 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12, const T& a13) { CImg r(1,14); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; return r; } //! Return a \c 1x15 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12, const T& a13, const T& a14) { CImg r(1,15); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; return r; } //! Return a \c 1x16 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12, const T& a13, const T& a14, const T& a15) { CImg r(1,16); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; return r; } //! Return a 1x1 matrix containing specified coefficients. /** \param a0 First matrix value. \note Equivalent to vector(const T&). **/ static CImg matrix(const T& a0) { return vector(a0); } //! Return a 2x2 matrix containing specified coefficients. /** \param a0 First matrix value. \param a1 Second matrix value. \param a2 Third matrix value. \param a3 Fourth matrix value. **/ static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3) { CImg r(2,2); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; return r; } //! Return a 3x3 matrix containing specified coefficients. /** \param a0 First matrix value. \param a1 Second matrix value. \param a2 Third matrix value. \param a3 Fourth matrix value. \param a4 Fifth matrix value. \param a5 Sixth matrix value. \param a6 Seventh matrix value. \param a7 Eighth matrix value. \param a8 Nineth matrix value. **/ static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8) { CImg r(3,3); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; return r; } //! Return a 4x4 matrix containing specified coefficients. static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12, const T& a13, const T& a14, const T& a15) { CImg r(4,4); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; return r; } //! Return a 5x5 matrix containing specified coefficients. static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, const T& a12, const T& a13, const T& a14, const T& a15, const T& a16, const T& a17, const T& a18, const T& a19, const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) { CImg r(5,5); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19; *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24; return r; } //! Return a 1x1 symmetric matrix containing specified coefficients. /** \param a0 First matrix value. \note Equivalent to vector(const T&). **/ static CImg tensor(const T& a0) { return matrix(a0); } //! Return a 2x2 symmetric matrix tensor containing specified coefficients. static CImg tensor(const T& a0, const T& a1, const T& a2) { return matrix(a0,a1,a1,a2); } //! Return a 3x3 symmetric matrix containing specified coefficients. static CImg tensor(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { return matrix(a0,a1,a2,a1,a3,a4,a2,a4,a5); } //! Return a 1x1 diagonal matrix containing specified coefficients. static CImg diagonal(const T& a0) { return matrix(a0); } //! Return a 2x2 diagonal matrix containing specified coefficients. static CImg diagonal(const T& a0, const T& a1) { return matrix(a0,0,0,a1); } //! Return a 3x3 diagonal matrix containing specified coefficients. static CImg diagonal(const T& a0, const T& a1, const T& a2) { return matrix(a0,0,0,0,a1,0,0,0,a2); } //! Return a 4x4 diagonal matrix containing specified coefficients. static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3) { return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3); } //! Return a 5x5 diagonal matrix containing specified coefficients. static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4); } //! Return a NxN identity matrix. /** \param N Dimension of the matrix. **/ static CImg identity_matrix(const unsigned int N) { CImg res(N,N,1,1,0); cimg_forX(res,x) res(x,x) = 1; return res; } //! Return a N-numbered sequence vector from \p a0 to \p a1. /** \param N Size of the resulting vector. \param a0 Starting value of the sequence. \param a1 Ending value of the sequence. **/ static CImg sequence(const unsigned int N, const T& a0, const T& a1) { if (N) return CImg(1,N).sequence(a0,a1); return CImg(); } //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w. /** \param x X-coordinate of the rotation axis, or first quaternion coordinate. \param y Y-coordinate of the rotation axis, or second quaternion coordinate. \param z Z-coordinate of the rotation axis, or third quaternion coordinate. \param w Angle of the rotation axis, or fourth quaternion coordinate. \param is_quaternion Tell is the four arguments denotes a set { axis + angle } or a quaternion. **/ static CImg rotation_matrix(const float x, const float y, const float z, const float w, const bool is_quaternion=false) { float X,Y,Z,W; if (!is_quaternion) { const float norm = (float)std::sqrt(x*x + y*y + z*z), nx = norm>0?x/norm:0, ny = norm>0?y/norm:0, nz = norm>0?z/norm:1, nw = norm>0?w:0, sina = (float)std::sin(nw/2), cosa = (float)std::cos(nw/2); X = nx*sina; Y = ny*sina; Z = nz*sina; W = cosa; } else { const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w); if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; } else { X = Y = Z = 0; W = 1; } } const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W; return CImg::matrix((T)(1 - 2*(yy + zz)), (T)(2*(xy + zw)), (T)(2*(xz - yw)), (T)(2*(xy - zw)), (T)(1 - 2*(xx + zz)), (T)(2*(yz + xw)), (T)(2*(xz + yw)), (T)(2*(yz - xw)), (T)(1 - 2*(xx + yy))); } //@} //----------------------------------- // //! \name Value Manipulation //@{ //----------------------------------- //! Fill all pixel values with specified value. /** \param val Fill value. **/ CImg& fill(const T& val) { if (is_empty()) return *this; if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val; else std::memset(_data,(int)val,sizeof(T)*size()); return *this; } //! Fill all pixel values with specified value \newinstance. CImg get_fill(const T& val) const { return CImg(_width,_height,_depth,_spectrum).fill(val); } //! Fill sequentially all pixel values with specified values. /** \param val0 First fill value. \param val1 Second fill value. **/ CImg& fill(const T& val0, const T& val1) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 1; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 2; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 3; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 4; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 5; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 6; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 7; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 8; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 9; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 10; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 11; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 12; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 13; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13, const T& val14) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 14; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13, const T& val14) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13,val14); } //! Fill sequentially all pixel values with specified values \overloading. CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13, const T& val14, const T& val15) { if (is_empty()) return *this; T *ptrd, *ptre = end() - 15; for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12, const T& val13, const T& val14, const T& val15) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13,val14,val15); } //! Fill sequentially pixel values according to a given expression. /** \param expression C-string describing a math formula, or a list of values. \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling. \param allow_formula tells if a formula is allowed or only a list of values. \param list_inputs In case of a mathematical expression, attach a list of images to the specified expression. \param list_outputs In case of a mathematical expression, attach a list of images to the specified expression. **/ CImg& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) { return _fill(expression,repeat_values,allow_formula,list_inputs,list_outputs,"fill",0); } CImg& _fill(const char *const expression, const bool repeat_values, const bool allow_formula, const CImgList *const list_inputs, CImgList *const list_outputs, const char *const calling_function, const CImg *provides_copy) { if (is_empty() || !expression || !*expression) return *this; const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); CImg is_error; if (allow_formula) try { // Try to fill values according to a formula CImg base = provides_copy?provides_copy->get_shared():get_shared(); _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*' || *expression==':'?1:0), calling_function,base,this,list_inputs,list_outputs); if (!provides_copy && expression && *expression!='>' && *expression!='<' && *expression!=':' && mp.need_input_copy) base.assign().assign(*this); // Needs input copy bool do_in_parallel = false; #ifdef cimg_use_openmp cimg_openmp_if(*expression=='*' || *expression==':' || (mp.is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)) do_in_parallel = true; #endif if (mp.result_dim) { // Vector-valued expression const unsigned int N = cimg::min(mp.result_dim,_spectrum); const ulongT whd = (ulongT)_width*_height*_depth; T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data; if (*expression=='<') { CImg res(1,mp.result_dim); cimg_rofXYZ(*this,x,y,z) { mp(x,y,z,0,res._data); const double *ptrs = res._data; T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } } } else if (*expression=='>' || !do_in_parallel) { CImg res(1,mp.result_dim); cimg_forXYZ(*this,x,y,z) { mp(x,y,z,0,res._data); const double *ptrs = res._data; T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } } } else { #ifdef cimg_use_openmp #pragma omp parallel { _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; #pragma omp for collapse(2) cimg_forYZ(*this,y,z) { CImg res(1,lmp.result_dim); T *ptrd = data(0,y,z,0); cimg_forX(*this,x) { lmp(x,y,z,0,res._data); const double *ptrs = res._data; T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } } } } #endif } } else { // Scalar-valued expression T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c); else if (*expression=='>' || !do_in_parallel) cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); else { #ifdef cimg_use_openmp #pragma omp parallel { _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; #pragma omp for collapse(3) cimg_forYZC(*this,y,z,c) { T *ptrd = data(0,y,z,c); cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c); } } #endif } } } catch (CImgException& e) { CImg::string(e._message).move_to(is_error); } // If failed, try to recognize a list of values. if (!allow_formula || is_error) { char *const item = new char[16384], sep = 0; const char *nexpression = expression; ulongT nb = 0; const ulongT siz = size(); T *ptrd = _data; for (double val = 0; *nexpression && nb0 && cimg_sscanf(item,"%lf",&val)==1 && (sep==',' || sep==';' || err==1)) { nexpression+=std::strlen(item) + (err>1?1:0); *(ptrd++) = (T)val; } else break; } delete[] item; cimg::exception_mode(omode); if (nb get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, const CImgList *const list_inputs=0, CImgList *const list_outputs=0) const { return (+*this).fill(expression,repeat_values,allow_formula,list_inputs,list_outputs); } //! Fill sequentially pixel values according to the values found in another image. /** \param values Image containing the values used for the filling. \param repeat_values In case there are less values than necessary in \c values, tells if these values must be repeated for the filling. **/ template CImg& fill(const CImg& values, const bool repeat_values=true) { if (is_empty() || !values) return *this; T *ptrd = _data, *ptre = ptrd + size(); for (t *ptrs = values._data, *ptrs_end = ptrs + values.size(); ptrs CImg get_fill(const CImg& values, const bool repeat_values=true) const { return repeat_values?CImg(_width,_height,_depth,_spectrum).fill(values,repeat_values): (+*this).fill(values,repeat_values); } //! Fill pixel values along the X-axis at a specified pixel position. /** \param y Y-coordinate of the filled column. \param z Z-coordinate of the filled column. \param c C-coordinate of the filled column. \param a0 First fill value. **/ CImg& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) { #define _cimg_fill1(x,y,z,c,off,siz,t) { \ va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \ for (unsigned int k = 1; k& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) { if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double); return *this; } //! Fill pixel values along the Y-axis at a specified pixel position. /** \param x X-coordinate of the filled row. \param z Z-coordinate of the filled row. \param c C-coordinate of the filled row. \param a0 First fill value. **/ CImg& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const int a0, ...) { if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,int); return *this; } //! Fill pixel values along the Y-axis at a specified pixel position \overloading. CImg& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) { if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double); return *this; } //! Fill pixel values along the Z-axis at a specified pixel position. /** \param x X-coordinate of the filled slice. \param y Y-coordinate of the filled slice. \param c C-coordinate of the filled slice. \param a0 First fill value. **/ CImg& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const int a0, ...) { const ulongT wh = (ulongT)_width*_height; if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,int); return *this; } //! Fill pixel values along the Z-axis at a specified pixel position \overloading. CImg& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const double a0, ...) { const ulongT wh = (ulongT)_width*_height; if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,double); return *this; } //! Fill pixel values along the C-axis at a specified pixel position. /** \param x X-coordinate of the filled channel. \param y Y-coordinate of the filled channel. \param z Z-coordinate of the filled channel. \param a0 First filling value. **/ CImg& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) { const ulongT whd = (ulongT)_width*_height*_depth; if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,int); return *this; } //! Fill pixel values along the C-axis at a specified pixel position \overloading. CImg& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) { const ulongT whd = (ulongT)_width*_height*_depth; if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,double); return *this; } //! Discard specified sequence of values in the image buffer, along a specific axis. /** \param values Sequence of values to discard. \param axis Axis along which the values are discarded. If set to \c 0 (default value) the method does it for all the buffer values and returns a one-column vector. \note Discarded values will change the image geometry, so the resulting image is returned as a one-column vector. **/ template CImg& discard(const CImg& values, const char axis=0) { if (is_empty() || !values) return *this; return get_discard(values,axis).move_to(*this); } template CImg get_discard(const CImg& values, const char axis=0) const { CImg res; if (!values) return +*this; if (is_empty()) return res; const ulongT vsiz = values.size(); const char _axis = cimg::uncase(axis); ulongT j = 0; unsigned int k = 0; int i0 = 0; res.assign(width(),height(),depth(),spectrum()); switch (_axis) { case 'x' : { cimg_forX(*this,i) { if ((*this)(i)!=(T)values[j]) { if (j) --i; res.draw_image(k,get_columns(i0,i)); k+=i - i0 + 1; i0 = i + 1; j = 0; } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } } } if (i0=vsiz) { j = 0; i0 = i + 1; } } } if (i0=vsiz) { j = 0; i0 = i + 1; } } } if (i0=vsiz) { j = 0; i0 = i + 1; } } } if (i0=vsiz) { j = 0; i0 = (int)i + 1; }} } const ulongT siz = size(); if ((ulongT)i0& discard(const char axis=0) { return get_discard(axis).move_to(*this); } //! Discard neighboring duplicates in the image buffer, along the specified axis \newinstance. CImg get_discard(const char axis=0) const { CImg res; if (is_empty()) return res; const char _axis = cimg::uncase(axis); T current = *_data?0:(T)1; int j = 0; res.assign(width(),height(),depth(),spectrum()); switch (_axis) { case 'x' : { cimg_forX(*this,i) if ((*this)(i)!=current) { res.draw_image(j++,get_column(i)); current = (*this)(i); } res.resize(j,-100,-100,-100,0); } break; case 'y' : { cimg_forY(*this,i) if ((*this)(0,i)!=current) { res.draw_image(0,j++,get_row(i)); current = (*this)(0,i); } res.resize(-100,j,-100,-100,0); } break; case 'z' : { cimg_forZ(*this,i) if ((*this)(0,0,i)!=current) { res.draw_image(0,0,j++,get_slice(i)); current = (*this)(0,0,i); } res.resize(-100,-100,j,-100,0); } break; case 'c' : { cimg_forC(*this,i) if ((*this)(0,0,0,i)!=current) { res.draw_image(0,0,0,j++,get_channel(i)); current = (*this)(0,0,0,i); } res.resize(-100,-100,-100,j,0); } break; default : { res.unroll('y'); cimg_foroff(*this,i) if ((*this)[i]!=current) res[j++] = current = (*this)[i]; res.resize(-100,j,-100,-100,0); } } return res; } //! Invert endianness of all pixel values. /** **/ CImg& invert_endianness() { cimg::invert_endianness(_data,size()); return *this; } //! Invert endianness of all pixel values \newinstance. CImg get_invert_endianness() const { return (+*this).invert_endianness(); } //! Fill image with random values in specified range. /** \param val_min Minimal authorized random value. \param val_max Maximal authorized random value. \note Random variables are uniformely distributed in [val_min,val_max]. **/ CImg& rand(const T& val_min, const T& val_max) { const float delta = (float)val_max - (float)val_min + (cimg::type::is_float()?0:1); if (cimg::type::is_float()) cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta); else cimg_for(*this,ptrd,T) *ptrd = cimg::min(val_max,(T)(val_min + cimg::rand()*delta)); return *this; } //! Fill image with random values in specified range \newinstance. CImg get_rand(const T& val_min, const T& val_max) const { return (+*this).rand(val_min,val_max); } //! Round pixel values. /** \param y Rounding precision. \param rounding_type Rounding type. Can be: - \c -1: Backward. - \c 0: Nearest. - \c 1: Forward. **/ CImg& round(const double y=1, const int rounding_type=0) { if (y>0) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=8192) #endif cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type); return *this; } //! Round pixel values \newinstance. CImg get_round(const double y=1, const unsigned int rounding_type=0) const { return (+*this).round(y,rounding_type); } //! Add random noise to pixel values. /** \param sigma Amplitude of the random additive noise. If \p sigma<0, it stands for a percentage of the global value range. \param noise_type Type of additive noise (can be \p 0=gaussian, \p 1=uniform, \p 2=Salt and Pepper, \p 3=Poisson or \p 4=Rician). \return A reference to the modified image instance. \note - For Poisson noise (\p noise_type=3), parameter \p sigma is ignored, as Poisson noise only depends on the image value itself. - Function \p CImg::get_noise() is also defined. It returns a non-shared modified copy of the image instance. \par Example \code const CImg img("reference.jpg"), res = img.get_noise(40); (img,res.normalize(0,255)).display(); \endcode \image html ref_noise.jpg **/ CImg& noise(const double sigma, const unsigned int noise_type=0) { if (is_empty()) return *this; const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0; if (nsigma==0 && noise_type!=3) return *this; if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M); if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0); switch (noise_type) { case 0 : { // Gaussian noise cimg_rof(*this,ptrd,T) { Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand()); if (val>vmax) val = vmax; if (valvmax) val = vmax; if (val::is_float()?1:cimg::type::max()); } cimg_rof(*this,ptrd,T) if (cimg::rand(100)vmax) val = vmax; if (val get_noise(const double sigma, const unsigned int noise_type=0) const { return (+*this).noise(sigma,noise_type); } //! Linearly normalize pixel values. /** \param min_value Minimum desired value of the resulting image. \param max_value Maximum desired value of the resulting image. \par Example \code const CImg img("reference.jpg"), res = img.get_normalize(160,220); (img,res).display(); \endcode \image html ref_normalize2.jpg **/ CImg& normalize(const T& min_value, const T& max_value) { if (is_empty()) return *this; const T a = min_value=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a); return *this; } //! Linearly normalize pixel values \newinstance. CImg get_normalize(const T& min_value, const T& max_value) const { return CImg(*this,false).normalize((Tfloat)min_value,(Tfloat)max_value); } //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm. /** \par Example \code const CImg img("reference.jpg"), res = img.get_normalize(); (img,res.normalize(0,255)).display(); \endcode \image html ref_normalize.jpg **/ CImg& normalize() { const ulongT whd = (ulongT)_width*_height*_depth; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { T *ptrd = data(0,y,z,0); cimg_forX(*this,x) { const T *ptrs = ptrd; float n = 0; cimg_forC(*this,c) { n+=cimg::sqr((float)*ptrs); ptrs+=whd; } n = (float)std::sqrt(n); T *_ptrd = ptrd++; if (n>0) cimg_forC(*this,c) { *_ptrd = (T)(*_ptrd/n); _ptrd+=whd; } else cimg_forC(*this,c) { *_ptrd = (T)0; _ptrd+=whd; } } } return *this; } //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm \newinstance. CImg get_normalize() const { return CImg(*this,false).normalize(); } //! Compute Lp-norm of each multi-valued pixel of the image instance. /** \param norm_type Type of computed vector norm (can be \p -1=Linf, or \p>=0). \par Example \code const CImg img("reference.jpg"), res = img.get_norm(); (img,res.normalize(0,255)).display(); \endcode \image html ref_norm.jpg **/ CImg& norm(const int norm_type=2) { if (_spectrum==1 && norm_type) return abs(); return get_norm(norm_type).move_to(*this); } //! Compute L2-norm of each multi-valued pixel of the image instance \newinstance. CImg get_norm(const int norm_type=2) const { if (is_empty()) return *this; if (_spectrum==1 && norm_type) return get_abs(); const ulongT whd = (ulongT)_width*_height*_depth; CImg res(_width,_height,_depth); switch (norm_type) { case -1 : { // Linf-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { const ulongT off = (ulongT)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { Tfloat n = 0; const T *_ptrs = ptrs++; cimg_forC(*this,c) { const Tfloat val = (Tfloat)cimg::abs(*_ptrs); if (val>n) n = val; _ptrs+=whd; } *(ptrd++) = n; } } } break; case 0 : { // L0-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { const ulongT off = (ulongT)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { unsigned int n = 0; const T *_ptrs = ptrs++; cimg_forC(*this,c) { n+=*_ptrs==0?0:1; _ptrs+=whd; } *(ptrd++) = (Tfloat)n; } } } break; case 1 : { // L1-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { const ulongT off = (ulongT)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { Tfloat n = 0; const T *_ptrs = ptrs++; cimg_forC(*this,c) { n+=cimg::abs(*_ptrs); _ptrs+=whd; } *(ptrd++) = n; } } } break; case 2 : { // L2-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { const ulongT off = (ulongT)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { Tfloat n = 0; const T *_ptrs = ptrs++; cimg_forC(*this,c) { n+=cimg::sqr((Tfloat)*_ptrs); _ptrs+=whd; } *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n); } } } break; default : { // Linf-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { const ulongT off = (ulongT)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { Tfloat n = 0; const T *_ptrs = ptrs++; cimg_forC(*this,c) { n+=std::pow(cimg::abs((Tfloat)*_ptrs),(Tfloat)norm_type); _ptrs+=whd; } *(ptrd++) = (Tfloat)std::pow((Tfloat)n,1/(Tfloat)norm_type); } } } } return res; } //! Cut pixel values in specified range. /** \param min_value Minimum desired value of the resulting image. \param max_value Maximum desired value of the resulting image. \par Example \code const CImg img("reference.jpg"), res = img.get_cut(160,220); (img,res).display(); \endcode \image html ref_cut.jpg **/ CImg& cut(const T& min_value, const T& max_value) { if (is_empty()) return *this; const T a = min_value=32768) #endif cimg_rof(*this,ptrd,T) *ptrd = (*ptrdb)?b:*ptrd); return *this; } //! Cut pixel values in specified range \newinstance. CImg get_cut(const T& min_value, const T& max_value) const { return (+*this).cut(min_value,max_value); } //! Uniformly quantize pixel values. /** \param nb_levels Number of quantization levels. \param keep_range Tells if resulting values keep the same range as the original ones. \par Example \code const CImg img("reference.jpg"), res = img.get_quantize(4); (img,res).display(); \endcode \image html ref_quantize.jpg **/ CImg& quantize(const unsigned int nb_levels, const bool keep_range=true) { if (!nb_levels) throw CImgArgumentException(_cimg_instance "quantize(): Invalid quantization request with 0 values.", cimg_instance); if (is_empty()) return *this; Tfloat m, M = (Tfloat)max_min(m), range = M - m; if (range>0) { if (keep_range) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels); } else #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); *ptrd = (T)cimg::min(val,nb_levels - 1); } } return *this; } //! Uniformly quantize pixel values \newinstance. CImg get_quantize(const unsigned int n, const bool keep_range=true) const { return (+*this).quantize(n,keep_range); } //! Threshold pixel values. /** \param value Threshold value \param soft_threshold Tells if soft thresholding must be applied (instead of hard one). \param strict_threshold Tells if threshold value is strict. \par Example \code const CImg img("reference.jpg"), res = img.get_threshold(128); (img,res.normalize(0,255)).display(); \endcode \image html ref_threshold.jpg **/ CImg& threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) { if (is_empty()) return *this; if (strict_threshold) { if (soft_threshold) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T v = *ptrd; *ptrd = v>value?(T)(v-value):v<-(float)value?(T)(v + value):(T)0; } else #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0; } else { if (soft_threshold) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=32768) #endif cimg_rof(*this,ptrd,T) { const T v = *ptrd; *ptrd = v>=value?(T)(v-value):v<=-(float)value?(T)(v + value):(T)0; } else #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=65536) #endif cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0; } return *this; } //! Threshold pixel values \newinstance. CImg get_threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) const { return (+*this).threshold(value,soft_threshold,strict_threshold); } //! Compute the histogram of pixel values. /** \param nb_levels Number of desired histogram levels. \param min_value Minimum pixel value considered for the histogram computation. All pixel values lower than \p min_value will not be counted. \param max_value Maximum pixel value considered for the histogram computation. All pixel values higher than \p max_value will not be counted. \note - The histogram H of an image I is the 1d function where H(x) counts the number of occurences of the value x in the image I. - The resulting histogram is always defined in 1d. Histograms of multi-valued images are not multi-dimensional. \par Example \code const CImg img = CImg("reference.jpg").histogram(256); img.display_graph(0,3); \endcode \image html ref_histogram.jpg **/ CImg& histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) { return get_histogram(nb_levels,min_value,max_value).move_to(*this); } //! Compute the histogram of pixel values \overloading. CImg& histogram(const unsigned int nb_levels) { return get_histogram(nb_levels).move_to(*this); } //! Compute the histogram of pixel values \newinstance. CImg get_histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) const { if (!nb_levels || is_empty()) return CImg(); const double vmin = (double)(min_value res(nb_levels,1,1,1,0); cimg_rof(*this,ptrs,T) { const T val = *ptrs; if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels - 1:(unsigned int)((val - vmin)*nb_levels/(vmax - vmin))]; } return res; } //! Compute the histogram of pixel values \newinstance. CImg get_histogram(const unsigned int nb_levels) const { if (!nb_levels || is_empty()) return CImg(); T vmax = 0, vmin = min_max(vmax); return get_histogram(nb_levels,vmin,vmax); } //! Equalize histogram of pixel values. /** \param nb_levels Number of histogram levels used for the equalization. \param min_value Minimum pixel value considered for the histogram computation. All pixel values lower than \p min_value will not be counted. \param max_value Maximum pixel value considered for the histogram computation. All pixel values higher than \p max_value will not be counted. \par Example \code const CImg img("reference.jpg"), res = img.get_equalize(256); (img,res).display(); \endcode \image html ref_equalize.jpg **/ CImg& equalize(const unsigned int nb_levels, const T& min_value, const T& max_value) { if (!nb_levels || is_empty()) return *this; const T vmin = min_value hist = get_histogram(nb_levels,vmin,vmax); ulongT cumul = 0; cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } if (!cumul) cumul = 1; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(size()>=1048576) #endif cimg_rof(*this,ptrd,T) { const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin)); if (pos>=0 && pos<(int)nb_levels) *ptrd = (T)(vmin + (vmax-vmin)*hist[pos]/cumul); } return *this; } //! Equalize histogram of pixel values \overloading. CImg& equalize(const unsigned int nb_levels) { if (!nb_levels || is_empty()) return *this; T vmax = 0, vmin = min_max(vmax); return equalize(nb_levels,vmin,vmax); } //! Equalize histogram of pixel values \newinstance. CImg get_equalize(const unsigned int nblevels, const T& val_min, const T& val_max) const { return (+*this).equalize(nblevels,val_min,val_max); } //! Equalize histogram of pixel values \newinstance. CImg get_equalize(const unsigned int nblevels) const { return (+*this).equalize(nblevels); } //! Index multi-valued pixels regarding to a specified colormap. /** \param colormap Multi-valued colormap used as the basis for multi-valued pixel indexing. \param dithering Level of dithering (0=disable, 1=standard level). \param map_indexes Tell if the values of the resulting image are the colormap indices or the colormap vectors. \note - \p img.index(colormap,dithering,1) is equivalent to img.index(colormap,dithering,0).map(colormap). \par Example \code const CImg img("reference.jpg"), colormap(3,1,1,3, 0,128,255, 0,128,255, 0,128,255); const CImg res = img.get_index(colormap,1,true); (img,res).display(); \endcode \image html ref_index.jpg **/ template CImg& index(const CImg& colormap, const float dithering=1, const bool map_indexes=false) { return get_index(colormap,dithering,map_indexes).move_to(*this); } //! Index multi-valued pixels regarding to a specified colormap \newinstance. template CImg::Tuint> get_index(const CImg& colormap, const float dithering=1, const bool map_indexes=true) const { if (colormap._spectrum!=_spectrum) throw CImgArgumentException(_cimg_instance "index(): Instance and specified colormap (%u,%u,%u,%u,%p) " "have incompatible dimensions.", cimg_instance, colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data); typedef typename CImg::Tuint tuint; if (is_empty()) return CImg(); const ulongT whd = (ulongT)_width*_height*_depth, pwhd = (ulongT)colormap._width*colormap._height*colormap._depth; CImg res(_width,_height,_depth,map_indexes?_spectrum:1); tuint *ptrd = res._data; if (dithering>0) { // Dithered versions. const float ndithering = (dithering<0?0:dithering>1?1:dithering)/16; Tfloat valm = 0, valM = (Tfloat)max_min(valm); if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; } CImg cache = get_crop(-1,0,0,0,_width,1,0,_spectrum - 1); Tfloat *cache_current = cache.data(1,0,0,0), *cache_next = cache.data(1,1,0,0); const ulongT cwhd = (ulongT)cache._width*cache._height*cache._depth; switch (_spectrum) { case 1 : { // Optimized for scalars. cimg_forYZ(*this,y,z) { if (yvalM?valM:_val0; Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0valM?valM:_val0, _val1 = (Tfloat)*ptrs1, val1 = _val1valM?valM:_val1; Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0valM?valM:_val0, _val1 = (Tfloat)*ptrs1, val1 = _val1valM?valM:_val1, _val2 = (Tfloat)*ptrs2, val2 = _val2valM?valM:_val2; Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, *ptrp_end = ptrp1; ptrp0::max(); const t *ptrmin = colormap._data; for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrpvalM?valM:_val; dist+=cimg::sqr((*_ptrs=val) - (Tfloat)*_ptrp); _ptrs+=cwhd; _ptrp+=pwhd; } if (dist=64 && _height*_depth>=16 && pwhd>=16) #endif cimg_forYZ(*this,y,z) { tuint *ptrd = res.data(0,y,z); for (const T *ptrs0 = data(0,y,z), *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0=64 && _height*_depth>=16 && pwhd>=16) #endif cimg_forYZ(*this,y,z) { tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd; for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0=64 && _height*_depth>=16 && pwhd>=16) #endif cimg_forYZ(*this,y,z) { tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd; for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd, *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, *ptrp_end = ptrp1; ptrp0=64 && _height*_depth>=16 && pwhd>=16) #endif cimg_forYZ(*this,y,z) { tuint *ptrd = res.data(0,y,z); for (const T *ptrs = data(0,y,z), *ptrs_end = ptrs + _width; ptrs::max(); const t *ptrmin = colormap._data; for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrp img("reference.jpg"), colormap1(3,1,1,3, 0,128,255, 0,128,255, 0,128,255), colormap2(3,1,1,3, 255,0,0, 0,255,0, 0,0,255), res = img.get_index(colormap1,0).map(colormap2); (img,res).display(); \endcode \image html ref_map.jpg **/ template CImg& map(const CImg& colormap, const unsigned int boundary_conditions=0) { return get_map(colormap,boundary_conditions).move_to(*this); } //! Map predefined colormap on the scalar (indexed) image instance \newinstance. template CImg get_map(const CImg& colormap, const unsigned int boundary_conditions=0) const { if (_spectrum!=1 && colormap._spectrum!=1) throw CImgArgumentException(_cimg_instance "map(): Instance and specified colormap (%u,%u,%u,%u,%p) " "have incompatible dimensions.", cimg_instance, colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data); const ulongT whd = (ulongT)_width*_height*_depth, pwhd = (ulongT)colormap._width*colormap._height*colormap._depth; CImg res(_width,_height,_depth,colormap._spectrum==1?_spectrum:colormap._spectrum); switch (colormap._spectrum) { case 1 : { // Optimized for scalars. const T *ptrs = _data; switch (boundary_conditions) { case 2 : // Periodic boundaries. cimg_for(res,ptrd,t) { const ulongT ind = (ulongT)*(ptrs++); *ptrd = colormap[ind%pwhd]; } break; case 1 : // Neumann boundaries. cimg_for(res,ptrd,t) { const longT ind = (longT)*(ptrs++); *ptrd = colormap[ind<0?0:ind>=(longT)pwhd?pwhd - 1:ind]; } break; default : // Dirichlet boundaries. cimg_for(res,ptrd,t) { const ulongT ind = (ulongT)*(ptrs++); *ptrd = ind=(longT)pwhd?(longT)pwhd - 1:_ind; *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; } } break; default : { // Dirichlet boundaries. const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd; t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs=(longT)pwhd?(longT)pwhd - 1:_ind; *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind]; } } break; default : { // Dirichlet boundaries. const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd; t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs=(longT)pwhd?(longT)pwhd - 1:_ind; const t *ptrp = colormap._data + ind; t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; } } } break; default : { // Dirichlet boundaries. t *ptrd = res._data; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs& label(const bool is_high_connectivity=false, const Tfloat tolerance=0) { return get_label(is_high_connectivity,tolerance).move_to(*this); } //! Label connected components \newinstance. CImg get_label(const bool is_high_connectivity=false, const Tfloat tolerance=0) const { if (is_empty()) return CImg(); // Create neighborhood tables. int dx[13], dy[13], dz[13], nb = 0; dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0; dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0; if (is_high_connectivity) { dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0; dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0; } if (_depth>1) { // 3d version. dx[nb] = 0; dy[nb] = 0; dz[nb++]=1; if (is_high_connectivity) { dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1; dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1; dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1; dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1; dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1; dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1; dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1; dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1; } } return _get_label(nb,dx,dy,dz,tolerance); } //! Label connected components \overloading. /** \param connectivity_mask Mask of the neighboring pixels. \param tolerance Tolerance used to determine if two neighboring pixels belong to the same region. **/ template CImg& label(const CImg& connectivity_mask, const Tfloat tolerance=0) { return get_label(connectivity_mask,tolerance).move_to(*this); } //! Label connected components \newinstance. template CImg get_label(const CImg& connectivity_mask, const Tfloat tolerance=0) const { int nb = 0; cimg_for(connectivity_mask,ptr,t) if (*ptr) ++nb; CImg dx(nb,1,1,1,0), dy(nb,1,1,1,0), dz(nb,1,1,1,0); nb = 0; cimg_forXYZ(connectivity_mask,x,y,z) if ((x || y || z) && connectivity_mask(x,y,z)) { dx[nb] = x; dy[nb] = y; dz[nb++] = z; } return _get_label(nb,dx,dy,dz,tolerance); } CImg _get_label(const unsigned int nb, const int *const dx, const int *const dy, const int *const dz, const Tfloat tolerance) const { CImg res(_width,_height,_depth,_spectrum); cimg_forC(*this,c) { CImg _res = res.get_shared_channel(c); // Init label numbers. ulongT *ptr = _res.data(); cimg_foroff(_res,p) *(ptr++) = p; // For each neighbour-direction, label. for (unsigned int n = 0; n& _system_strescape() { #define cimg_system_strescape(c,s) case c : if (p!=ptrs) CImg(ptrs,(unsigned int)(p-ptrs),1,1,1,false).\ move_to(list); \ CImg(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p + 1; break CImgList list; const T *ptrs = _data; cimg_for(*this,p,T) switch ((int)*p) { cimg_system_strescape('\\',"\\\\"); cimg_system_strescape('\"',"\\\""); cimg_system_strescape('!',"\"\\!\""); cimg_system_strescape('`',"\\`"); cimg_system_strescape('$',"\\$"); } if (ptrs(ptrs,(unsigned int)(end()-ptrs),1,1,1,false).move_to(list); return (list>'x').move_to(*this); } //@} //--------------------------------- // //! \name Color Base Management //@{ //--------------------------------- //! Return colormap \e "default", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_default.jpg **/ static const CImg& default_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { colormap.assign(1,256,1,3); for (unsigned int index = 0, r = 16; r<256; r+=32) for (unsigned int g = 16; g<256; g+=32) for (unsigned int b = 32; b<256; b+=64) { colormap(0,index,0) = (Tuchar)r; colormap(0,index,1) = (Tuchar)g; colormap(0,index++,2) = (Tuchar)b; } } cimg::mutex(8,0); return colormap; } //! Return colormap \e "HSV", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_hsv.jpg **/ static const CImg& HSV_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { CImg tmp(1,256,1,3,1); tmp.get_shared_channel(0).sequence(0,359); colormap = tmp.HSVtoRGB(); } cimg::mutex(8,0); return colormap; } //! Return colormap \e "lines", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_lines.jpg **/ static const CImg& lines_LUT256() { static const unsigned char pal[] = { 217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226, 17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119, 238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20, 233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74, 81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219, 1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12, 87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0, 223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32, 233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4, 137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224, 4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247, 11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246, 0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10, 141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143, 116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244, 255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0, 235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251, 129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30, 243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215, 95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3, 141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174, 154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87, 33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21, 23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 }; static const CImg colormap(pal,1,256,1,3,false); return colormap; } //! Return colormap \e "hot", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_hot.jpg **/ static const CImg& hot_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { colormap.assign(1,4,1,3,0); colormap[1] = colormap[2] = colormap[3] = colormap[6] = colormap[7] = colormap[11] = 255; colormap.resize(1,256,1,3,3); } cimg::mutex(8,0); return colormap; } //! Return colormap \e "cool", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_cool.jpg **/ static const CImg& cool_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) colormap.assign(1,2,1,3).fill(0,255,255,0,255,255).resize(1,256,1,3,3); cimg::mutex(8,0); return colormap; } //! Return colormap \e "jet", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_jet.jpg **/ static const CImg& jet_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { colormap.assign(1,4,1,3,0); colormap[2] = colormap[3] = colormap[5] = colormap[6] = colormap[8] = colormap[9] = 255; colormap.resize(1,256,1,3,3); } cimg::mutex(8,0); return colormap; } //! Return colormap \e "flag", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_flag.jpg **/ static const CImg& flag_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { colormap.assign(1,4,1,3,0); colormap[0] = colormap[1] = colormap[5] = colormap[9] = colormap[10] = 255; colormap.resize(1,256,1,3,0,2); } cimg::mutex(8,0); return colormap; } //! Return colormap \e "cube", containing 256 colors entries in RGB. /** \return The following \c 256x1x1x3 colormap is returned: \image html ref_colormap_cube.jpg **/ static const CImg& cube_LUT256() { static CImg colormap; cimg::mutex(8); if (!colormap) { colormap.assign(1,8,1,3,0); colormap[1] = colormap[3] = colormap[5] = colormap[7] = colormap[10] = colormap[11] = colormap[12] = colormap[13] = colormap[20] = colormap[21] = colormap[22] = colormap[23] = 255; colormap.resize(1,256,1,3,3); } cimg::mutex(8,0); return colormap; } //! Convert pixel values from sRGB to RGB color spaces. CImg& sRGBtoRGB() { cimg_for(*this,ptr,T) { const Tfloat sval = (Tfloat)*ptr, nsval = (sval<0?0:sval>255?255:sval)/255, val = (Tfloat)(nsval<=0.04045f?nsval/12.92f:std::pow((nsval + 0.055f)/(1.055f),2.4f)); *ptr = (T)(val*255); } return *this; } //! Convert pixel values from sRGB to RGB color spaces \newinstance. CImg get_sRGBtoRGB() const { return CImg(*this,false).sRGBtoRGB(); } //! Convert pixel values from RGB to sRGB color spaces. CImg& RGBtosRGB() { cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr, nval = (val<0?0:val>255?255:val)/255, sval = (Tfloat)(nval<=0.0031308f?nval*12.92f:1.055f*std::pow(nval,0.416667f)-0.055f); *ptr = (T)(sval*255); } return *this; } //! Convert pixel values from RGB to sRGB color spaces \newinstance. CImg get_RGBtosRGB() const { return CImg(*this,false).RGBtosRGB(); } //! Convert pixel values from RGB to HSV color spaces. CImg& RGBtoHSV() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoHSV(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1, G = (Tfloat)*p2, B = (Tfloat)*p3, nR = (R<0?0:(R>255?255:R))/255, nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = cimg::min(nR,nG,nB), M = cimg::max(nR,nG,nB); Tfloat H = 0, S = 0; if (M!=m) { const Tfloat f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)), i = (Tfloat)((nR==m)?3:((nG==m)?5:1)); H = (i-f/(M-m)); if (H>=6) H-=6; H*=60; S = (M-m)/M; } *(p1++) = (T)H; *(p2++) = (T)S; *(p3++) = (T)M; } return *this; } //! Convert pixel values from RGB to HSV color spaces \newinstance. CImg get_RGBtoHSV() const { return CImg(*this,false).RGBtoHSV(); } //! Convert pixel values from HSV to RGB color spaces. CImg& HSVtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "HSVtoRGB(): Instance is not a HSV image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { Tfloat H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, V = (Tfloat)*p3, R = 0, G = 0, B = 0; if (H==0 && S==0) R = G = B = V; else { H/=60; const int i = (int)std::floor(H); const Tfloat f = (i&1)?(H - i):(1 - H + i), m = V*(1 - S), n = V*(1 - S*f); switch (i) { case 6 : case 0 : R = V; G = n; B = m; break; case 1 : R = n; G = V; B = m; break; case 2 : R = m; G = V; B = n; break; case 3 : R = m; G = n; B = V; break; case 4 : R = n; G = m; B = V; break; case 5 : R = V; G = m; B = n; break; } } R*=255; G*=255; B*=255; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from HSV to RGB color spaces \newinstance. CImg get_HSVtoRGB() const { return CImg(*this,false).HSVtoRGB(); } //! Convert pixel values from RGB to HSL color spaces. CImg& RGBtoHSL() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoHSL(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1, G = (Tfloat)*p2, B = (Tfloat)*p3, nR = (R<0?0:(R>255?255:R))/255, nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = cimg::min(nR,nG,nB), M = cimg::max(nR,nG,nB), L = (m + M)/2; Tfloat H = 0, S = 0; if (M==m) H = S = 0; else { const Tfloat f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)), i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f); H = (i-f/(M-m)); if (H>=6) H-=6; H*=60; S = (2*L<=1)?((M - m)/(M + m)):((M - m)/(2 - M - m)); } *(p1++) = (T)H; *(p2++) = (T)S; *(p3++) = (T)L; } return *this; } //! Convert pixel values from RGB to HSL color spaces \newinstance. CImg get_RGBtoHSL() const { return CImg< Tfloat>(*this,false).RGBtoHSL(); } //! Convert pixel values from HSL to RGB color spaces. CImg& HSLtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "HSLtoRGB(): Instance is not a HSL image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, L = (Tfloat)*p3, q = 2*L<1?L*(1 + S):(L + S - L*S), p = 2*L - q, h = H/360, tr = h + 1.0f/3, tg = h, tb = h - 1.0f/3, ntr = tr<0?tr + 1:(tr>1?tr - 1:tr), ntg = tg<0?tg + 1:(tg>1?tg - 1:tg), ntb = tb<0?tb + 1:(tb>1?tb - 1:tb), R = 255*(6*ntr<1?p + (q - p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p + (q - p)*6*(2.0f/3 - ntr):p))), G = 255*(6*ntg<1?p + (q - p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p + (q - p)*6*(2.0f/3 - ntg):p))), B = 255*(6*ntb<1?p + (q - p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p + (q - p)*6*(2.0f/3 - ntb):p))); *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from HSL to RGB color spaces \newinstance. CImg get_HSLtoRGB() const { return CImg(*this,false).HSLtoRGB(); } //! Convert pixel values from RGB to HSI color spaces. CImg& RGBtoHSI() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoHSI(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1, G = (Tfloat)*p2, B = (Tfloat)*p3, nR = (R<0?0:(R>255?255:R))/255, nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = cimg::min(nR,nG,nB), theta = (Tfloat)(std::acos(0.5f*((nR - nG) + (nR - nB))/ std::sqrt(std::pow(nR - nG,2) + (nR - nB)*(nG - nB)))*180/cimg::PI), sum = nR + nG + nB; Tfloat H = 0, S = 0, I = 0; if (theta>0) H = (nB<=nG)?theta:360 - theta; if (sum>0) S = 1 - 3/sum*m; I = sum/3; *(p1++) = (T)H; *(p2++) = (T)S; *(p3++) = (T)I; } return *this; } //! Convert pixel values from RGB to HSI color spaces \newinstance. CImg get_RGBtoHSI() const { return CImg(*this,false).RGBtoHSI(); } //! Convert pixel values from HSI to RGB color spaces. CImg& HSItoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "HSItoRGB(): Instance is not a HSI image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { Tfloat H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, I = (Tfloat)*p3, a = I*(1-S), R = 0, G = 0, B = 0; if (H<120) { B = a; R = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); G = 3*I - (R + B); } else if (H<240) { H-=120; R = a; G = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); B = 3*I - (R + G); } else { H-=240; G = a; B = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); R = 3*I - (G + B); } R*=255; G*=255; B*=255; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from HSI to RGB color spaces \newinstance. CImg get_HSItoRGB() const { return CImg< Tuchar>(*this,false).HSItoRGB(); } //! Convert pixel values from RGB to YCbCr color spaces. CImg& RGBtoYCbCr() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoYCbCr(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1, G = (Tfloat)*p2, B = (Tfloat)*p3, Y = (66*R + 129*G + 25*B + 128)/256 + 16, Cb = (-38*R - 74*G + 112*B + 128)/256 + 128, Cr = (112*R - 94*G - 18*B + 128)/256 + 128; *(p1++) = (T)(Y<0?0:(Y>255?255:Y)); *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb)); *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr)); } return *this; } //! Convert pixel values from RGB to YCbCr color spaces \newinstance. CImg get_RGBtoYCbCr() const { return CImg(*this,false).RGBtoYCbCr(); } //! Convert pixel values from RGB to YCbCr color spaces. CImg& YCbCrtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "YCbCrtoRGB(): Instance is not a YCbCr image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat Y = (Tfloat)*p1 - 16, Cb = (Tfloat)*p2 - 128, Cr = (Tfloat)*p3 - 128, R = (298*Y + 409*Cr + 128)/256, G = (298*Y - 100*Cb - 208*Cr + 128)/256, B = (298*Y + 516*Cb + 128)/256; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from RGB to YCbCr color spaces \newinstance. CImg get_YCbCrtoRGB() const { return CImg(*this,false).YCbCrtoRGB(); } //! Convert pixel values from RGB to YUV color spaces. CImg& RGBtoYUV() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoYUV(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1/255, G = (Tfloat)*p2/255, B = (Tfloat)*p3/255, Y = 0.299f*R + 0.587f*G + 0.114f*B; *(p1++) = (T)Y; *(p2++) = (T)(0.492f*(B-Y)); *(p3++) = (T)(0.877*(R-Y)); } return *this; } //! Convert pixel values from RGB to YUV color spaces \newinstance. CImg get_RGBtoYUV() const { return CImg(*this,false).RGBtoYUV(); } //! Convert pixel values from YUV to RGB color spaces. CImg& YUVtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "YUVtoRGB(): Instance is not a YUV image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat Y = (Tfloat)*p1, U = (Tfloat)*p2, V = (Tfloat)*p3, R = (Y + 1.140f*V)*255, G = (Y - 0.395f*U - 0.581f*V)*255, B = (Y + 2.032f*U)*255; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from YUV to RGB color spaces \newinstance. CImg get_YUVtoRGB() const { return CImg< Tuchar>(*this,false).YUVtoRGB(); } //! Convert pixel values from RGB to CMY color spaces. CImg& RGBtoCMY() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoCMY(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1, G = (Tfloat)*p2, B = (Tfloat)*p3, C = 255 - R, M = 255 - G, Y = 255 - B; *(p1++) = (T)(C<0?0:(C>255?255:C)); *(p2++) = (T)(M<0?0:(M>255?255:M)); *(p3++) = (T)(Y<0?0:(Y>255?255:Y)); } return *this; } //! Convert pixel values from RGB to CMY color spaces \newinstance. CImg get_RGBtoCMY() const { return CImg(*this,false).RGBtoCMY(); } //! Convert pixel values from CMY to RGB color spaces. CImg& CMYtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "CMYtoRGB(): Instance is not a CMY image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat C = (Tfloat)*p1, M = (Tfloat)*p2, Y = (Tfloat)*p3, R = 255 - C, G = 255 - M, B = 255 - Y; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from CMY to RGB color spaces \newinstance. CImg get_CMYtoRGB() const { return CImg(*this,false).CMYtoRGB(); } //! Convert pixel values from CMY to CMYK color spaces. CImg& CMYtoCMYK() { return get_CMYtoCMYK().move_to(*this); } //! Convert pixel values from CMY to CMYK color spaces \newinstance. CImg get_CMYtoCMYK() const { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "CMYtoCMYK(): Instance is not a CMY image.", cimg_instance); CImg res(_width,_height,_depth,4); const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2); Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { Tfloat C = (Tfloat)*(ps1++), M = (Tfloat)*(ps2++), Y = (Tfloat)*(ps3++), K = cimg::min(C,M,Y); if (K>=255) C = M = Y = 0; else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; } *(pd1++) = (Tfloat)(C<0?0:(C>255?255:C)); *(pd2++) = (Tfloat)(M<0?0:(M>255?255:M)); *(pd3++) = (Tfloat)(Y<0?0:(Y>255?255:Y)); *(pd4++) = (Tfloat)(K<0?0:(K>255?255:K)); } return res; } //! Convert pixel values from CMYK to CMY color spaces. CImg& CMYKtoCMY() { return get_CMYKtoCMY().move_to(*this); } //! Convert pixel values from CMYK to CMY color spaces \newinstance. CImg get_CMYKtoCMY() const { if (_spectrum!=4) throw CImgInstanceException(_cimg_instance "CMYKtoCMY(): Instance is not a CMYK image.", cimg_instance); CImg res(_width,_height,_depth,3); const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3); Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat C = (Tfloat)*(ps1++), M = (Tfloat)*(ps2++), Y = (Tfloat)*(ps3++), K = (Tfloat)*(ps4++), K1 = 1 - K/255, nC = C*K1 + K, nM = M*K1 + K, nY = Y*K1 + K; *(pd1++) = (Tfloat)(nC<0?0:(nC>255?255:nC)); *(pd2++) = (Tfloat)(nM<0?0:(nM>255?255:nM)); *(pd3++) = (Tfloat)(nY<0?0:(nY>255?255:nY)); } return res; } //! Convert pixel values from RGB to XYZ_709 color spaces. /** \note Uses the standard D65 white point. **/ CImg& RGBtoXYZ() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "RGBtoXYZ(): Instance is not a RGB image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat R = (Tfloat)*p1/255, G = (Tfloat)*p2/255, B = (Tfloat)*p3/255; *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B); *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B); *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B); } return *this; } //! Convert pixel values from RGB to XYZ_709 color spaces \newinstance. CImg get_RGBtoXYZ() const { return CImg(*this,false).RGBtoXYZ(); } //! Convert pixel values from XYZ_709 to RGB color spaces. CImg& XYZtoRGB() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "XYZtoRGB(): Instance is not a XYZ image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat X = (Tfloat)*p1*255, Y = (Tfloat)*p2*255, Z = (Tfloat)*p3*255, R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z, G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z, B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z; *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); } return *this; } //! Convert pixel values from XYZ_709 to RGB color spaces \newinstance. CImg get_XYZtoRGB() const { return CImg(*this,false).XYZtoRGB(); } //! Convert pixel values from XYZ_709 to Lab color spaces. CImg& XYZtoLab() { #define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x) + 16.0f/116)) if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "XYZtoLab(): Instance is not a XYZ image.", cimg_instance); const Tfloat Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f), Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f), Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat X = (Tfloat)*p1, Y = (Tfloat)*p2, Z = (Tfloat)*p3, XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn, fX = (Tfloat)_cimg_Labf(XXn), fY = (Tfloat)_cimg_Labf(YYn), fZ = (Tfloat)_cimg_Labf(ZZn); *(p1++) = (T)cimg::max(0.0f,116*fY - 16); *(p2++) = (T)(500*(fX - fY)); *(p3++) = (T)(200*(fY - fZ)); } return *this; } //! Convert pixel values from XYZ_709 to Lab color spaces \newinstance. CImg get_XYZtoLab() const { return CImg(*this,false).XYZtoLab(); } //! Convert pixel values from Lab to XYZ_709 color spaces. CImg& LabtoXYZ() { #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f)) if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "LabtoXYZ(): Instance is not a Lab image.", cimg_instance); const Tfloat Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f), Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f), Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat L = (Tfloat)*p1, a = (Tfloat)*p2, b = (Tfloat)*p3, cY = (L + 16)/116, Y = (Tfloat)(Yn*_cimg_Labfi(cY)), cX = a/500 + cY, X = (Tfloat)(Xn*_cimg_Labfi(cX)), cZ = cY - b/200, Z = (Tfloat)(Zn*_cimg_Labfi(cZ)); *(p1++) = (T)(X); *(p2++) = (T)(Y); *(p3++) = (T)(Z); } return *this; } //! Convert pixel values from Lab to XYZ_709 color spaces \newinstance. CImg get_LabtoXYZ() const { return CImg(*this,false).LabtoXYZ(); } //! Convert pixel values from XYZ_709 to xyY color spaces. CImg& XYZtoxyY() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "XYZtoxyY(): Instance is not a XYZ image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat X = (Tfloat)*p1, Y = (Tfloat)*p2, Z = (Tfloat)*p3, sum = X + Y + Z, nsum = sum>0?sum:1; *(p1++) = (T)(X/nsum); *(p2++) = (T)(Y/nsum); *(p3++) = (T)Y; } return *this; } //! Convert pixel values from XYZ_709 to xyY color spaces \newinstance. CImg get_XYZtoxyY() const { return CImg(*this,false).XYZtoxyY(); } //! Convert pixel values from xyY pixels to XYZ_709 color spaces. CImg& xyYtoXYZ() { if (_spectrum!=3) throw CImgInstanceException(_cimg_instance "xyYtoXYZ(): Instance is not a xyY image.", cimg_instance); T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (ulongT N = (ulongT)_width*_height*_depth; N; --N) { const Tfloat px = (Tfloat)*p1, py = (Tfloat)*p2, Y = (Tfloat)*p3, ny = py>0?py:1; *(p1++) = (T)(px*Y/ny); *(p2++) = (T)Y; *(p3++) = (T)((1 - px - py)*Y/ny); } return *this; } //! Convert pixel values from xyY pixels to XYZ_709 color spaces \newinstance. CImg get_xyYtoXYZ() const { return CImg(*this,false).xyYtoXYZ(); } //! Convert pixel values from RGB to Lab color spaces. CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); } //! Convert pixel values from RGB to Lab color spaces \newinstance. CImg get_RGBtoLab() const { return CImg(*this,false).RGBtoLab(); } //! Convert pixel values from Lab to RGB color spaces. CImg& LabtoRGB() { return LabtoXYZ().XYZtoRGB(); } //! Convert pixel values from Lab to RGB color spaces \newinstance. CImg get_LabtoRGB() const { return CImg(*this,false).LabtoRGB(); } //! Convert pixel values from RGB to xyY color spaces. CImg& RGBtoxyY() { return RGBtoXYZ().XYZtoxyY(); } //! Convert pixel values from RGB to xyY color spaces \newinstance. CImg get_RGBtoxyY() const { return CImg(*this,false).RGBtoxyY(); } //! Convert pixel values from xyY to RGB color spaces. CImg& xyYtoRGB() { return xyYtoXYZ().XYZtoRGB(); } //! Convert pixel values from xyY to RGB color spaces \newinstance. CImg get_xyYtoRGB() const { return CImg(*this,false).xyYtoRGB(); } //! Convert pixel values from RGB to CMYK color spaces. CImg& RGBtoCMYK() { return RGBtoCMY().CMYtoCMYK(); } //! Convert pixel values from RGB to CMYK color spaces \newinstance. CImg get_RGBtoCMYK() const { return CImg(*this,false).RGBtoCMYK(); } //! Convert pixel values from CMYK to RGB color spaces. CImg& CMYKtoRGB() { return CMYKtoCMY().CMYtoRGB(); } //! Convert pixel values from CMYK to RGB color spaces \newinstance. CImg get_CMYKtoRGB() const { return CImg(*this,false).CMYKtoRGB(); } //@} //------------------------------------------ // //! \name Geometric / Spatial Manipulation //@{ //------------------------------------------ static float _cimg_lanczos(const float x) { if (x<=-2 || x>=2) return 0; const float a = (float)cimg::PI*x, b = 0.5f*a; return (float)(x?std::sin(a)*std::sin(b)/(a*b):1); } //! Resize image to new dimensions. /** \param size_x Number of columns (new size along the X-axis). \param size_y Number of rows (new size along the Y-axis). \param size_z Number of slices (new size along the Z-axis). \param size_c Number of vector-channels (new size along the C-axis). \param interpolation_type Method of interpolation: - -1 = no interpolation: raw memory resizing. - 0 = no interpolation: additional space is filled according to \p boundary_conditions. - 1 = nearest-neighbor interpolation. - 2 = moving average interpolation. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = cubic interpolation. - 6 = lanczos interpolation. \param boundary_conditions Border condition type. \param centering_x Set centering type (only if \p interpolation_type=0). \param centering_y Set centering type (only if \p interpolation_type=0). \param centering_z Set centering type (only if \p interpolation_type=0). \param centering_c Set centering type (only if \p interpolation_type=0). \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ CImg& resize(const int size_x, const int size_y=-100, const int size_z=-100, const int size_c=-100, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) { if (!size_x || !size_y || !size_z || !size_c) return assign(); const unsigned int _sx = (unsigned int)(size_x<0?-size_x*width()/100:size_x), _sy = (unsigned int)(size_y<0?-size_y*height()/100:size_y), _sz = (unsigned int)(size_z<0?-size_z*depth()/100:size_z), _sc = (unsigned int)(size_c<0?-size_c*spectrum()/100:size_c), sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1; if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return *this; if (is_empty()) return assign(sx,sy,sz,sc,(T)0); if (interpolation_type==-1 && sx*sy*sz*sc==size()) { _width = sx; _height = sy; _depth = sz; _spectrum = sc; return *this; } return get_resize(sx,sy,sz,sc,interpolation_type,boundary_conditions, centering_x,centering_y,centering_z,centering_c).move_to(*this); } //! Resize image to new dimensions \newinstance. CImg get_resize(const int size_x, const int size_y = -100, const int size_z = -100, const int size_c = -100, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) const { if (centering_x<0 || centering_x>1 || centering_y<0 || centering_y>1 || centering_z<0 || centering_z>1 || centering_c<0 || centering_c>1) throw CImgArgumentException(_cimg_instance "resize(): Specified centering arguments (%g,%g,%g,%g) are outside range [0,1].", cimg_instance, centering_x,centering_y,centering_z,centering_c); if (!size_x || !size_y || !size_z || !size_c) return CImg(); const unsigned int _sx = (unsigned int)(size_x<0?-size_x*width()/100:size_x), _sy = (unsigned int)(size_y<0?-size_y*height()/100:size_y), _sz = (unsigned int)(size_z<0?-size_z*depth()/100:size_z), _sc = (unsigned int)(size_c<0?-size_c*spectrum()/100:size_c), sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1; if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return +*this; if (is_empty()) return CImg(sx,sy,sz,sc,0); CImg res; switch (interpolation_type) { // Raw resizing. // case -1 : std::memcpy(res.assign(sx,sy,sz,sc,0)._data,_data,sizeof(T)*cimg::min(size(),sx*sy*sz*sc)); break; // No interpolation. // case 0 : { const int xc = (int)(centering_x*((int)sx - width())), yc = (int)(centering_y*((int)sy - height())), zc = (int)(centering_z*((int)sz - depth())), cc = (int)(centering_c*((int)sc - spectrum())); switch (boundary_conditions) { case 2 : { // Periodic boundary. res.assign(sx,sy,sz,sc); const int x0 = ((int)xc%width()) - width(), y0 = ((int)yc%height()) - height(), z0 = ((int)zc%depth()) - depth(), c0 = ((int)cc%spectrum()) - spectrum(); #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=65536) #endif for (int c = c0; c<(int)sc; c+=spectrum()) for (int z = z0; z<(int)sz; z+=depth()) for (int y = y0; y<(int)sy; y+=height()) for (int x = x0; x<(int)sx; x+=width()) res.draw_image(x,y,z,c,*this); } break; case 1 : { // Neumann boundary. res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this); CImg sprite; if (xc>0) { // X-backward res.get_crop(xc,yc,zc,cc,xc,yc + height() - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); for (int x = xc - 1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite); } if (xc + width()<(int)sx) { // X-forward res.get_crop(xc + width() - 1,yc,zc,cc,xc + width() - 1,yc + height() - 1, zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); for (int x = xc + width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite); } if (yc>0) { // Y-backward res.get_crop(0,yc,zc,cc,sx - 1,yc,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); for (int y = yc - 1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite); } if (yc + height()<(int)sy) { // Y-forward res.get_crop(0,yc + height() - 1,zc,cc,sx - 1,yc + height() - 1, zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); for (int y = yc + height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite); } if (zc>0) { // Z-backward res.get_crop(0,0,zc,cc,sx - 1,sy - 1,zc,cc + spectrum() - 1).move_to(sprite); for (int z = zc - 1; z>=0; --z) res.draw_image(0,0,z,cc,sprite); } if (zc + depth()<(int)sz) { // Z-forward res.get_crop(0,0,zc +depth() - 1,cc,sx - 1,sy - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); for (int z = zc + depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite); } if (cc>0) { // C-backward res.get_crop(0,0,0,cc,sx - 1,sy - 1,sz - 1,cc).move_to(sprite); for (int c = cc - 1; c>=0; --c) res.draw_image(0,0,0,c,sprite); } if (cc + spectrum()<(int)sc) { // C-forward res.get_crop(0,0,0,cc + spectrum() - 1,sx - 1,sy - 1,sz - 1,cc + spectrum() - 1).move_to(sprite); for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); } } break; default : // Dirichlet boundary. res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this); } break; } break; // Nearest neighbor interpolation. // case 1 : { res.assign(sx,sy,sz,sc); CImg off_x(sx), off_y(sy + 1), off_z(sz + 1), off_c(sc + 1); const ulongT wh = (ulongT)_width*_height, whd = (ulongT)_width*_height*_depth, sxy = (ulongT)sx*sy, sxyz = (ulongT)sx*sy*sz; if (sx==_width) off_x.fill(1); else { ulongT *poff_x = off_x._data, curr = 0; cimg_forX(res,x) { const ulongT old = curr; curr = (ulongT)((x + 1.0)*_width/sx); *(poff_x++) = curr - old; } } if (sy==_height) off_y.fill(_width); else { ulongT *poff_y = off_y._data, curr = 0; cimg_forY(res,y) { const ulongT old = curr; curr = (ulongT)((y + 1.0)*_height/sy); *(poff_y++) = _width*(curr - old); } *poff_y = 0; } if (sz==_depth) off_z.fill(wh); else { ulongT *poff_z = off_z._data, curr = 0; cimg_forZ(res,z) { const ulongT old = curr; curr = (ulongT)((z + 1.0)*_depth/sz); *(poff_z++) = wh*(curr - old); } *poff_z = 0; } if (sc==_spectrum) off_c.fill(whd); else { ulongT *poff_c = off_c._data, curr = 0; cimg_forC(res,c) { const ulongT old = curr; curr = (ulongT)((c + 1.0)*_spectrum/sc); *(poff_c++) = whd*(curr - old); } *poff_c = 0; } T *ptrd = res._data; const T* ptrc = _data; const ulongT *poff_c = off_c._data; for (unsigned int c = 0; c tmp(sx,_height,_depth,_spectrum,0); for (unsigned int a = _width*sx, b = _width, c = sx, s = 0, t = 0; a; ) { const unsigned int d = cimg::min(b,c); a-=d; b-=d; c-=d; cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d; if (!b) { cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)/=_width; ++t; b = _width; } if (!c) { ++s; c = sx; } } tmp.move_to(res); instance_first = false; } if (sy!=_height) { CImg tmp(sx,sy,_depth,_spectrum,0); for (unsigned int a = _height*sy, b = _height, c = sy, s = 0, t = 0; a; ) { const unsigned int d = cimg::min(b,c); a-=d; b-=d; c-=d; if (instance_first) cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d; else cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d; if (!b) { cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)/=_height; ++t; b = _height; } if (!c) { ++s; c = sy; } } tmp.move_to(res); instance_first = false; } if (sz!=_depth) { CImg tmp(sx,sy,sz,_spectrum,0); for (unsigned int a = _depth*sz, b = _depth, c = sz, s = 0, t = 0; a; ) { const unsigned int d = cimg::min(b,c); a-=d; b-=d; c-=d; if (instance_first) cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d; else cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d; if (!b) { cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)/=_depth; ++t; b = _depth; } if (!c) { ++s; c = sz; } } tmp.move_to(res); instance_first = false; } if (sc!=_spectrum) { CImg tmp(sx,sy,sz,sc,0); for (unsigned int a = _spectrum*sc, b = _spectrum, c = sc, s = 0, t = 0; a; ) { const unsigned int d = cimg::min(b,c); a-=d; b-=d; c-=d; if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d; else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d; if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=_spectrum; ++t; b = _spectrum; } if (!c) { ++s; c = sc; } } tmp.move_to(res); instance_first = false; } } break; // Linear interpolation. // case 3 : { CImg off(cimg::max(sx,sy,sz,sc)); CImg foff(off._width); CImg resx, resy, resz, resc; if (sx!=_width) { if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); else { if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resx.size()>=65536) #endif cimg_forYZC(resx,y,z,c) { const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1; T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forX(resx,x) { const float alpha = *(pfoff++); const T val1 = *ptrs, val2 = ptrssy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr-(unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forY(resy,y) { const float alpha = *(pfoff++); const T val1 = *ptrs, val2 = ptrssz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resz.size()>=65536) #endif cimg_forXYC(resz,x,y,c) { const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forZ(resz,z) { const float alpha = *(pfoff++); const T val1 = *ptrs, val2 = ptrssc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resc.size()>=65536) #endif cimg_forXYZ(resc,x,y,z) { const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forC(resc,c) { const float alpha = *(pfoff++); const T val1 = *ptrs, val2 = ptrs resx, resy, resz, resc; if (sx!=_width) { if (sx<_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); else { resx.assign(sx,_height,_depth,_spectrum,0); const int dx = (int)(2*sx), dy = 2*width(); int err = (int)(dy + centering_x*(sx*dy/width() - dy)), xs = 0; cimg_forX(resx,x) if ((err-=dy)<=0) { cimg_forYZC(resx,y,z,c) resx(x,y,z,c) = (*this)(xs,y,z,c); ++xs; err+=dx; } } } else resx.assign(*this,true); if (sy!=_height) { if (sy<_height) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); else { resy.assign(sx,sy,_depth,_spectrum,0); const int dx = (int)(2*sy), dy = 2*height(); int err = (int)(dy + centering_y*(sy*dy/height() - dy)), ys = 0; cimg_forY(resy,y) if ((err-=dy)<=0) { cimg_forXZC(resy,x,z,c) resy(x,y,z,c) = resx(x,ys,z,c); ++ys; err+=dx; } } resx.assign(); } else resy.assign(resx,true); if (sz!=_depth) { if (sz<_depth) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); else { resz.assign(sx,sy,sz,_spectrum,0); const int dx = (int)(2*sz), dy = 2*depth(); int err = (int)(dy + centering_z*(sz*dy/depth() - dy)), zs = 0; cimg_forZ(resz,z) if ((err-=dy)<=0) { cimg_forXYC(resz,x,y,c) resz(x,y,z,c) = resy(x,y,zs,c); ++zs; err+=dx; } } resy.assign(); } else resz.assign(resy,true); if (sc!=_spectrum) { if (sc<_spectrum) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); else { resc.assign(sx,sy,sz,sc,0); const int dx = (int)(2*sc), dy = 2*spectrum(); int err = (int)(dy + centering_c*(sc*dy/spectrum() - dy)), cs = 0; cimg_forC(resc,c) if ((err-=dy)<=0) { cimg_forXYZ(resc,x,y,z) resc(x,y,z,c) = resz(x,y,z,cs); ++cs; err+=dx; } } resz.assign(); } else resc.assign(resz,true); return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; } break; // Cubic interpolation. // case 5 : { const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); CImg off(cimg::max(sx,sy,sz,sc)); CImg foff(off._width); CImg resx, resy, resz, resc; if (sx!=_width) { if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); else { if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resx.size()>=65536) #endif cimg_forYZC(resx,y,z,c) { const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2); T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forX(resx,x) { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, val0 = ptrs>ptrs0?(Tfloat)*(ptrs - 1):val1, val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val1, val3 = ptrsvmax?vmax:val); ptrs+=*(poff++); } } } } } else resx.assign(*this,true); if (sy!=_height) { if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); else { if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forY(resy,y) { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sx):val1, val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val1, val3 = ptrsvmax?vmax:val); ptrd+=sx; ptrs+=*(poff++); } } } } resx.assign(); } else resy.assign(resx,true); if (sz!=_depth) { if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); else { if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resz.size()>=65536) #endif cimg_forXYC(resz,x,y,c) { const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forZ(resz,z) { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxy):val1, val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val1, val3 = ptrsvmax?vmax:val); ptrd+=sxy; ptrs+=*(poff++); } } } } resy.assign(); } else resz.assign(resy,true); if (sc!=_spectrum) { if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); else { if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resc.size()>=65536) #endif cimg_forXYZ(resc,x,y,z) { const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forC(resc,c) { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxyz):val1, val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val1, val3 = ptrsvmax?vmax:val); ptrd+=sxyz; ptrs+=*(poff++); } } } } resz.assign(); } else resc.assign(resz,true); return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; } break; // Lanczos interpolation. // case 6 : { const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); CImg off(cimg::max(sx,sy,sz,sc)); CImg foff(off._width); CImg resx, resy, resz, resc; if (sx!=_width) { if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); else { if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resx.size()>=65536) #endif cimg_forYZC(resx,y,z,c) { const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1, *const ptrsmax = ptrs0 + (_width - 2); T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forX(resx,x) { const float t = *(pfoff++), w0 = _cimg_lanczos(t + 2), w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), w3 = _cimg_lanczos(t - 1), w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - 1):val2, val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2):val1, val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val2, val4 = ptrsvmax?vmax:val); ptrs+=*(poff++); } } } } } else resx.assign(*this,true); if (sy!=_height) { if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); else { if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx, *const ptrsmax = ptrs0 + (_height - 2)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forY(resy,y) { const float t = *(pfoff++), w0 = _cimg_lanczos(t + 2), w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), w3 = _cimg_lanczos(t - 1), w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sx):val2, val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sx):val1, val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val2, val4 = ptrsvmax?vmax:val); ptrd+=sx; ptrs+=*(poff++); } } } } resx.assign(); } else resy.assign(resx,true); if (sz!=_depth) { if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); else { if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resz.size()>=65536) #endif cimg_forXYC(resz,x,y,c) { const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy, *const ptrsmax = ptrs0 + (_depth - 2)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forZ(resz,z) { const float t = *(pfoff++), w0 = _cimg_lanczos(t + 2), w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), w3 = _cimg_lanczos(t - 1), w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxy):val2, val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxy):val1, val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val2, val4 = ptrsvmax?vmax:val); ptrd+=sxy; ptrs+=*(poff++); } } } } resy.assign(); } else resz.assign(resy,true); if (sc!=_spectrum) { if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); else { if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); float curr = 0, old = 0; unsigned int *poff = off._data; float *pfoff = foff._data; cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resc.size()>=65536) #endif cimg_forXYZ(resc,x,y,z) { const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forC(resc,c) { const float t = *(pfoff++), w0 = _cimg_lanczos(t + 2), w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), w3 = _cimg_lanczos(t - 1), w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxyz):val2, val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxyz):val1, val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val2, val4 = ptrsvmax?vmax:val); ptrd+=sxyz; ptrs+=*(poff++); } } } } resz.assign(); } else resc.assign(resz,true); return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; } break; // Unknow interpolation. // default : throw CImgArgumentException(_cimg_instance "resize(): Invalid specified interpolation %d " "(should be { -1=raw | 0=none | 1=nearest | 2=average | 3=linear | 4=grid | " "5=cubic | 6=lanczos }).", cimg_instance, interpolation_type); } return res; } //! Resize image to dimensions of another image. /** \param src Reference image used for dimensions. \param interpolation_type Interpolation method. \param boundary_conditions Boundary conditions. \param centering_x Set centering type (only if \p interpolation_type=0). \param centering_y Set centering type (only if \p interpolation_type=0). \param centering_z Set centering type (only if \p interpolation_type=0). \param centering_c Set centering type (only if \p interpolation_type=0). **/ template CImg& resize(const CImg& src, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) { return resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions, centering_x,centering_y,centering_z,centering_c); } //! Resize image to dimensions of another image \newinstance. template CImg get_resize(const CImg& src, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) const { return get_resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions, centering_x,centering_y,centering_z,centering_c); } //! Resize image to dimensions of a display window. /** \param disp Reference display window used for dimensions. \param interpolation_type Interpolation method. \param boundary_conditions Boundary conditions. \param centering_x Set centering type (only if \p interpolation_type=0). \param centering_y Set centering type (only if \p interpolation_type=0). \param centering_z Set centering type (only if \p interpolation_type=0). \param centering_c Set centering type (only if \p interpolation_type=0). **/ CImg& resize(const CImgDisplay& disp, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) { return resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions, centering_x,centering_y,centering_z,centering_c); } //! Resize image to dimensions of a display window \newinstance. CImg get_resize(const CImgDisplay& disp, const int interpolation_type=1, const unsigned int boundary_conditions=0, const float centering_x = 0, const float centering_y = 0, const float centering_z = 0, const float centering_c = 0) const { return get_resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions, centering_x,centering_y,centering_z,centering_c); } //! Resize image to half-size along XY axes, using an optimized filter. CImg& resize_halfXY() { return get_resize_halfXY().move_to(*this); } //! Resize image to half-size along XY axes, using an optimized filter \newinstance. CImg get_resize_halfXY() const { if (is_empty()) return *this; static const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f, 0.1231940459f, 0.1935127547f, 0.1231940459f, 0.07842776544f, 0.1231940459f, 0.07842776544f }; CImg I(9), res(_width/2,_height/2,_depth,_spectrum); T *ptrd = res._data; cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) if (x%2 && y%2) *(ptrd++) = (T) (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] + I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] + I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]); return res; } //! Resize image to double-size, using the Scale2X algorithm. /** \note Use anisotropic upscaling algorithm described here. **/ CImg& resize_doubleXY() { return get_resize_doubleXY().move_to(*this); } //! Resize image to double-size, using the Scale2X algorithm \newinstance. CImg get_resize_doubleXY() const { #define _cimg_gs2x_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width) #define _cimg_gs2x_for3x3(img,x,y,z,c,I,T) \ _cimg_gs2x_for3((img)._height,y) for (int x = 0, \ _p1##x = 0, \ _n1##x = (int)( \ (I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ (I[7] = (T)(img)(0,_n1##y,z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x; \ I[1] = I[2], \ I[3] = I[4], I[4] = I[5], \ I[7] = I[8], \ _p1##x = x++, ++_n1##x) if (is_empty()) return *this; CImg res(_width<<1,_height<<1,_depth,_spectrum); CImg_3x3(I,T); cimg_forZC(*this,z,c) { T *ptrd1 = res.data(0,0,z,c), *ptrd2 = ptrd1 + res._width; _cimg_gs2x_for3x3(*this,x,y,z,c,I,T) { if (Icp!=Icn && Ipc!=Inc) { *(ptrd1++) = Ipc==Icp?Ipc:Icc; *(ptrd1++) = Icp==Inc?Inc:Icc; *(ptrd2++) = Ipc==Icn?Ipc:Icc; *(ptrd2++) = Icn==Inc?Inc:Icc; } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; } } } return res; } //! Resize image to triple-size, using the Scale3X algorithm. /** \note Use anisotropic upscaling algorithm described here. **/ CImg& resize_tripleXY() { return get_resize_tripleXY().move_to(*this); } //! Resize image to triple-size, using the Scale3X algorithm \newinstance. CImg get_resize_tripleXY() const { #define _cimg_gs3x_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width) #define _cimg_gs3x_for3x3(img,x,y,z,c,I,T) \ _cimg_gs3x_for3((img)._height,y) for (int x = 0, \ _p1##x = 0, \ _n1##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ x==--_n1##x; \ I[0] = I[1], I[1] = I[2], \ I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], \ _p1##x = x++, ++_n1##x) if (is_empty()) return *this; CImg res(3*_width,3*_height,_depth,_spectrum); CImg_3x3(I,T); cimg_forZC(*this,z,c) { T *ptrd1 = res.data(0,0,z,c), *ptrd2 = ptrd1 + res._width, *ptrd3 = ptrd2 + res._width; _cimg_gs3x_for3x3(*this,x,y,z,c,I,T) { if (Icp != Icn && Ipc != Inc) { *(ptrd1++) = Ipc==Icp?Ipc:Icc; *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc; *(ptrd1++) = Icp==Inc?Inc:Icc; *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc; *(ptrd2++) = Icc; *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc; *(ptrd3++) = Ipc==Icn?Ipc:Icc; *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc; *(ptrd3++) = Icn==Inc?Inc:Icc; } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc; } } } return res; } //! Mirror image content along specified axis. /** \param axis Mirror axis **/ CImg& mirror(const char axis) { if (is_empty()) return *this; T *pf, *pb, *buf = 0; switch (cimg::uncase(axis)) { case 'x' : { pf = _data; pb = data(_width - 1); const unsigned int width2 = _width/2; for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) { for (unsigned int x = 0; x get_mirror(const char axis) const { return (+*this).mirror(axis); } //! Mirror image content along specified axes. /** \param axes Mirror axes, as a C-string. \note \c axes may contains multiple characters, e.g. \c "xyz" **/ CImg& mirror(const char *const axes) { for (const char *s = axes; *s; ++s) mirror(*s); return *this; } //! Mirror image content along specified axes \newinstance. CImg get_mirror(const char *const axes) const { return (+*this).mirror(axes); } //! Shift image content. /** \param delta_x Amount of displacement along the X-axis. \param delta_y Amount of displacement along the Y-axis. \param delta_z Amount of displacement along the Z-axis. \param delta_c Amount of displacement along the C-axis. \param boundary_conditions Border condition. - \c boundary_conditions can be: - 0: Zero border condition (Dirichlet). - 1: Nearest neighbors (Neumann). - 2: Repeat Pattern (Fourier style). **/ CImg& shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0, const int boundary_conditions=0) { if (is_empty()) return *this; if (delta_x) // Shift along X-axis switch (boundary_conditions) { case 0 : if (cimg::abs(delta_x)>=width()) return fill(0); if (delta_x<0) cimg_forYZC(*this,y,z,c) { std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width + delta_x)*sizeof(T)); std::memset(data(_width + delta_x,y,z,c),0,-delta_x*sizeof(T)); } else cimg_forYZC(*this,y,z,c) { std::memmove(data(delta_x,y,z,c),data(0,y,z,c),(_width-delta_x)*sizeof(T)); std::memset(data(0,y,z,c),0,delta_x*sizeof(T)); } break; case 1 : if (delta_x<0) { const int ndelta_x = (-delta_x>=width())?width() - 1:-delta_x; if (!ndelta_x) return *this; cimg_forYZC(*this,y,z,c) { std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); T *ptrd = data(_width - 1,y,z,c); const T val = *ptrd; for (int l = 0; l=width())?width() - 1:delta_x; if (!ndelta_x) return *this; cimg_forYZC(*this,y,z,c) { std::memmove(data(ndelta_x,y,z,c),data(0,y,z,c),(_width-ndelta_x)*sizeof(T)); T *ptrd = data(0,y,z,c); const T val = *ptrd; for (int l = 0; l0) cimg_forYZC(*this,y,z,c) { std::memcpy(buf,data(0,y,z,c),ndelta_x*sizeof(T)); std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); std::memcpy(data(_width-ndelta_x,y,z,c),buf,ndelta_x*sizeof(T)); } else cimg_forYZC(*this,y,z,c) { std::memcpy(buf,data(_width + ndelta_x,y,z,c),-ndelta_x*sizeof(T)); std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width + ndelta_x)*sizeof(T)); std::memcpy(data(0,y,z,c),buf,-ndelta_x*sizeof(T)); } delete[] buf; } } if (delta_y) // Shift along Y-axis switch (boundary_conditions) { case 0 : if (cimg::abs(delta_y)>=height()) return fill(0); if (delta_y<0) cimg_forZC(*this,z,c) { std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height + delta_y)*sizeof(T)); std::memset(data(0,_height + delta_y,z,c),0,-delta_y*_width*sizeof(T)); } else cimg_forZC(*this,z,c) { std::memmove(data(0,delta_y,z,c),data(0,0,z,c),_width*(_height-delta_y)*sizeof(T)); std::memset(data(0,0,z,c),0,delta_y*_width*sizeof(T)); } break; case 1 : if (delta_y<0) { const int ndelta_y = (-delta_y>=height())?height() - 1:-delta_y; if (!ndelta_y) return *this; cimg_forZC(*this,z,c) { std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T)); T *ptrd = data(0,_height-ndelta_y,z,c), *ptrs = data(0,_height - 1,z,c); for (int l = 0; l=height())?height() - 1:delta_y; if (!ndelta_y) return *this; cimg_forZC(*this,z,c) { std::memmove(data(0,ndelta_y,z,c),data(0,0,z,c),_width*(_height-ndelta_y)*sizeof(T)); T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c); for (int l = 0; l0) cimg_forZC(*this,z,c) { std::memcpy(buf,data(0,0,z,c),_width*ndelta_y*sizeof(T)); std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T)); std::memcpy(data(0,_height-ndelta_y,z,c),buf,_width*ndelta_y*sizeof(T)); } else cimg_forZC(*this,z,c) { std::memcpy(buf,data(0,_height + ndelta_y,z,c),-ndelta_y*_width*sizeof(T)); std::memmove(data(0,-ndelta_y,z,c),data(0,0,z,c),_width*(_height + ndelta_y)*sizeof(T)); std::memcpy(data(0,0,z,c),buf,-ndelta_y*_width*sizeof(T)); } delete[] buf; } } if (delta_z) // Shift along Z-axis switch (boundary_conditions) { case 0 : if (cimg::abs(delta_z)>=depth()) return fill(0); if (delta_z<0) cimg_forC(*this,c) { std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth + delta_z)*sizeof(T)); std::memset(data(0,0,_depth + delta_z,c),0,_width*_height*(-delta_z)*sizeof(T)); } else cimg_forC(*this,c) { std::memmove(data(0,0,delta_z,c),data(0,0,0,c),_width*_height*(_depth-delta_z)*sizeof(T)); std::memset(data(0,0,0,c),0,delta_z*_width*_height*sizeof(T)); } break; case 1 : if (delta_z<0) { const int ndelta_z = (-delta_z>=depth())?depth() - 1:-delta_z; if (!ndelta_z) return *this; cimg_forC(*this,c) { std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); T *ptrd = data(0,0,_depth-ndelta_z,c), *ptrs = data(0,0,_depth - 1,c); for (int l = 0; l=depth())?depth() - 1:delta_z; if (!ndelta_z) return *this; cimg_forC(*this,c) { std::memmove(data(0,0,ndelta_z,c),data(0,0,0,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c); for (int l = 0; l0) cimg_forC(*this,c) { std::memcpy(buf,data(0,0,0,c),_width*_height*ndelta_z*sizeof(T)); std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); std::memcpy(data(0,0,_depth-ndelta_z,c),buf,_width*_height*ndelta_z*sizeof(T)); } else cimg_forC(*this,c) { std::memcpy(buf,data(0,0,_depth + ndelta_z,c),-ndelta_z*_width*_height*sizeof(T)); std::memmove(data(0,0,-ndelta_z,c),data(0,0,0,c),_width*_height*(_depth + ndelta_z)*sizeof(T)); std::memcpy(data(0,0,0,c),buf,-ndelta_z*_width*_height*sizeof(T)); } delete[] buf; } } if (delta_c) // Shift along C-axis switch (boundary_conditions) { case 0 : if (cimg::abs(delta_c)>=spectrum()) return fill(0); if (delta_c<0) { std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum + delta_c)*sizeof(T)); std::memset(data(0,0,0,_spectrum + delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T)); } else { std::memmove(data(0,0,0,delta_c),_data,_width*_height*_depth*(_spectrum-delta_c)*sizeof(T)); std::memset(_data,0,delta_c*_width*_height*_depth*sizeof(T)); } break; case 1 : if (delta_c<0) { const int ndelta_c = (-delta_c>=spectrum())?spectrum() - 1:-delta_c; if (!ndelta_c) return *this; std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); T *ptrd = data(0,0,0,_spectrum-ndelta_c), *ptrs = data(0,0,0,_spectrum - 1); for (int l = 0; l=spectrum())?spectrum() - 1:delta_c; if (!ndelta_c) return *this; std::memmove(data(0,0,0,ndelta_c),_data,_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); T *ptrd = data(0,0,0,1); for (int l = 0; l0) { std::memcpy(buf,_data,_width*_height*_depth*ndelta_c*sizeof(T)); std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); std::memcpy(data(0,0,0,_spectrum-ndelta_c),buf,_width*_height*_depth*ndelta_c*sizeof(T)); } else { std::memcpy(buf,data(0,0,0,_spectrum + ndelta_c),-ndelta_c*_width*_height*_depth*sizeof(T)); std::memmove(data(0,0,0,-ndelta_c),_data,_width*_height*_depth*(_spectrum + ndelta_c)*sizeof(T)); std::memcpy(_data,buf,-ndelta_c*_width*_height*_depth*sizeof(T)); } delete[] buf; } } return *this; } //! Shift image content \newinstance. CImg get_shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0, const int boundary_conditions=0) const { return (+*this).shift(delta_x,delta_y,delta_z,delta_c,boundary_conditions); } //! Permute axes order. /** \param order Axes permutations, as a C-string of 4 characters. This function permutes image content regarding the specified axes permutation. **/ CImg& permute_axes(const char *const order) { return get_permute_axes(order).move_to(*this); } //! Permute axes order \newinstance. CImg get_permute_axes(const char *const order) const { const T foo = (T)0; return _get_permute_axes(order,foo); } template CImg _get_permute_axes(const char *const permut, const t&) const { if (is_empty() || !permut) return CImg(*this,false); CImg res; const T* ptrs = _data; if (!cimg::strncasecmp(permut,"xyzc",4)) return +*this; if (!cimg::strncasecmp(permut,"xycz",4)) { res.assign(_width,_height,_spectrum,_depth); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(x,y,c,z,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"xzyc",4)) { res.assign(_width,_depth,_height,_spectrum); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(x,z,y,c,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"xzcy",4)) { res.assign(_width,_depth,_spectrum,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(x,z,c,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"xcyz",4)) { res.assign(_width,_spectrum,_height,_depth); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(x,c,y,z,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"xczy",4)) { res.assign(_width,_spectrum,_depth,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(x,c,z,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"yxzc",4)) { res.assign(_height,_width,_depth,_spectrum); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,x,z,c,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"yxcz",4)) { res.assign(_height,_width,_spectrum,_depth); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,x,c,z,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"yzxc",4)) { res.assign(_height,_depth,_width,_spectrum); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,z,x,c,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"yzcx",4)) { res.assign(_height,_depth,_spectrum,_width); switch (_width) { case 1 : { t *ptr_r = res.data(0,0,0,0); for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { *(ptr_r++) = (t)*(ptrs++); } } break; case 2 : { t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1); for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); } } break; case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2); for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++); } } break; case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2), *ptr_a = res.data(0,0,0,3); for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++); *(ptr_a++) = (t)*(ptrs++); } } break; default : { const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,z,c,x,wh,whd) = *(ptrs++); return res; } } } if (!cimg::strncasecmp(permut,"ycxz",4)) { res.assign(_height,_spectrum,_width,_depth); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,c,x,z,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"yczx",4)) { res.assign(_height,_spectrum,_depth,_width); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(y,c,z,x,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zxyc",4)) { res.assign(_depth,_width,_height,_spectrum); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,x,y,c,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zxcy",4)) { res.assign(_depth,_width,_spectrum,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,x,c,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zyxc",4)) { res.assign(_depth,_height,_width,_spectrum); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,y,x,c,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zycx",4)) { res.assign(_depth,_height,_spectrum,_width); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,y,c,x,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zcxy",4)) { res.assign(_depth,_spectrum,_width,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,c,x,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"zcyx",4)) { res.assign(_depth,_spectrum,_height,_width); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(z,c,y,x,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"cxyz",4)) { res.assign(_spectrum,_width,_height,_depth); switch (_spectrum) { case 1 : { const T *ptr_r = data(0,0,0,0); t *ptrd = res._data; for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) *(ptrd++) = (t)*(ptr_r++); } break; case 2 : { const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1); t *ptrd = res._data; for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); } } break; case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); t *ptrd = res._data; for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++); } } break; case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); t *ptrd = res._data; for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++); *(ptrd++) = (t)*(ptr_a++); } } break; default : { const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,x,y,z,wh,whd) = (t)*(ptrs++); } } } if (!cimg::strncasecmp(permut,"cxzy",4)) { res.assign(_spectrum,_width,_depth,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,x,z,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"cyxz",4)) { res.assign(_spectrum,_height,_width,_depth); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,y,x,z,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"cyzx",4)) { res.assign(_spectrum,_height,_depth,_width); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,y,z,x,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"czxy",4)) { res.assign(_spectrum,_depth,_width,_height); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,z,x,y,wh,whd) = (t)*(ptrs++); } if (!cimg::strncasecmp(permut,"czyx",4)) { res.assign(_spectrum,_depth,_height,_width); const ulongT wh = (ulongT)res._width*res._height, whd = wh*res._depth; cimg_forXYZC(*this,x,y,z,c) res(c,z,y,x,wh,whd) = (t)*(ptrs++); } if (!res) throw CImgArgumentException(_cimg_instance "permute_axes(): Invalid specified permutation '%s'.", cimg_instance, permut); return res; } //! Unroll pixel values along specified axis. /** \param axis Unroll axis (can be \c 'x', \c 'y', \c 'z' or c 'c'). **/ CImg& unroll(const char axis) { const unsigned int siz = (unsigned int)size(); if (siz) switch (cimg::uncase(axis)) { case 'x' : _width = siz; _height = _depth = _spectrum = 1; break; case 'y' : _height = siz; _width = _depth = _spectrum = 1; break; case 'z' : _depth = siz; _width = _height = _spectrum = 1; break; default : _spectrum = siz; _width = _height = _depth = 1; } return *this; } //! Unroll pixel values along specified axis \newinstance. CImg get_unroll(const char axis) const { return (+*this).unroll(axis); } //! Rotate image with arbitrary angle. /** \param angle Rotation angle, in degrees. \param interpolation Type of interpolation. Can be { 0=nearest | 1=linear | 2=cubic }. \param boundary Boundary conditions. Can be { 0=dirichlet | 1=neumann | 2=periodic }. \note Most of the time, size of the image is modified. **/ CImg& rotate(const float angle, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { const float nangle = cimg::mod(angle,360.0f); if (nangle==0.0f) return *this; return get_rotate(angle,interpolation,boundary_conditions).move_to(*this); } //! Rotate image with arbitrary angle \newinstance. CImg get_rotate(const float angle, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { if (is_empty()) return *this; CImg res; const float nangle = cimg::mod(angle,360.0f); if (boundary_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // Optimized version for orthogonal angles. const int wm1 = width() - 1, hm1 = height() - 1; const int iangle = (int)nangle/90; switch (iangle) { case 1 : { // 90 deg. res.assign(_height,_width,_depth,_spectrum); T *ptrd = res._data; cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(y,hm1-x,z,c); } break; case 2 : { // 180 deg. res.assign(_width,_height,_depth,_spectrum); T *ptrd = res._data; cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-x,hm1-y,z,c); } break; case 3 : { // 270 deg. res.assign(_height,_width,_depth,_spectrum); T *ptrd = res._data; cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-y,x,z,c); } break; default : // 0 deg. return *this; } } else { // Generic angle. const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); const float rad = (float)(nangle*cimg::PI/180.0), ca = (float)std::cos(rad), sa = (float)std::sin(rad), ux = cimg::abs(_width*ca), uy = cimg::abs(_width*sa), vx = cimg::abs(_height*sa), vy = cimg::abs(_height*ca), w2 = 0.5f*_width, h2 = 0.5f*_height, dw2 = 0.5f*(ux + vx), dh2 = 0.5f*(uy + vy); res.assign((int)(ux + vx),(int)(uy + vy),_depth,_spectrum); switch (boundary_conditions) { case 0 : { // Dirichlet boundaries. switch (interpolation) { case 2 : { // Cubic interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0); } break; default : { // Nearest-neighbor interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c,0); } } } break; case 1 : { // Neumann boundaries. switch (interpolation) { case 2 : { // Cubic interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = _cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)_linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c); } break; default : { // Nearest-neighbor interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c); } } } break; case 2 : { // Periodic boundaries. switch (interpolation) { case 2 : { // Cubic interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = _cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()), cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)_linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()), cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c); } break; default : { // Nearest-neighbor interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width()), cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height()),z,c); } } } break; default : throw CImgArgumentException(_cimg_instance "rotate(): Invalid specified border conditions %d " "(should be { 0=dirichlet | 1=neumann | 2=periodic }).", cimg_instance, boundary_conditions); } } return res; } //! Rotate image with arbitrary angle, around a center point. /** \param angle Rotation angle, in degrees. \param cx X-coordinate of the rotation center. \param cy Y-coordinate of the rotation center. \param zoom Zoom factor. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann | 2=periodic }. \param interpolation_type Type of interpolation. Can be { 0=nearest | 1=linear | 2=cubic }. **/ CImg& rotate(const float angle, const float cx, const float cy, const float zoom, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { return get_rotate(angle,cx,cy,zoom,interpolation,boundary_conditions).move_to(*this); } //! Rotate image with arbitrary angle, around a center point \newinstance. CImg get_rotate(const float angle, const float cx, const float cy, const float zoom, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { if (interpolation>2) throw CImgArgumentException(_cimg_instance "rotate(): Invalid specified interpolation type %d " "(should be { 0=none | 1=linear | 2=cubic }).", cimg_instance, interpolation); if (is_empty()) return *this; CImg res(_width,_height,_depth,_spectrum); const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); const float rad = (float)((angle*cimg::PI)/180.0), ca = (float)std::cos(rad)/zoom, sa = (float)std::sin(rad)/zoom; switch (boundary_conditions) { case 0 : { switch (interpolation) { case 2 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c,0); } } } break; case 1 : { switch (interpolation) { case 2 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = _cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)_linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c); } } } break; case 2 : { switch (interpolation) { case 2 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) { const Tfloat val = _cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()), cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c); res(x,y,z,c) = (T)(valvmax?vmax:val); } } break; case 1 : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (T)_linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()), cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=2048) #endif cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width()), cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height()),z,c); } } } break; default : throw CImgArgumentException(_cimg_instance "rotate(): Invalid specified border conditions %d " "(should be { 0=dirichlet | 1=neumann | 2=periodic }).", cimg_instance, boundary_conditions); } return res; } //! Warp image content by a warping field. /** \param warp Warping field. \param mode Can be { 0=backward-absolute | 1=backward-relative | 2=forward-absolute | 3=foward-relative } \param is_relative Tells if warping field gives absolute or relative warping coordinates. \param interpolation Can be { 0=nearest | 1=linear | 2=cubic }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann | 2=periodic }. **/ template CImg& warp(const CImg& warp, const unsigned int mode=0, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { return get_warp(warp,mode,interpolation,boundary_conditions).move_to(*this); } //! Warp image content by a warping field \newinstance template CImg get_warp(const CImg& warp, const unsigned int mode=0, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { if (is_empty() || !warp) return *this; if (mode && !is_sameXYZ(warp)) throw CImgArgumentException(_cimg_instance "warp(): Instance and specified relative warping field (%u,%u,%u,%u,%p) " "have different XYZ dimensions.", cimg_instance, warp._width,warp._height,warp._depth,warp._spectrum,warp._data); CImg res(warp._width,warp._height,warp._depth,_spectrum); if (warp._spectrum==1) { // 1d warping. if (mode>=3) { // Forward-relative warp. res.fill(0); if (interpolation>=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atX(*(ptrs++),x + (float)*(ptrs0++),y,z,c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = x + (int)*(ptrs0++); if (X>=0 && X=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atX(*(ptrs++),(float)*(ptrs0++),y,z,c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = (int)*(ptrs0++); if (X>=0 && X=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(x - (float)*(ptrs0++),y,z,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atX(x - (float)*(ptrs0++),y,z,c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(x - (float)*(ptrs0++),y,z,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atX(x - (float)*(ptrs0++),y,z,c,0); } } else { // Nearest-neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width),y,z,c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atX(x - (int)*(ptrs0++),y,z,c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,0); } } } else { // Backward-absolute warp. if (interpolation==2) { // Cubic interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atX((float)*(ptrs0++),0,0,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atX((float)*(ptrs0++),0,0,c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atX((float)*(ptrs0++),0,0,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atX((float)*(ptrs0++),0,0,c,0); } } else { // Nearest-neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width),0,0,c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atX((int)*(ptrs0++),0,0,c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atX((int)*(ptrs0++),0,0,c,0); } } } } else if (warp._spectrum==2) { // 2d warping. if (mode>=3) { // Forward-relative warp. res.fill(0); if (interpolation>=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),z,c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++); if (X>=0 && X=0 && Y=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),z,c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++); if (X>=0 && X=0 && Y=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width), cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width), cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,0); } } else { // Nearest-neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width), cimg::mod(y - (int)*(ptrs1++),(int)_height),z,c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,0); } } } else { // Backward-absolute warp. if (interpolation==2) { // Cubic interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY(cimg::mod((float)*(ptrs0++),(float)_width), cimg::mod((float)*(ptrs1++),(float)_height),0,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod((float)*(ptrs0++),(float)_width), cimg::mod((float)*(ptrs1++),(float)_height),0,c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,0); } } else { // Nearest-neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width), cimg::mod((int)*(ptrs1++),(int)_height),0,c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c,0); } } } } else { // 3d warping. if (mode>=3) { // Forward-relative warp. res.fill(0); if (interpolation>=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++), z + (float)*(ptrs2++),c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++), Z = z + (int)*(ptrs2++); if (X>=0 && X=0 && Y=0 && Z=1) // Linear interpolation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); } else // Nearest-neighbor interpolation. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); const T *ptrs = data(0,y,z,c); cimg_forX(res,x) { const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++), Z = (int)*(ptrs2++); if (X>=0 && X=0 && Y=0 && Z=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width), cimg::mod(y - (float)*(ptrs1++),(float)_height), cimg::mod(z - (float)*(ptrs2++),(float)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width), cimg::mod(y - (float)*(ptrs1++),(float)_height), cimg::mod(z - (float)*(ptrs2++),(float)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,0); } } else { // Nearest neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width), cimg::mod(y - (int)*(ptrs1++),(int)_height), cimg::mod(z - (int)*(ptrs2++),(int)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,0); } } } else { // Backward-absolute warp. if (interpolation==2) { // Cubic interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width), cimg::mod((float)*(ptrs1++),(float)_height), cimg::mod((float)*(ptrs2++),(float)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_cubic_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=4096) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)cubic_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c,0); } } else if (interpolation==1) { // Linear interpolation. if (boundary_conditions==2) // Periodic boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width), cimg::mod((float)*(ptrs1++),(float)_height), cimg::mod((float)*(ptrs2++),(float)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); } else // Dirichlet boundaries. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (res.size()>=1048576) #endif cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (T)linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c,0); } } else { // Nearest-neighbor interpolation. if (boundary_conditions==2) // Periodic boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width), cimg::mod((int)*(ptrs1++),(int)_height), cimg::mod((int)*(ptrs2++),(int)_depth),c); } else if (boundary_conditions==1) // Neumann boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = _atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c); } else // Dirichlet boundaries. cimg_forYZC(res,y,z,c) { const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); T *ptrd = res.data(0,y,z,c); cimg_forX(res,x) *(ptrd++) = atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c,0); } } } } return res; } //! Generate a 2d representation of a 3d image, with XY,XZ and YZ views. /** \param x0 X-coordinate of the projection point. \param y0 Y-coordinate of the projection point. \param z0 Z-coordinate of the projection point. **/ CImg get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) const { if (is_empty() || _depth<2) return +*this; const unsigned int _x0 = (x0>=_width)?_width - 1:x0, _y0 = (y0>=_height)?_height - 1:y0, _z0 = (z0>=_depth)?_depth - 1:z0; const CImg img_xy = get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1), img_zy = get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).permute_axes("xzyc"). resize(_depth,_height,1,-100,-1), img_xz = get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1); return CImg(_width + _depth,_height + _depth,1,_spectrum,cimg::min(img_xy.min(),img_zy.min(),img_xz.min())). draw_image(0,0,img_xy).draw_image(img_xy._width,0,img_zy). draw_image(0,img_xy._height,img_xz); } //! Construct a 2d representation of a 3d image, with XY,XZ and YZ views \inplace. CImg& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) { if (_depth<2) return *this; return get_projections2d(x0,y0,z0).move_to(*this); } //! Crop image region. /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param z0 = Z-coordinate of the upper-left crop rectangle corner. \param c0 = C-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param z1 = Z-coordinate of the lower-right crop rectangle corner. \param c1 = C-coordinate of the lower-right crop rectangle corner. \param boundary_conditions = Dirichlet (false) or Neumann border conditions. **/ CImg& crop(const int x0, const int y0, const int z0, const int c0, const int x1, const int y1, const int z1, const int c1, const bool boundary_conditions=false) { return get_crop(x0,y0,z0,c0,x1,y1,z1,c1,boundary_conditions).move_to(*this); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int y0, const int z0, const int c0, const int x1, const int y1, const int z1, const int c1, const bool boundary_conditions=false) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "crop(): Empty instance.", cimg_instance); const int nx0 = x0 res(1U + nx1 - nx0,1U + ny1 - ny0,1U + nz1 - nz0,1U + nc1 - nc0); if (nx0<0 || nx1>=width() || ny0<0 || ny1>=height() || nz0<0 || nz1>=depth() || nc0<0 || nc1>=spectrum()) { if (boundary_conditions) cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0 + x,ny0 + y,nz0 + z,nc0 + c); else res.fill(0).draw_image(-nx0,-ny0,-nz0,-nc0,*this); } else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this); return res; } //! Crop image region \overloading. CImg& crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool boundary_conditions=false) { return crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool boundary_conditions=false) const { return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); } //! Crop image region \overloading. CImg& crop(const int x0, const int y0, const int x1, const int y1, const bool boundary_conditions=false) { return crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int y0, const int x1, const int y1, const bool boundary_conditions=false) const { return get_crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Crop image region \overloading. CImg& crop(const int x0, const int x1, const bool boundary_conditions=false) { return crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int x1, const bool boundary_conditions=false) const { return get_crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Autocrop image region, regarding the specified background value. CImg& autocrop(const T& value, const char *const axes="czyx") { if (is_empty()) return *this; for (const char *s = axes; *s; ++s) { const char axis = cimg::uncase(*s); const CImg coords = _autocrop(value,axis); if (coords[0]==-1 && coords[1]==-1) return assign(); // Image has only 'value' pixels. else switch (axis) { case 'x' : { const int x0 = coords[0], x1 = coords[1]; if (x0>=0 && x1>=0) crop(x0,x1); } break; case 'y' : { const int y0 = coords[0], y1 = coords[1]; if (y0>=0 && y1>=0) crop(0,y0,_width - 1,y1); } break; case 'z' : { const int z0 = coords[0], z1 = coords[1]; if (z0>=0 && z1>=0) crop(0,0,z0,_width - 1,_height - 1,z1); } break; default : { const int c0 = coords[0], c1 = coords[1]; if (c0>=0 && c1>=0) crop(0,0,0,c0,_width - 1,_height - 1,_depth - 1,c1); } } } return *this; } //! Autocrop image region, regarding the specified background value \newinstance. CImg get_autocrop(const T& value, const char *const axes="czyx") const { return (+*this).autocrop(value,axes); } //! Autocrop image region, regarding the specified background color. /** \param color Color used for the crop. If \c 0, color is guessed. \param axes Axes used for the crop. **/ CImg& autocrop(const T *const color=0, const char *const axes="zyx") { if (is_empty()) return *this; if (!color) { // Guess color. const CImg col1 = get_vector_at(0,0,0); const unsigned int w = _width, h = _height, d = _depth, s = _spectrum; autocrop(col1,axes); if (_width==w && _height==h && _depth==d && _spectrum==s) { const CImg col2 = get_vector_at(w - 1,h - 1,d - 1); autocrop(col2,axes); } return *this; } for (const char *s = axes; *s; ++s) { const char axis = cimg::uncase(*s); switch (axis) { case 'x' : { int x0 = width(), x1 = -1; cimg_forC(*this,c) { const CImg coords = get_shared_channel(c)._autocrop(color[c],'x'); const int nx0 = coords[0], nx1 = coords[1]; if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); } } if (x0==width() && x1==-1) return assign(); else crop(x0,x1); } break; case 'y' : { int y0 = height(), y1 = -1; cimg_forC(*this,c) { const CImg coords = get_shared_channel(c)._autocrop(color[c],'y'); const int ny0 = coords[0], ny1 = coords[1]; if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); } } if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width - 1,y1); } break; default : { int z0 = depth(), z1 = -1; cimg_forC(*this,c) { const CImg coords = get_shared_channel(c)._autocrop(color[c],'z'); const int nz0 = coords[0], nz1 = coords[1]; if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); } } if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width - 1,_height - 1,z1); } } } return *this; } //! Autocrop image region, regarding the specified background color \newinstance. CImg get_autocrop(const T *const color=0, const char *const axes="zyx") const { return (+*this).autocrop(color,axes); } //! Autocrop image region, regarding the specified background color \overloading. template CImg& autocrop(const CImg& color, const char *const axes="zyx") { return get_autocrop(color,axes).move_to(*this); } //! Autocrop image region, regarding the specified background color \newinstance. template CImg get_autocrop(const CImg& color, const char *const axes="zyx") const { return get_autocrop(color._data,axes); } CImg _autocrop(const T& value, const char axis) const { CImg res; switch (cimg::uncase(axis)) { case 'x' : { int x0 = -1, x1 = -1; cimg_forX(*this,x) cimg_forYZC(*this,y,z,c) if ((*this)(x,y,z,c)!=value) { x0 = x; x = width(); y = height(); z = depth(); c = spectrum(); } if (x0>=0) { for (int x = width() - 1; x>=0; --x) cimg_forYZC(*this,y,z,c) if ((*this)(x,y,z,c)!=value) { x1 = x; x = 0; y = height(); z = depth(); c = spectrum(); } } res = CImg::vector(x0,x1); } break; case 'y' : { int y0 = -1, y1 = -1; cimg_forY(*this,y) cimg_forXZC(*this,x,z,c) if ((*this)(x,y,z,c)!=value) { y0 = y; x = width(); y = height(); z = depth(); c = spectrum(); } if (y0>=0) { for (int y = height() - 1; y>=0; --y) cimg_forXZC(*this,x,z,c) if ((*this)(x,y,z,c)!=value) { y1 = y; x = width(); y = 0; z = depth(); c = spectrum(); } } res = CImg::vector(y0,y1); } break; case 'z' : { int z0 = -1, z1 = -1; cimg_forZ(*this,z) cimg_forXYC(*this,x,y,c) if ((*this)(x,y,z,c)!=value) { z0 = z; x = width(); y = height(); z = depth(); c = spectrum(); } if (z0>=0) { for (int z = depth() - 1; z>=0; --z) cimg_forXYC(*this,x,y,c) if ((*this)(x,y,z,c)!=value) { z1 = z; x = width(); y = height(); z = 0; c = spectrum(); } } res = CImg::vector(z0,z1); } break; default : { int c0 = -1, c1 = -1; cimg_forC(*this,c) cimg_forXYZ(*this,x,y,z) if ((*this)(x,y,z,c)!=value) { c0 = c; x = width(); y = height(); z = depth(); c = spectrum(); } if (c0>=0) { for (int c = spectrum() - 1; c>=0; --c) cimg_forXYZ(*this,x,y,z) if ((*this)(x,y,z,c)!=value) { c1 = c; x = width(); y = height(); z = depth(); c = 0; } } res = CImg::vector(c0,c1); } } return res; } //! Return specified image column. /** \param x0 Image column. **/ CImg get_column(const int x0) const { return get_columns(x0,x0); } //! Return specified image column \inplace. CImg& column(const int x0) { return columns(x0,x0); } //! Return specified range of image columns. /** \param x0 Starting image column. \param x1 Ending image column. **/ CImg& columns(const int x0, const int x1) { return get_columns(x0,x1).move_to(*this); } //! Return specified range of image columns \inplace. CImg get_columns(const int x0, const int x1) const { return get_crop(x0,0,0,0,x1,height() - 1,depth() - 1,spectrum() - 1); } //! Return specified image row. CImg get_row(const int y0) const { return get_rows(y0,y0); } //! Return specified image row \inplace. /** \param y0 Image row. **/ CImg& row(const int y0) { return rows(y0,y0); } //! Return specified range of image rows. /** \param y0 Starting image row. \param y1 Ending image row. **/ CImg get_rows(const int y0, const int y1) const { return get_crop(0,y0,0,0,width() - 1,y1,depth() - 1,spectrum() - 1); } //! Return specified range of image rows \inplace. CImg& rows(const int y0, const int y1) { return get_rows(y0,y1).move_to(*this); } //! Return specified image slice. /** \param z0 Image slice. **/ CImg get_slice(const int z0) const { return get_slices(z0,z0); } //! Return specified image slice \inplace. CImg& slice(const int z0) { return slices(z0,z0); } //! Return specified range of image slices. /** \param z0 Starting image slice. \param z1 Ending image slice. **/ CImg get_slices(const int z0, const int z1) const { return get_crop(0,0,z0,0,width() - 1,height() - 1,z1,spectrum() - 1); } //! Return specified range of image slices \inplace. CImg& slices(const int z0, const int z1) { return get_slices(z0,z1).move_to(*this); } //! Return specified image channel. /** \param c0 Image channel. **/ CImg get_channel(const int c0) const { return get_channels(c0,c0); } //! Return specified image channel \inplace. CImg& channel(const int c0) { return channels(c0,c0); } //! Return specified range of image channels. /** \param c0 Starting image channel. \param c1 Ending image channel. **/ CImg get_channels(const int c0, const int c1) const { return get_crop(0,0,0,c0,width() - 1,height() - 1,depth() - 1,c1); } //! Return specified range of image channels \inplace. CImg& channels(const int c0, const int c1) { return get_channels(c0,c1).move_to(*this); } //! Return stream line of a 2d or 3d vector field. CImg get_streamline(const float x, const float y, const float z, const float L=256, const float dl=0.1f, const unsigned int interpolation_type=2, const bool is_backward_tracking=false, const bool is_oriented_only=false) const { if (_spectrum!=2 && _spectrum!=3) throw CImgInstanceException(_cimg_instance "streamline(): Instance is not a 2d or 3d vector field.", cimg_instance); if (_spectrum==2) { if (is_oriented_only) { typename CImg::_functor4d_streamline2d_oriented func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, 0,0,0,_width - 1.0f,_height - 1.0f,0.0f); } else { typename CImg::_functor4d_streamline2d_directed func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, 0,0,0,_width - 1.0f,_height - 1.0f,0.0f); } } if (is_oriented_only) { typename CImg::_functor4d_streamline3d_oriented func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, 0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f); } typename CImg::_functor4d_streamline3d_directed func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, 0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f); } //! Return stream line of a 3d vector field. /** \param func Vector field function. \param x X-coordinate of the starting point of the streamline. \param y Y-coordinate of the starting point of the streamline. \param z Z-coordinate of the starting point of the streamline. \param L Streamline length. \param dl Streamline length increment. \param interpolation_type Type of interpolation. Can be { 0=nearest int | 1=linear | 2=2nd-order RK | 3=4th-order RK. }. \param is_backward_tracking Tells if the streamline is estimated forward or backward. \param is_oriented_only Tells if the direction of the vectors must be ignored. \param x0 X-coordinate of the first bounding-box vertex. \param y0 Y-coordinate of the first bounding-box vertex. \param z0 Z-coordinate of the first bounding-box vertex. \param x1 X-coordinate of the second bounding-box vertex. \param y1 Y-coordinate of the second bounding-box vertex. \param z1 Z-coordinate of the second bounding-box vertex. **/ template static CImg streamline(const tfunc& func, const float x, const float y, const float z, const float L=256, const float dl=0.1f, const unsigned int interpolation_type=2, const bool is_backward_tracking=false, const bool is_oriented_only=false, const float x0=0, const float y0=0, const float z0=0, const float x1=0, const float y1=0, const float z1=0) { if (dl<=0) throw CImgArgumentException("CImg<%s>::streamline(): Invalid specified integration length %g " "(should be >0).", pixel_type(), dl); const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1); if (L<=0 || (is_bounded && (xx1 || yy1 || zz1))) return CImg(); const unsigned int size_L = (unsigned int)cimg::round(L/dl + 1); CImg coordinates(size_L,3); const float dl2 = dl/2; float *ptr_x = coordinates.data(0,0), *ptr_y = coordinates.data(0,1), *ptr_z = coordinates.data(0,2), pu = (float)(dl*func(x,y,z,0)), pv = (float)(dl*func(x,y,z,1)), pw = (float)(dl*func(x,y,z,2)), X = x, Y = y, Z = z; switch (interpolation_type) { case 0 : { // Nearest integer interpolation. cimg_forX(coordinates,l) { *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; const int xi = (int)(X>0?X + 0.5f:X - 0.5f), yi = (int)(Y>0?Y + 0.5f:Y - 0.5f), zi = (int)(Z>0?Z + 0.5f:Z - 0.5f); float u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)), v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)), w = (float)(dl*func((float)xi,(float)yi,(float)zi,2)); if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } if (is_bounded && (Xx1 || Yy1 || Zz1)) break; } } break; case 1 : { // First-order interpolation. cimg_forX(coordinates,l) { *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; float u = (float)(dl*func(X,Y,Z,0)), v = (float)(dl*func(X,Y,Z,1)), w = (float)(dl*func(X,Y,Z,2)); if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } if (is_bounded && (Xx1 || Yy1 || Zz1)) break; } } break; case 2 : { // Second order interpolation. cimg_forX(coordinates,l) { *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; float u0 = (float)(dl2*func(X,Y,Z,0)), v0 = (float)(dl2*func(X,Y,Z,1)), w0 = (float)(dl2*func(X,Y,Z,2)); if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } float u = (float)(dl*func(X + u0,Y + v0,Z + w0,0)), v = (float)(dl*func(X + u0,Y + v0,Z + w0,1)), w = (float)(dl*func(X + u0,Y + v0,Z + w0,2)); if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } if (is_bounded && (Xx1 || Yy1 || Zz1)) break; } } break; default : { // Fourth order interpolation. cimg_forX(coordinates,x) { *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; float u0 = (float)(dl2*func(X,Y,Z,0)), v0 = (float)(dl2*func(X,Y,Z,1)), w0 = (float)(dl2*func(X,Y,Z,2)); if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } float u1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,0)), v1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,1)), w1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,2)); if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; } float u2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,0)), v2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,1)), w2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,2)); if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; } float u3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,0)), v3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,1)), w3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,2)); if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; } const float u = (u0 + u3)/3 + (u1 + u2)/1.5f, v = (v0 + v3)/3 + (v1 + v2)/1.5f, w = (w0 + w3)/3 + (w1 + w2)/1.5f; if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } if (is_bounded && (Xx1 || Yy1 || Zz1)) break; } } } if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0); return coordinates; } //! Return stream line of a 3d vector field \overloading. static CImg streamline(const char *const expression, const float x, const float y, const float z, const float L=256, const float dl=0.1f, const unsigned int interpolation_type=2, const bool is_backward_tracking=true, const bool is_oriented_only=false, const float x0=0, const float y0=0, const float z0=0, const float x1=0, const float y1=0, const float z1=0) { _functor4d_streamline_expr func(expression); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1); } struct _functor4d_streamline2d_directed { const CImg& ref; _functor4d_streamline2d_directed(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z, const unsigned int c) const { return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0; } }; struct _functor4d_streamline3d_directed { const CImg& ref; _functor4d_streamline3d_directed(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z, const unsigned int c) const { return (float)ref._linear_atXYZ(x,y,z,c); } }; struct _functor4d_streamline2d_oriented { const CImg& ref; CImg *pI; _functor4d_streamline2d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,1,2); } ~_functor4d_streamline2d_oriented() { delete pI; } float operator()(const float x, const float y, const float z, const unsigned int c) const { #define _cimg_vecalign2d(i,j) \ if (I(i,j,0)*I(0,0,0) + I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); } int xi = (int)x - (x>=0?0:1), nxi = xi + 1, yi = (int)y - (y>=0?0:1), nyi = yi + 1, zi = (int)z; const float dx = x - xi, dy = y - yi; if (c==0) { CImg& I = *pI; if (xi<0) xi = 0; if (nxi<0) nxi = 0; if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1; if (yi<0) yi = 0; if (nyi<0) nyi = 0; if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1; I(0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,1) = (float)ref(xi,yi,zi,1); I(1,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,1) = (float)ref(nxi,yi,zi,1); I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1); I(0,1,0) = (float)ref(xi,nyi,zi,0); I(0,1,1) = (float)ref(xi,nyi,zi,1); _cimg_vecalign2d(1,0); _cimg_vecalign2d(1,1); _cimg_vecalign2d(0,1); } return c<2?(float)pI->_linear_atXY(dx,dy,0,c):0; } }; struct _functor4d_streamline3d_oriented { const CImg& ref; CImg *pI; _functor4d_streamline3d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,2,3); } ~_functor4d_streamline3d_oriented() { delete pI; } float operator()(const float x, const float y, const float z, const unsigned int c) const { #define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0) + I(i,j,k,1)*I(0,0,0,1) + I(i,j,k,2)*I(0,0,0,2)<0) { \ I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); } int xi = (int)x - (x>=0?0:1), nxi = xi + 1, yi = (int)y - (y>=0?0:1), nyi = yi + 1, zi = (int)z - (z>=0?0:1), nzi = zi + 1; const float dx = x - xi, dy = y - yi, dz = z - zi; if (c==0) { CImg& I = *pI; if (xi<0) xi = 0; if (nxi<0) nxi = 0; if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1; if (yi<0) yi = 0; if (nyi<0) nyi = 0; if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1; if (zi<0) zi = 0; if (nzi<0) nzi = 0; if (zi>=ref.depth()) zi = ref.depth() - 1; if (nzi>=ref.depth()) nzi = ref.depth() - 1; I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1); I(0,0,0,2) = (float)ref(xi,yi,zi,2); I(1,0,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2); I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1); I(1,1,0,2) = (float)ref(nxi,nyi,zi,2); I(0,1,0,0) = (float)ref(xi,nyi,zi,0); I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,nyi,zi,2); I(0,0,1,0) = (float)ref(xi,yi,nzi,0); I(0,0,1,1) = (float)ref(xi,yi,nzi,1); I(0,0,1,2) = (float)ref(xi,yi,nzi,2); I(1,0,1,0) = (float)ref(nxi,yi,nzi,0); I(1,0,1,1) = (float)ref(nxi,yi,nzi,1); I(1,0,1,2) = (float)ref(nxi,yi,nzi,2); I(1,1,1,0) = (float)ref(nxi,nyi,nzi,0); I(1,1,1,1) = (float)ref(nxi,nyi,nzi,1); I(1,1,1,2) = (float)ref(nxi,nyi,nzi,2); I(0,1,1,0) = (float)ref(xi,nyi,nzi,0); I(0,1,1,1) = (float)ref(xi,nyi,nzi,1); I(0,1,1,2) = (float)ref(xi,nyi,nzi,2); _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0); _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1); } return (float)pI->_linear_atXYZ(dx,dy,dz,c); } }; struct _functor4d_streamline_expr { _cimg_math_parser *mp; ~_functor4d_streamline_expr() { delete mp; } _functor4d_streamline_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(expr,"streamline",CImg::const_empty(),0); } float operator()(const float x, const float y, const float z, const unsigned int c) const { return (float)(*mp)(x,y,z,c); } }; //! Return a shared-memory image referencing a range of pixels of the image instance. /** \param x0 X-coordinate of the starting pixel. \param x1 X-coordinate of the ending pixel. \param y0 Y-coordinate. \param z0 Z-coordinate. \param c0 C-coordinate. **/ CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) { const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = (unsigned int)offset(x1,y0,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", cimg_instance, x0,x1,y0,z0,c0); return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); } //! Return a shared-memory image referencing a range of pixels of the image instance \const. const CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const { const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = (unsigned int)offset(x1,y0,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", cimg_instance, x0,x1,y0,z0,c0); return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); } //! Return a shared-memory image referencing a range of rows of the image instance. /** \param y0 Y-coordinate of the starting row. \param y1 Y-coordinate of the ending row. \param z0 Z-coordinate. \param c0 C-coordinate. **/ CImg get_shared_rows(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int c0=0) { const unsigned int beg = (unsigned int)offset(0,y0,z0,c0), end = (unsigned int)offset(0,y1,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_rows(): Invalid request of a shared-memory subset " "(0->%u,%u->%u,%u,%u).", cimg_instance, _width - 1,y0,y1,z0,c0); return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); } //! Return a shared-memory image referencing a range of rows of the image instance \const. const CImg get_shared_rows(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int c0=0) const { const unsigned int beg = (unsigned int)offset(0,y0,z0,c0), end = (unsigned int)offset(0,y1,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_rows(): Invalid request of a shared-memory subset " "(0->%u,%u->%u,%u,%u).", cimg_instance, _width - 1,y0,y1,z0,c0); return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); } //! Return a shared-memory image referencing one row of the image instance. /** \param y0 Y-coordinate. \param z0 Z-coordinate. \param c0 C-coordinate. **/ CImg get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) { return get_shared_rows(y0,y0,z0,c0); } //! Return a shared-memory image referencing one row of the image instance \const. const CImg get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) const { return get_shared_rows(y0,y0,z0,c0); } //! Return a shared memory image referencing a range of slices of the image instance. /** \param z0 Z-coordinate of the starting slice. \param z1 Z-coordinate of the ending slice. \param c0 C-coordinate. **/ CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) { const unsigned int beg = (unsigned int)offset(0,0,z0,c0), end = (unsigned int)offset(0,0,z1,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_slices(): Invalid request of a shared-memory subset " "(0->%u,0->%u,%u->%u,%u).", cimg_instance, _width - 1,_height - 1,z0,z1,c0); return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); } //! Return a shared memory image referencing a range of slices of the image instance \const. const CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) const { const unsigned int beg = (unsigned int)offset(0,0,z0,c0), end = (unsigned int)offset(0,0,z1,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_slices(): Invalid request of a shared-memory subset " "(0->%u,0->%u,%u->%u,%u).", cimg_instance, _width - 1,_height - 1,z0,z1,c0); return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); } //! Return a shared-memory image referencing one slice of the image instance. /** \param z0 Z-coordinate. \param c0 C-coordinate. **/ CImg get_shared_slice(const unsigned int z0, const unsigned int c0=0) { return get_shared_slices(z0,z0,c0); } //! Return a shared-memory image referencing one slice of the image instance \const. const CImg get_shared_slice(const unsigned int z0, const unsigned int c0=0) const { return get_shared_slices(z0,z0,c0); } //! Return a shared-memory image referencing a range of channels of the image instance. /** \param c0 C-coordinate of the starting channel. \param c1 C-coordinate of the ending channel. **/ CImg get_shared_channels(const unsigned int c0, const unsigned int c1) { const unsigned int beg = (unsigned int)offset(0,0,0,c0), end = (unsigned int)offset(0,0,0,c1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_channels(): Invalid request of a shared-memory subset " "(0->%u,0->%u,0->%u,%u->%u).", cimg_instance, _width - 1,_height - 1,_depth - 1,c0,c1); return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); } //! Return a shared-memory image referencing a range of channels of the image instance \const. const CImg get_shared_channels(const unsigned int c0, const unsigned int c1) const { const unsigned int beg = (unsigned int)offset(0,0,0,c0), end = (unsigned int)offset(0,0,0,c1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_channels(): Invalid request of a shared-memory subset " "(0->%u,0->%u,0->%u,%u->%u).", cimg_instance, _width - 1,_height - 1,_depth - 1,c0,c1); return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); } //! Return a shared-memory image referencing one channel of the image instance. /** \param c0 C-coordinate. **/ CImg get_shared_channel(const unsigned int c0) { return get_shared_channels(c0,c0); } //! Return a shared-memory image referencing one channel of the image instance \const. const CImg get_shared_channel(const unsigned int c0) const { return get_shared_channels(c0,c0); } //! Return a shared-memory version of the image instance. CImg get_shared() { return CImg(_data,_width,_height,_depth,_spectrum,true); } //! Return a shared-memory version of the image instance \const. const CImg get_shared() const { return CImg(_data,_width,_height,_depth,_spectrum,true); } //! Split image into a list along specified axis. /** \param axis Splitting axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param nb Number of splitted parts. \note - If \c nb==0, instance image is splitted into blocs of egal values along the specified axis. - If \c nb<=0, instance image is splitted into blocs of -\c nb pixel wide. - If \c nb>0, instance image is splitted into \c nb blocs. **/ CImgList get_split(const char axis, const int nb=-1) const { CImgList res; if (is_empty()) return res; const char _axis = cimg::uncase(axis); if (nb<0) { // Split by bloc size. const unsigned int dp = (unsigned int)(nb?-nb:1); switch (_axis) { case 'x': { if (_width>dp) { res.assign(_width/dp + (_width%dp?1:0),1,1); const unsigned int pe = _width - dp; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=128 && _height*_depth*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { res.assign(_height/dp + (_height%dp?1:0),1,1); const unsigned int pe = _height - dp; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_depth*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { res.assign(_depth/dp + (_depth%dp?1:0),1,1); const unsigned int pe = _depth - dp; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1); const unsigned int pe = _spectrum - dp; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_depth>=128) #endif for (unsigned int p = 0; p0) { // Split by number of (non-homogeneous) blocs. const unsigned int siz = _axis=='x'?_width:_axis=='y'?_height:_axis=='z'?_depth:_axis=='c'?_spectrum:0; if ((unsigned int)nb>siz) throw CImgArgumentException(_cimg_instance "get_split(): Instance cannot be split along %c-axis into %u blocs.", cimg_instance, axis,nb); if (nb==1) res.assign(*this); else { int err = (int)siz; unsigned int _p = 0; switch (_axis) { case 'x' : { cimg_forX(*this,p) if ((err-=nb)<=0) { get_crop(_p,0,0,0,p,_height - 1,_depth - 1,_spectrum - 1).move_to(res); err+=(int)siz; _p = p + 1U; } } break; case 'y' : { cimg_forY(*this,p) if ((err-=nb)<=0) { get_crop(0,_p,0,0,_width - 1,p,_depth - 1,_spectrum - 1).move_to(res); err+=(int)siz; _p = p + 1U; } } break; case 'z' : { cimg_forZ(*this,p) if ((err-=nb)<=0) { get_crop(0,0,_p,0,_width - 1,_height - 1,p,_spectrum - 1).move_to(res); err+=(int)siz; _p = p + 1U; } } break; case 'c' : { cimg_forC(*this,p) if ((err-=nb)<=0) { get_crop(0,0,0,_p,_width - 1,_height - 1,_depth - 1,p).move_to(res); err+=(int)siz; _p = p + 1U; } } } } } else { // Split by egal values according to specified axis. T current = *_data; switch (_axis) { case 'x' : { int i0 = 0; cimg_forX(*this,i) if ((*this)(i)!=current) { get_columns(i0,i - 1).move_to(res); i0 = i; current = (*this)(i); } get_columns(i0,width() - 1).move_to(res); } break; case 'y' : { int i0 = 0; cimg_forY(*this,i) if ((*this)(0,i)!=current) { get_rows(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,i); } get_rows(i0,height() - 1).move_to(res); } break; case 'z' : { int i0 = 0; cimg_forZ(*this,i) if ((*this)(0,0,i)!=current) { get_slices(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,i); } get_slices(i0,depth() - 1).move_to(res); } break; case 'c' : { int i0 = 0; cimg_forC(*this,i) if ((*this)(0,0,0,i)!=current) { get_channels(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,0,i); } get_channels(i0,spectrum() - 1).move_to(res); } break; default : { longT i0 = 0; cimg_foroff(*this,i) if ((*this)[i]!=current) { CImg(_data + i0,1,i - i0).move_to(res); i0 = (longT)i; current = (*this)[i]; } CImg(_data + i0,1,size() - i0).move_to(res); } } } return res; } //! Split image into a list of sub-images, according to a specified splitting value sequence and optionnally axis. /** \param values Splitting value sequence. \param axis Axis along which the splitting is performed. Can be '0' to ignore axis. \param keep_values Tells if the splitting sequence must be kept in the splitted blocs. **/ template CImgList get_split(const CImg& values, const char axis=0, const bool keep_values=true) const { CImgList res; if (is_empty()) return res; const ulongT vsiz = values.size(); const char _axis = cimg::uncase(axis); if (!vsiz) return CImgList(*this); if (vsiz==1) { // Split according to a single value. const T value = *values; switch (_axis) { case 'x' : { unsigned int i0 = 0, i = 0; do { while (i<_width && (*this)(i)==value) ++i; if (i>i0) { if (keep_values) get_columns(i0,i - 1).move_to(res); i0 = i; } while (i<_width && (*this)(i)!=value) ++i; if (i>i0) { get_columns(i0,i - 1).move_to(res); i0 = i; } } while (i<_width); } break; case 'y' : { unsigned int i0 = 0, i = 0; do { while (i<_height && (*this)(0,i)==value) ++i; if (i>i0) { if (keep_values) get_rows(i0,i - 1).move_to(res); i0 = i; } while (i<_height && (*this)(0,i)!=value) ++i; if (i>i0) { get_rows(i0,i - 1).move_to(res); i0 = i; } } while (i<_height); } break; case 'z' : { unsigned int i0 = 0, i = 0; do { while (i<_depth && (*this)(0,0,i)==value) ++i; if (i>i0) { if (keep_values) get_slices(i0,i - 1).move_to(res); i0 = i; } while (i<_depth && (*this)(0,0,i)!=value) ++i; if (i>i0) { get_slices(i0,i - 1).move_to(res); i0 = i; } } while (i<_depth); } break; case 'c' : { unsigned int i0 = 0, i = 0; do { while (i<_spectrum && (*this)(0,0,0,i)==value) ++i; if (i>i0) { if (keep_values) get_channels(i0,i - 1).move_to(res); i0 = i; } while (i<_spectrum && (*this)(0,0,0,i)!=value) ++i; if (i>i0) { get_channels(i0,i - 1).move_to(res); i0 = i; } } while (i<_spectrum); } break; default : { const ulongT siz = size(); ulongT i0 = 0, i = 0; do { while (ii0) { if (keep_values) CImg(_data + i0,1,i - i0).move_to(res); i0 = i; } while (ii0) { CImg(_data + i0,1,i - i0).move_to(res); i0 = i; } } while (i=vsiz) j = 0; } i-=j; if (i>i1) { if (i1>i0) get_columns(i0,i1 - 1).move_to(res); if (keep_values) get_columns(i1,i - 1).move_to(res); i0 = i; } else ++i; } else ++i; } while (i<_width); if (i0<_width) get_columns(i0,width() - 1).move_to(res); } break; case 'y' : { unsigned int i0 = 0, i1 = 0, i = 0; do { if ((*this)(0,i)==*values) { i1 = i; j = 0; while (i<_height && (*this)(0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } i-=j; if (i>i1) { if (i1>i0) get_rows(i0,i1 - 1).move_to(res); if (keep_values) get_rows(i1,i - 1).move_to(res); i0 = i; } else ++i; } else ++i; } while (i<_height); if (i0<_height) get_rows(i0,height() - 1).move_to(res); } break; case 'z' : { unsigned int i0 = 0, i1 = 0, i = 0; do { if ((*this)(0,0,i)==*values) { i1 = i; j = 0; while (i<_depth && (*this)(0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } i-=j; if (i>i1) { if (i1>i0) get_slices(i0,i1 - 1).move_to(res); if (keep_values) get_slices(i1,i - 1).move_to(res); i0 = i; } else ++i; } else ++i; } while (i<_depth); if (i0<_depth) get_slices(i0,depth() - 1).move_to(res); } break; case 'c' : { unsigned int i0 = 0, i1 = 0, i = 0; do { if ((*this)(0,0,0,i)==*values) { i1 = i; j = 0; while (i<_spectrum && (*this)(0,0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } i-=j; if (i>i1) { if (i1>i0) get_channels(i0,i1 - 1).move_to(res); if (keep_values) get_channels(i1,i - 1).move_to(res); i0 = i; } else ++i; } else ++i; } while (i<_spectrum); if (i0<_spectrum) get_channels(i0,spectrum() - 1).move_to(res); } break; default : { ulongT i0 = 0, i1 = 0, i = 0; const ulongT siz = size(); do { if ((*this)[i]==*values) { i1 = i; j = 0; while (i=vsiz) j = 0; } i-=j; if (i>i1) { if (i1>i0) CImg(_data + i0,1,i1 - i0).move_to(res); if (keep_values) CImg(_data + i1,1,i - i1).move_to(res); i0 = i; } else ++i; } else ++i; } while (i(_data + i0,1,siz - i0).move_to(res); } break; } } return res; } //! Append two images along specified axis. /** \param img Image to append with instance image. \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Append alignment in \c [0,1]. **/ template CImg& append(const CImg& img, const char axis='x', const float align=0) { if (is_empty()) return assign(img,false); if (!img) return *this; return CImgList(*this,true).insert(img).get_append(axis,align).move_to(*this); } //! Append two images along specified axis \specialization. CImg& append(const CImg& img, const char axis='x', const float align=0) { if (is_empty()) return assign(img,false); if (!img) return *this; return CImgList(*this,img,true).get_append(axis,align).move_to(*this); } //! Append two images along specified axis \const. template CImg<_cimg_Tt> get_append(const CImg& img, const char axis='x', const float align=0) const { if (is_empty()) return +img; if (!img) return +*this; return CImgList<_cimg_Tt>(*this,true).insert(img).get_append(axis,align); } //! Append two images along specified axis \specialization. CImg get_append(const CImg& img, const char axis='x', const float align=0) const { if (is_empty()) return +img; if (!img) return +*this; return CImgList(*this,img,true).get_append(axis,align); } //@} //--------------------------------------- // //! \name Filtering / Transforms //@{ //--------------------------------------- //! Correlate image by a mask. /** \param mask = the correlation kernel. \param boundary_conditions = the border condition type (0=zero, 1=dirichlet) \param is_normalized = enable local normalization. \note - The correlation of the image instance \p *this by the mask \p mask is defined to be: res(x,y,z) = sum_{i,j,k} (*this)(x + i,y + j,z + k)*mask(i,j,k). **/ template CImg& correlate(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) { if (is_empty() || !mask) return *this; return get_correlate(mask,boundary_conditions,is_normalized).move_to(*this); } //! Correlate image by a mask \newinstance. template CImg<_cimg_Ttfloat> get_correlate(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) const { if (is_empty() || !mask) return *this; typedef _cimg_Ttfloat Ttfloat; CImg res(_width,_height,_depth,cimg::max(_spectrum,mask._spectrum)); if (boundary_conditions && mask._width==mask._height && ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) { // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1) Ttfloat *ptrd = res._data; CImg I; switch (mask._depth) { case 3 : { I.assign(27); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_for3x3x3(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24] + I[25]*I[25] + I[26]*I[26]); *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26])/std::sqrt(N):0); } } else cimg_for3x3x3(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26]); } } break; case 2 : { I.assign(8); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_for2x2x2(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] + I[3]*I[3] + I[4]*I[4] + I[5]*I[5] + I[6]*I[6] + I[7]*I[7]); *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] + I[6]*_mask[6] + I[7]*_mask[7])/std::sqrt(N):0); } } else cimg_for2x2x2(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] + I[6]*_mask[6] + I[7]*_mask[7]); } } break; default : case 1 : switch (mask._width) { case 6 : { I.assign(36); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] + I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]); *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35])/ std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35]); } } break; case 5 : { I.assign(25); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]); *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24])/std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24]); } } break; case 4 : { I.assign(16); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]); *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15])/ std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15]); } } break; case 3 : { I.assign(9); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_forZ(_img,z) cimg_for3x3(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] + I[3]*I[3] + I[4]*I[4] + I[5]*I[5] + I[6]*I[6] + I[7]*I[7] + I[8]*I[8]); *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] + I[6]*_mask[6] + I[7]*_mask[7] + I[8]*_mask[8])/std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for3x3(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3] + I[4]*_mask[4] + I[5]*_mask[5] + I[6]*_mask[6] + I[7]*_mask[7] + I[8]*_mask[8]); } } break; case 2 : { I.assign(4); cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; cimg_forZ(_img,z) cimg_for2x2(_img,x,y,z,0,I,T) { const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] + I[3]*I[3]); *(ptrd++) = (Ttfloat)(N?(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3])/std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for2x2(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[0]*_mask[0] + I[1]*_mask[1] + I[2]*_mask[2] + I[3]*_mask[3]); } } break; case 1 : if (is_normalized) res.fill(1); else cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); res.get_shared_channel(c).assign(_img)*=_mask[0]; } break; } } } else { // Generic version for other masks and boundary conditions. const int mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._spectrum>=2) #endif cimg_forC(res,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { // Normalized correlation. const Ttfloat _M = (Ttfloat)_mask.magnitude(2), M = _M*_M; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768) #endif for (int z = mz1; z=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Ttfloat val = 0, N = 0; for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const Ttfloat _val = (Ttfloat)_img._atXYZ(x + xm,y + ym,z + zm); val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm); N+=_val*_val; } N*=M; res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0); } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Ttfloat val = 0, N = 0; for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const Ttfloat _val = (Ttfloat)_img.atXYZ(x + xm,y + ym,z + zm,0,0); val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm); N+=_val*_val; } N*=M; res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0); } } else { // Classical correlation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768) #endif for (int z = mz1; z=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Ttfloat val = 0; for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) val+=_img._atXYZ(x + xm,y + ym,z + zm)*_mask(mx1 + xm,my1 + ym,mz1 + zm); res(x,y,z,c) = (Ttfloat)val; } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Ttfloat val = 0; for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) val+=_img.atXYZ(x + xm,y + ym,z + zm,0,0)*_mask(mx1 + xm,my1 + ym,mz1 + zm); res(x,y,z,c) = (Ttfloat)val; } } } } return res; } //! Convolve image by a mask. /** \param mask = the correlation kernel. \param boundary_conditions = the border condition type (0=zero, 1=dirichlet) \param is_normalized = enable local normalization. \note - The result \p res of the convolution of an image \p img by a mask \p mask is defined to be: res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k) **/ template CImg& convolve(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) { if (is_empty() || !mask) return *this; return get_convolve(mask,boundary_conditions,is_normalized).move_to(*this); } //! Cumulate image values, optionally along specified axis. /** \param axis Cumulation axis. Set it to 0 to cumulate all values globally without taking axes into account. **/ CImg& cumulate(const char axis=0) { switch (cimg::uncase(axis)) { case 'x' : #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=512 && _height*_depth*_spectrum>=16) #endif cimg_forYZC(*this,y,z,c) { T *ptrd = data(0,y,z,c); Tlong cumul = 0; cimg_forX(*this,x) { cumul+=(Tlong)*ptrd; *(ptrd++) = (T)cumul; } } break; case 'y' : { const ulongT w = (ulongT)_width; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_height>=512 && _width*_depth*_spectrum>=16) #endif cimg_forXZC(*this,x,z,c) { T *ptrd = data(x,0,z,c); Tlong cumul = 0; cimg_forY(*this,y) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=w; } } } break; case 'z' : { const ulongT wh = (ulongT)_width*_height; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_depth>=512 && _width*_depth*_spectrum>=16) #endif cimg_forXYC(*this,x,y,c) { T *ptrd = data(x,y,0,c); Tlong cumul = 0; cimg_forZ(*this,z) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=wh; } } } break; case 'c' : { const ulongT whd = (ulongT)_width*_height*_depth; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_spectrum>=512 && _width*_height*_depth>=16) #endif cimg_forXYZ(*this,x,y,z) { T *ptrd = data(x,y,z,0); Tlong cumul = 0; cimg_forC(*this,c) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=whd; } } } break; default : { // Global cumulation. Tlong cumul = 0; cimg_for(*this,ptrd,T) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; } } } return *this; } //! Cumulate image values, optionally along specified axis \newinstance. CImg get_cumulate(const char axis=0) const { return CImg(*this,false).cumulate(axis); } //! Cumulate image values, along specified axes. /** \param axes Cumulation axes, as a C-string. \note \c axes may contains multiple characters, e.g. \c "xyz" **/ CImg& cumulate(const char *const axes) { for (const char *s = axes; *s; ++s) cumulate(*s); return *this; } //! Cumulate image values, along specified axes \newintance. CImg get_cumulate(const char *const axes) const { return CImg(*this,false).cumulate(axes); } //! Convolve image by a mask \newinstance. template CImg<_cimg_Ttfloat> get_convolve(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) const { if (is_empty() || !mask) return *this; return get_correlate(CImg(mask._data,mask.size(),1,1,1,true).get_mirror('x'). resize(mask,-1),boundary_conditions,is_normalized); } //! Erode image by a structuring element. /** \param mask Structuring element. \param boundary_conditions Boundary conditions. \param is_normalized Tells if the erosion is locally normalized. **/ template CImg& erode(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) { if (is_empty() || !mask) return *this; return get_erode(mask,boundary_conditions,is_normalized).move_to(*this); } //! Erode image by a structuring element \newinstance. template CImg<_cimg_Tt> get_erode(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) const { if (is_empty() || !mask) return *this; typedef _cimg_Tt Tt; CImg res(_width,_height,_depth,cimg::max(_spectrum,mask._spectrum)); const int mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { // Normalized erosion. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768) #endif for (int z = mz1; z::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) + mval); if (mval && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) + mval); if (mval && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) + mval); if (mval && cval=32768) #endif for (int z = mz1; z::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const Tt cval = (Tt)_img(x + xm,y + ym,z + zm); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,0); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this; if (sx>1 && _width>1) { // Along X-axis. const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forYZC(*this,y,z,c) { T *const ptrdb = buf._data, *ptrd = buf._data, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(0,y,z,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val1 && _height>1) { // Along Y-axis. const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forXZC(*this,x,z,c) { T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; } } *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(x,0,z,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val1 && _depth>1) { // Along Z-axis. const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forXYC(*this,x,y,c) { T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; } } *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(x,y,0,c); cur = cimg::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val get_erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { return (+*this).erode(sx,sy,sz); } //! Erode the image by a square structuring element of specified size. /** \param s Size of the structuring element. **/ CImg& erode(const unsigned int s) { return erode(s,s,s); } //! Erode the image by a square structuring element of specified size \newinstance. CImg get_erode(const unsigned int s) const { return (+*this).erode(s); } //! Dilate image by a structuring element. /** \param mask Structuring element. \param boundary_conditions Boundary conditions. \param is_normalized Tells if the erosion is locally normalized. **/ template CImg& dilate(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) { if (is_empty() || !mask) return *this; return get_dilate(mask,boundary_conditions,is_normalized).move_to(*this); } //! Dilate image by a structuring element \newinstance. template CImg<_cimg_Tt> get_dilate(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) const { if (is_empty() || !mask) return *this; typedef _cimg_Tt Tt; CImg res(_width,_height,_depth,_spectrum); const int mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { cimg_test_abort(); const CImg _img = get_shared_channel(c%_spectrum); const CImg _mask = mask.get_shared_channel(c%mask._spectrum); if (is_normalized) { // Normalized dilation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width*_height*_depth>=32768) #endif for (int z = mz1; z::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) - mval); if (mval && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } if (boundary_conditions) #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) - mval); if (mval && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(*this,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) - mval); if (mval && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } } else { // Classical dilation. #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth>=128) #endif for (int z = mz1; z::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const Tt cval = (Tt)_img(x + xm,y + ym,z + zm); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } if (boundary_conditions) #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,0); if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } } } return res; } //! Dilate image by a rectangular structuring element of specified size. /** \param sx Width of the structuring element. \param sy Height of the structuring element. \param sz Depth of the structuring element. **/ CImg& dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this; if (sx>1 && _width>1) { // Along X-axis. const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forYZC(*this,y,z,c) { T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } } *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(0,y,z,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } for (int p = L - s - 1; p>0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } *(ptrd++) = cur; } ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } } } } if (sy>1 && _height>1) { // Along Y-axis. const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forXZC(*this,x,z,c) { T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } } *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(x,0,z,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } for (int p = L - s - 1; p>0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } *(ptrd++) = cur; } ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } } } } if (sz>1 && _depth>1) { // Along Z-axis. const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; CImg buf(L); #ifdef cimg_use_opemp #pragma omp parallel for collapse(3) firstprivate(buf) if (size()>524288) #endif cimg_forXYC(*this,x,y,c) { T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; T cur = *ptrs; ptrs+=off; bool is_first = true; for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } } *(ptrd++) = cur; if (ptrs>=ptrse) { T *pd = data(x,y,0,c); cur = cimg::max(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; } } else { for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } for (int p = L - s - 1; p>0; --p) { const T val = *ptrs; ptrs+=off; if (is_first) { const T *nptrs = ptrs - off; cur = val; for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } *(ptrd++) = cur; } ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } } } } return *this; } //! Dilate image by a rectangular structuring element of specified size \newinstance. CImg get_dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { return (+*this).dilate(sx,sy,sz); } //! Dilate image by a square structuring element of specified size. /** \param s Size of the structuring element. **/ CImg& dilate(const unsigned int s) { return dilate(s,s,s); } //! Dilate image by a square structuring element of specified size \newinstance. CImg get_dilate(const unsigned int s) const { return (+*this).dilate(s); } //! Compute watershed transform. /** \param priority Priority map. \param is_high_connectivity Boolean that choose between 4(false)- or 8(true)-connectivity in 2d case, and between 6(false)- or 26(true)-connectivity in 3d case. \note Non-zero values of the instance instance are propagated to zero-valued ones according to specified the priority map. **/ template CImg& watershed(const CImg& priority, const bool is_high_connectivity=false) { #define _cimg_watershed_init(cond,X,Y,Z) \ if (cond && !(*this)(X,Y,Z)) Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,nb_seeds) #define _cimg_watershed_propagate(cond,X,Y,Z) \ if (cond) { \ if ((*this)(X,Y,Z)) { \ ns = labels(X,Y,Z) - 1; xs = seeds(ns,0); ys = seeds(ns,1); zs = seeds(ns,2); \ d = cimg::sqr((float)x - xs) + cimg::sqr((float)y - ys) + cimg::sqr((float)z - zs); \ if (d labels(_width,_height,_depth,1,0), seeds(64,3); CImg::type> Q; unsigned int sizeQ = 0; int px, nx, py, ny, pz, nz; bool is_px, is_nx, is_py, is_ny, is_pz, is_nz; const bool is_3d = _depth>1; // Find seed points and insert them in priority queue. unsigned int nb_seeds = 0; const T *ptrs = _data; cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { // 3d version if (nb_seeds>=seeds._width) seeds.resize(2*seeds._width,3,1,1,0); seeds(nb_seeds,0) = x; seeds(nb_seeds,1) = y; seeds(nb_seeds++,2) = z; px = x - 1; nx = x + 1; py = y - 1; ny = y + 1; pz = z - 1; nz = z + 1; is_px = px>=0; is_nx = nx=0; is_ny = ny=0; is_nz = nz=0; is_nx = nx=0; is_ny = ny=0; is_nz = nz::inf(); T label = 0; _cimg_watershed_propagate(is_px,px,y,z); _cimg_watershed_propagate(is_nx,nx,y,z); _cimg_watershed_propagate(is_py,x,py,z); _cimg_watershed_propagate(is_ny,x,ny,z); if (is_3d) { _cimg_watershed_propagate(is_pz,x,y,pz); _cimg_watershed_propagate(is_nz,x,y,nz); } if (is_high_connectivity) { _cimg_watershed_propagate(is_px && is_py,px,py,z); _cimg_watershed_propagate(is_nx && is_py,nx,py,z); _cimg_watershed_propagate(is_px && is_ny,px,ny,z); _cimg_watershed_propagate(is_nx && is_ny,nx,ny,z); if (is_3d) { _cimg_watershed_propagate(is_px && is_pz,px,y,pz); _cimg_watershed_propagate(is_nx && is_pz,nx,y,pz); _cimg_watershed_propagate(is_px && is_nz,px,y,nz); _cimg_watershed_propagate(is_nx && is_nz,nx,y,nz); _cimg_watershed_propagate(is_py && is_pz,x,py,pz); _cimg_watershed_propagate(is_ny && is_pz,x,ny,pz); _cimg_watershed_propagate(is_py && is_nz,x,py,nz); _cimg_watershed_propagate(is_ny && is_nz,x,ny,nz); _cimg_watershed_propagate(is_px && is_py && is_pz,px,py,pz); _cimg_watershed_propagate(is_nx && is_py && is_pz,nx,py,pz); _cimg_watershed_propagate(is_px && is_ny && is_pz,px,ny,pz); _cimg_watershed_propagate(is_nx && is_ny && is_pz,nx,ny,pz); _cimg_watershed_propagate(is_px && is_py && is_nz,px,py,nz); _cimg_watershed_propagate(is_nx && is_py && is_nz,nx,py,nz); _cimg_watershed_propagate(is_px && is_ny && is_nz,px,ny,nz); _cimg_watershed_propagate(is_nx && is_ny && is_nz,nx,ny,nz); } } (*this)(x,y,z) = label; labels(x,y,z) = ++nmin; } return *this; } //! Compute watershed transform \newinstance. template CImg get_watershed(const CImg& priority, const bool is_high_connectivity=false) const { return (+*this).watershed(priority,is_high_connectivity); } // [internal] Insert/Remove items in priority queue, for watershed/distance transforms. template bool _priority_queue_insert(CImg& is_queued, unsigned int& siz, const tv value, const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int n=1) { if (is_queued(x,y,z)) return false; is_queued(x,y,z) = (tq)n; if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); } (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z; for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos + 1)/2 - 1,0); pos = par) { cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1)); cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3)); } return true; } CImg& _priority_queue_remove(unsigned int& siz) { (*this)(0,0) = (*this)(--siz,0); (*this)(0,1) = (*this)(siz,1); (*this)(0,2) = (*this)(siz,2); (*this)(0,3) = (*this)(siz,3); const float value = (*this)(0,0); for (unsigned int pos = 0, left = 0, right = 0; ((right=2*(pos + 1),(left=right - 1))(*this)(right,0)) { cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1)); cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3)); pos = left; } else { cimg::swap((*this)(pos,0),(*this)(right,0)); cimg::swap((*this)(pos,1),(*this)(right,1)); cimg::swap((*this)(pos,2),(*this)(right,2)); cimg::swap((*this)(pos,3),(*this)(right,3)); pos = right; } } else { cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1)); cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3)); pos = left; } } return *this; } //! Apply recursive Deriche filter. /** \param sigma Standard deviation of the filter. \param order Order of the filter. Can be { 0=smooth-filter | 1=1st-derivative | 2=2nd-derivative }. \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. **/ CImg& deriche(const float sigma, const unsigned int order=0, const char axis='x', const bool boundary_conditions=true) { #define _cimg_deriche_apply \ CImg Y(N); \ Tfloat *ptrY = Y._data, yb = 0, yp = 0; \ T xp = (T)0; \ if (boundary_conditions) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \ for (int m = 0; m=0; --n) { \ const T xc = *(ptrX-=off); \ const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \ xa = xn; xn = xc; ya = yn; yn = yc; \ *ptrX = (T)(*(--ptrY)+yc); \ } const char naxis = cimg::uncase(axis); const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; if (is_empty() || (nsigma<0.1f && !order)) return *this; const float nnsigma = nsigma<0.1f?0.1f:nsigma, alpha = 1.695f/nnsigma, ema = (float)std::exp(-alpha), ema2 = (float)std::exp(-2*alpha), b1 = -2*ema, b2 = ema2; float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0; switch (order) { case 0 : { const float k = (1-ema)*(1-ema)/(1 + 2*alpha*ema-ema2); a0 = k; a1 = k*(alpha - 1)*ema; a2 = k*(alpha + 1)*ema; a3 = -k*ema2; } break; case 1 : { const float k = -(1-ema)*(1-ema)*(1-ema)/(2*(ema + 1)*ema); a0 = a3 = 0; a1 = k*ema; a2 = -a1; } break; case 2 : { const float ea = (float)std::exp(-alpha), k = -(ema2 - 1)/(2*alpha*ema), kn = (-2*(-1 + 3*ea - 3*ea*ea + ea*ea*ea)/(3*ea + 1 + 3*ea*ea + ea*ea*ea)); a0 = kn; a1 = -kn*(1 + k*alpha)*ema; a2 = kn*(1 - k*alpha)*ema; a3 = -kn*ema2; } break; default : throw CImgArgumentException(_cimg_instance "deriche(): Invalid specified filter order %u " "(should be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).", cimg_instance, order); } coefp = (a0 + a1)/(1 + b1 + b2); coefn = (a2 + a3)/(1 + b1 + b2); switch (naxis) { case 'x' : { const int N = width(); const ulongT off = 1U; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche_apply; } } break; case 'y' : { const int N = height(); const ulongT off = (ulongT)_width; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche_apply; } } break; case 'z' : { const int N = depth(); const ulongT off = (ulongT)_width*_height; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche_apply; } } break; default : { const int N = spectrum(); const ulongT off = (ulongT)_width*_height*_depth; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYZ(*this,x,y,z) { T *ptrX = data(x,y,z,0); _cimg_deriche_apply; } } } return *this; } //! Apply recursive Deriche filter \newinstance. CImg get_deriche(const float sigma, const unsigned int order=0, const char axis='x', const bool boundary_conditions=true) const { return CImg(*this,false).deriche(sigma,order,axis,boundary_conditions); } // [internal] Apply a recursive filter (used by CImg::vanvliet()). /* \param ptr the pointer of the data \param filter the coefficient of the filter in the following order [n,n - 1,n - 2,n - 3]. \param N size of the data \param off the offset between two data point \param order the order of the filter 0 (smoothing), 1st derivtive, 2nd derivative, 3rd derivative \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. \note Boundary condition using B. Triggs method (IEEE trans on Sig Proc 2005). */ static void _cimg_recursive_apply(T *data, const double filter[], const int N, const ulongT off, const unsigned int order, const bool boundary_conditions) { double val[4] = { 0 }; // res[n,n - 1,n - 2,n - 3,..] or res[n,n + 1,n + 2,n + 3,..] const double sumsq = filter[0], sum = sumsq * sumsq, a1 = filter[1], a2 = filter[2], a3 = filter[3], scaleM = 1.0 / ( (1.0 + a1 - a2 + a3) * (1.0 - a1 - a2 - a3) * (1.0 + a2 + (a1 - a3) * a3) ); double M[9]; // Triggs matrix M[0] = scaleM * (-a3 * a1 + 1.0 - a3 * a3 - a2); M[1] = scaleM * (a3 + a1) * (a2 + a3 * a1); M[2] = scaleM * a3 * (a1 + a3 * a2); M[3] = scaleM * (a1 + a3 * a2); M[4] = -scaleM * (a2 - 1.0) * (a2 + a3 * a1); M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.0); M[6] = scaleM * (a3 * a1 + a2 + a1 * a1 - a2 * a2); M[7] = scaleM * (a1 * a2 + a3 * a2 * a2 - a1 * a3 * a3 - a3 * a3 * a3 - a3 * a2 + a3); M[8] = scaleM * a3 * (a1 + a3 * a2); switch (order) { case 0 : { const double iplus = (boundary_conditions?data[(N - 1)*off]:0); for (int pass = 0; pass<2; ++pass) { if (!pass) { for (int k = 1; k<4; ++k) val[k] = (boundary_conditions?*data/sumsq:0); } else { /* apply Triggs border condition */ const double uplus = iplus/(1.0 - a1 - a2 - a3), vplus = uplus/(1.0 - a1 - a2 - a3), unp = val[1] - uplus, unp1 = val[2] - uplus, unp2 = val[3] - uplus; val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2 + vplus) * sum; val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2 + vplus) * sum; val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2 + vplus) * sum; *data = (T)val[0]; data -= off; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } for (int n = pass; n0; --k) val[k] = val[k - 1]; } if (!pass) data -= off; } } break; case 1 : { double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { if (!pass) { for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0); for (int k = 0; k<4; ++k) val[k] = 0; } else { /* apply Triggs border condition */ const double unp = val[1], unp1 = val[2], unp2 = val[3]; val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; *data = (T)val[0]; data -= off; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } for (int n = pass; n0; --k) x[k] = x[k - 1]; } else { data-=off;} for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } } break; case 2: { double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { if (!pass) { for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0); for (int k = 0; k<4; ++k) val[k] = 0; } else { /* apply Triggs border condition */ const double unp = val[1], unp1 = val[2], unp2 = val[3]; val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; *data = (T)val[0]; data -= off; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } for (int n = pass; n0; --k) x[k] = x[k - 1]; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } } break; case 3: { double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { if (!pass) { for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:0); for (int k = 0; k<4; ++k) val[k] = 0; } else { /* apply Triggs border condition */ const double unp = val[1], unp1 = val[2], unp2 = val[3]; val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; *data = (T)val[0]; data -= off; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } for (int n = pass; n0; --k) x[k] = x[k - 1]; for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } } break; } } //! Van Vliet recursive Gaussian filter. /** \param sigma standard deviation of the Gaussian filter \param order the order of the filter 0,1,2,3 \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. \note dirichlet boundary condition has a strange behavior I.T. Young, L.J. van Vliet, M. van Ginkel, Recursive Gabor filtering. IEEE Trans. Sig. Proc., vol. 50, pp. 2799-2805, 2002. (this is an improvement over Young-Van Vliet, Sig. Proc. 44, 1995) Boundary conditions (only for order 0) using Triggs matrix, from B. Triggs and M. Sdika. Boundary conditions for Young-van Vliet recursive filtering. IEEE Trans. Signal Processing, vol. 54, pp. 2365-2367, 2006. **/ CImg& vanvliet(const float sigma, const unsigned int order, const char axis='x', const bool boundary_conditions=true) { if (is_empty()) return *this; const char naxis = cimg::uncase(axis); const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; if (is_empty() || (nsigma<0.5f && !order)) return *this; const double nnsigma = nsigma<0.5f?0.5f:nsigma, m0 = 1.16680, m1 = 1.10783, m2 = 1.40586, m1sq = m1 * m1, m2sq = m2 * m2, q = (nnsigma<3.556?-0.2568 + 0.5784*nnsigma + 0.0561*nnsigma*nnsigma:2.5091 + 0.9804*(nnsigma - 3.556)), qsq = q * q, scale = (m0 + q) * (m1sq + m2sq + 2 * m1 * q + qsq), b1 = -q * (2 * m0 * m1 + m1sq + m2sq + (2 * m0 + 4 * m1) * q + 3 * qsq) / scale, b2 = qsq * (m0 + 2 * m1 + 3 * q) / scale, b3 = -qsq * q / scale, B = ( m0 * (m1sq + m2sq) ) / scale; double filter[4]; filter[0] = B; filter[1] = -b1; filter[2] = -b2; filter[3] = -b3; switch (naxis) { case 'x' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forYZC(*this,y,z,c) _cimg_recursive_apply(data(0,y,z,c),filter,_width,1U,order,boundary_conditions); } break; case 'y' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXZC(*this,x,z,c) _cimg_recursive_apply(data(x,0,z,c),filter,_height,(ulongT)_width,order,boundary_conditions); } break; case 'z' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYC(*this,x,y,c) _cimg_recursive_apply(data(x,y,0,c),filter,_depth,(ulongT)_width*_height, order,boundary_conditions); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYZ(*this,x,y,z) _cimg_recursive_apply(data(x,y,z,0),filter,_spectrum,(ulongT)_width*_height*_depth, order,boundary_conditions); } } return *this; } //! Blur image using Van Vliet recursive Gaussian filter. \newinstance. CImg get_vanvliet(const float sigma, const unsigned int order, const char axis='x', const bool boundary_conditions=true) const { return CImg(*this,false).vanvliet(sigma,order,axis,boundary_conditions); } //! Blur image. /** \param sigma_x Standard deviation of the blur, along the X-axis. \param sigma_y Standard deviation of the blur, along the Y-axis. \param sigma_z Standard deviation of the blur, along the Z-axis. \param boundary_conditions Boundary conditions. Can be { false=dirichlet | true=neumann }. \param is_gaussian Tells if the blur uses a gaussian (\c true) or quasi-gaussian (\c false) kernel. \note - The blur is computed as a 0-order Deriche filter. This is not a gaussian blur. - This is a recursive algorithm, not depending on the values of the standard deviations. \see deriche(), vanvliet(). **/ CImg& blur(const float sigma_x, const float sigma_y, const float sigma_z, const bool boundary_conditions=true, const bool is_gaussian=false) { if (is_empty()) return *this; if (is_gaussian) { if (_width>1) vanvliet(sigma_x,0,'x',boundary_conditions); if (_height>1) vanvliet(sigma_y,0,'y',boundary_conditions); if (_depth>1) vanvliet(sigma_z,0,'z',boundary_conditions); } else { if (_width>1) deriche(sigma_x,0,'x',boundary_conditions); if (_height>1) deriche(sigma_y,0,'y',boundary_conditions); if (_depth>1) deriche(sigma_z,0,'z',boundary_conditions); } return *this; } //! Blur image \newinstance. CImg get_blur(const float sigma_x, const float sigma_y, const float sigma_z, const bool boundary_conditions=true, const bool is_gaussian=false) const { return CImg(*this,false).blur(sigma_x,sigma_y,sigma_z,boundary_conditions,is_gaussian); } //! Blur image isotropically. /** \param sigma Standard deviation of the blur. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }.a \see deriche(), vanvliet(). **/ CImg& blur(const float sigma, const bool boundary_conditions=true, const bool is_gaussian=false) { const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; return blur(nsigma,nsigma,nsigma,boundary_conditions,is_gaussian); } //! Blur image isotropically \newinstance. CImg get_blur(const float sigma, const bool boundary_conditions=true, const bool is_gaussian=false) const { return CImg(*this,false).blur(sigma,boundary_conditions,is_gaussian); } //! Blur image anisotropically, directed by a field of diffusion tensors. /** \param G Field of square roots of diffusion tensors/vectors used to drive the smoothing. \param amplitude Amplitude of the smoothing. \param dl Spatial discretization. \param da Angular discretization. \param gauss_prec Precision of the diffusion process. \param interpolation_type Interpolation scheme. Can be { 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }. \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. **/ template CImg& blur_anisotropic(const CImg& G, const float amplitude=60, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const bool is_fast_approx=1) { // Check arguments and init variables if (!is_sameXYZ(G) || (G._spectrum!=3 && G._spectrum!=6)) throw CImgArgumentException(_cimg_instance "blur_anisotropic(): Invalid specified diffusion tensor field (%u,%u,%u,%u,%p).", cimg_instance, G._width,G._height,G._depth,G._spectrum,G._data); if (is_empty() || amplitude<=0 || dl<0) return *this; const bool is_3d = (G._spectrum==6); T val_min, val_max = max_min(val_min); if (da<=0) { // Iterated oriented Laplacians CImg velocity(_width,_height,_depth,_spectrum); for (unsigned int iteration = 0; iteration<(unsigned int)amplitude; ++iteration) { Tfloat *ptrd = velocity._data, veloc_max = 0; if (is_3d) // 3d version cimg_forC(*this,c) { cimg_test_abort(); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat ixx = Incc + Ipcc - 2*Iccc, ixy = (Innc + Ippc - Inpc - Ipnc)/4, ixz = (Incn + Ipcp - Incp - Ipcn)/4, iyy = Icnc + Icpc - 2*Iccc, iyz = (Icnn + Icpp - Icnp - Icpn)/4, izz = Iccn + Iccp - 2*Iccc, veloc = (Tfloat)(G(x,y,z,0)*ixx + 2*G(x,y,z,1)*ixy + 2*G(x,y,z,2)*ixz + G(x,y,z,3)*iyy + 2*G(x,y,z,4)*iyz + G(x,y,z,5)*izz); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } } else // 2d version cimg_forZC(*this,z,c) { cimg_test_abort(); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat ixx = Inc + Ipc - 2*Icc, ixy = (Inn + Ipp - Inp - Ipn)/4, iyy = Icn + Icp - 2*Icc, veloc = (Tfloat)(G(x,y,0,0)*ixx + 2*G(x,y,0,1)*ixy + G(x,y,0,2)*iyy); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } } if (veloc_max>0) *this+=(velocity*=dl/veloc_max); } } else { // LIC-based smoothing. const ulongT whd = (ulongT)_width*_height*_depth; const float sqrt2amplitude = (float)std::sqrt(2*amplitude); const int dx1 = width() - 1, dy1 = height() - 1, dz1 = depth() - 1; CImg res(_width,_height,_depth,_spectrum,0), W(_width,_height,_depth,is_3d?4:3), val(_spectrum,1,1,1,0); int N = 0; if (is_3d) { // 3d version for (float phi = (180%(int)da)/2.0f; phi<=180; phi+=da) { const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)), da2 = datmp<1?360.0f:datmp; for (float theta = 0; theta<360; (theta+=da2),++N) { const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)*std::cos(phir)), vy = (float)(std::sin(thetar)*std::cos(phir)), vz = (float)std::sin(phir); const t *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2), *pd = G.data(0,0,0,3), *pe = G.data(0,0,0,4), *pf = G.data(0,0,0,5); Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2), *pd3 = W.data(0,0,0,3); cimg_forXYZ(G,xg,yg,zg) { const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++); const float u = (float)(a*vx + b*vy + c*vz), v = (float)(b*vx + d*vy + e*vz), w = (float)(c*vx + e*vy + f*vz), n = (float)std::sqrt(1e-5 + u*u + v*v + w*w), dln = dl/n; *(pd0++) = (Tfloat)(u*dln); *(pd1++) = (Tfloat)(v*dln); *(pd2++) = (Tfloat)(w*dln); *(pd3++) = (Tfloat)n; } cimg_test_abort(); #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val) #endif cimg_forXYZ(*this,x,y,z) { val.fill(0); const float n = (float)W(x,y,z,3), fsigma = (float)(n*sqrt2amplitude), fsigma2 = 2*fsigma*fsigma, length = gauss_prec*fsigma; float S = 0, X = (float)x, Y = (float)y, Z = (float)z; switch (interpolation_type) { case 0 : { // Nearest neighbor for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const int cx = (int)(X + 0.5f), cy = (int)(Y + 0.5f), cz = (int)(Z + 0.5f); const float u = (float)W(cx,cy,cz,0), v = (float)W(cx,cy,cz,1), w = (float)W(cx,cy,cz,2); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,cz,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,cz,c)); S+=coef; } X+=u; Y+=v; Z+=w; } } break; case 1 : { // Linear interpolation for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const float u = (float)(W._linear_atXYZ(X,Y,Z,0)), v = (float)(W._linear_atXYZ(X,Y,Z,1)), w = (float)(W._linear_atXYZ(X,Y,Z,2)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); S+=coef; } X+=u; Y+=v; Z+=w; } } break; default : { // 2nd order Runge Kutta for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const float u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)), v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)), w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2)), u = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,0)), v = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,1)), w = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,2)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); S+=coef; } X+=u; Y+=v; Z+=w; } } break; } Tfloat *ptrd = res.data(x,y,z); if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; } else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,z,c)); ptrd+=whd; } } } } } else { // 2d LIC algorithm for (float theta = (360%(int)da)/2.0f; theta<360; (theta+=da),++N) { const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar)); const t *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2); Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2); cimg_forXY(G,xg,yg) { const t a = *(pa++), b = *(pb++), c = *(pc++); const float u = (float)(a*vx + b*vy), v = (float)(b*vx + c*vy), n = (float)std::sqrt(1e-5 + u*u + v*v), dln = dl/n; *(pd0++) = (Tfloat)(u*dln); *(pd1++) = (Tfloat)(v*dln); *(pd2++) = (Tfloat)n; } cimg_test_abort(); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width>=256 && _height>=2) firstprivate(val) #endif cimg_forXY(*this,x,y) { val.fill(0); const float n = (float)W(x,y,0,2), fsigma = (float)(n*sqrt2amplitude), fsigma2 = 2*fsigma*fsigma, length = gauss_prec*fsigma; float S = 0, X = (float)x, Y = (float)y; switch (interpolation_type) { case 0 : { // Nearest-neighbor for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const int cx = (int)(X + 0.5f), cy = (int)(Y + 0.5f); const float u = (float)W(cx,cy,0,0), v = (float)W(cx,cy,0,1); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,0,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,0,c)); S+=coef; } X+=u; Y+=v; } } break; case 1 : { // Linear interpolation for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const float u = (float)(W._linear_atXY(X,Y,0,0)), v = (float)(W._linear_atXY(X,Y,0,1)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); S+=coef; } X+=u; Y+=v; } } break; default : { // 2nd-order Runge-kutta interpolation for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const float u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)), v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1)), u = (float)(W._linear_atXY(X + u0,Y + v0,0,0)), v = (float)(W._linear_atXY(X + u0,Y + v0,0,1)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); S+=coef; } X+=u; Y+=v; } } } Tfloat *ptrd = res.data(x,y); if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; } else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,0,c)); ptrd+=whd; } } } } const Tfloat *ptrs = res._data; cimg_for(*this,ptrd,T) { const Tfloat val = *(ptrs++)/N; *ptrd = valval_max?val_max:(T)val); } } return *this; } //! Blur image anisotropically, directed by a field of diffusion tensors \newinstance. template CImg get_blur_anisotropic(const CImg& G, const float amplitude=60, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const bool is_fast_approx=true) const { return CImg(*this,false).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); } //! Blur image anisotropically, in an edge-preserving way. /** \param amplitude Amplitude of the smoothing. \param sharpness Sharpness. \param anisotropy Anisotropy. \param alpha Standard deviation of the gradient blur. \param sigma Standard deviation of the structure tensor blur. \param dl Spatial discretization. \param da Angular discretization. \param gauss_prec Precision of the diffusion process. \param interpolation_type Interpolation scheme. Can be { 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }. \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. **/ CImg& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const bool is_fast_approx=true) { return blur_anisotropic(get_diffusion_tensors(sharpness,anisotropy,alpha,sigma,interpolation_type!=3), amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); } //! Blur image anisotropically, in an edge-preserving way \newinstance. CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const bool is_fast_approx=true) const { return CImg(*this,false).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec, interpolation_type,is_fast_approx); } //! Blur image, with the joint bilateral filter. /** \param guide Image used to model the smoothing weights. \param sigma_x Amount of blur along the X-axis. \param sigma_y Amount of blur along the Y-axis. \param sigma_z Amount of blur along the Z-axis. \param sigma_r Amount of blur along the value axis. \param sampling_x Amount of downsampling along the X-axis used for the approximation. Defaults (0) to sigma_x. \param sampling_y Amount of downsampling along the Y-axis used for the approximation. Defaults (0) to sigma_y. \param sampling_z Amount of downsampling along the Z-axis used for the approximation. Defaults (0) to sigma_z. \param sampling_r Amount of downsampling along the value axis used for the approximation. Defaults (0) to sigma_r. \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006 (extended for 3d volumetric images). It is based on the reference implementation http://people.csail.mit.edu/jiawen/software/bilateralFilter.m **/ template CImg& blur_bilateral(const CImg& guide, const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, const float sampling_x, const float sampling_y, const float sampling_z, const float sampling_r) { if (!is_sameXYZ(guide)) throw CImgArgumentException(_cimg_instance "blur_bilateral(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", cimg_instance, guide._width,guide._height,guide._depth,guide._spectrum,guide._data); if (is_empty()) return *this; T edge_min, edge_max = guide.max_min(edge_min); if (edge_min==edge_max || sigma_r == 0.) return *this; const float edge_delta = (float)(edge_max - edge_min), _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100, _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100, _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100, _sigma_r = sigma_r>=0?sigma_r:-sigma_r*(edge_max-edge_min)/100, _sampling_x = sampling_x?sampling_x:cimg::max(_sigma_x,1.0f), _sampling_y = sampling_y?sampling_y:cimg::max(_sigma_y,1.0f), _sampling_z = sampling_z?sampling_z:cimg::max(_sigma_z,1.0f), _sampling_r = sampling_r?sampling_r:cimg::max(_sigma_r,edge_delta/256), derived_sigma_x = _sigma_x / _sampling_x, derived_sigma_y = _sigma_y / _sampling_y, derived_sigma_z = _sigma_z / _sampling_z, derived_sigma_r = _sigma_r / _sampling_r; const int padding_x = (int)(2*derived_sigma_x) + 1, padding_y = (int)(2*derived_sigma_y) + 1, padding_z = (int)(2*derived_sigma_z) + 1, padding_r = (int)(2*derived_sigma_r) + 1; const unsigned int bx = (unsigned int)((_width - 1)/_sampling_x + 1 + 2*padding_x), by = (unsigned int)((_height - 1)/_sampling_y + 1 + 2*padding_y), bz = (unsigned int)((_depth - 1)/_sampling_z + 1 + 2*padding_z), br = (unsigned int)(edge_delta/_sampling_r + 1 + 2*padding_r); if (bx>0 || by>0 || bz>0 || br>0) { const bool is_3d = (_depth>1); if (is_3d) { // 3d version of the algorithm CImg bgrid(bx,by,bz,br), bgridw(bx,by,bz,br); cimg_forC(*this,c) { const CImg _guide = guide.get_shared_channel(c%guide._spectrum); bgrid.fill(0); bgridw.fill(0); cimg_forXYZ(*this,x,y,z) { const T val = (*this)(x,y,z,c); const float edge = (float)_guide(x,y,z); const int X = (int)cimg::round(x/_sampling_x) + padding_x, Y = (int)cimg::round(y/_sampling_y) + padding_y, Z = (int)cimg::round(z/_sampling_z) + padding_z, R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r; bgrid(X,Y,Z,R)+=(float)val; bgridw(X,Y,Z,R)+=1; } bgrid.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); bgridw.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); cimg_forXYZ(*this,x,y,z) { const float edge = (float)_guide(x,y,z); const float X = x/_sampling_x + padding_x, Y = y/_sampling_y + padding_y, Z = z/_sampling_z + padding_z, R = (edge-edge_min)/_sampling_r + padding_r; const float bval0 = bgrid.linear_atXYZC(X,Y,Z,R), bval1 = bgridw.linear_atXYZC(X,Y,Z,R); (*this)(x,y,z,c) = (T)(bval0/bval1); } } } else { // 2d version of the algorithm CImg bgrid(bx,by,br,2); cimg_forC(*this,c) { const CImg _guide = guide.get_shared_channel(c%guide._spectrum); bgrid.fill(0); cimg_forXY(*this,x,y) { const T val = (*this)(x,y,c); const float edge = (float)_guide(x,y); const int X = (int)cimg::round(x/_sampling_x) + padding_x, Y = (int)cimg::round(y/_sampling_y) + padding_y, R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r; bgrid(X,Y,R,0)+=(float)val; bgrid(X,Y,R,1)+=1; } bgrid.blur(derived_sigma_x,derived_sigma_y,0,true).blur(0,0,derived_sigma_r,false); cimg_forXY(*this,x,y) { const float edge = (float)_guide(x,y); const float X = x/_sampling_x + padding_x, Y = y/_sampling_y + padding_y, R = (edge-edge_min)/_sampling_r + padding_r; const float bval0 = bgrid.linear_atXYZ(X,Y,R,0), bval1 = bgrid.linear_atXYZ(X,Y,R,1); (*this)(x,y,c) = (T)(bval0/bval1); } } } } return *this; } //! Blur image, with the joint bilateral filter \newinstance. template CImg get_blur_bilateral(const CImg& guide, const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, const float sampling_x, const float sampling_y, const float sampling_z, const float sampling_r) const { return CImg(*this,false).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r, sampling_x,sampling_y,sampling_z,sampling_r); } //! Blur image using the joint bilateral filter. /** \param guide Image used to model the smoothing weights. \param sigma_s Amount of blur along the XYZ-axes. \param sigma_r Amount of blur along the value axis. \param sampling_s Amount of downsampling along the XYZ-axes used for the approximation. Defaults to sigma_s. \param sampling_r Amount of downsampling along the value axis used for the approximation. Defaults to sigma_r. **/ template CImg& blur_bilateral(const CImg& guide, const float sigma_s, const float sigma_r, const float sampling_s=0, const float sampling_r=0) { const float _sigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100; return blur_bilateral(guide,_sigma_s,_sigma_s,_sigma_s,sigma_r,sampling_s,sampling_s,sampling_s,sampling_r); } //! Blur image using the bilateral filter \newinstance. template CImg get_blur_bilateral(const CImg& guide, const float sigma_s, const float sigma_r, const float sampling_s=0, const float sampling_r=0) const { return CImg(*this,false).blur_bilateral(guide,sigma_s,sigma_r,sampling_s,sampling_r); } // [internal] Apply a box filter (used by CImg::boxfilter() and CImg::blur_box()). /* \param ptr the pointer of the data \param N size of the data \param sigma sigma of the box filter \param off the offset between two data point \param order the order of the filter 0 (smoothing), 1st derivtive and 2nd derivative. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. */ static void _cimg_blur_box_apply(T *ptr, const float sigma, const int N, const ulongT off, const int order, const bool boundary_conditions) { // Smooth. if (sigma>1) { const int w2 = (int)(sigma - 1)/2; const unsigned int winsize = 2*w2 + 1U; const double frac = (sigma - winsize)/2.0; CImg win(winsize); Tfloat sum = 0; // window sum for (int x = -w2; x<=w2; ++x) { win[x + w2] = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x); sum+=win[x + w2]; } int ifirst = 0, ilast = 2*w2; Tfloat prev = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-w2 - 1), next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,w2 + 1); for (int x = 0; x < N - 1; ++x) { const double sum2 = sum + frac * (prev + next); ptr[x*off] = (T)(sum2/sigma); prev = win[ifirst]; sum-=prev; ifirst = (int)((ifirst + 1)%winsize); ilast = (int)((ilast + 1)%winsize); win[ilast] = next; sum+=next; next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + w2 + 2); } const double sum2 = sum + frac * (prev + next); ptr[(N - 1)*off] = (T)(sum2/sigma); } // Derive. switch (order) { case 0 : break; case 1 : { Tfloat p = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-1), c = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,0), n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,1); for (int x = 0; x=N) return boundary_conditions?ptr[(N - 1)*off]:T(); return ptr[x*off]; } // Apply box filter of order 0,1,2. /** \param sigma sigma of the box filter \param order the order of the filter 0,1 or 2. \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. **/ CImg& boxfilter(const float sigma, const int order, const char axis='x', const bool boundary_conditions=true) { if (is_empty() || !sigma || (sigma<=1 && !order)) return *this; const char naxis = cimg::uncase(axis); const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; switch (naxis) { case 'x' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forYZC(*this,y,z,c) _cimg_blur_box_apply(data(0,y,z,c),nsigma,_width,1U,order,boundary_conditions); } break; case 'y' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXZC(*this,x,z,c) _cimg_blur_box_apply(data(x,0,z,c),nsigma,_height,(ulongT)_width,order,boundary_conditions); } break; case 'z' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYC(*this,x,y,c) _cimg_blur_box_apply(data(x,y,0,c),nsigma,_depth,(ulongT)_width*_height,order,boundary_conditions); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYZ(*this,x,y,z) _cimg_blur_box_apply(data(x,y,z,0),nsigma,_spectrum,(ulongT)_width*_height*_depth, order,boundary_conditions); } } return *this; } // Apply box filter of order 0,1 or 2 \newinstance. CImg get_boxfilter(const float sigma, const int order, const char axis='x', const bool boundary_conditions=true) const { return CImg(*this,false).boxfilter(sigma,order,axis,boundary_conditions); } //! Blur image with a box filter. /** \param sigma_x Size of the box window, along the X-axis. \param sigma_y Size of the box window, along the Y-axis. \param sigma_z Size of the box window, along the Z-axis. \param boundary_conditions Boundary conditions. Can be { false=dirichlet | true=neumann }. \note - This is a recursive algorithm, not depending on the values of the box kernel size. \see blur(). **/ CImg& blur_box(const float sigma_x, const float sigma_y, const float sigma_z, const bool boundary_conditions=true) { if (is_empty()) return *this; if (_width>1) boxfilter(sigma_x,0,'x',boundary_conditions); if (_height>1) boxfilter(sigma_y,0,'y',boundary_conditions); if (_depth>1) boxfilter(sigma_z,0,'z',boundary_conditions); return *this; } //! Blur image with a box filter \newinstance. CImg get_blur_box(const float sigma_x, const float sigma_y, const float sigma_z, const bool boundary_conditions=true) const { return CImg(*this,false).blur_box(sigma_x,sigma_y,sigma_z,boundary_conditions); } //! Blur image with a box filter. /** \param sigma Size of the box window. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }.a \see deriche(), vanvliet(). **/ CImg& blur_box(const float sigma, const bool boundary_conditions=true) { const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; return blur_box(nsigma,nsigma,nsigma,boundary_conditions); } //! Blur image with a box filter \newinstance. CImg get_blur_box(const float sigma, const bool boundary_conditions=true) const { return CImg(*this,false).blur_box(sigma,boundary_conditions); } //! Blur image, with the image guided filter. /** \param guide Image used to guide the smoothing process. \param radius Spatial radius. \param regularization Regularization parameter. \note This method implements the filtering algorithm described in: He, Kaiming; Sun, Jian; Tang, Xiaoou, "Guided Image Filtering," Pattern Analysis and Machine Intelligence, IEEE Transactions on , vol.35, no.6, pp.1397,1409, June 2013 **/ template CImg& blur_guided(const CImg& guide, const float radius, const float regularization) { return get_blur_guided(guide,radius,regularization).move_to(*this); } //! Blur image, with the image guided filter \newinstance. template CImg get_blur_guided(const CImg& guide, const float radius, const float regularization) const { if (!is_sameXYZ(guide)) throw CImgArgumentException(_cimg_instance "blur_guided(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", cimg_instance, guide._width,guide._height,guide._depth,guide._spectrum,guide._data); if (is_empty() || !radius) return *this; const int _radius = radius>=0?(int)radius:(int)(-radius*cimg::max(_width,_height,_depth)/100); const unsigned int psize = (unsigned int)(1 + 2*_radius); const CImg N = CImg(_width,_height,_depth,1,1)._blur_guided(psize); CImg mean_I = CImg(guide,false)._blur_guided(psize).div(N), mean_p = CImg(*this,false)._blur_guided(psize).div(N), cov_Ip = CImg(*this,false).mul(guide)._blur_guided(psize).div(N)-=mean_p.get_mul(mean_I), var_I = CImg(guide,false).sqr()._blur_guided(psize).div(N)-=mean_I.get_sqr(), &a = cov_Ip.div(var_I+=regularization), &b = mean_p-=a.get_mul(mean_I); a._blur_guided(psize).div(N); b._blur_guided(psize).div(N); return a.mul(guide)+=b; } // [internal] Perform box filter with dirichlet boundary conditions. CImg& _blur_guided(const unsigned int psize) { const int p1 = (int)psize/2, p2 = (int)psize - p1; if (_depth!=1) { CImg cumul = get_cumulate('z'), cumul2 = cumul.get_shift(0,0,p2,0,1); (cumul.shift(0,0,-p1,0,1)-=cumul2).move_to(*this); } if (_height!=1) { CImg cumul = get_cumulate('y'), cumul2 = cumul.get_shift(0,p2,0,0,1); (cumul.shift(0,-p1,0,0,1)-=cumul2).move_to(*this); } if (_width!=1) { CImg cumul = get_cumulate('x'), cumul2 = cumul.get_shift(p2,0,0,0,1); (cumul.shift(-p1,0,0,0,1)-=cumul2).move_to(*this); } return *this; } //! Blur image using patch-based space. /** \param sigma_s Amount of blur along the XYZ-axes. \param sigma_p Amount of blur along the value axis. \param patch_size Size of the patchs. \param lookup_size Size of the window to search similar patchs. \param smoothness Smoothness for the patch comparison. \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. **/ CImg& blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) { if (is_empty() || !patch_size || !lookup_size) return *this; return get_blur_patch(sigma_s,sigma_p,patch_size,lookup_size,smoothness,is_fast_approx).move_to(*this); } //! Blur image using patch-based space \newinstance. CImg get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) const { #define _cimg_blur_patch3d_fast(N) \ cimg_for##N##XYZ(res,x,y,z) { \ T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \ const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \ x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ float sum_weights = 0; \ cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0) - img(p,q,r,0))3?0.0f:1.0f; \ sum_weights+=weight; \ cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \ } \ if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \ else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ } #define _cimg_blur_patch3d(N) \ cimg_for##N##XYZ(res,x,y,z) { \ T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \ const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \ x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ float sum_weights = 0, weight_max = 0; \ cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { \ T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \ float distance2 = 0; \ pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \ distance2/=Pnorm; \ const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \ alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)std::exp(-alldist); \ if (weight>weight_max) weight_max = weight; \ sum_weights+=weight; \ cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \ } \ sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); \ if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \ else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ } #define _cimg_blur_patch2d_fast(N) \ cimg_for##N##XY(res,x,y) { \ T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \ const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ float sum_weights = 0; \ cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0,0) - img(p,q,0,0))3?0.0f:1.0f; \ sum_weights+=weight; \ cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \ } \ if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \ else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ } #define _cimg_blur_patch2d(N) \ cimg_for##N##XY(res,x,y) { \ T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \ const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ float sum_weights = 0, weight_max = 0; \ cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { \ T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \ float distance2 = 0; \ pQ = Q._data; cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(pQ++); distance2+=dI*dI; } \ distance2/=Pnorm; \ const float dx = (float)p - x, dy = (float)q - y, \ alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)std::exp(-alldist); \ if (weight>weight_max) weight_max = weight; \ sum_weights+=weight; \ cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \ } \ sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); \ if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \ else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ } if (is_empty() || !patch_size || !lookup_size) return +*this; CImg res(_width,_height,_depth,_spectrum,0); const CImg _img = smoothness>0?get_blur(smoothness):CImg(),&img = smoothness>0?_img:*this; CImg P(patch_size*patch_size*_spectrum), Q(P); const float nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100, sigma_s2 = nsigma_s*nsigma_s, sigma_p2 = sigma_p*sigma_p, sigma_p3 = 3*sigma_p, Pnorm = P.size()*sigma_p2; const int rsize2 = (int)lookup_size/2, rsize1 = (int)lookup_size - rsize2 - 1; const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size; cimg::unused(N2,N3); if (_depth>1) switch (patch_size) { // 3d case 2 : if (is_fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break; case 3 : if (is_fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break; default : { const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; if (is_fast_approx) #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (res._width>=32 && res._height*res._depth>=4) private(P,Q) #endif cimg_forXYZ(res,x,y,z) { // Fast P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; float sum_weights = 0; cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0)-img(p,q,r,0))3?0.0f:1.0f; sum_weights+=weight; cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); } if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (res._width>=32 && res._height*res._depth>=4) firstprivate(P,Q) #endif cimg_forXYZ(res,x,y,z) { // Exact P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; float sum_weights = 0, weight_max = 0; cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P; const float dx = (float)x - p, dy = (float)y - q, dz = (float)z - r, distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2), weight = (float)std::exp(-distance2); if (weight>weight_max) weight_max = weight; sum_weights+=weight; cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); } sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); } } } else switch (patch_size) { // 2d case 2 : if (is_fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break; case 3 : if (is_fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break; case 4 : if (is_fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break; case 5 : if (is_fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break; case 6 : if (is_fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break; case 7 : if (is_fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break; case 8 : if (is_fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break; case 9 : if (is_fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break; default : { // Fast const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; if (is_fast_approx) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q) #endif cimg_forXY(res,x,y) { // 2d fast approximation. P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; float sum_weights = 0; cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0)-img(p,q,0))3?0.0f:1.0f; sum_weights+=weight; cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); } if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); } else #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q) #endif cimg_forXY(res,x,y) { // 2d exact algorithm. P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; float sum_weights = 0, weight_max = 0; cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P; const float dx = (float)x - p, dy = (float)y - q, distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2), weight = (float)std::exp(-distance2); if (weight>weight_max) weight_max = weight; sum_weights+=weight; cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); } sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; else cimg_forC(res,c) res(x,y,0,c) = (Tfloat)((*this)(x,y,c)); } } } return res; } //! Blur image with the median filter. /** \param n Size of the median filter. \param threshold Threshold used to discard pixels too far from the current pixel value in the median computation. **/ CImg& blur_median(const unsigned int n, const float threshold=0) { if (!n) return *this; return get_blur_median(n,threshold).move_to(*this); } //! Blur image with the median filter \newinstance. CImg get_blur_median(const unsigned int n, const float threshold=0) const { if (is_empty() || n<=1) return +*this; CImg res(_width,_height,_depth,_spectrum); T *ptrd = res._data; cimg::unused(ptrd); const int hl = (int)n/2, hr = hl - 1 + (int)n%2; if (res._depth!=1) { // 3d if (threshold>0) #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=16 && _height*_depth*_spectrum>=4) #endif cimg_forXYZC(*this,x,y,z,c) { // With threshold. const int x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; const float val0 = (float)(*this)(x,y,z,c); CImg values(n*n*n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r) if (cimg::abs((float)(*this)(p,q,r,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,r,c); ++nb_values; } res(x,y,z,c) = values.get_shared_points(0,nb_values - 1).median(); } else #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=16 && _height*_depth*_spectrum>=4) #endif cimg_forXYZC(*this,x,y,z,c) { // Without threshold. const int x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median(); } } else { #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b) if (res._height!=1) { // 2d if (threshold>0) #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=16 && _height*_spectrum>=4) #endif cimg_forXYC(*this,x,y,c) { // With threshold. const int x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; const float val0 = (float)(*this)(x,y,c); CImg values(n*n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q) if (cimg::abs((float)(*this)(p,q,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,c); ++nb_values; } res(x,y,c) = values.get_shared_points(0,nb_values - 1).median(); } else switch (n) { // Without threshold. case 3 : { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { T I[9] = { 0 }; CImg_3x3(J,T); cimg_for3x3(*this,x,y,0,c,I,T) { std::memcpy(J,I,9*sizeof(T)); _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn); _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc); _cimg_median_sort(Jcc, Jnp); res(x,y,c) = Jcc; } } } break; case 5 : { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { T I[25] = { 0 }; CImg_5x5(J,T); cimg_for5x5(*this,x,y,0,c,I,T) { std::memcpy(J,I,25*sizeof(T)); _cimg_median_sort(Jbb,Jpb); _cimg_median_sort(Jnb,Jab); _cimg_median_sort(Jcb,Jab); _cimg_median_sort(Jcb,Jnb); _cimg_median_sort(Jpp,Jcp); _cimg_median_sort(Jbp,Jcp); _cimg_median_sort(Jbp,Jpp); _cimg_median_sort(Jap,Jbc); _cimg_median_sort(Jnp,Jbc); _cimg_median_sort(Jnp,Jap); _cimg_median_sort(Jcc,Jnc); _cimg_median_sort(Jpc,Jnc); _cimg_median_sort(Jpc,Jcc); _cimg_median_sort(Jbn,Jpn); _cimg_median_sort(Jac,Jpn); _cimg_median_sort(Jac,Jbn); _cimg_median_sort(Jnn,Jan); _cimg_median_sort(Jcn,Jan); _cimg_median_sort(Jcn,Jnn); _cimg_median_sort(Jpa,Jca); _cimg_median_sort(Jba,Jca); _cimg_median_sort(Jba,Jpa); _cimg_median_sort(Jna,Jaa); _cimg_median_sort(Jcb,Jbp); _cimg_median_sort(Jnb,Jpp); _cimg_median_sort(Jbb,Jpp); _cimg_median_sort(Jbb,Jnb); _cimg_median_sort(Jab,Jcp); _cimg_median_sort(Jpb,Jcp); _cimg_median_sort(Jpb,Jab); _cimg_median_sort(Jpc,Jac); _cimg_median_sort(Jnp,Jac); _cimg_median_sort(Jnp,Jpc); _cimg_median_sort(Jcc,Jbn); _cimg_median_sort(Jap,Jbn); _cimg_median_sort(Jap,Jcc); _cimg_median_sort(Jnc,Jpn); _cimg_median_sort(Jbc,Jpn); _cimg_median_sort(Jbc,Jnc); _cimg_median_sort(Jba,Jna); _cimg_median_sort(Jcn,Jna); _cimg_median_sort(Jcn,Jba); _cimg_median_sort(Jpa,Jaa); _cimg_median_sort(Jnn,Jaa); _cimg_median_sort(Jnn,Jpa); _cimg_median_sort(Jan,Jca); _cimg_median_sort(Jnp,Jcn); _cimg_median_sort(Jap,Jnn); _cimg_median_sort(Jbb,Jnn); _cimg_median_sort(Jbb,Jap); _cimg_median_sort(Jbc,Jan); _cimg_median_sort(Jpb,Jan); _cimg_median_sort(Jpb,Jbc); _cimg_median_sort(Jpc,Jba); _cimg_median_sort(Jcb,Jba); _cimg_median_sort(Jcb,Jpc); _cimg_median_sort(Jcc,Jpa); _cimg_median_sort(Jnb,Jpa); _cimg_median_sort(Jnb,Jcc); _cimg_median_sort(Jnc,Jca); _cimg_median_sort(Jab,Jca); _cimg_median_sort(Jab,Jnc); _cimg_median_sort(Jac,Jna); _cimg_median_sort(Jbp,Jna); _cimg_median_sort(Jbp,Jac); _cimg_median_sort(Jbn,Jaa); _cimg_median_sort(Jpp,Jaa); _cimg_median_sort(Jpp,Jbn); _cimg_median_sort(Jcp,Jpn); _cimg_median_sort(Jcp,Jan); _cimg_median_sort(Jnc,Jpa); _cimg_median_sort(Jbn,Jna); _cimg_median_sort(Jcp,Jnc); _cimg_median_sort(Jcp,Jbn); _cimg_median_sort(Jpb,Jap); _cimg_median_sort(Jnb,Jpc); _cimg_median_sort(Jbp,Jcn); _cimg_median_sort(Jpc,Jcn); _cimg_median_sort(Jap,Jcn); _cimg_median_sort(Jab,Jbc); _cimg_median_sort(Jpp,Jcc); _cimg_median_sort(Jcp,Jac); _cimg_median_sort(Jab,Jpp); _cimg_median_sort(Jab,Jcp); _cimg_median_sort(Jcc,Jac); _cimg_median_sort(Jbc,Jac); _cimg_median_sort(Jpp,Jcp); _cimg_median_sort(Jbc,Jcc); _cimg_median_sort(Jpp,Jbc); _cimg_median_sort(Jpp,Jcn); _cimg_median_sort(Jcc,Jcn); _cimg_median_sort(Jcp,Jcn); _cimg_median_sort(Jcp,Jbc); _cimg_median_sort(Jcc,Jnn); _cimg_median_sort(Jcp,Jcc); _cimg_median_sort(Jbc,Jnn); _cimg_median_sort(Jcc,Jba); _cimg_median_sort(Jbc,Jba); _cimg_median_sort(Jbc,Jcc); res(x,y,c) = Jcc; } } } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=16 && _height*_spectrum>=4) #endif cimg_forXYC(*this,x,y,c) { const int x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median(); } } } } else { // 1d CImg I; if (threshold>0) #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2) #endif cimg_forXC(*this,x,c) { // With threshold. const int x0 = x - hl, x1 = x + hr, nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1; const float val0 = (float)(*this)(x,c); CImg values(n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inX(*this,nx0,nx1,p) if (cimg::abs((float)(*this)(p,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,c); ++nb_values; } res(x,c) = values.get_shared_points(0,nb_values - 1).median(); } else switch (n) { // Without threshold. case 2 : { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { I.assign(4); cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1])); } } break; case 3 : { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { I.assign(9); cimg_for3x3(*this,x,y,0,c,I,T) res(x,c) = I[3]=16 && _spectrum>=2) #endif cimg_forXC(*this,x,c) { const int x0 = x - hl, x1 = x + hr, nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1; res(x,c) = get_crop(nx0,0,0,c,nx1,0,0,c).median(); } } } } } return res; } //! Sharpen image. /** \param amplitude Sharpening amplitude \param sharpen_type Select sharpening method. Can be { false=inverse diffusion | true=shock filters }. \param edge Edge threshold (shock filters only). \param alpha Gradient smoothness (shock filters only). \param sigma Tensor smoothness (shock filters only). **/ CImg& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) { if (is_empty()) return *this; T val_min, val_max = max_min(val_min); const float nedge = edge/2; CImg velocity(_width,_height,_depth,_spectrum), _veloc_max(_spectrum); if (_depth>1) { // 3d if (sharpen_type) { // Shock filters. CImg G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); if (sigma>0) G.blur(sigma); #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=32 && _height*_depth>=16) #endif cimg_forYZ(G,y,z) { Tfloat *ptrG0 = G.data(0,y,z,0), *ptrG1 = G.data(0,y,z,1), *ptrG2 = G.data(0,y,z,2), *ptrG3 = G.data(0,y,z,3); CImg val, vec; cimg_forX(G,x) { G.get_tensor_at(x,y,z).symmetric_eigen(val,vec); if (val[0]<0) val[0] = 0; if (val[1]<0) val[1] = 0; if (val[2]<0) val[2] = 0; *(ptrG0++) = vec(0,0); *(ptrG1++) = vec(0,1); *(ptrG2++) = vec(0,2); *(ptrG3++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1] + val[2],-(Tfloat)nedge); } } #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=512 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat u = G(x,y,z,0), v = G(x,y,z,1), w = G(x,y,z,2), amp = G(x,y,z,3), ixx = Incc + Ipcc - 2*Iccc, ixy = (Innc + Ippc - Inpc - Ipnc)/4, ixz = (Incn + Ipcp - Incp - Ipcn)/4, iyy = Icnc + Icpc - 2*Iccc, iyz = (Icnn + Icpp - Icnp - Icpn)/4, izz = Iccn + Iccp - 2*Iccc, ixf = Incc - Iccc, ixb = Iccc - Ipcc, iyf = Icnc - Iccc, iyb = Iccc - Icpc, izf = Iccn - Iccc, izb = Iccc - Iccp, itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz, it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb), veloc = -amp*cimg::sign(itt)*cimg::abs(it); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } _veloc_max[c] = veloc_max; } } else // Inverse diffusion. cimg_forC(*this,c) { Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat veloc = -Ipcc - Incc - Icpc - Icnc - Iccp - Iccn + 6*Iccc; *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } _veloc_max[c] = veloc_max; } } else { // 2d. if (sharpen_type) { // Shock filters. CImg G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); if (sigma>0) G.blur(sigma); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width>=32 && _height>=16) #endif cimg_forY(G,y) { CImg val, vec; Tfloat *ptrG0 = G.data(0,y,0,0), *ptrG1 = G.data(0,y,0,1), *ptrG2 = G.data(0,y,0,2); cimg_forX(G,x) { G.get_tensor_at(x,y).symmetric_eigen(val,vec); if (val[0]<0) val[0] = 0; if (val[1]<0) val[1] = 0; *(ptrG0++) = vec(0,0); *(ptrG1++) = vec(0,1); *(ptrG2++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1],-(Tfloat)nedge); } } #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height>=512 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) { const Tfloat u = G(x,y,0), v = G(x,y,1), amp = G(x,y,2), ixx = Inc + Ipc - 2*Icc, ixy = (Inn + Ipp - Inp - Ipn)/4, iyy = Icn + Icp - 2*Icc, ixf = Inc - Icc, ixb = Icc - Ipc, iyf = Icn - Icc, iyb = Icc - Icp, itt = u*u*ixx + v*v*iyy + 2*u*v*ixy, it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb), veloc = -amp*cimg::sign(itt)*cimg::abs(it); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } _veloc_max[c] = veloc_max; } } else // Inverse diffusion. cimg_forC(*this,c) { Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) { const Tfloat veloc = -Ipc - Inc - Icp - Icn + 4*Icc; *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } _veloc_max[c] = veloc_max; } } const Tfloat veloc_max = _veloc_max.max(); if (veloc_max<=0) return *this; return ((velocity*=amplitude/veloc_max)+=*this).cut(val_min,val_max).move_to(*this); } //! Sharpen image \newinstance. CImg get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) const { return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma); } //! Return image gradient. /** \param axes Axes considered for the gradient computation, as a C-string (e.g "xy"). \param scheme = Numerical scheme used for the gradient computation: - -1 = Backward finite differences - 0 = Centered finite differences - 1 = Forward finite differences - 2 = Using Sobel masks - 3 = Using rotation invariant masks - 4 = Using Deriche recusrsive filter. - 5 = Using Van Vliet recusrsive filter. **/ CImgList get_gradient(const char *const axes=0, const int scheme=3) const { CImgList grad(2,_width,_height,_depth,_spectrum); bool is_3d = false; if (axes) { for (unsigned int a = 0; axes[a]; ++a) { const char axis = cimg::uncase(axes[a]); switch (axis) { case 'x' : case 'y' : break; case 'z' : is_3d = true; break; default : throw CImgArgumentException(_cimg_instance "get_gradient(): Invalid specified axis '%c'.", cimg_instance, axis); } } } else is_3d = (_depth>1); if (is_3d) { CImg(_width,_height,_depth,_spectrum).move_to(grad); switch (scheme) { // 3d. case -1 : { // Backward finite differences. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { const ulongT off = (ulongT)c*_width*_height*_depth; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off; CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Iccc - Ipcc; *(ptrd1++) = Iccc - Icpc; *(ptrd2++) = Iccc - Iccp; } } } break; case 1 : { // Forward finite differences. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { const ulongT off = (ulongT)c*_width*_height*_depth; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off; CImg_2x2x2(I,Tfloat); cimg_for2x2x2(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Incc - Iccc; *(ptrd1++) = Icnc - Iccc; *(ptrd2++) = Iccn - Iccc; } } } break; case 4 : { // Deriche filter with low standard variation. grad[0] = get_deriche(0,1,'x'); grad[1] = get_deriche(0,1,'y'); grad[2] = get_deriche(0,1,'z'); } break; case 5 : { // Van Vliet filter with low standard variation. grad[0] = get_vanvliet(0,1,'x'); grad[1] = get_vanvliet(0,1,'y'); grad[2] = get_vanvliet(0,1,'z'); } break; default : { // Central finite differences. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { const ulongT off = (ulongT)c*_width*_height*_depth; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off, *ptrd2 = grad[2]._data + off; CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = (Incc - Ipcc)/2; *(ptrd1++) = (Icnc - Icpc)/2; *(ptrd2++) = (Iccn - Iccp)/2; } } } } } else switch (scheme) { // 2d. case -1 : { // Backward finite differences. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Icc - Ipc; *(ptrd1++) = Icc - Icp; } } } break; case 1 : { // Forward finite differences. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_2x2(I,Tfloat); cimg_for2x2(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Inc - Icc; *(ptrd1++) = Icn - Icc; } } } break; case 2 : { // Sobel scheme. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = -Ipp - 2*Ipc - Ipn + Inp + 2*Inc + Inn; *(ptrd1++) = -Ipp - 2*Icp - Inp + Ipn + 2*Icn + Inn; } } } break; case 3 : { // Rotation invariant mask. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_3x3(I,Tfloat); const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f) - 1)); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn; *(ptrd1++) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn; } } } break; case 4 : { // Van Vliet filter with low standard variation grad[0] = get_deriche(0,1,'x'); grad[1] = get_deriche(0,1,'y'); } break; case 5 : { // Deriche filter with low standard variation grad[0] = get_vanvliet(0,1,'x'); grad[1] = get_vanvliet(0,1,'y'); } break; default : { // Central finite differences #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = (Inc - Ipc)/2; *(ptrd1++) = (Icn - Icp)/2; } } } } if (!axes) return grad; CImgList res; for (unsigned int l = 0; axes[l]; ++l) { const char axis = cimg::uncase(axes[l]); switch (axis) { case 'x' : res.insert(grad[0]); break; case 'y' : res.insert(grad[1]); break; case 'z' : res.insert(grad[2]); break; } } grad.assign(); return res; } //! Return image hessian. /** \param axes Axes considered for the hessian computation, as a C-string (e.g "xy"). **/ CImgList get_hessian(const char *const axes=0) const { CImgList res; const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz"; if (!axes) naxes = _depth>1?def_axes3d:def_axes2d; const unsigned int lmax = (unsigned int)std::strlen(naxes); if (lmax%2) throw CImgArgumentException(_cimg_instance "get_hessian(): Invalid specified axes '%s'.", cimg_instance, naxes); res.assign(lmax/2,_width,_height,_depth,_spectrum); if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { const ulongT off = (ulongT)c*_width*_height*_depth; Tfloat *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off, *ptrd3 = res[3]._data + off, *ptrd4 = res[4]._data + off, *ptrd5 = res[5]._data + off; CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Ipcc + Incc - 2*Iccc; // Ixx *(ptrd1++) = (Ippc + Innc - Ipnc - Inpc)/4; // Ixy *(ptrd2++) = (Ipcp + Incn - Ipcn - Incp)/4; // Ixz *(ptrd3++) = Icpc + Icnc - 2*Iccc; // Iyy *(ptrd4++) = (Icpp + Icnn - Icpn - Icnp)/4; // Iyz *(ptrd5++) = Iccn + Iccp - 2*Iccc; // Izz } } } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // 2d #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off; CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = Ipc + Inc - 2*Icc; // Ixx *(ptrd1++) = (Ipp + Inn - Ipn - Inp)/4; // Ixy *(ptrd2++) = Icp + Icn - 2*Icc; // Iyy } } } else for (unsigned int l = 0; laxis2) cimg::swap(axis1,axis2); bool valid_axis = false; if (axis1=='x' && axis2=='x') { // Ixx valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { Tfloat *ptrd = res[l2].data(0,0,z,c); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Ipc + Inc - 2*Icc; } } else if (axis1=='x' && axis2=='y') { // Ixy valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { Tfloat *ptrd = res[l2].data(0,0,z,c); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipp + Inn - Ipn - Inp)/4; } } else if (axis1=='x' && axis2=='z') { // Ixz valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res[l2].data(0,0,0,c); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipcp + Incn - Ipcn - Incp)/4; } } else if (axis1=='y' && axis2=='y') { // Iyy valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forZC(*this,z,c) { Tfloat *ptrd = res[l2].data(0,0,z,c); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Icp + Icn - 2*Icc; } } else if (axis1=='y' && axis2=='z') { // Iyz valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res[l2].data(0,0,0,c); CImg_3x3x3(I,Tfloat); cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Icpp + Icnn - Icpn - Icnp)/4; } } else if (axis1=='z' && axis2=='z') { // Izz valid_axis = true; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res[l2].data(0,0,0,c); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Iccn + Iccp - 2*Iccc; } } else if (!valid_axis) throw CImgArgumentException(_cimg_instance "get_hessian(): Invalid specified axes '%s'.", cimg_instance, naxes); } return res; } //! Compute image laplacian. CImg& laplacian() { return get_laplacian().move_to(*this); } //! Compute image laplacian \newinstance. CImg get_laplacian() const { if (is_empty()) return CImg(); CImg res(_width,_height,_depth,_spectrum); if (_depth>1) { // 3d #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res.data(0,0,0,c); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Incc + Ipcc + Icnc + Icpc + Iccn + Iccp - 6*Iccc; } } else if (_height>1) { // 2d #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res.data(0,0,0,c); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc + Icn + Icp - 4*Icc; } } else { // 1d #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width>=1048576 && _height*_depth*_spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd = res.data(0,0,0,c); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc - 2*Icc; } } return res; } //! Compute the structure tensor field of an image. /** \param is_fwbw_scheme scheme. Can be { false=centered | true=forward-backward } **/ CImg& structure_tensors(const bool is_fwbw_scheme=false) { return get_structure_tensors(is_fwbw_scheme).move_to(*this); } //! Compute the structure tensor field of an image \newinstance. CImg get_structure_tensors(const bool is_fwbw_scheme=false) const { if (is_empty()) return *this; CImg res; if (_depth>1) { // 3d res.assign(_width,_height,_depth,6,0); if (!is_fwbw_scheme) { // Classical central finite differences #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat ix = (Incc - Ipcc)/2, iy = (Icnc - Icpc)/2, iz = (Iccn - Iccp)/2; *(ptrd0++)+=ix*ix; *(ptrd1++)+=ix*iy; *(ptrd2++)+=ix*iz; *(ptrd3++)+=iy*iy; *(ptrd4++)+=iy*iz; *(ptrd5++)+=iz*iz; } } } else { // Forward/backward finite differences. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); CImg_3x3x3(I,Tfloat); cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { const Tfloat ixf = Incc - Iccc, ixb = Iccc - Ipcc, iyf = Icnc - Iccc, iyb = Iccc - Icpc, izf = Iccn - Iccc, izb = Iccc - Iccp; *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4; *(ptrd3++)+=(iyf*iyf + iyb*iyb)/2; *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4; *(ptrd5++)+=(izf*izf + izb*izb)/2; } } } } else { // 2d res.assign(_width,_height,_depth,3,0); if (!is_fwbw_scheme) { // Classical central finite differences #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) { const Tfloat ix = (Inc - Ipc)/2, iy = (Icn - Icp)/2; *(ptrd0++)+=ix*ix; *(ptrd1++)+=ix*iy; *(ptrd2++)+=iy*iy; } } } else { // Forward/backward finite differences (version 2). #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) #endif cimg_forC(*this,c) { Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); CImg_3x3(I,Tfloat); cimg_for3x3(*this,x,y,0,c,I,Tfloat) { const Tfloat ixf = Inc - Icc, ixb = Icc - Ipc, iyf = Icn - Icc, iyb = Icc - Icp; *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2; } } } } return res; } //! Compute field of diffusion tensors for edge-preserving smoothing. /** \param sharpness Sharpness \param anisotropy Anisotropy \param alpha Standard deviation of the gradient blur. \param sigma Standard deviation of the structure tensor blur. \param is_sqrt Tells if the square root of the tensor field is computed instead. **/ CImg& diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) { CImg res; const float nsharpness = cimg::max(sharpness,1e-5f), power1 = (is_sqrt?0.5f:1)*nsharpness, power2 = power1/(1e-7f + 1 - anisotropy); blur(alpha).normalize(0,(T)255); if (_depth>1) { // 3d get_structure_tensors().move_to(res).blur(sigma); #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if(_width>=256 && _height*_depth>=256) #endif cimg_forYZ(*this,y,z) { Tfloat *ptrd0 = res.data(0,y,z,0), *ptrd1 = res.data(0,y,z,1), *ptrd2 = res.data(0,y,z,2), *ptrd3 = res.data(0,y,z,3), *ptrd4 = res.data(0,y,z,4), *ptrd5 = res.data(0,y,z,5); CImg val(3), vec(3,3); cimg_forX(*this,x) { res.get_tensor_at(x,y,z).symmetric_eigen(val,vec); const float _l1 = val[2], _l2 = val[1], _l3 = val[0], l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0, ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), n1 = (float)std::pow(1 + l1 + l2 + l3,-power1), n2 = (float)std::pow(1 + l1 + l2 + l3,-power2); *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx; *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy; *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz; *(ptrd3++) = n1*(uy*uy + vy*vy) + n2*wy*wy; *(ptrd4++) = n1*(uy*uz + vy*vz) + n2*wy*wz; *(ptrd5++) = n1*(uz*uz + vz*vz) + n2*wz*wz; } } } else { // for 2d images get_structure_tensors().move_to(res).blur(sigma); #ifdef cimg_use_openmp #pragma omp parallel for if(_width>=256 && _height>=256) #endif cimg_forY(*this,y) { Tfloat *ptrd0 = res.data(0,y,0,0), *ptrd1 = res.data(0,y,0,1), *ptrd2 = res.data(0,y,0,2); CImg val(2), vec(2,2); cimg_forX(*this,x) { res.get_tensor_at(x,y).symmetric_eigen(val,vec); const float _l1 = val[1], _l2 = val[0], l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, ux = vec(1,0), uy = vec(1,1), vx = vec(0,0), vy = vec(0,1), n1 = (float)std::pow(1 + l1 + l2,-power1), n2 = (float)std::pow(1 + l1 + l2,-power2); *(ptrd0++) = n1*ux*ux + n2*vx*vx; *(ptrd1++) = n1*ux*uy + n2*vx*vy; *(ptrd2++) = n1*uy*uy + n2*vy*vy; } } } return res.move_to(*this); } //! Compute field of diffusion tensors for edge-preserving smoothing \newinstance. CImg get_diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const { return CImg(*this,false).diffusion_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt); } //! Estimate displacement field between two images. /** \param source Reference image. \param smoothness Smoothness of estimated displacement field. \param precision Precision required for algorithm convergence. \param nb_scales Number of scales used to estimate the displacement field. \param iteration_max Maximum number of iterations allowed for one scale. \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)). \param guide Image used as the initial correspondence estimate for the algorithm. 'guide' may have a last channel with boolean values (0=false | other=true) that tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). **/ CImg& displacement(const CImg& source, const float smoothness=0.1f, const float precision=5.0f, const unsigned int nb_scales=0, const unsigned int iteration_max=10000, const bool is_backward=false, const CImg& guide=CImg::const_empty()) { return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide). move_to(*this); } //! Estimate displacement field between two images \newinstance. CImg get_displacement(const CImg& source, const float smoothness=0.1f, const float precision=5.0f, const unsigned int nb_scales=0, const unsigned int iteration_max=10000, const bool is_backward=false, const CImg& guide=CImg::const_empty()) const { if (is_empty() || !source) return +*this; if (!is_sameXYZC(source)) throw CImgArgumentException(_cimg_instance "displacement(): Instance and source image (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, source._width,source._height,source._depth,source._spectrum,source._data); if (precision<0) throw CImgArgumentException(_cimg_instance "displacement(): Invalid specified precision %g " "(should be >=0)", cimg_instance, precision); const bool is_3d = source._depth>1; const unsigned int constraint = is_3d?3:2; if (guide && (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum0?nb_scales: (unsigned int)cimg::round(std::log(mins/8.0)/std::log(1.5),1,1); const float _precision = (float)std::pow(10.0,-(double)precision); float sm, sM = source.max_min(sm), tm, tM = max_min(tm); const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm); CImg U, V; floatT bound = 0; for (int scale = (int)_nb_scales - 1; scale>=0; --scale) { const float factor = (float)std::pow(1.5,(double)scale); const unsigned int _sw = (unsigned int)(_width/factor), sw = _sw?_sw:1, _sh = (unsigned int)(_height/factor), sh = _sh?_sh:1, _sd = (unsigned int)(_depth/factor), sd = _sd?_sd:1; if (sw<5 && sh<5 && (!is_3d || sd<5)) continue; // skip too small scales. const CImg I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta, I2 = (get_resize(I1,2)-=tm)/=tdelta; if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V); if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3); else { if (guide) guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U); else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0); } float dt = 2, energy = cimg::type::max(); const CImgList dI = is_backward?I1.get_gradient():I2.get_gradient(); for (unsigned int iteration = 0; iteration=0) // Isotropic regularization. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy) #endif cimg_forYZ(U,y,z) { const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; } else { if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; } _energy+=delta_I*delta_I + smoothness*_energy_regul; } if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints. U(x,y,z,0) = V(x,y,z,0)/factor; U(x,y,z,1) = V(x,y,z,1)/factor; U(x,y,z,2) = V(x,y,z,2)/factor; } } else { // Anisotropic regularization. const float nsmoothness = -smoothness; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy) #endif cimg_forYZ(U,y,z) { const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; } else { if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; } _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints. U(x,y,z,0) = V(x,y,z,0)/factor; U(x,y,z,1) = V(x,y,z,1)/factor; U(x,y,z,2) = V(x,y,z,2)/factor; } } } } else { // 2d version. if (smoothness>=0) // Isotropic regularization. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy) #endif cimg_forY(U,y) { const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; if (U(x,y,1)>y) U(x,y,1) = (float)y; bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; } else { if (U(x,y,0)<-x) U(x,y,0) = -(float)x; if (U(x,y,1)<-y) U(x,y,1) = -(float)y; bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; } _energy+=delta_I*delta_I + smoothness*_energy_regul; } if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints. U(x,y,0) = V(x,y,0)/factor; U(x,y,1) = V(x,y,1)/factor; } } else { // Anisotropic regularization. const float nsmoothness = -smoothness; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy) #endif cimg_forY(U,y) { const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; if (U(x,y,1)>y) U(x,y,1) = (float)y; bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; } else { if (U(x,y,0)<-x) U(x,y,0) = -(float)x; if (U(x,y,1)<-y) U(x,y,1) = -(float)y; bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; } _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints. U(x,y,0) = V(x,y,0)/factor; U(x,y,1) = V(x,y,1)/factor; } } } } const float d_energy = (_energy - energy)/(sw*sh*sd); if (d_energy<=0 && -d_energy<_precision) break; if (d_energy>0) dt*=0.5f; energy = _energy; } } return U; } //! Compute correspondence map between two images, using the patch-match algorithm. /** \param patch_image The image containing the reference patches to match with the instance image. \param patch_width Width of the patch used for matching. \param patch_height Height of the patch used for matching. \param patch_depth Depth of the patch used for matching. \param nb_iterations Number of patch-match iterations. \param nb_randoms Number of randomization attempts (per pixel). \param guide Image used as the initial correspondence estimate for the algorithm. 'guide' may have a last channel with boolean values (0=false | other=true) that tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). \param[out] matching_score Returned as the image of matching scores. \note The patch-match algorithm is described in this paper: Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman(2009), PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing **/ template CImg& patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth, const unsigned int nb_iterations, const unsigned int nb_randoms, const CImg &guide, CImg &matching_score) { return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms,guide,matching_score).move_to(*this); } //! Compute correspondence map between two images, using the patch-match algorithm \newinstance. template CImg get_patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth, const unsigned int nb_iterations, const unsigned int nb_randoms, const CImg &guide, CImg &matching_score) const { return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms, guide,true,matching_score); } //! Compute correspondence map between two images, using the patch-match algorithm \overloading. template CImg& patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth, const unsigned int nb_iterations, const unsigned int nb_randoms, const CImg &guide) { return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms,guide).move_to(*this); } //! Compute correspondence map between two images, using the patch-match algorithm \overloading. template CImg get_patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth, const unsigned int nb_iterations, const unsigned int nb_randoms, const CImg &guide) const { return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms, guide,false,CImg::empty()); } //! Compute correspondence map between two images, using the patch-match algorithm \overloading. CImg& patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth=1, const unsigned int nb_iterations=5, const unsigned int nb_randoms=5) { return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms).move_to(*this); } //! Compute correspondence map between two images, using the patch-match algorithm \overloading. CImg get_patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth=1, const unsigned int nb_iterations=5, const unsigned int nb_randoms=5) const { return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, nb_iterations,nb_randoms, CImg::const_empty(), false,CImg::empty()); } template CImg _get_patchmatch(const CImg& patch_image, const unsigned int patch_width, const unsigned int patch_height, const unsigned int patch_depth, const unsigned int nb_iterations, const unsigned int nb_randoms, const CImg &guide, const bool is_matching_score, CImg &matching_score) const { if (is_empty()) return CImg::const_empty(); if (patch_image._spectrum!=_spectrum) throw CImgArgumentException(_cimg_instance "patchmatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) " "have different spectrums.", cimg_instance, patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, patch_image._data); if (patch_width>_width || patch_height>_height || patch_depth>_depth) throw CImgArgumentException(_cimg_instance "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions " "of the instance image.", cimg_instance,patch_width,patch_height,patch_depth); if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth) throw CImgArgumentException(_cimg_instance "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions " "of the patch image image (%u,%u,%u,%u,%p).", cimg_instance,patch_width,patch_height,patch_depth, patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, patch_image._data); const unsigned int _constraint = patch_image._depth>1?3:2, constraint = guide._spectrum>_constraint?_constraint:0; if (guide && (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint)) throw CImgArgumentException(_cimg_instance "patchmatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions " "considering instance and patch image image (%u,%u,%u,%u,%p).", cimg_instance, guide._width,guide._height,guide._depth,guide._spectrum,guide._data, patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, patch_image._data); CImg map(_width,_height,_depth,patch_image._depth>1?3:2); CImg score(_width,_height,_depth); const int psizew = (int)patch_width, psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1, psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1, psized = (int)patch_depth, psized1 = psized/2, psized2 = psized - psized1 - 1; if (_depth>1 || patch_image._depth>1) { // 3d version. // Initialize correspondence map. if (guide) cimg_forXYZ(*this,x,y,z) { // User-defined initialization. const int cx1 = x<=psizew1?x:(x::inf()); } else cimg_forXYZ(*this,x,y,z) { // Random initialization. const int cx1 = x<=psizew1?x:(x::inf()); } // Start iteration loop. for (unsigned int iter = 0; iter64 && iter0) { // Compare with left neighbor. const int u = map(x - 1,y,z,0), v = map(x - 1,y,z,1), w = map(x - 1,y,z,2); if (u>=cx1 - 1 && u=cy1 && v=cz1 && w0) { // Compare with up neighbor. const int u = map(x,y - 1,z,0), v = map(x,y - 1,z,1), w = map(x,y - 1,z,2); if (u>=cx1 && u=cy1 - 1 && v=cz1 && w0) { // Compare with backward neighbor. const int u = map(x,y,z - 1,0), v = map(x,y,z - 1,1), w = map(x,y,z - 1,2); if (u>=cx1 && u=cy1 && v=cz1 - 1 && w=cx1 + 1 && u=cy1 && v=cz1 && w=cx1 && u=cy1 + 1 && v=cz1 && w=cx1 && u=cy1 && v=cz1 + 1 && w::inf()); } else cimg_forXY(*this,x,y) { // Random initialization. const int cx1 = x<=psizew1?x:(x::inf()); } // Start iteration loop. for (unsigned int iter = 0; iter64 && iter0) { // Compare with left neighbor. const int u = map(x - 1,y,0), v = map(x - 1,y,1); if (u>=cx1 - 1 && u=cy1 && v0) { // Compare with up neighbor. const int u = map(x,y - 1,0), v = map(x,y - 1,1); if (u>=cx1 && u=cy1 - 1 && v=cx1 + 1 && u=cy1 && v=cx1 && u=cy1 + 1 && v& img1, const CImg& img2, const unsigned int psizew, const unsigned int psizeh, const int x1, const int y1, const int x2, const int y2, const float max_ssd) { // 2d version. const T *p1 = img1.data(x1,y1), *p2 = img2.data(x2,y2); const ulongT offx1 = (ulongT)img1._width - psizew, offx2 = (ulongT)img2._width - psizew, offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width, offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width; float ssd = 0; cimg_forC(img1,c) { for (unsigned int j = 0; jmax_ssd) return max_ssd; p1+=offx1; p2+=offx2; } p1+=offy1; p2+=offy2; } return ssd; } static float _patchmatch(const CImg& img1, const CImg& img2, const unsigned int psizew, const unsigned int psizeh, const unsigned int psized, const int x1, const int y1, const int z1, const int x2, const int y2, const int z2, const float max_ssd) { // 3d version. const T *p1 = img1.data(x1,y1,z1), *p2 = img2.data(x2,y2,z2); const ulongT offx1 = (ulongT)img1._width - psizew, offx2 = (ulongT)img2._width - psizew, offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width - psizew, offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width - psizew, offz1 = (ulongT)img1._width*img1._height*img1._depth - psized*img1._width*img1._height - psizeh*img1._width - psizew, offz2 = (ulongT)img2._width*img2._height*img2._depth - psized*img2._width*img2._height - psizeh*img2._width - psizew; float ssd = 0; cimg_forC(img1,c) { for (unsigned int k = 0; kmax_ssd) return max_ssd; p1+=offx1; p2+=offx2; } p1+=offy1; p2+=offy2; } p1+=offz1; p2+=offz2; } return ssd; } //! Compute Euclidean distance function to a specified value. /** \param value Reference value. \param metric Type of metric. Can be { 0=Chebyshev | 1=Manhattan | 2=Euclidean | 3=Squared-euclidean }. \note The distance transform implementation has been submitted by A. Meijster, and implements the article 'W.H. Hesselink, A. Meijster, J.B.T.M. Roerdink, "A general algorithm for computing distance transforms in linear time.", In: Mathematical Morphology and its Applications to Image and Signal Processing, J. Goutsias, L. Vincent, and D.S. Bloomberg (eds.), Kluwer, 2000, pp. 331-340.' The submitted code has then been modified to fit CImg coding style and constraints. **/ CImg& distance(const T& value, const unsigned int metric=2) { if (is_empty()) return *this; if (cimg::type::string()!=cimg::type::string()) // For datatype < int. return CImg(*this,false).distance((Tint)value,metric). cut((Tint)cimg::type::min(),(Tint)cimg::type::max()).move_to(*this); bool is_value = false; cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)cimg::max(0,99999999); // Trick to avoid VC++ warning if (!is_value) return fill(cimg::type::max()); switch (metric) { case 0 : return _distance_core(_distance_sep_cdt,_distance_dist_cdt); // Chebyshev. case 1 : return _distance_core(_distance_sep_mdt,_distance_dist_mdt); // Manhattan. case 3 : return _distance_core(_distance_sep_edt,_distance_dist_edt); // Squared Euclidean. default : return _distance_core(_distance_sep_edt,_distance_dist_edt).sqrt(); // Euclidean. } return *this; } //! Compute distance to a specified value \newinstance. CImg get_distance(const T& value, const unsigned int metric=2) const { return CImg(*this,false).distance((Tfloat)value,metric); } static longT _distance_sep_edt(const longT i, const longT u, const longT *const g) { return (u*u - i*i + g[u] - g[i])/(2*(u - i)); } static longT _distance_dist_edt(const longT x, const longT i, const longT *const g) { return (x - i)*(x - i) + g[i]; } static longT _distance_sep_mdt(const longT i, const longT u, const longT *const g) { return (u - i<=g[u] - g[i]?999999999:(g[u] - g[i] + u + i)/2); } static longT _distance_dist_mdt(const longT x, const longT i, const longT *const g) { return (x=0) && f(t[q],s[q],g)>f(t[q],u,g)) { --q; } if (q<0) { q = 0; s[0] = u; } else { const longT w = 1 + sep(s[q], u, g); if (w<(longT)len) { ++q; s[q] = u; t[q] = w; }} } for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan. } CImg& _distance_core(longT (*const sep)(const longT, const longT, const longT *const), longT (*const f)(const longT, const longT, const longT *const)) { // Check for g++ 4.9.X, as OpenMP seems to crash for this particular function. I have no clues why. #define cimg_is_gcc49x (__GNUC__==4 && __GNUC_MINOR__==9) const ulongT wh = (ulongT)_width*_height; #if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { CImg g(_width), dt(_width), s(_width), t(_width); CImg img = get_shared_channel(c); #if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) firstprivate(g,dt,s,t) #endif cimg_forYZ(*this,y,z) { // Over X-direction. cimg_forX(*this,x) g[x] = (longT)img(x,y,z,0,wh); _distance_scan(_width,g,sep,f,s,t,dt); cimg_forX(*this,x) img(x,y,z,0,wh) = (T)dt[x]; } if (_height>1) { g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height); #if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_height>=512 && _width*_depth>=16) firstprivate(g,dt,s,t) #endif cimg_forXZ(*this,x,z) { // Over Y-direction. cimg_forY(*this,y) g[y] = (longT)img(x,y,z,0,wh); _distance_scan(_height,g,sep,f,s,t,dt); cimg_forY(*this,y) img(x,y,z,0,wh) = (T)dt[y]; } } if (_depth>1) { g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth); #if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_depth>=512 && _width*_height>=16) firstprivate(g,dt,s,t) #endif cimg_forXY(*this,x,y) { // Over Z-direction. cimg_forZ(*this,z) g[z] = (longT)img(x,y,z,0,wh); _distance_scan(_depth,g,sep,f,s,t,dt); cimg_forZ(*this,z) img(x,y,z,0,wh) = (T)dt[z]; } } } return *this; } //! Compute chamfer distance to a specified value, with a custom metric. /** \param value Reference value. \param metric_mask Metric mask. \note The algorithm code has been initially proposed by A. Meijster, and modified by D. Tschumperlé. **/ template CImg& distance(const T& value, const CImg& metric_mask) { if (is_empty()) return *this; bool is_value = false; cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999; if (!is_value) return fill(cimg::type::max()); const ulongT wh = (ulongT)_width*_height; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) #endif cimg_forC(*this,c) { CImg img = get_shared_channel(c); #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width*_height*_depth>=1024) #endif cimg_forXYZ(metric_mask,dx,dy,dz) { const t weight = metric_mask(dx,dy,dz); if (weight) { for (int z = dz, nz = 0; z=0; --z,--nz) { // Backward scan. for (int y = height() - 1 - dy, ny = height() - 1; y>=0; --y,--ny) { for (int x = width() - 1 - dx, nx = width() - 1; x>=0; --x,--nx) { const T dd = img(nx,ny,nz,0,wh) + weight; if (dd CImg get_distance(const T& value, const CImg& metric_mask) const { return CImg(*this,false).distance(value,metric_mask); } //! Compute distance to a specified value, according to a custom metric (use dijkstra algorithm). /** \param value Reference value. \param metric Field of distance potentials. \param is_high_connectivity Tells if the algorithm uses low or high connectivity. **/ template CImg& distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, CImg& return_path) { return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this); } //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm) \newinstance. template CImg::type> get_distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, CImg& return_path) const { if (is_empty()) return return_path.assign(); if (!is_sameXYZ(metric)) throw CImgArgumentException(_cimg_instance "distance_dijkstra(): image instance and metric map (%u,%u,%u,%u) " "have incompatible dimensions.", cimg_instance, metric._width,metric._height,metric._depth,metric._spectrum); typedef typename cimg::superset::type td; // Type used for computing cumulative distances. CImg result(_width,_height,_depth,_spectrum), Q; CImg is_queued(_width,_height,_depth,1); if (return_path) return_path.assign(_width,_height,_depth,_spectrum); cimg_forC(*this,c) { const CImg img = get_shared_channel(c); const CImg met = metric.get_shared_channel(c%metric._spectrum); CImg res = result.get_shared_channel(c); CImg path = return_path?return_path.get_shared_channel(c):CImg(); unsigned int sizeQ = 0; // Detect initial seeds. is_queued.fill(0); cimg_forXYZ(img,x,y,z) if (img(x,y,z)==value) { Q._priority_queue_insert(is_queued,sizeQ,0,x,y,z); res(x,y,z) = 0; if (path) path(x,y,z) = (to)0; } // Start distance propagation. while (sizeQ) { // Get and remove point with minimal potential from the queue. const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3); const td P = (td)-Q(0,0); Q._priority_queue_remove(sizeQ); // Update neighbors. td npot = 0; if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) { res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) { res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8; } if (y + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) { res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32; } if (z + 1=0 && y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) { res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) { res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9; } if (x - 1>=0 && y + 1=0) { // Diagonal neighbors on slice z - 1. if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) { res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) { res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40; } if (y + 1=0 && y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)), x - 1,y - 1,z - 1)) { res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)), x + 1,y - 1,z - 1)) { res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41; } if (x - 1>=0 && y + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) { res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) { res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24; } if (y + 1=0 && y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)), x - 1,y - 1,z + 1)) { res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26; } if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)), x + 1,y - 1,z + 1)) { res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25; } if (x - 1>=0 && y + 1 CImg& distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity=false) { return get_distance_dijkstra(value,metric,is_high_connectivity).move_to(*this); } //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. template CImg get_distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity=false) const { CImg return_path; return get_distance_dijkstra(value,metric,is_high_connectivity,return_path); } //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm). /** \param value Reference value. \param metric Field of distance potentials. **/ template CImg& distance_eikonal(const T& value, const CImg& metric) { return get_distance_eikonal(value,metric).move_to(*this); } //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm). template CImg get_distance_eikonal(const T& value, const CImg& metric) const { if (is_empty()) return *this; if (!is_sameXYZ(metric)) throw CImgArgumentException(_cimg_instance "distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have " "incompatible dimensions.", cimg_instance, metric._width,metric._height,metric._depth,metric._spectrum); CImg result(_width,_height,_depth,_spectrum,cimg::type::max()), Q; CImg state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen. #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state) #endif cimg_forC(*this,c) { const CImg img = get_shared_channel(c); const CImg met = metric.get_shared_channel(c%metric._spectrum); CImg res = result.get_shared_channel(c); unsigned int sizeQ = 0; state.fill(-1); // Detect initial seeds. Tfloat *ptr1 = res._data; char *ptr2 = state._data; cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; } // Initialize seeds neighbors. ptr2 = state._data; cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) { if (x - 1>=0 && state(x - 1,y,z)==-1) { const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z); } if (x + 1=0 && state(x,y - 1,z)==-1) { const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z); } if (y + 1=0 && state(x,y,z - 1)==-1) { const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1); } if (z + 1=0) { if (x - 1>=0 && state(x - 1,y,z)!=1) { const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); if (dist=0 && state(x,y - 1,z)!=1) { const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); if (dist=0 && state(x,y,z - 1)!=1) { const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); if (dist& res, const Tfloat P, const int x=0, const int y=0, const int z=0) const { const T M = cimg::type::max(); T T1 = cimg::min(x - 1>=0?res(x - 1,y,z):M,x + 11) { // 3d. T T2 = cimg::min(y - 1>=0?res(x,y - 1,z):M,y + 1=0?res(x,y,z - 1):M,z + 1T2) cimg::swap(T1,T2); if (T2>T3) cimg::swap(T2,T3); if (T1>T2) cimg::swap(T1,T2); if (P<=0) return (Tfloat)T1; if (T31) { // 2d. T T2 = cimg::min(y - 1>=0?res(x,y - 1,z):M,y + 1T2) cimg::swap(T1,T2); if (P<=0) return (Tfloat)T1; if (T2 void _eik_priority_queue_insert(CImg& state, unsigned int& siz, const t value, const unsigned int x, const unsigned int y, const unsigned int z) { if (state(x,y,z)>0) return; state(x,y,z) = 0; if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); } (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z; for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos + 1)/2 - 1,0); pos = par) { cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1)); cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3)); } } //! Compute distance function to 0-valued isophotes, using the Eikonal PDE. /** \param nb_iterations Number of PDE iterations. \param band_size Size of the narrow band. \param time_step Time step of the PDE iterations. **/ CImg& distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) { if (is_empty()) return *this; CImg velocity(*this); for (unsigned int iteration = 0; iteration1) { // 3d CImg_3x3x3(I,Tfloat); cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) if (band_size<=0 || cimg::abs(Iccc)0?(Incc - Iccc):(Iccc - Ipcc), iy = gy*sgn>0?(Icnc - Iccc):(Iccc - Icpc), iz = gz*sgn>0?(Iccn - Iccc):(Iccc - Iccp), ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy + gz*gz)), ngx = gx/ng, ngy = gy/ng, ngz = gz/ng, veloc = sgn*(ngx*ix + ngy*iy + ngz*iz - 1); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } else *(ptrd++) = 0; } else { // 2d version CImg_3x3(I,Tfloat); cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) if (band_size<=0 || cimg::abs(Icc)0?(Inc - Icc):(Icc - Ipc), iy = gy*sgn>0?(Icn - Icc):(Icc - Icp), ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy)), ngx = gx/ng, ngy = gy/ng, veloc = sgn*(ngx*ix + ngy*iy - 1); *(ptrd++) = veloc; if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; } else *(ptrd++) = 0; } if (veloc_max>0) *this+=(velocity*=time_step/veloc_max); } return *this; } //! Compute distance function to 0-valued isophotes, using the Eikonal PDE \newinstance. CImg get_distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) const { return CImg(*this,false).distance_eikonal(nb_iterations,band_size,time_step); } //! Compute Haar multiscale wavelet transform. /** \param axis Axis considered for the transform. \param invert Set inverse of direct transform. \param nb_scales Number of scales used for the transform. **/ CImg& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) { return get_haar(axis,invert,nb_scales).move_to(*this); } //! Compute Haar multiscale wavelet transform \newinstance. CImg get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const { if (is_empty() || !nb_scales) return +*this; CImg res; const Tfloat sqrt2 = std::sqrt(2.0f); if (nb_scales==1) { switch (cimg::uncase(axis)) { // Single scale transform case 'x' : { const unsigned int w = _width/2; if (w) { if ((w%2) && w!=1) throw CImgInstanceException(_cimg_instance "haar(): Sub-image width %u is not even.", cimg_instance, w); res.assign(_width,_height,_depth,_spectrum); if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X for (unsigned int x = 0, xw = w, x2 = 0; x& haar(const bool invert=false, const unsigned int nb_scales=1) { return get_haar(invert,nb_scales).move_to(*this); } //! Compute Haar multiscale wavelet transform \newinstance. CImg get_haar(const bool invert=false, const unsigned int nb_scales=1) const { CImg res; if (nb_scales==1) { // Single scale transform if (_width>1) get_haar('x',invert,1).move_to(res); if (_height>1) { if (res) res.haar('y',invert,1); else get_haar('y',invert,1).move_to(res); } if (_depth>1) { if (res) res.haar('z',invert,1); else get_haar('z',invert,1).move_to(res); } if (res) return res; } else { // Multi-scale transform if (invert) { // Inverse transform res.assign(*this); if (_width>1) { if (_height>1) { if (_depth>1) { unsigned int w = _width, h = _height, d = _depth; for (unsigned int s = 1; w && h && d && s1) { unsigned int w = _width, d = _depth; for (unsigned int s = 1; w && d && s1) { if (_depth>1) { unsigned int h = _height, d = _depth; for (unsigned int s = 1; h && d && s1) { unsigned int d = _depth; for (unsigned int s = 1; d && s1) { if (_height>1) { if (_depth>1) for (unsigned int s = 1, w = _width/2, h = _height/2, d = _depth/2; w && h && d && s1) for (unsigned int s = 1, w = _width/2, d = _depth/2; w && d && s1) { if (_depth>1) for (unsigned int s = 1, h = _height/2, d = _depth/2; h && d && s1) for (unsigned int s = 1, d = _depth/2; d && s get_FFT(const char axis, const bool is_invert=false) const { CImgList res(*this,CImg()); CImg::FFT(res[0],res[1],axis,is_invert); return res; } //! Compute n-d Fast Fourier Transform. /* \param is_invert Tells if the forward (\c false) or inverse (\c true) FFT is computed. **/ CImgList get_FFT(const bool is_invert=false) const { CImgList res(*this,CImg()); CImg::FFT(res[0],res[1],is_invert); return res; } //! Compute 1d Fast Fourier Transform, along a specified axis. /** \param[in,out] real Real part of the pixel values. \param[in,out] imag Imaginary part of the pixel values. \param axis Axis along which the FFT is computed. \param is_invert Tells if the forward (\c false) or inverse (\c true) FFT is computed. **/ static void FFT(CImg& real, CImg& imag, const char axis, const bool is_invert=false) { if (!real) throw CImgInstanceException("CImg<%s>::FFT(): Specified real part is empty.", pixel_type()); if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0); if (!real.is_sameXYZC(imag)) throw CImgInstanceException("CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and " "imaginary part (%u,%u,%u,%u,%p) have different dimensions.", pixel_type(), real._width,real._height,real._depth,real._spectrum,real._data, imag._width,imag._height,imag._depth,imag._spectrum,imag._data); #ifdef cimg_use_fftw3 cimg::mutex(12); fftw_complex *data_in; fftw_plan data_plan; switch (cimg::uncase(axis)) { case 'x' : { // Fourier along X, using FFTW library. data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width); if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " "for computing FFT of image (%u,%u,%u,%u) along the X-axis.", pixel_type(), cimg::strbuffersize(sizeof(fftw_complex)*real._width), real._width,real._height,real._depth,real._spectrum); data_plan = fftw_plan_dft_1d(real._width,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); cimg_forYZC(real,y,z,c) { T *ptrr = real.data(0,y,z,c), *ptri = imag.data(0,y,z,c); double *ptrd = (double*)data_in; cimg_forX(real,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); } fftw_execute(data_plan); const unsigned int fact = real._width; if (is_invert) cimg_forX(real,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); } else cimg_forX(real,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); } } } break; case 'y' : { // Fourier along Y, using FFTW library. data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._height); if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " "for computing FFT of image (%u,%u,%u,%u) along the Y-axis.", pixel_type(), cimg::strbuffersize(sizeof(fftw_complex)*real._height), real._width,real._height,real._depth,real._spectrum); data_plan = fftw_plan_dft_1d(real._height,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); const unsigned int off = real._width; cimg_forXZC(real,x,z,c) { T *ptrr = real.data(x,0,z,c), *ptri = imag.data(x,0,z,c); double *ptrd = (double*)data_in; cimg_forY(real,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } fftw_execute(data_plan); const unsigned int fact = real._height; if (is_invert) cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } else cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } } } break; case 'z' : { // Fourier along Z, using FFTW library. data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._depth); if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " "for computing FFT of image (%u,%u,%u,%u) along the Z-axis.", pixel_type(), cimg::strbuffersize(sizeof(fftw_complex)*real._depth), real._width,real._height,real._depth,real._spectrum); data_plan = fftw_plan_dft_1d(real._depth,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); const ulongT off = (ulongT)real._width*real._height; cimg_forXYC(real,x,y,c) { T *ptrr = real.data(x,y,0,c), *ptri = imag.data(x,y,0,c); double *ptrd = (double*)data_in; cimg_forZ(real,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } fftw_execute(data_plan); const unsigned int fact = real._depth; if (is_invert) cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } else cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } } } break; default : throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts " "(%u,%u,%u,%u) " "(should be { x | y | z }).", pixel_type(),axis, real._width,real._height,real._depth,real._spectrum); } fftw_destroy_plan(data_plan); fftw_free(data_in); cimg::mutex(12,0); #else switch (cimg::uncase(axis)) { case 'x' : { // Fourier along X, using built-in functions. const unsigned int N = real._width, N2 = N>>1; if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the X-axis.", pixel_type(), real._width,real._height,real._depth,real._spectrum); for (unsigned int i = 0, j = 0; ii) cimg_forYZC(real,y,z,c) { cimg::swap(real(i,y,z,c),real(j,y,z,c)); cimg::swap(imag(i,y,z,c),imag(j,y,z,c)); if (j=m; j-=m, m = n, n>>=1) {} } for (unsigned int delta = 2; delta<=N; delta<<=1) { const unsigned int delta2 = delta>>1; for (unsigned int i = 0; i>1; if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the Y-axis.", pixel_type(), real._width,real._height,real._depth,real._spectrum); for (unsigned int i = 0, j = 0; ii) cimg_forXZC(real,x,z,c) { cimg::swap(real(x,i,z,c),real(x,j,z,c)); cimg::swap(imag(x,i,z,c),imag(x,j,z,c)); if (j=m; j-=m, m = n, n>>=1) {} } for (unsigned int delta = 2; delta<=N; delta<<=1) { const unsigned int delta2 = (delta>>1); for (unsigned int i = 0; i>1; if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the Z-axis.", pixel_type(), real._width,real._height,real._depth,real._spectrum); for (unsigned int i = 0, j = 0; ii) cimg_forXYC(real,x,y,c) { cimg::swap(real(x,y,i,c),real(x,y,j,c)); cimg::swap(imag(x,y,i,c),imag(x,y,j,c)); if (j=m; j-=m, m = n, n>>=1) {} } for (unsigned int delta = 2; delta<=N; delta<<=1) { const unsigned int delta2 = (delta>>1); for (unsigned int i = 0; i::FFT(): Invalid specified axis '%c' for real and imaginary parts " "(%u,%u,%u,%u) " "(should be { x | y | z }).", pixel_type(),axis, real._width,real._height,real._depth,real._spectrum); } #endif } //! Compute n-d Fast Fourier Transform. /** \param[in,out] real Real part of the pixel values. \param[in,out] imag Imaginary part of the pixel values. \param is_invert Tells if the forward (\c false) or inverse (\c true) FFT is computed. \param nb_threads Number of parallel threads used for the computation. Use \c 0 to set this to the number of available cpus. **/ static void FFT(CImg& real, CImg& imag, const bool is_invert=false, const unsigned int nb_threads=0) { if (!real) throw CImgInstanceException("CImgList<%s>::FFT(): Empty specified real part.", pixel_type()); if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0); if (!real.is_sameXYZC(imag)) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and " "imaginary part (%u,%u,%u,%u,%p) have different dimensions.", pixel_type(), real._width,real._height,real._depth,real._spectrum,real._data, imag._width,imag._height,imag._depth,imag._spectrum,imag._data); #ifdef cimg_use_fftw3 cimg::mutex(12); #ifndef cimg_use_fftw3_singlethread const unsigned int _nb_threads = nb_threads?nb_threads:cimg::nb_cpus(); static int fftw_st = fftw_init_threads(); cimg::unused(fftw_st); fftw_plan_with_nthreads(_nb_threads); #else cimg::unused(nb_threads); #endif fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth); if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " "for computing FFT of image (%u,%u,%u,%u).", pixel_type(), cimg::strbuffersize(sizeof(fftw_complex)*real._width* real._height*real._depth*real._spectrum), real._width,real._height,real._depth,real._spectrum); fftw_plan data_plan; const ulongT w = (ulongT)real._width, wh = w*real._height, whd = wh*real._depth; data_plan = fftw_plan_dft_3d(real._width,real._height,real._depth,data_in,data_in, is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); cimg_forC(real,c) { T *ptrr = real.data(0,0,0,c), *ptri = imag.data(0,0,0,c); double *ptrd = (double*)data_in; for (unsigned int x = 0; x1) FFT(real,imag,'z',is_invert); if (real._height>1) FFT(real,imag,'y',is_invert); if (real._width>1) FFT(real,imag,'x',is_invert); #endif } //@} //------------------------------------- // //! \name 3d Objects Management //@{ //------------------------------------- //! Shift 3d object's vertices. /** \param tx X-coordinate of the 3d displacement vector. \param ty Y-coordinate of the 3d displacement vector. \param tz Z-coordinate of the 3d displacement vector. **/ CImg& shift_object3d(const float tx, const float ty=0, const float tz=0) { if (_height!=3 || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "shift_object3d(): Instance is not a set of 3d vertices.", cimg_instance); get_shared_row(0)+=tx; get_shared_row(1)+=ty; get_shared_row(2)+=tz; return *this; } //! Shift 3d object's vertices \newinstance. CImg get_shift_object3d(const float tx, const float ty=0, const float tz=0) const { return CImg(*this,false).shift_object3d(tx,ty,tz); } //! Shift 3d object's vertices, so that it becomes centered. /** \note The object center is computed as its barycenter. **/ CImg& shift_object3d() { if (_height!=3 || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "shift_object3d(): Instance is not a set of 3d vertices.", cimg_instance); CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2; return *this; } //! Shift 3d object's vertices, so that it becomes centered \newinstance. CImg get_shift_object3d() const { return CImg(*this,false).shift_object3d(); } //! Resize 3d object. /** \param sx Width of the 3d object's bounding box. \param sy Height of the 3d object's bounding box. \param sz Depth of the 3d object's bounding box. **/ CImg& resize_object3d(const float sx, const float sy=-100, const float sz=-100) { if (_height!=3 || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "resize_object3d(): Instance is not a set of 3d vertices.", cimg_instance); CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); if (xm0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; } if (ym0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; } if (zm0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; } return *this; } //! Resize 3d object \newinstance. CImg get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const { return CImg(*this,false).resize_object3d(sx,sy,sz); } //! Resize 3d object to unit size. CImg resize_object3d() { if (_height!=3 || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "resize_object3d(): Instance is not a set of 3d vertices.", cimg_instance); CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz); if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; } return *this; } //! Resize 3d object to unit size \newinstance. CImg get_resize_object3d() const { return CImg(*this,false).resize_object3d(); } //! Merge two 3d objects together. /** \param[in,out] primitives Primitives data of the current 3d object. \param obj_vertices Vertices data of the additional 3d object. \param obj_primitives Primitives data of the additional 3d object. **/ template CImg& append_object3d(CImgList& primitives, const CImg& obj_vertices, const CImgList& obj_primitives) { if (!obj_vertices || !obj_primitives) return *this; if (obj_vertices._height!=3 || obj_vertices._depth>1 || obj_vertices._spectrum>1) throw CImgInstanceException(_cimg_instance "append_object3d(): Specified vertice image (%u,%u,%u,%u,%p) is not a " "set of 3d vertices.", cimg_instance, obj_vertices._width,obj_vertices._height, obj_vertices._depth,obj_vertices._spectrum,obj_vertices._data); if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); } if (_height!=3 || _depth>1 || _spectrum>1) throw CImgInstanceException(_cimg_instance "append_object3d(): Instance is not a set of 3d vertices.", cimg_instance); const unsigned int P = _width; append(obj_vertices,'x'); const unsigned int N = primitives._width; primitives.insert(obj_primitives); for (unsigned int i = N; i &p = primitives[i]; switch (p.size()) { case 1 : p[0]+=P; break; // Point. case 5 : p[0]+=P; p[1]+=P; break; // Sphere. case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment. case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle. case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle. } } return *this; } //! Texturize primitives of a 3d object. /** \param[in,out] primitives Primitives data of the 3d object. \param[in,out] colors Colors data of the 3d object. \param texture Texture image to map to 3d object. \param coords Texture-mapping coordinates. **/ template const CImg& texturize_object3d(CImgList& primitives, CImgList& colors, const CImg& texture, const CImg& coords=CImg::const_empty()) const { if (is_empty()) return *this; if (_height!=3) throw CImgInstanceException(_cimg_instance "texturize_object3d(): image instance is not a set of 3d points.", cimg_instance); if (coords && (coords._width!=_width || coords._height!=2)) throw CImgArgumentException(_cimg_instance "texturize_object3d(): Invalid specified texture coordinates (%u,%u,%u,%u,%p).", cimg_instance, coords._width,coords._height,coords._depth,coords._spectrum,coords._data); CImg _coords; if (!coords) { // If no texture coordinates specified, do a default XY-projection. _coords.assign(_width,2); float xmin, xmax = (float)get_shared_row(0).max_min(xmin), ymin, ymax = (float)get_shared_row(1).max_min(ymin), dx = xmax>xmin?xmax-xmin:1, dy = ymax>ymin?ymax-ymin:1; cimg_forX(*this,p) { _coords(p,0) = (int)(((*this)(p,0) - xmin)*texture._width/dx); _coords(p,1) = (int)(((*this)(p,1) - ymin)*texture._height/dy); } } else _coords = coords; int texture_ind = -1; cimglist_for(primitives,l) { CImg &p = primitives[l]; const unsigned int siz = p.size(); switch (siz) { case 1 : { // Point. const unsigned int i0 = (unsigned int)p[0]; const int x0 = _coords(i0,0), y0 = _coords(i0,1); texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).move_to(colors[l]); } break; case 2 : case 6 : { // Line. const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1]; const int x0 = _coords(i0,0), y0 = _coords(i0,1), x1 = _coords(i1,0), y1 = _coords(i1,1); if (texture_ind<0) colors[texture_ind=l].assign(texture,false); else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,x0,y0,x1,y1).move_to(p); } break; case 3 : case 9 : { // Triangle. const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2]; const int x0 = _coords(i0,0), y0 = _coords(i0,1), x1 = _coords(i1,0), y1 = _coords(i1,1), x2 = _coords(i2,0), y2 = _coords(i2,1); if (texture_ind<0) colors[texture_ind=l].assign(texture,false); else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,i2,x0,y0,x1,y1,x2,y2).move_to(p); } break; case 4 : case 12 : { // Quadrangle. const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3]; const int x0 = _coords(i0,0), y0 = _coords(i0,1), x1 = _coords(i1,0), y1 = _coords(i1,1), x2 = _coords(i2,0), y2 = _coords(i2,1), x3 = _coords(i3,0), y3 = _coords(i3,1); if (texture_ind<0) colors[texture_ind=l].assign(texture,false); else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,i2,i3,x0,y0,x1,y1,x2,y2,x3,y3).move_to(p); } break; } } return *this; } //! Generate a 3d elevation of the image instance. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param[out] colors The returned list of the 3d object colors. \param elevation The input elevation map. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img("reference.jpg"); CImgList faces3d; CImgList colors3d; const CImg points3d = img.get_elevation3d(faces3d,colors3d,img.get_norm()*0.2); CImg().display_object3d("Elevation3d",points3d,faces3d,colors3d); \endcode \image html ref_elevation3d.jpg **/ template CImg get_elevation3d(CImgList& primitives, CImgList& colors, const CImg& elevation) const { if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1) throw CImgArgumentException(_cimg_instance "get_elevation3d(): Instance and specified elevation (%u,%u,%u,%u,%p) " "have incompatible dimensions.", cimg_instance, elevation._width,elevation._height,elevation._depth, elevation._spectrum,elevation._data); if (is_empty()) return *this; float m, M = (float)max_min(m); if (M==m) ++M; colors.assign(); const unsigned int size_x1 = _width - 1, size_y1 = _height - 1; for (unsigned int y = 0; y1?((*this)(x,y,1) - m)*255/(M-m):r), b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r); CImg::vector((tc)r,(tc)g,(tc)b).move_to(colors); } const typename CImg::_functor2d_int func(elevation); return elevation3d(primitives,func,0,0,_width - 1.0f,_height - 1.0f,_width,_height); } //! Generate the 3d projection planes of the image instance. /** \param[out] primitives Primitives data of the returned 3d object. \param[out] colors Colors data of the returned 3d object. \param x0 X-coordinate of the projection point. \param y0 Y-coordinate of the projection point. \param z0 Z-coordinate of the projection point. \param normalize_colors Tells if the created textures have normalized colors. **/ template CImg get_projections3d(CImgList& primitives, CImgList& colors, const unsigned int x0, const unsigned int y0, const unsigned int z0, const bool normalize_colors=false) const { float m = 0, M = 0, delta = 1; if (normalize_colors) { m = (float)min_max(M); delta = 255/(m==M?1:M-m); } const unsigned int _x0 = (x0>=_width)?_width - 1:x0, _y0 = (y0>=_height)?_height - 1:y0, _z0 = (z0>=_depth)?_depth - 1:z0; CImg img_xy, img_xz, img_yz; if (normalize_colors) { ((get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1)-=m)*=delta).move_to(img_xy); ((get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_width,_depth,1,-100,-1). move_to(img_xz); ((get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_height,_depth,1,-100,-1). move_to(img_yz); } else { get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1).move_to(img_xy); get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1).move_to(img_xz); get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).resize(_height,_depth,1,-100,-1).move_to(img_yz); } CImg points(12,3,1,1, 0,_width - 1,_width - 1,0, 0,_width - 1,_width - 1,0, _x0,_x0,_x0,_x0, 0,0,_height - 1,_height - 1, _y0,_y0,_y0,_y0, 0,_height - 1,_height - 1,0, _z0,_z0,_z0,_z0, 0,0,_depth - 1,_depth - 1, 0,0,_depth - 1,_depth - 1); primitives.assign(); CImg::vector(0,1,2,3,0,0,img_xy._width - 1,0,img_xy._width - 1,img_xy._height - 1,0,img_xy._height - 1). move_to(primitives); CImg::vector(4,5,6,7,0,0,img_xz._width - 1,0,img_xz._width - 1,img_xz._height - 1,0,img_xz._height - 1). move_to(primitives); CImg::vector(8,9,10,11,0,0,img_yz._width - 1,0,img_yz._width - 1,img_yz._height - 1,0,img_yz._height - 1). move_to(primitives); colors.assign(); img_xy.move_to(colors); img_xz.move_to(colors); img_yz.move_to(colors); return points; } //! Generate a isoline of the image instance as a 3d object. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param isovalue The returned list of the 3d object colors. \param size_x The number of subdivisions along the X-axis. \param size_y The number of subdisivions along the Y-axis. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img("reference.jpg"); CImgList faces3d; const CImg points3d = img.get_isoline3d(faces3d,100); CImg().display_object3d("Isoline3d",points3d,faces3d,colors3d); \endcode \image html ref_isoline3d.jpg **/ template CImg get_isoline3d(CImgList& primitives, const float isovalue, const int size_x=-100, const int size_y=-100) const { if (_spectrum>1) throw CImgInstanceException(_cimg_instance "get_isoline3d(): Instance is not a scalar image.", cimg_instance); if (_depth>1) throw CImgInstanceException(_cimg_instance "get_isoline3d(): Instance is not a 2d image.", cimg_instance); primitives.assign(); if (is_empty()) return *this; CImg vertices; if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) { const _functor2d_int func(*this); vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,width(),height()); } else { const _functor2d_float func(*this); vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,size_x,size_y); } return vertices; } //! Generate an isosurface of the image instance as a 3d object. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param isovalue The returned list of the 3d object colors. \param size_x Number of subdivisions along the X-axis. \param size_y Number of subdisivions along the Y-axis. \param size_z Number of subdisivions along the Z-axis. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img = CImg("reference.jpg").resize(-100,-100,20); CImgList faces3d; const CImg points3d = img.get_isosurface3d(faces3d,100); CImg().display_object3d("Isosurface3d",points3d,faces3d,colors3d); \endcode \image html ref_isosurface3d.jpg **/ template CImg get_isosurface3d(CImgList& primitives, const float isovalue, const int size_x=-100, const int size_y=-100, const int size_z=-100) const { if (_spectrum>1) throw CImgInstanceException(_cimg_instance "get_isosurface3d(): Instance is not a scalar image.", cimg_instance); primitives.assign(); if (is_empty()) return *this; CImg vertices; if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) { const _functor3d_int func(*this); vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f, width(),height(),depth()); } else { const _functor3d_float func(*this); vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f, size_x,size_y,size_z); } return vertices; } //! Compute 3d elevation of a function as a 3d object. /** \param[out] primitives Primitives data of the resulting 3d object. \param func Elevation function. Is of type float (*func)(const float x,const float y). \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param size_x Resolution of the function along the X-axis. \param size_y Resolution of the function along the Y-axis. **/ template static CImg elevation3d(CImgList& primitives, const tfunc& func, const float x0, const float y0, const float x1, const float y1, const int size_x=256, const int size_y=256) { const float nx0 = x0=0?size_x:(nx1-nx0)*-size_x/100), nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1, _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100), nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1; if (nsize_x<2 || nsize_y<2) throw CImgArgumentException("CImg<%s>::elevation3d(): Invalid specified size (%d,%d).", pixel_type(), nsize_x,nsize_y); CImg vertices(nsize_x*nsize_y,3); floatT *ptr_x = vertices.data(0,0), *ptr_y = vertices.data(0,1), *ptr_z = vertices.data(0,2); for (unsigned int y = 0; y static CImg elevation3d(CImgList& primitives, const char *const expression, const float x0, const float y0, const float x1, const float y1, const int size_x=256, const int size_y=256) { const _functor2d_expr func(expression); return elevation3d(primitives,func,x0,y0,x1,y1,size_x,size_y); } //! Compute 0-isolines of a function, as a 3d object. /** \param[out] primitives Primitives data of the resulting 3d object. \param func Elevation function. Is of type float (*func)(const float x,const float y). \param isovalue Isovalue to extract from function. \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param size_x Resolution of the function along the X-axis. \param size_y Resolution of the function along the Y-axis. \note Use the marching squares algorithm for extracting the isolines. **/ template static CImg isoline3d(CImgList& primitives, const tfunc& func, const float isovalue, const float x0, const float y0, const float x1, const float y1, const int size_x=256, const int size_y=256) { static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 }; static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 }, { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 }, { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 }, { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } }; const unsigned int _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)), _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)), nx = _nx?_nx:1, ny = _ny?_ny:1, nxm1 = nx - 1, nym1 = ny - 1; primitives.assign(); if (!nxm1 || !nym1) return CImg(); const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1; CImgList vertices; CImg indices1(nx,1,1,2,-1), indices2(nx,1,1,2); CImg values1(nx), values2(nx); float X = x0, Y = y0, nX = X + dx, nY = Y + dy; // Fill first line with values cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; } // Run the marching squares algorithm for (unsigned int yi = 0, nyi = 1; yi::vector(Xi,Y,0).move_to(vertices); } if ((edge&2) && indices1(nxi,1)<0) { const float Yi = Y + (isovalue-val1)*dy/(val2-val1); indices1(nxi,1) = vertices.width(); CImg::vector(nX,Yi,0).move_to(vertices); } if ((edge&4) && indices2(xi,0)<0) { const float Xi = X + (isovalue-val3)*dx/(val2-val3); indices2(xi,0) = vertices.width(); CImg::vector(Xi,nY,0).move_to(vertices); } if ((edge&8) && indices1(xi,1)<0) { const float Yi = Y + (isovalue-val0)*dy/(val3-val0); indices1(xi,1) = vertices.width(); CImg::vector(X,Yi,0).move_to(vertices); } // Create segments for (const int *segment = segments[configuration]; *segment!=-1; ) { const unsigned int p0 = (unsigned int)*(segment++), p1 = (unsigned int)*(segment++); const tf i0 = (tf)(_isoline3d_indice(p0,indices1,indices2,xi,nxi)), i1 = (tf)(_isoline3d_indice(p1,indices1,indices2,xi,nxi)); CImg::vector(i0,i1).move_to(primitives); } } } values1.swap(values2); indices1.swap(indices2); } return vertices>'x'; } //! Compute isolines of a function, as a 3d object \overloading. template static CImg isoline3d(CImgList& primitives, const char *const expression, const float isovalue, const float x0, const float y0, const float x1, const float y1, const int size_x=256, const int size_y=256) { const _functor2d_expr func(expression); return isoline3d(primitives,func,isovalue,x0,y0,x1,y1,size_x,size_y); } template static int _isoline3d_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, const unsigned int x, const unsigned int nx) { switch (edge) { case 0 : return (int)indices1(x,0); case 1 : return (int)indices1(nx,1); case 2 : return (int)indices2(x,0); case 3 : return (int)indices1(x,1); } return 0; } //! Compute isosurface of a function, as a 3d object. /** \param[out] primitives Primitives data of the resulting 3d object. \param func Implicit function. Is of type float (*func)(const float x, const float y, const float z). \param isovalue Isovalue to extract. \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param z0 Z-coordinate of the starting point. \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param z1 Z-coordinate of the ending point. \param size_x Resolution of the elevation function along the X-axis. \param size_y Resolution of the elevation function along the Y-axis. \param size_z Resolution of the elevation function along the Z-axis. \note Use the marching cubes algorithm for extracting the isosurface. **/ template static CImg isosurface3d(CImgList& primitives, const tfunc& func, const float isovalue, const float x0, const float y0, const float z0, const float x1, const float y1, const float z1, const int size_x=32, const int size_y=32, const int size_z=32) { static const unsigned int edges[256] = { 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 }; static const int triangles[256][16] = { { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }; const unsigned int _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)), _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)), _nz = (unsigned int)(size_z>=0?size_z:cimg::round((z1-z0)*-size_z/100 + 1)), nx = _nx?_nx:1, ny = _ny?_ny:1, nz = _nz?_nz:1, nxm1 = nx - 1, nym1 = ny - 1, nzm1 = nz - 1; primitives.assign(); if (!nxm1 || !nym1 || !nzm1) return CImg(); const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1, dz = (z1 - z0)/nzm1; CImgList vertices; CImg indices1(nx,ny,1,3,-1), indices2(indices1); CImg values1(nx,ny), values2(nx,ny); float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0; // Fill the first plane with function values Y = y0; cimg_forY(values1,y) { X = x0; cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=dx; } Y+=dy; } // Run Marching Cubes algorithm Z = z0; nZ = Z + dz; for (unsigned int zi = 0; zi::vector(Xi,Y,Z).move_to(vertices); } if ((edge&2) && indices1(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val1)*dy/(val2-val1); indices1(nxi,yi,1) = vertices.width(); CImg::vector(nX,Yi,Z).move_to(vertices); } if ((edge&4) && indices1(xi,nyi,0)<0) { const float Xi = X + (isovalue-val3)*dx/(val2-val3); indices1(xi,nyi,0) = vertices.width(); CImg::vector(Xi,nY,Z).move_to(vertices); } if ((edge&8) && indices1(xi,yi,1)<0) { const float Yi = Y + (isovalue-val0)*dy/(val3-val0); indices1(xi,yi,1) = vertices.width(); CImg::vector(X,Yi,Z).move_to(vertices); } if ((edge&16) && indices2(xi,yi,0)<0) { const float Xi = X + (isovalue-val4)*dx/(val5-val4); indices2(xi,yi,0) = vertices.width(); CImg::vector(Xi,Y,nZ).move_to(vertices); } if ((edge&32) && indices2(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val5)*dy/(val6-val5); indices2(nxi,yi,1) = vertices.width(); CImg::vector(nX,Yi,nZ).move_to(vertices); } if ((edge&64) && indices2(xi,nyi,0)<0) { const float Xi = X + (isovalue-val7)*dx/(val6-val7); indices2(xi,nyi,0) = vertices.width(); CImg::vector(Xi,nY,nZ).move_to(vertices); } if ((edge&128) && indices2(xi,yi,1)<0) { const float Yi = Y + (isovalue-val4)*dy/(val7-val4); indices2(xi,yi,1) = vertices.width(); CImg::vector(X,Yi,nZ).move_to(vertices); } if ((edge&256) && indices1(xi,yi,2)<0) { const float Zi = Z+ (isovalue-val0)*dz/(val4-val0); indices1(xi,yi,2) = vertices.width(); CImg::vector(X,Y,Zi).move_to(vertices); } if ((edge&512) && indices1(nxi,yi,2)<0) { const float Zi = Z + (isovalue-val1)*dz/(val5-val1); indices1(nxi,yi,2) = vertices.width(); CImg::vector(nX,Y,Zi).move_to(vertices); } if ((edge&1024) && indices1(nxi,nyi,2)<0) { const float Zi = Z + (isovalue-val2)*dz/(val6-val2); indices1(nxi,nyi,2) = vertices.width(); CImg::vector(nX,nY,Zi).move_to(vertices); } if ((edge&2048) && indices1(xi,nyi,2)<0) { const float Zi = Z + (isovalue-val3)*dz/(val7-val3); indices1(xi,nyi,2) = vertices.width(); CImg::vector(X,nY,Zi).move_to(vertices); } // Create triangles for (const int *triangle = triangles[configuration]; *triangle!=-1; ) { const unsigned int p0 = (unsigned int)*(triangle++), p1 = (unsigned int)*(triangle++), p2 = (unsigned int)*(triangle++); const tf i0 = (tf)(_isosurface3d_indice(p0,indices1,indices2,xi,yi,nxi,nyi)), i1 = (tf)(_isosurface3d_indice(p1,indices1,indices2,xi,yi,nxi,nyi)), i2 = (tf)(_isosurface3d_indice(p2,indices1,indices2,xi,yi,nxi,nyi)); CImg::vector(i0,i2,i1).move_to(primitives); } } } } cimg::swap(values1,values2); cimg::swap(indices1,indices2); } return vertices>'x'; } //! Compute isosurface of a function, as a 3d object \overloading. template static CImg isosurface3d(CImgList& primitives, const char *const expression, const float isovalue, const float x0, const float y0, const float z0, const float x1, const float y1, const float z1, const int dx=32, const int dy=32, const int dz=32) { const _functor3d_expr func(expression); return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz); } template static int _isosurface3d_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) { switch (edge) { case 0 : return indices1(x,y,0); case 1 : return indices1(nx,y,1); case 2 : return indices1(x,ny,0); case 3 : return indices1(x,y,1); case 4 : return indices2(x,y,0); case 5 : return indices2(nx,y,1); case 6 : return indices2(x,ny,0); case 7 : return indices2(x,y,1); case 8 : return indices1(x,y,2); case 9 : return indices1(nx,y,2); case 10 : return indices1(nx,ny,2); case 11 : return indices1(x,ny,2); } return 0; } // Define functors for accessing image values (used in previous functions). struct _functor2d_int { const CImg& ref; _functor2d_int(const CImg& pref):ref(pref) {} float operator()(const float x, const float y) const { return (float)ref((int)x,(int)y); } }; struct _functor2d_float { const CImg& ref; _functor2d_float(const CImg& pref):ref(pref) {} float operator()(const float x, const float y) const { return (float)ref._linear_atXY(x,y); } }; struct _functor2d_expr { _cimg_math_parser *mp; _functor2d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(expr,0,CImg::const_empty(),0); } ~_functor2d_expr() { delete mp; } float operator()(const float x, const float y) const { return (float)(*mp)(x,y,0,0); } }; struct _functor3d_int { const CImg& ref; _functor3d_int(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z) const { return (float)ref((int)x,(int)y,(int)z); } }; struct _functor3d_float { const CImg& ref; _functor3d_float(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z) const { return (float)ref._linear_atXYZ(x,y,z); } }; struct _functor3d_expr { _cimg_math_parser *mp; ~_functor3d_expr() { delete mp; } _functor3d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(expr,0,CImg::const_empty(),0); } float operator()(const float x, const float y, const float z) const { return (float)(*mp)(x,y,z,0); } }; struct _functor4d_int { const CImg& ref; _functor4d_int(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z, const unsigned int c) const { return (float)ref((int)x,(int)y,(int)z,c); } }; //! Generate a 3d box object. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param size_x The width of the box (dimension along the X-axis). \param size_y The height of the box (dimension along the Y-axis). \param size_z The depth of the box (dimension along the Z-axis). \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::box3d(faces3d,10,20,30); CImg().display_object3d("Box3d",points3d,faces3d); \endcode \image html ref_box3d.jpg **/ template static CImg box3d(CImgList& primitives, const float size_x=200, const float size_y=100, const float size_z=100) { primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5); return CImg(8,3,1,1, 0.,size_x,size_x, 0., 0.,size_x,size_x, 0., 0., 0.,size_y,size_y, 0., 0.,size_y,size_y, 0., 0., 0., 0.,size_z,size_z,size_z,size_z); } //! Generate a 3d cone. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param radius The radius of the cone basis. \param size_z The cone's height. \param subdivisions The number of basis angular subdivisions. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::cone3d(faces3d,50); CImg().display_object3d("Cone3d",points3d,faces3d); \endcode \image html ref_cone3d.jpg **/ template static CImg cone3d(CImgList& primitives, const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { primitives.assign(); if (!subdivisions) return CImg(); CImgList vertices(2,1,3,1,1, 0.,0.,size_z, 0.,0.,0.); for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) { const float a = (float)(angle*cimg::PI/180); CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0).move_to(vertices); } const unsigned int nbr = vertices._width - 2; for (unsigned int p = 0; p::vector(1,next,curr).move_to(primitives); CImg::vector(0,curr,next).move_to(primitives); } return vertices>'x'; } //! Generate a 3d cylinder. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param radius The radius of the cylinder basis. \param size_z The cylinder's height. \param subdivisions The number of basis angular subdivisions. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::cylinder3d(faces3d,50); CImg().display_object3d("Cylinder3d",points3d,faces3d); \endcode \image html ref_cylinder3d.jpg **/ template static CImg cylinder3d(CImgList& primitives, const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { primitives.assign(); if (!subdivisions) return CImg(); CImgList vertices(2,1,3,1,1, 0.,0.,0., 0.,0.,size_z); for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) { const float a = (float)(angle*cimg::PI/180); CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.0f).move_to(vertices); CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices); } const unsigned int nbr = (vertices._width - 2)/2; for (unsigned int p = 0; p::vector(0,next,curr).move_to(primitives); CImg::vector(1,curr + 1,next + 1).move_to(primitives); CImg::vector(curr,next,next + 1,curr + 1).move_to(primitives); } return vertices>'x'; } //! Generate a 3d torus. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param radius1 The large radius. \param radius2 The small radius. \param subdivisions1 The number of angular subdivisions for the large radius. \param subdivisions2 The number of angular subdivisions for the small radius. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::torus3d(faces3d,20,4); CImg().display_object3d("Torus3d",points3d,faces3d); \endcode \image html ref_torus3d.jpg **/ template static CImg torus3d(CImgList& primitives, const float radius1=100, const float radius2=30, const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) { primitives.assign(); if (!subdivisions1 || !subdivisions2) return CImg(); CImgList vertices; for (unsigned int v = 0; v::vector(x,y,z).move_to(vertices); } } for (unsigned int vv = 0; vv::vector(svv + nu,svv + uu,snv + uu,snv + nu).move_to(primitives); } } return vertices>'x'; } //! Generate a 3d XY-plane. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param size_x The width of the plane (dimension along the X-axis). \param size_y The height of the plane (dimensions along the Y-axis). \param subdivisions_x The number of planar subdivisions along the X-axis. \param subdivisions_y The number of planar subdivisions along the Y-axis. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::plane3d(faces3d,100,50); CImg().display_object3d("Plane3d",points3d,faces3d); \endcode \image html ref_plane3d.jpg **/ template static CImg plane3d(CImgList& primitives, const float size_x=100, const float size_y=100, const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10) { primitives.assign(); if (!subdivisions_x || !subdivisions_y) return CImg(); CImgList vertices; const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1; const float fx = (float)size_x/w, fy = (float)size_y/h; for (unsigned int y = 0; y::vector(fx*x,fy*y,0).move_to(vertices); for (unsigned int y = 0; y::vector(off1,off4,off3,off2).move_to(primitives); } return vertices>'x'; } //! Generate a 3d sphere. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param radius The radius of the sphere (dimension along the X-axis). \param subdivisions The number of recursive subdivisions from an initial icosahedron. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg points3d = CImg::sphere3d(faces3d,100,4); CImg().display_object3d("Sphere3d",points3d,faces3d); \endcode \image html ref_sphere3d.jpg **/ template static CImg sphere3d(CImgList& primitives, const float radius=50, const unsigned int subdivisions=3) { // Create initial icosahedron primitives.assign(); const double tmp = (1 + std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1 + tmp*tmp), b = tmp*a; CImgList vertices(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b, -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a); primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6, 8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3, 5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2); // edge - length/2 float he = (float)a; // Recurse subdivisions for (unsigned int i = 0; i::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices.width() - 1; } if (i1<0) { CImg::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices.width() - 1; } if (i2<0) { CImg::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices.width() - 1; } primitives.remove(0); CImg::vector(p0,i0,i1).move_to(primitives); CImg::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives); CImg::vector((tf)i1,(tf)i2,(tf)p2).move_to(primitives); CImg::vector((tf)i1,(tf)i0,(tf)i2).move_to(primitives); } } return (vertices>'x')*=radius; } //! Generate a 3d ellipsoid. /** \param[out] primitives The returned list of the 3d object primitives (template type \e tf should be at least \e unsigned \e int). \param tensor The tensor which gives the shape and size of the ellipsoid. \param subdivisions The number of recursive subdivisions from an initial stretched icosahedron. \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; const CImg tensor = CImg::diagonal(10,7,3), points3d = CImg::ellipsoid3d(faces3d,tensor,4); CImg().display_object3d("Ellipsoid3d",points3d,faces3d); \endcode \image html ref_ellipsoid3d.jpg **/ template static CImg ellipsoid3d(CImgList& primitives, const CImg& tensor, const unsigned int subdivisions=3) { primitives.assign(); if (!subdivisions) return CImg(); CImg S, V; tensor.symmetric_eigen(S,V); const float orient = (V(0,1)*V(1,2) - V(0,2)*V(1,1))*V(2,0) + (V(0,2)*V(1,0) - V(0,0)*V(1,2))*V(2,1) + (V(0,0)*V(1,1) - V(0,1)*V(1,0))*V(2,2); if (orient<0) { V(2,0) = -V(2,0); V(2,1) = -V(2,1); V(2,2) = -V(2,2); } const float l0 = S[0], l1 = S[1], l2 = S[2]; CImg vertices = sphere3d(primitives,1.0,subdivisions); vertices.get_shared_row(0)*=l0; vertices.get_shared_row(1)*=l1; vertices.get_shared_row(2)*=l2; return V*vertices; } //! Convert 3d object into a CImg3d representation. /** \param primitives Primitives data of the 3d object. \param colors Colors data of the 3d object. \param opacities Opacities data of the 3d object. \param full_check Tells if full checking of the 3d object must be performed. **/ template CImg& object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const to& opacities, const bool full_check=true) { return get_object3dtoCImg3d(primitives,colors,opacities,full_check).move_to(*this); } //! Convert 3d object into a CImg3d representation \overloading. template CImg& object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const bool full_check=true) { return get_object3dtoCImg3d(primitives,colors,full_check).move_to(*this); } //! Convert 3d object into a CImg3d representation \overloading. template CImg& object3dtoCImg3d(const CImgList& primitives, const bool full_check=true) { return get_object3dtoCImg3d(primitives,full_check).move_to(*this); } //! Convert 3d object into a CImg3d representation \overloading. CImg& object3dtoCImg3d(const bool full_check=true) { return get_object3dtoCImg3d(full_check).move_to(*this); } //! Convert 3d object into a CImg3d representation \newinstance. template CImg get_object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const to& opacities, const bool full_check=true) const { CImg error_message(1024); if (!is_object3d(primitives,colors,opacities,full_check,error_message)) throw CImgInstanceException(_cimg_instance "object3dtoCImg3d(): Invalid specified 3d object (%u,%u) (%s).", cimg_instance,_width,primitives._width,error_message.data()); CImg res(1,_size_object3dtoCImg3d(primitives,colors,opacities)); float *ptrd = res._data; // Put magick number. *(ptrd++) = 'C' + 0.5f; *(ptrd++) = 'I' + 0.5f; *(ptrd++) = 'm' + 0.5f; *(ptrd++) = 'g' + 0.5f; *(ptrd++) = '3' + 0.5f; *(ptrd++) = 'd' + 0.5f; // Put number of vertices and primitives. *(ptrd++) = cimg::uint2float(_width); *(ptrd++) = cimg::uint2float(primitives._width); // Put vertex data. if (is_empty() || !primitives) return res; const T *ptrx = data(0,0), *ptry = data(0,1), *ptrz = data(0,2); cimg_forX(*this,p) { *(ptrd++) = (float)*(ptrx++); *(ptrd++) = (float)*(ptry++); *(ptrd++) = (float)*(ptrz++); } // Put primitive data. cimglist_for(primitives,p) { *(ptrd++) = (float)primitives[p].size(); const tp *ptrp = primitives[p]._data; cimg_foroff(primitives[p],i) *(ptrd++) = cimg::uint2float((unsigned int)*(ptrp++)); } // Put color/texture data. const unsigned int csiz = cimg::min(colors._width,primitives._width); for (int c = 0; c<(int)csiz; ++c) { const CImg& color = colors[c]; const tc *ptrc = color._data; if (color.size()==3) { *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*ptrc; } else { *(ptrd++) = -128.0f; int shared_ind = -1; if (color.is_shared()) for (int i = 0; i float* _object3dtoCImg3d(const CImgList& opacities, float *ptrd) const { cimglist_for(opacities,o) { const CImg& opacity = opacities[o]; const to *ptro = opacity._data; if (opacity.size()==1) *(ptrd++) = (float)*ptro; else { *(ptrd++) = -128.0f; int shared_ind = -1; if (opacity.is_shared()) for (int i = 0; i float* _object3dtoCImg3d(const CImg& opacities, float *ptrd) const { const to *ptro = opacities._data; cimg_foroff(opacities,o) *(ptrd++) = (float)*(ptro++); return ptrd; } template unsigned int _size_object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const CImgList& opacities) const { unsigned int siz = 8U + 3*_width; cimglist_for(primitives,p) siz+=primitives[p].size() + 1; for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) { if (colors[c].is_shared()) siz+=4; else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; } } if (colors._width unsigned int _size_object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const CImg& opacities) const { unsigned int siz = 8U + 3*_width; cimglist_for(primitives,p) siz+=primitives[p].size() + 1; for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; } if (colors._width CImg get_object3dtoCImg3d(const CImgList& primitives, const CImgList& colors, const bool full_check=true) const { CImgList opacities; return get_object3dtoCImg3d(primitives,colors,opacities,full_check); } //! Convert 3d object into a CImg3d representation \overloading. template CImg get_object3dtoCImg3d(const CImgList& primitives, const bool full_check=true) const { CImgList colors, opacities; return get_object3dtoCImg3d(primitives,colors,opacities,full_check); } //! Convert 3d object into a CImg3d representation \overloading. CImg get_object3dtoCImg3d(const bool full_check=true) const { CImgList opacities, colors; CImgList primitives(width(),1,1,1,1); cimglist_for(primitives,p) primitives(p,0) = p; return get_object3dtoCImg3d(primitives,colors,opacities,full_check); } //! Convert CImg3d representation into a 3d object. /** \param[out] primitives Primitives data of the 3d object. \param[out] colors Colors data of the 3d object. \param[out] opacities Opacities data of the 3d object. \param full_check Tells if full checking of the 3d object must be performed. **/ template CImg& CImg3dtoobject3d(CImgList& primitives, CImgList& colors, CImgList& opacities, const bool full_check=true) { return get_CImg3dtoobject3d(primitives,colors,opacities,full_check).move_to(*this); } //! Convert CImg3d representation into a 3d object \newinstance. template CImg get_CImg3dtoobject3d(CImgList& primitives, CImgList& colors, CImgList& opacities, const bool full_check=true) const { CImg error_message(1024); if (!is_CImg3d(full_check,error_message)) throw CImgInstanceException(_cimg_instance "CImg3dtoobject3d(): image instance is not a CImg3d (%s).", cimg_instance,error_message.data()); const T *ptrs = _data + 6; const unsigned int nb_points = cimg::float2uint((float)*(ptrs++)), nb_primitives = cimg::float2uint((float)*(ptrs++)); const CImg points = CImg(ptrs,3,nb_points,1,1,true).get_transpose(); ptrs+=3*nb_points; primitives.assign(nb_primitives); cimglist_for(primitives,p) { const unsigned int nb_inds = (unsigned int)*(ptrs++); primitives[p].assign(1,nb_inds); tp *ptrp = primitives[p]._data; for (unsigned int i = 0; i CImg& _draw_scanline(const int x0, const int x1, const int y, const tc *const color, const float opacity, const float brightness, const float nopacity, const float copacity, const ulongT whd) { static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const int nx0 = x0>0?x0:0, nx1 = x1=0) { const tc *col = color; const ulongT off = whd - dx - 1; T *ptrd = data(nx0,y); if (opacity>=1) { // ** Opaque drawing ** if (brightness==1) { // Brightness==1 if (sizeof(T)!=1) cimg_forC(*this,c) { const T val = (T)*(col++); for (int x = dx; x>=0; --x) *(ptrd++) = val; ptrd+=off; } else cimg_forC(*this,c) { const T val = (T)*(col++); std::memset(ptrd,(int)val,dx + 1); ptrd+=whd; } } else if (brightness<1) { // Brightness<1 if (sizeof(T)!=1) cimg_forC(*this,c) { const T val = (T)(*(col++)*brightness); for (int x = dx; x>=0; --x) *(ptrd++) = val; ptrd+=off; } else cimg_forC(*this,c) { const T val = (T)(*(col++)*brightness); std::memset(ptrd,(int)val,dx + 1); ptrd+=whd; } } else { // Brightness>1 if (sizeof(T)!=1) cimg_forC(*this,c) { const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval); for (int x = dx; x>=0; --x) *(ptrd++) = val; ptrd+=off; } else cimg_forC(*this,c) { const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval); std::memset(ptrd,(int)val,dx + 1); ptrd+=whd; } } } else { // ** Transparent drawing ** if (brightness==1) { // Brightness==1 cimg_forC(*this,c) { const T val = (T)*(col++); for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } ptrd+=off; } } else if (brightness<=1) { // Brightness<1 cimg_forC(*this,c) { const T val = (T)(*(col++)*brightness); for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } ptrd+=off; } } else { // Brightness>1 cimg_forC(*this,c) { const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval); for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } ptrd+=off; } } } } return *this; } //! Draw a 3d point. /** \param x0 X-coordinate of the point. \param y0 Y-coordinate of the point. \param z0 Z-coordinate of the point. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \note - To set pixel values without clipping needs, you should use the faster CImg::operator()() function. \par Example: \code CImg img(100,100,1,3,0); const unsigned char color[] = { 255,128,64 }; img.draw_point(50,50,color); \endcode **/ template CImg& draw_point(const int x0, const int y0, const int z0, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_point(): Specified color is (null).", cimg_instance); if (x0>=0 && y0>=0 && z0>=0 && x0=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } } return *this; } //! Draw a 2d point \simplification. template CImg& draw_point(const int x0, const int y0, const tc *const color, const float opacity=1) { return draw_point(x0,y0,0,color,opacity); } // Draw a points cloud. /** \param points Image of vertices coordinates. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_point(const CImg& points, const tc *const color, const float opacity=1) { if (is_empty() || !points) return *this; switch (points._height) { case 0 : case 1 : throw CImgArgumentException(_cimg_instance "draw_point(): Invalid specified point set (%u,%u,%u,%u,%p).", cimg_instance, points._width,points._height,points._depth,points._spectrum,points._data); case 2 : { cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),color,opacity); } break; default : { cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),(int)points(i,2),color,opacity); } } return *this; } //! Draw a 2d line. /** \param x0 X-coordinate of the starting line point. \param y0 Y-coordinate of the starting line point. \param x1 X-coordinate of the ending line point. \param y1 Y-coordinate of the ending line point. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if a reinitialization of the hash state must be done. \note - Line routine uses Bresenham's algorithm. - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern. \par Example: \code CImg img(100,100,1,3,0); const unsigned char color[] = { 255,128,64 }; img.draw_line(40,40,80,70,color); \endcode **/ template CImg& draw_line(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_line(): Specified color is (null).", cimg_instance); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { yleft-=(int)((float)xleft*((float)yright - yleft)/((float)xright - xleft)); xleft = 0; } if (xright>=width()) { yright-=(int)(((float)xright - width())*((float)yright - yleft)/((float)xright - xleft)); xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { xup-=(int)((float)yup*((float)xdown - xup)/((float)ydown - yup)); yup = 0; } if (ydown>=height()) { xdown-=(int)(((float)ydown - height())*((float)xdown - xup)/((float)ydown - yup)); ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); int dx = xright - xleft, dy = ydown - yup; const bool steep = dy>dx; if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); const longT offx = (longT)(nx0=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } return *this; } //! Draw a 2d line, with z-buffering. /** \param zbuffer Zbuffer image. \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param z0 Z-coordinate of the starting point \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param z1 Z-coordinate of the ending point. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if a reinitialization of the hash state must be done. **/ template CImg& draw_line(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_line(): Specified color is (null).", cimg_instance); if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { const float D = (float)xright - xleft; yleft-=(int)((float)xleft*((float)yright - yleft)/D); zleft-=(tzfloat)xleft*(zright - zleft)/D; xleft = 0; } if (xright>=width()) { const float d = (float)xright - width(), D = (float)xright - xleft; yright-=(int)(d*((float)yright - yleft)/D); zright-=(tzfloat)d*(zright - zleft)/D; xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { const float D = (float)ydown - yup; xup-=(int)((float)yup*((float)xdown - xup)/D); zup-=(tzfloat)yup*(zdown - zup)/D; yup = 0; } if (ydown>=height()) { const float d = (float)ydown - height(), D = (float)ydown - yup; xdown-=(int)(d*((float)xdown - xup)/D); zdown-=(tzfloat)d*(zdown - zup)/D; ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); tz *ptrz = zbuffer.data(nx0,ny0); int dx = xright - xleft, dy = ydown - yup; const bool steep = dy>dx; if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); const longT offx = (longT)(nx00?dx:1); if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz && pattern&hatch) { *ptrz = (tz)z; T *ptrd = ptrd0; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; T *ptrd = ptrd0; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } } ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz && pattern&hatch) { *ptrz = (tz)z; T *ptrd = ptrd0; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; T *ptrd = ptrd0; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } } ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } } return *this; } //! Draw a 3d line. /** \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param z0 Z-coordinate of the starting point \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param z1 Z-coordinate of the ending point. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if a reinitialization of the hash state must be done. **/ template CImg& draw_line(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_line(): Specified color is (null).", cimg_instance); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1; if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (nx1<0 || nx0>=width()) return *this; if (nx0<0) { const float D = 1.0f + nx1 - nx0; ny0-=(int)((float)nx0*(1.0f + ny1 - ny0)/D); nz0-=(int)((float)nx0*(1.0f + nz1 - nz0)/D); nx0 = 0; } if (nx1>=width()) { const float d = (float)nx1 - width(), D = 1.0f + nx1 - nx0; ny1+=(int)(d*(1.0f + ny0 - ny1)/D); nz1+=(int)(d*(1.0f + nz0 - nz1)/D); nx1 = width() - 1; } if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (ny1<0 || ny0>=height()) return *this; if (ny0<0) { const float D = 1.0f + ny1 - ny0; nx0-=(int)((float)ny0*(1.0f + nx1 - nx0)/D); nz0-=(int)((float)ny0*(1.0f + nz1 - nz0)/D); ny0 = 0; } if (ny1>=height()) { const float d = (float)ny1 - height(), D = 1.0f + ny1 - ny0; nx1+=(int)(d*(1.0f + nx0 - nx1)/D); nz1+=(int)(d*(1.0f + nz0 - nz1)/D); ny1 = height() - 1; } if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (nz1<0 || nz0>=depth()) return *this; if (nz0<0) { const float D = 1.0f + nz1 - nz0; nx0-=(int)((float)nz0*(1.0f + nx1 - nx0)/D); ny0-=(int)((float)nz0*(1.0f + ny1 - ny0)/D); nz0 = 0; } if (nz1>=depth()) { const float d = (float)nz1 - depth(), D = 1.0f + nz1 - nz0; nx1+=(int)(d*(1.0f + nx0 - nx1)/D); ny1+=(int)(d*(1.0f + ny0 - ny1)/D); nz1 = depth() - 1; } const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0); const ulongT whd = (ulongT)_width*_height*_depth; const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax; float x = (float)nx0, y = (float)ny0, z = (float)nz0; if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) { if (!(~pattern) || (~pattern && pattern&hatch)) { T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z); const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } } x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); for (unsigned int t = 0; t<=dmax; ++t) { if (!(~pattern) || (~pattern && pattern&hatch)) { T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z); const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } } x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); } } } return *this; } //! Draw a textured 2d line. /** \param x0 X-coordinate of the starting line point. \param y0 Y-coordinate of the starting line point. \param x1 X-coordinate of the ending line point. \param y1 Y-coordinate of the ending line point. \param texture Texture image defining the pixel colors. \param tx0 X-coordinate of the starting texture point. \param ty0 Y-coordinate of the starting texture point. \param tx1 X-coordinate of the ending texture point. \param ty1 Y-coordinate of the ending texture point. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if the hash variable must be reinitialized. \note - Line routine uses the well known Bresenham's algorithm. \par Example: \code CImg img(100,100,1,3,0), texture("texture256x256.ppm"); const unsigned char color[] = { 255,128,64 }; img.draw_line(40,40,80,70,texture,0,0,255,255); \endcode **/ template CImg& draw_line(const int x0, const int y0, const int x1, const int y1, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty()) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { const float D = (float)xright - xleft; yleft-=(int)((float)xleft*((float)yright - yleft)/D); txleft-=(int)((float)xleft*((float)txright - txleft)/D); tyleft-=(int)((float)xleft*((float)tyright - tyleft)/D); xleft = 0; } if (xright>=width()) { const float d = (float)xright - width(), D = (float)xright - xleft; yright-=(int)(d*((float)yright - yleft)/D); txright-=(int)(d*((float)txright - txleft)/D); tyright-=(int)(d*((float)tyright - tyleft)/D); xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { const float D = (float)ydown - yup; xup-=(int)((float)yup*((float)xdown - xup)/D); txup-=(int)((float)yup*((float)txdown - txup)/D); tyup-=(int)((float)yup*((float)tydown - tyup)/D); yup = 0; } if (ydown>=height()) { const float d = (float)ydown - height(), D = (float)ydown - yup; xdown-=(int)(d*((float)xdown - xup)/D); txdown-=(int)(d*((float)txdown - txup)/D); tydown-=(int)(d*((float)tydown - tyup)/D); ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); int dx = xright - xleft, dy = ydown - yup; const bool steep = dy>dx; if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); const longT offx = (longT)(nx00?dx:1); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; const tc *col = &texture._atXY(tx,ty); cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; const tc *col = &texture._atXY(tx,ty); cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; if (pattern&hatch) { const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; const tc *col = &texture._atXY(tx,ty); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; const tc *col = &texture._atXY(tx,ty); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } return *this; } //! Draw a textured 2d line, with perspective correction. /** \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param z0 Z-coordinate of the starting point \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param z1 Z-coordinate of the ending point. \param texture Texture image defining the pixel colors. \param tx0 X-coordinate of the starting texture point. \param ty0 Y-coordinate of the starting texture point. \param tx1 X-coordinate of the ending texture point. \param ty1 Y-coordinate of the ending texture point. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if the hash variable must be reinitialized. **/ template CImg& draw_line(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty() && z0<=0 && z1<=0) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { const float D = (float)xright - xleft; yleft-=(int)((float)xleft*((float)yright - yleft)/D); zleft-=(float)xleft*(zright - zleft)/D; txleft-=(float)xleft*(txright - txleft)/D; tyleft-=(float)xleft*(tyright - tyleft)/D; xleft = 0; } if (xright>=width()) { const float d = (float)xright - width(), D = (float)xright - xleft; yright-=(int)(d*((float)yright - yleft)/D); zright-=d*(zright - zleft)/D; txright-=d*(txright - txleft)/D; tyright-=d*(tyright - tyleft)/D; xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { const float D = (float)ydown - yup; xup-=(int)((float)yup*((float)xdown - xup)/D); zup-=(float)yup*(zdown - zup)/D; txup-=(float)yup*(txdown - txup)/D; tyup-=(float)yup*(tydown - tyup)/D; yup = 0; } if (ydown>=height()) { const float d = (float)ydown - height(), D = (float)ydown - yup; xdown-=(int)(d*((float)xdown - xup)/D); zdown-=d*(zdown - zup)/D; txdown-=d*(txdown - txup)/D; tydown-=d*(tydown - tyup)/D; ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); int dx = xright - xleft, dy = ydown - yup; const bool steep = dy>dx; if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); const longT offx = (longT)(nx00?dx:1); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } } return *this; } //! Draw a textured 2d line, with perspective correction and z-buffering. /** \param zbuffer Z-buffer image. \param x0 X-coordinate of the starting point. \param y0 Y-coordinate of the starting point. \param z0 Z-coordinate of the starting point \param x1 X-coordinate of the ending point. \param y1 Y-coordinate of the ending point. \param z1 Z-coordinate of the ending point. \param texture Texture image defining the pixel colors. \param tx0 X-coordinate of the starting texture point. \param ty0 Y-coordinate of the starting texture point. \param tx1 X-coordinate of the ending texture point. \param ty1 Y-coordinate of the ending texture point. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch Tells if the hash variable must be reinitialized. **/ template CImg& draw_line(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0) return *this; if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); static unsigned int hatch = ~0U - (~0U>>1); if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { const float D = (float)xright - xleft; yleft-=(int)((float)xleft*((float)yright - yleft)/D); zleft-=(float)xleft*(zright - zleft)/D; txleft-=(float)xleft*(txright - txleft)/D; tyleft-=(float)xleft*(tyright - tyleft)/D; xleft = 0; } if (xright>=width()) { const float d = (float)xright - width(), D = (float)xright - xleft; yright-=(int)(d*((float)yright - yleft)/D); zright-=d*(zright - zleft)/D; txright-=d*(txright - txleft)/D; tyright-=d*(tyright - tyleft)/D; xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { const float D = (float)ydown - yup; xup-=(int)((float)yup*((float)xdown - xup)/D); zup-=yup*(zdown - zup)/D; txup-=yup*(txdown - txup)/D; tyup-=yup*(tydown - tyup)/D; yup = 0; } if (ydown>=height()) { const float d = (float)ydown - height(), D = (float)ydown - yup; xdown-=(int)(d*((float)xdown - xup)/D); zdown-=d*(zdown - zup)/D; txdown-=d*(txdown - txup)/D; tydown-=d*(tydown - tyup)/D; ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); tz *ptrz = zbuffer.data(nx0,ny0); int dx = xright - xleft, dy = ydown - yup; const bool steep = dy>dx; if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); const longT offx = (longT)(nx00?dx:1); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } } else { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } ptrd0+=offx; ptrz+=offx; if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } } } return *this; } //! Draw a set of consecutive lines. /** \param points Coordinates of vertices, stored as a list of vectors. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch If set to true, init hatch motif. \note - This function uses several call to the single CImg::draw_line() procedure, depending on the vectors size in \p points. **/ template CImg& draw_line(const CImg& points, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty() || !points || points._width<2) return *this; bool ninit_hatch = init_hatch; switch (points._height) { case 0 : case 1 : throw CImgArgumentException(_cimg_instance "draw_line(): Invalid specified point set (%u,%u,%u,%u,%p).", cimg_instance, points._width,points._height,points._depth,points._spectrum,points._data); case 2 : { const int x0 = (int)points(0,0), y0 = (int)points(0,1); int ox = x0, oy = y0; for (unsigned int i = 1; i CImg& draw_arrow(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1, const float angle=30, const float length=-10, const unsigned int pattern=~0U) { if (is_empty()) return *this; const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v, deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f, l = (length>=0)?length:-length*(float)std::sqrt(sq)/100; if (sq>0) { const float cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg), cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg); const int xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl), xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr), xc = x1 + (int)((l + 1)*(cl + cr))/2, yc = y1 + (int)((l + 1)*(sl + sr))/2; draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); } else draw_point(x0,y0,color,opacity); return *this; } //! Draw a 2d spline. /** \param x0 X-coordinate of the starting curve point \param y0 Y-coordinate of the starting curve point \param u0 X-coordinate of the starting velocity \param v0 Y-coordinate of the starting velocity \param x1 X-coordinate of the ending curve point \param y1 Y-coordinate of the ending curve point \param u1 X-coordinate of the ending velocity \param v1 Y-coordinate of the ending velocity \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param precision Curve drawing precision. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch If \c true, init hatch motif. \note - The curve is a 2d cubic Bezier spline, from the set of specified starting/ending points and corresponding velocity vectors. - The spline is drawn as a serie of connected segments. The \p precision parameter sets the average number of pixels in each drawn segment. - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), (\p xb,\p yb), (\p x1,\p y1) } where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point and (\p xa,\p ya), (\p xb,\p yb) are two \e control points. The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb). \par Example: \code CImg img(100,100,1,3,0); const unsigned char color[] = { 255,255,255 }; img.draw_spline(30,30,0,100,90,40,0,-100,color); \endcode **/ template CImg& draw_spline(const int x0, const int y0, const float u0, const float v0, const int x1, const int y1, const float u1, const float v1, const tc *const color, const float opacity=1, const float precision=0.25, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_spline(): Specified color is (null).", cimg_instance); if (x0==x1 && y0==y1) return draw_point(x0,y0,color,opacity); bool ninit_hatch = init_hatch; const float ax = u0 + u1 + 2*(x0 - x1), bx = 3*(x1 - x0) - 2*u0 - u1, ay = v0 + v1 + 2*(y0 - y1), by = 3*(y1 - y0) - 2*v0 - v1, _precision = 1/(std::sqrt(cimg::sqr((float)x0 - x1) + cimg::sqr((float)y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0; for (float t = 0; t<1; t+=_precision) { const float t2 = t*t, t3 = t2*t; const int nx = (int)(ax*t3 + bx*t2 + u0*t + x0), ny = (int)(ay*t3 + by*t2 + v0*t + y0); draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch); ninit_hatch = false; ox = nx; oy = ny; } return draw_line(ox,oy,x1,y1,color,opacity,pattern,false); } //! Draw a 3d spline \overloading. /** \note - Similar to CImg::draw_spline() for a 3d spline in a volumetric image. **/ template CImg& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0, const int x1, const int y1, const int z1, const float u1, const float v1, const float w1, const tc *const color, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_spline(): Specified color is (null).", cimg_instance); if (x0==x1 && y0==y1 && z0==z1) return draw_point(x0,y0,z0,color,opacity); bool ninit_hatch = init_hatch; const float ax = u0 + u1 + 2*(x0 - x1), bx = 3*(x1 - x0) - 2*u0 - u1, ay = v0 + v1 + 2*(y0 - y1), by = 3*(y1 - y0) - 2*v0 - v1, az = w0 + w1 + 2*(z0 - z1), bz = 3*(z1 - z0) - 2*w0 - w1, _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0, oz = z0; for (float t = 0; t<1; t+=_precision) { const float t2 = t*t, t3 = t2*t; const int nx = (int)(ax*t3 + bx*t2 + u0*t + x0), ny = (int)(ay*t3 + by*t2 + v0*t + y0), nz = (int)(az*t3 + bz*t2 + w0*t + z0); draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch); ninit_hatch = false; ox = nx; oy = ny; oz = nz; } return draw_line(ox,oy,oz,x1,y1,z1,color,opacity,pattern,false); } //! Draw a textured 2d spline. /** \param x0 X-coordinate of the starting curve point \param y0 Y-coordinate of the starting curve point \param u0 X-coordinate of the starting velocity \param v0 Y-coordinate of the starting velocity \param x1 X-coordinate of the ending curve point \param y1 Y-coordinate of the ending curve point \param u1 X-coordinate of the ending velocity \param v1 Y-coordinate of the ending velocity \param texture Texture image defining line pixel colors. \param tx0 X-coordinate of the starting texture point. \param ty0 Y-coordinate of the starting texture point. \param tx1 X-coordinate of the ending texture point. \param ty1 Y-coordinate of the ending texture point. \param precision Curve drawing precision. \param opacity Drawing opacity. \param pattern An integer whose bits describe the line pattern. \param init_hatch if \c true, reinit hatch motif. **/ template CImg& draw_spline(const int x0, const int y0, const float u0, const float v0, const int x1, const int y1, const float u1, const float v1, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true) { if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_spline(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_empty()) return *this; if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch); if (x0==x1 && y0==y1) return draw_point(x0,y0,texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, y0<=0?0:y0>=texture.height()?texture.height() - 1:y0),opacity); bool ninit_hatch = init_hatch; const float ax = u0 + u1 + 2*(x0 - x1), bx = 3*(x1 - x0) - 2*u0 - u1, ay = v0 + v1 + 2*(y0 - y1), by = 3*(y1 - y0) - 2*v0 - v1, _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0, otx = tx0, oty = ty0; for (float t1 = 0; t1<1; t1+=_precision) { const float t2 = t1*t1, t3 = t2*t1; const int nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0), ny = (int)(ay*t3 + by*t2 + v0*t1 + y0), ntx = tx0 + (int)((tx1 - tx0)*t1), nty = ty0 + (int)((ty1 - ty0)*t1); draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch); ninit_hatch = false; ox = nx; oy = ny; otx = ntx; oty = nty; } return draw_line(ox,oy,x1,y1,texture,otx,oty,tx1,ty1,opacity,pattern,false); } //! Draw a set of consecutive splines. /** \param points Vertices data. \param tangents Tangents data. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param is_closed_set Tells if the drawn spline set is closed. \param precision Precision of the drawing. \param pattern An integer whose bits describe the line pattern. \param init_hatch If \c true, init hatch motif. **/ template CImg& draw_spline(const CImg& points, const CImg& tangents, const tc *const color, const float opacity=1, const bool is_closed_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty() || !points || !tangents || points._width<2 || tangents._width<2) return *this; bool ninit_hatch = init_hatch; switch (points._height) { case 0 : case 1 : throw CImgArgumentException(_cimg_instance "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).", cimg_instance, points._width,points._height,points._depth,points._spectrum,points._data); case 2 : { const int x0 = (int)points(0,0), y0 = (int)points(0,1); const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1); int ox = x0, oy = y0; float ou = u0, ov = v0; for (unsigned int i = 1; i CImg& draw_spline(const CImg& points, const tc *const color, const float opacity=1, const bool is_closed_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true) { if (is_empty() || !points || points._width<2) return *this; CImg tangents; switch (points._height) { case 0 : case 1 : throw CImgArgumentException(_cimg_instance "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).", cimg_instance, points._width,points._height,points._depth,points._spectrum,points._data); case 2 : { tangents.assign(points._width,points._height); cimg_forX(points,p) { const unsigned int p0 = is_closed_set?(p + points._width - 1)%points._width:(p?p - 1:0), p1 = is_closed_set?(p + 1)%points._width:(p + 1=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ _sxn=1, \ _sxr=1, \ _sxl=1, \ _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \ _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \ _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, \ _errr = _dyr/2, \ _errl = _dyl/2, \ _rxn = _dyn?(x2-x1)/_dyn:0, \ _rxr = _dyr?(x2-x0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \ for (int y = y0<0?0:y0, \ xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \ xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \ _sxn=1, _scn=1, \ _sxr=1, _scr=1, \ _sxl=1, _scl=1, \ _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \ _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \ _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \ _dcn = c2>c1?c2-c1:(_scn=-1,c1 - c2), \ _dcr = c2>c0?c2-c0:(_scr=-1,c0 - c2), \ _dcl = c1>c0?c1-c0:(_scl=-1,c0 - c1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \ _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \ _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \ cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errcn = _errn, \ _errr = _dyr/2, _errcr = _errr, \ _errl = _dyl/2, _errcl = _errl, \ _rxn = _dyn?(x2 - x1)/_dyn:0, \ _rcn = _dyn?(c2 - c1)/_dyn:0, \ _rxr = _dyr?(x2 - x0)/_dyr:0, \ _rcr = _dyr?(c2 - c0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \ xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \ _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \ for (int y = y0<0?0:y0, \ xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ _sxn=1, _stxn=1, _styn=1, \ _sxr=1, _stxr=1, _styr=1, \ _sxl=1, _stxl=1, _styl=1, \ _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \ _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \ _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \ _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \ _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \ _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \ _rxn = _dyn?(x2 - x1)/_dyn:0, \ _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ _rxr = _dyr?(x2 - x0)/_dyr:0, \ _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\ _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \ for (int y = y0<0?0:y0, \ xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \ txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \ txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ _sxn=1, _scn=1, _stxn=1, _styn=1, \ _sxr=1, _scr=1, _stxr=1, _styr=1, \ _sxl=1, _scl=1, _stxl=1, _styl=1, \ _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \ _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \ _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \ _dcn = c2>c1?c2 - c1:(_scn=-1,c1 - c2), \ _dcr = c2>c0?c2 - c0:(_scr=-1,c0 - c2), \ _dcl = c1>c0?c1 - c0:(_scl=-1,c0 - c1), \ _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ _dyn = y2 - y1, \ _dyr = y2 - y0, \ _dyl = y1 - y0, \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \ _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \ _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \ _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \ _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \ _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \ _rxn = _dyn?(x2 - x1)/_dyn:0, \ _rcn = _dyn?(c2 - c1)/_dyn:0, \ _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ _rxr = _dyr?(x2 - x0)/_dyr:0, \ _rcr = _dyr?(c2 - c0)/_dyr:0, \ _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ _rcl = (y0!=y1 && y1>0)?(_dyl?(c1 - c0)/_dyl:0): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \ _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \ txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \ txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,\ tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \ for (int y = y0<0?0:y0, \ xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ lxr = y0>=0?lx0:(lx0 - y0*(lx2 - lx0)/(y2 - y0)), \ lyr = y0>=0?ly0:(ly0 - y0*(ly2 - ly0)/(y2 - y0)), \ xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0 - y0*(lx1 - lx0)/(y1 - y0))):(lx1 - y1*(lx2 - lx1)/(y2 - y1)), \ lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0 - y0*(ly1 - ly0)/(y1 - y0))):(ly1 - y1*(ly2 - ly1)/(y2 - y1)), \ _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \ _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \ _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \ _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), _dyn = y2 - y1, \ _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), _dyr = y2 - y0, \ _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), _dyl = y1 - y0, \ _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ _dlxn = lx2>lx1?lx2 - lx1:(_slxn=-1,lx1 - lx2), \ _dlxr = lx2>lx0?lx2 - lx0:(_slxr=-1,lx0 - lx2), \ _dlxl = lx1>lx0?lx1 - lx0:(_slxl=-1,lx0 - lx1), \ _dlyn = ly2>ly1?ly2 - ly1:(_slyn=-1,ly1 - ly2), \ _dlyr = ly2>ly0?ly2 - ly0:(_slyr=-1,ly0 - ly2), \ _dlyl = ly1>ly0?ly1 - ly0:(_slyl=-1,ly0 - ly1), \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \ _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \ _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \ _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \ _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \ _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \ cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \ _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \ _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \ _rxn = _dyn?(x2 - x1)/_dyn:0, \ _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ _rlxn = _dyn?(lx2 - lx1)/_dyn:0, \ _rlyn = _dyn?(ly2 - ly1)/_dyn:0, \ _rxr = _dyr?(x2 - x0)/_dyr:0, \ _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ _rlxr = _dyr?(lx2 - lx0)/_dyr:0, \ _rlyr = _dyr?(ly2 - ly0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \ _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1 - lx0)/_dyl:0): \ (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \ _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1 - ly0)/_dyl:0): \ (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \ lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \ xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \ lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \ _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \ _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \ _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) // [internal] Draw a filled triangle. template CImg& _draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity, const float brightness) { cimg_init_scanline(color,opacity); const float nbrightness = brightness<0?0:(brightness>2?2:brightness); int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2); if (ny0=0) { if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0) _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) cimg_draw_scanline(xl,xr,y,color,opacity,nbrightness); else _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) cimg_draw_scanline(xr,xl,y,color,opacity,nbrightness); } return *this; } //! Draw a filled 2d triangle. /** \param x0 X-coordinate of the first vertex. \param y0 Y-coordinate of the first vertex. \param x1 X-coordinate of the second vertex. \param y1 Y-coordinate of the second vertex. \param x2 X-coordinate of the third vertex. \param y2 Y-coordinate of the third vertex. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1); return *this; } //! Draw a outlined 2d triangle. /** \param x0 X-coordinate of the first vertex. \param y0 Y-coordinate of the first vertex. \param x1 X-coordinate of the second vertex. \param y1 Y-coordinate of the second vertex. \param x2 X-coordinate of the third vertex. \param y2 Y-coordinate of the third vertex. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the outline pattern. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity, const unsigned int pattern) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); draw_line(x0,y0,x1,y1,color,opacity,pattern,true). draw_line(x1,y1,x2,y2,color,opacity,pattern,false). draw_line(x2,y2,x0,y0,color,opacity,pattern,false); return *this; } //! Draw a filled 2d triangle, with z-buffering. /** \param zbuffer Z-buffer image. \param x0 X-coordinate of the first vertex. \param y0 Y-coordinate of the first vertex. \param z0 Z-coordinate of the first vertex. \param x1 X-coordinate of the second vertex. \param y1 Y-coordinate of the second vertex. \param z1 Z-coordinate of the second vertex. \param x2 X-coordinate of the third vertex. \param y2 Y-coordinate of the third vertex. \param z2 Z-coordinate of the third vertex. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. \param brightness Brightness factor. **/ template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const float opacity=1, const float brightness=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { if (y==ny1) { zl = nz1; pzl = pzn; } int xleft = xleft0, xright = xright0; tzfloat zleft = zl, zright = zr; if (xright=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0; if (opacity>=1) { if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } } else { if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; } } zr+=pzr; zl+=pzl; } return *this; } //! Draw a Gouraud-shaded 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param brightness0 Brightness factor of the first vertex (in [0,2]). \param brightness1 brightness factor of the second vertex (in [0,2]). \param brightness2 brightness factor of the third vertex (in [0,2]). \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2); if (ny0>=height() || ny2<0) return *this; _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; if (xrightcleft?cright - cleft:cleft - cright, rc = dx?(cright - cleft)/dx:0, sc = cright>cleft?1:-1, ndc = dc - (dx?dx*(dc/dx):0); int errc = dx>>1; if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx; if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); ptrd+=whd; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = color; cimg_forC(*this,c) { const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } } return *this; } //! Draw a Gouraud-shaded 2d triangle, with z-buffering \overloading. template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2); if (ny0>=height() || ny2<0) return *this; tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { if (y==ny1) { zl = nz1; pzl = pzn; } int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; tzfloat zleft = zl, zright = zr; if (xrightcleft?cright - cleft:cleft - cright, rc = dx?(cright - cleft)/dx:0, sc = cright>cleft?1:-1, ndc = dc - (dx?dx*(dc/dx):0); const tzfloat pentez = (zright - zleft)/dx; int errc = dx>>1; if (xleft<0 && dx) { cleft-=xleft*(cright - cleft)/dx; zleft-=xleft*(zright - zleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y); tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0; if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } zr+=pzr; zl+=pzl; } return *this; } //! Draw a color-interpolated 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param color1 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the first vertex. \param color2 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the seconf vertex. \param color3 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the third vertex. \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc1 *const color1, const tc2 *const color2, const tc3 *const color3, const float opacity=1) { const unsigned char one = 1; cimg_forC(*this,c) get_shared_channel(c).draw_triangle(x0,y0,x1,y1,x2,y2,&one,color1[c],color2[c],color3[c],opacity); return *this; } //! Draw a textured 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param texture Texture image used to fill the triangle. \param tx0 X-coordinate of the first vertex in the texture image. \param ty0 Y-coordinate of the first vertex in the texture image. \param tx1 X-coordinate of the second vertex in the texture image. \param ty1 Y-coordinate of the second vertex in the texture image. \param tx2 X-coordinate of the third vertex in the texture image. \param ty2 Y-coordinate of the third vertex in the texture image. \param opacity Drawing opacity. \param brightness Brightness factor of the drawing (in [0,2]). **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1) { if (is_empty()) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2); if (ny0>=height() || ny2<0) return *this; _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y, nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) { int xleft = xleft0, xright = xright0, txleft = txleft0, txright = txright0, tyleft = tyleft0, tyright = tyright0; if (xrighttxleft?txright - txleft:txleft - txright, dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, rtx = dx?(txright - txleft)/dx:0, rty = dx?(tyright - tyleft)/dx:0, stx = txright>txleft?1:-1, sty = tyright>tyleft?1:-1, ndtx = dtx - (dx?dx*(dtx/dx):0), ndty = dty - (dx?dx*(dty/dx):0); int errtx = dx>>1, errty = errtx; if (xleft<0 && dx) { txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) { if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } } else { if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } } } return *this; } //! Draw a 2d textured triangle, with perspective correction. template CImg& draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1) { if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2, nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0; float zleft = zl, zright = zr, txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; if (xright=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) { if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } } else { if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a textured 2d triangle, with perspective correction and z-buffering. template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0; float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; tzfloat zleft = zl, zright = zr; if (xright=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y,0,0); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) { if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } } else { if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a Phong-shaded 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param light Light image. \param lx0 X-coordinate of the first vertex in the light image. \param ly0 Y-coordinate of the first vertex in the light image. \param lx1 X-coordinate of the second vertex in the light image. \param ly1 Y-coordinate of the second vertex in the light image. \param lx2 X-coordinate of the third vertex in the light image. \param ly2 Y-coordinate of the third vertex in the light image. \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const CImg& light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); if (light._depth>1 || light._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; const ulongT whd = (ulongT)_width*_height*_depth, lwh = (ulongT)light._width*light._height, offx = _spectrum*whd - 1; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2); if (ny0>=height() || ny2<0) return *this; _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { int xleft = xleft0, xright = xright0, lxleft = lxleft0, lxright = lxright0, lyleft = lyleft0, lyright = lyright0; if (xrightlxleft?lxright - lxleft:lxleft - lxright, dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, rlx = dx?(lxright - lxleft)/dx:0, rly = dx?(lyright - lyleft)/dx:0, slx = lxright>lxleft?1:-1, sly = lyright>lyleft?1:-1, ndlx = dlx - (dx?dx*(dlx/dx):0), ndly = dly - (dx?dx*(dly/dx):0); int errlx = dx>>1, errly = errlx; if (xleft<0 && dx) { lxleft-=xleft*(lxright - lxleft)/dx; lyleft-=xleft*(lyright - lyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = color; const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; *ptrd = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval)); ptrd+=whd; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = color; const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const T val = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval)); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } } return *this; } //! Draw a Phong-shaded 2d triangle, with z-buffering. template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const CImg& light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_triangle(): Specified color is (null).", cimg_instance); if (light._depth>1 || light._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color, +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, lwh = (ulongT)light._width*light._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { if (y==ny1) { zl = nz1; pzl = pzn; } int xleft = xleft0, xright = xright0, lxleft = lxleft0, lxright = lxright0, lyleft = lyleft0, lyright = lyright0; tzfloat zleft = zl, zright = zr; if (xrightlxleft?lxright - lxleft:lxleft - lxright, dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, rlx = dx?(lxright - lxleft)/dx:0, rly = dx?(lyright - lyleft)/dx:0, slx = lxright>lxleft?1:-1, sly = lyright>lyleft?1:-1, ndlx = dlx - (dx?dx*(dlx/dx):0), ndly = dly - (dx?dx*(dly/dx):0); const tzfloat pentez = (zright - zleft)/dx; int errlx = dx>>1, errly = errlx; if (xleft<0 && dx) { zleft-=xleft*(zright - zleft)/dx; lxleft-=xleft*(lxright - lxleft)/dx; lyleft-=xleft*(lyright - lyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y,0,0); tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0; if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const tc cval = *(col++); *ptrd = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval); ptrd+=whd; lig+=lwh; } ptrd-=offx; } zleft+=pentez; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const tc cval = *(col++); const T val = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; lig+=lwh; } ptrd-=offx; } zleft+=pentez; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } zr+=pzr; zl+=pzl; } return *this; } //! Draw a textured Gouraud-shaded 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param texture Texture image used to fill the triangle. \param tx0 X-coordinate of the first vertex in the texture image. \param ty0 Y-coordinate of the first vertex in the texture image. \param tx1 X-coordinate of the second vertex in the texture image. \param ty1 Y-coordinate of the second vertex in the texture image. \param tx2 X-coordinate of the third vertex in the texture image. \param ty2 Y-coordinate of the third vertex in the texture image. \param brightness0 Brightness factor of the first vertex. \param brightness1 Brightness factor of the second vertex. \param brightness2 Brightness factor of the third vertex. \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1) { if (is_empty()) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2); if (ny0>=height() || ny2<0) return *this; _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y, nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) { int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0, txleft = txleft0, txright = txright0, tyleft = tyleft0, tyright = tyright0; if (xrightcleft?cright - cleft:cleft - cright, dtx = txright>txleft?txright - txleft:txleft - txright, dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, rc = dx?(cright - cleft)/dx:0, rtx = dx?(txright - txleft)/dx:0, rty = dx?(tyright - tyleft)/dx:0, sc = cright>cleft?1:-1, stx = txright>txleft?1:-1, sty = tyright>tyleft?1:-1, ndc = dc - (dx?dx*(dc/dx):0), ndtx = dtx - (dx?dx*(dtx/dx):0), ndty = dty - (dx?dx*(dty/dx):0); int errc = dx>>1, errtx = errc, errty = errc; if (xleft<0 && dx) { cleft-=xleft*(cright - cleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); ptrd+=whd; col+=twh; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } } return *this; } //! Draw a textured Gouraud-shaded 2d triangle, with perspective correction \overloading. template CImg& draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1) { if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2, nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; float zleft = zl, zright = zr, txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; if (xrightcleft?cright - cleft:cleft - cright, rc = dx?(cright - cleft)/dx:0, sc = cright>cleft?1:-1, ndc = dc - (dx?dx*(dc/dx):0); const float pentez = (zright - zleft)/dx, pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx; int errc = dx>>1; if (xleft<0 && dx) { cleft-=xleft*(cright - cleft)/dx; zleft-=xleft*(zright - zleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a textured Gouraud-shaded 2d triangle, with perspective correction and z-buffering \overloading. template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; tzfloat zleft = zl, zright = zr; if (xrightcleft?cright - cleft:cleft - cright, rc = dx?(cright - cleft)/dx:0, sc = cright>cleft?1:-1, ndc = dc - (dx?dx*(dc/dx):0); float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx; const tzfloat pentez = (zright - zleft)/dx; int errc = dx>>1; if (xleft<0 && dx) { cleft-=xleft*(cright - cleft)/dx; zleft-=xleft*(zright - zleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a textured Phong-shaded 2d triangle. /** \param x0 X-coordinate of the first vertex in the image instance. \param y0 Y-coordinate of the first vertex in the image instance. \param x1 X-coordinate of the second vertex in the image instance. \param y1 Y-coordinate of the second vertex in the image instance. \param x2 X-coordinate of the third vertex in the image instance. \param y2 Y-coordinate of the third vertex in the image instance. \param texture Texture image used to fill the triangle. \param tx0 X-coordinate of the first vertex in the texture image. \param ty0 Y-coordinate of the first vertex in the texture image. \param tx1 X-coordinate of the second vertex in the texture image. \param ty1 Y-coordinate of the second vertex in the texture image. \param tx2 X-coordinate of the third vertex in the texture image. \param ty2 Y-coordinate of the third vertex in the texture image. \param light Light image. \param lx0 X-coordinate of the first vertex in the light image. \param ly0 Y-coordinate of the first vertex in the light image. \param lx1 X-coordinate of the second vertex in the light image. \param ly1 Y-coordinate of the second vertex in the light image. \param lx2 X-coordinate of the third vertex in the light image. \param ly2 Y-coordinate of the third vertex in the light image. \param opacity Drawing opacity. **/ template CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg& light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1) { if (is_empty()) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (light._depth>1 || light._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, lwh = (ulongT)light._width*light._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2); if (ny0>=height() || ny2<0) return *this; _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y, nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) { int xleft = xleft0, xright = xright0, lxleft = lxleft0, lxright = lxright0, lyleft = lyleft0, lyright = lyright0, txleft = txleft0, txright = txright0, tyleft = tyleft0, tyright = tyright0; if (xrightlxleft?lxright - lxleft:lxleft - lxright, dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, dtx = txright>txleft?txright - txleft:txleft - txright, dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, rlx = dx?(lxright - lxleft)/dx:0, rly = dx?(lyright - lyleft)/dx:0, rtx = dx?(txright - txleft)/dx:0, rty = dx?(tyright - tyleft)/dx:0, slx = lxright>lxleft?1:-1, sly = lyright>lyleft?1:-1, stx = txright>txleft?1:-1, sty = tyright>tyleft?1:-1, ndlx = dlx - (dx?dx*(dlx/dx):0), ndly = dly - (dx?dx*(dly/dx):0), ndtx = dtx - (dx?dx*(dtx/dx):0), ndty = dty - (dx?dx*(dty/dx):0); int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx; if (xleft<0 && dx) { lxleft-=xleft*(lxright - lxleft)/dx; lyleft-=xleft*(lyright - lyleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = &texture._atXY(txleft,tyleft); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } } return *this; } //! Draw a textured Phong-shaded 2d triangle, with perspective correction. template CImg& draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg& light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1) { if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (light._depth>1 || light._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); if (is_overlapped(light)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2, +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, lwh = (ulongT)light._width*light._height, offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2, nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0, lxleft = lxleft0, lxright = lxright0, lyleft = lyleft0, lyright = lyright0; float zleft = zl, zright = zr, txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; if (xrightlxleft?lxright - lxleft:lxleft - lxright, dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, rlx = dx?(lxright - lxleft)/dx:0, rly = dx?(lyright - lyleft)/dx:0, slx = lxright>lxleft?1:-1, sly = lyright>lyleft?1:-1, ndlx = dlx - (dx?dx*(dlx/dx):0), ndly = dly - (dx?dx*(dly/dx):0); const float pentez = (zright - zleft)/dx, pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx; int errlx = dx>>1, errly = errlx; if (xleft<0 && dx) { zleft-=xleft*(zright - zleft)/dx; lxleft-=xleft*(lxright - lxleft)/dx; lyleft-=xleft*(lyright - lyleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a textured Phong-shaded 2d triangle, with perspective correction and z-buffering. template CImg& draw_triangle(CImg& zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg& texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg& light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1) { typedef typename cimg::superset::type tzfloat; if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; if (!is_sameXY(zbuffer)) throw CImgArgumentException(_cimg_instance "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " "different dimensions.", cimg_instance, zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); if (texture._depth>1 || texture._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", cimg_instance, texture._width,texture._height,texture._depth,texture._spectrum,texture._data); if (light._depth>1 || light._spectrum<_spectrum) throw CImgArgumentException(_cimg_instance "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth, twh = (ulongT)texture._width*texture._height, lwh = (ulongT)light._width*light._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; float ntx0 = tx0/z0, nty0 = ty0/z0, ntx1 = tx1/z1, nty1 = ty1/z1, ntx2 = tx2/z2, nty2 = ty2/z2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2); if (ny0>=height() || ny2<0) return *this; float ptxl = (ntx1 - ntx0)/(ny1 - ny0), ptxr = (ntx2 - ntx0)/(ny2 - ny0), ptxn = (ntx2 - ntx1)/(ny2 - ny1), ptyl = (nty1 - nty0)/(ny1 - ny0), ptyr = (nty2 - nty0)/(ny2 - ny0), ptyn = (nty2 - nty1)/(ny2 - ny1), txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))): (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))): (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); tzfloat pzl = (nz1 - nz0)/(ny1 - ny0), pzr = (nz2 - nz0)/(ny2 - ny0), pzn = (nz2 - nz1)/(ny2 - ny1), zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } int xleft = xleft0, xright = xright0, lxleft = lxleft0, lxright = lxright0, lyleft = lyleft0, lyright = lyright0; float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr; tzfloat zleft = zl, zright = zr; if (xrightlxleft?lxright - lxleft:lxleft - lxright, dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, rlx = dx?(lxright - lxleft)/dx:0, rly = dx?(lyright - lyleft)/dx:0, slx = lxright>lxleft?1:-1, sly = lyright>lyleft?1:-1, ndlx = dlx - (dx?dx*(dlx/dx):0), ndly = dly - (dx?dx*(dly/dx):0); float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx; const tzfloat pentez = (zright - zleft)/dx; int errlx = dx>>1, errly = errlx; if (xleft<0 && dx) { zleft-=xleft*(zright - zleft)/dx; lxleft-=xleft*(lxright - lxleft)/dx; lyleft-=xleft*(lyright - lyleft)/dx; txleft-=xleft*(txright - txleft)/dx; tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { const tl l = *lig; const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; } zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; } return *this; } //! Draw a filled 4d rectangle. /** \param x0 X-coordinate of the upper-left rectangle corner. \param y0 Y-coordinate of the upper-left rectangle corner. \param z0 Z-coordinate of the upper-left rectangle corner. \param c0 C-coordinate of the upper-left rectangle corner. \param x1 X-coordinate of the lower-right rectangle corner. \param y1 Y-coordinate of the lower-right rectangle corner. \param z1 Z-coordinate of the lower-right rectangle corner. \param c1 C-coordinate of the lower-right rectangle corner. \param val Scalar value used to fill the rectangle area. \param opacity Drawing opacity. **/ CImg& draw_rectangle(const int x0, const int y0, const int z0, const int c0, const int x1, const int y1, const int z1, const int c1, const T val, const float opacity=1) { if (is_empty()) return *this; const bool bx = (x0=width()?width() - 1 - nx1:0) + (nx0<0?nx0:0), lY = (1 + ny1 - ny0) + (ny1>=height()?height() - 1 - ny1:0) + (ny0<0?ny0:0), lZ = (1 + nz1 - nz0) + (nz1>=depth()?depth() - 1 - nz1:0) + (nz0<0?nz0:0), lC = (1 + nc1 - nc0) + (nc1>=spectrum()?spectrum() - 1 - nc1:0) + (nc0<0?nc0:0); const ulongT offX = (ulongT)_width - lX, offY = (ulongT)_width*(_height - lY), offZ = (ulongT)_width*_height*(_depth - lZ); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); T *ptrd = data(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nc0<0?0:nc0); if (lX>0 && lY>0 && lZ>0 && lC>0) for (int v = 0; v=1) { if (sizeof(T)!=1) { for (int x = 0; x CImg& draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_rectangle(): Specified color is (null).", cimg_instance); cimg_forC(*this,c) draw_rectangle(x0,y0,z0,c,x1,y1,z1,c,(T)color[c],opacity); return *this; } //! Draw an outlined 3d rectangle \overloading. template CImg& draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity, const unsigned int pattern) { return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true). draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false). draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false). draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false). draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true). draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false). draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false). draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false). draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true). draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true). draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true). draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true); } //! Draw a filled 2d rectangle. /** \param x0 X-coordinate of the upper-left rectangle corner. \param y0 Y-coordinate of the upper-left rectangle corner. \param x1 X-coordinate of the lower-right rectangle corner. \param y1 Y-coordinate of the lower-right rectangle corner. \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_rectangle(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1) { return draw_rectangle(x0,y0,0,x1,y1,_depth - 1,color,opacity); } //! Draw a outlined 2d rectangle \overloading. template CImg& draw_rectangle(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity, const unsigned int pattern) { if (is_empty()) return *this; if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true); if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true); const bool bx = (x0 CImg& draw_polygon(const CImg& points, const tc *const color, const float opacity=1) { if (is_empty() || !points) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_polygon(): Specified color is (null).", cimg_instance); // Normalize 2d input coordinates (remove adjacent duplicates). CImg npoints(points._width,2); unsigned int nb_points = 1, p = 0; int cx = npoints(0,0) = (int)points(0,0), cy = npoints(0,1) = (int)points(0,1); const int cx0 = cx, cy0 = cy; for (p = 1; p npoints_x = npoints.get_shared_row(0), npoints_y = npoints.get_shared_row(1); int xmax = 0, xmin = (int)npoints_x.min_max(xmax), ymax = 0, ymin = (int)npoints_y.min_max(ymax); if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this; if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,opacity,1); const unsigned int nxmin = xmin<0?0:(unsigned int)xmin, nxmax = xmax>=width()?_width - 1:(unsigned int)xmax, nymin = ymin<0?0:(unsigned int)ymin, nymax = ymax>=height()?_height - 1:(unsigned int)ymax, dx = 1 + nxmax - nxmin, dy = 1 + nymax - nymin; npoints_x-=nxmin; npoints_y-=nymin; unsigned char one = 1; const CImg mask = CImg(dx,dy,1,1,0).draw_polygon(npoints,&one,1); CImg _color(dx,dy,1,spectrum()); cimg_forC(_color,c) _color.get_shared_channel(c).fill(color[c]); return draw_image(nxmin,nymin,0,0,_color,mask,opacity,1); } // Draw polygon segments. int xmax = 0, xmin = (int)npoints.get_shared_points(0,nb_points - 1,0).min_max(xmax), ymax = 0, ymin = (int)npoints.get_shared_points(0,nb_points - 1,1).min_max(ymax); if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this; if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,1,1); const unsigned int nymin = ymin<0?0:(unsigned int)ymin, nymax = ymax>=height()?_height - 1:(unsigned int)ymax, dy = 1 + nymax - nymin; CImg X(1 + 2*nb_points,dy,1,1,0), tmp; cx = (int)npoints(0,0), cy = (int)npoints(0,1); unsigned int cp = 0; for (unsigned int p = 0; pay && cy>ny))?1:0; for (int x = cx, y = y0, _sx = 1, _sy = 1, _dx = nx>cx?nx - cx:((_sx=-1),cx - nx), _dy = y1>y0?y1 - y0:((_sy=-1),y0 - y1), _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy), _err = _dx>>1, _rx = _dy?(nx - cx)/_dy:0; _counter>=countermin; --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0)) if (y>=0 && y<(int)dy) X(++X(0,y),y) = x; cp = np; cx = nx; cy = ny; } else { const int pp = (int)(cp?cp - 1:nb_points - 1), py = (int)npoints(pp,1); if (y0>=0 && y0<(int)dy) { cimg_draw_scanline(cxpy && ay>cy) || (cy CImg& draw_polygon(const CImg& points, const tc *const color, const float opacity, const unsigned int pattern) { if (is_empty() || !points || points._width<3) return *this; bool ninit_hatch = true; switch (points._height) { case 0 : case 1 : throw CImgArgumentException(_cimg_instance "draw_polygon(): Invalid specified point set.", cimg_instance); case 2 : { // 2d version. CImg npoints(points._width,2); int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1); unsigned int nb_points = 1; for (unsigned int p = 1; p npoints(points._width,3); int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1), z = npoints(0,2) = (int)points(0,2); unsigned int nb_points = 1; for (unsigned int p = 1; p CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity=1) { return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U); } //! Draw a filled 2d ellipse \overloading. /** \param x0 X-coordinate of the ellipse center. \param y0 Y-coordinate of the ellipse center. \param tensor Diffusion tensor describing the ellipse. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_ellipse(const int x0, const int y0, const CImg &tensor, const tc *const color, const float opacity=1) { CImgList eig = tensor.get_symmetric_eigen(); const CImg &val = eig[0], &vec = eig[1]; return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)), std::atan2(vec(0,1),vec(0,0))*180/cimg::PI, color,opacity); } //! Draw an outlined 2d ellipse. /** \param x0 X-coordinate of the ellipse center. \param y0 Y-coordinate of the ellipse center. \param r1 First radius of the ellipse. \param r2 Second radius of the ellipse. \param angle Angle of the first radius. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the outline pattern. **/ template CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity, const unsigned int pattern) { if (pattern) _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,pattern); return *this; } //! Draw an outlined 2d ellipse \overloading. /** \param x0 X-coordinate of the ellipse center. \param y0 Y-coordinate of the ellipse center. \param tensor Diffusion tensor describing the ellipse. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern An integer whose bits describe the outline pattern. **/ template CImg& draw_ellipse(const int x0, const int y0, const CImg &tensor, const tc *const color, const float opacity, const unsigned int pattern) { CImgList eig = tensor.get_symmetric_eigen(); const CImg &val = eig[0], &vec = eig[1]; return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)), std::atan2(vec(0,1),vec(0,0))*180/cimg::PI, color,opacity,pattern); } template CImg& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity, const unsigned int pattern) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_ellipse(): Specified color is (null).", cimg_instance); if (r1<=0 || r2<=0) return draw_point(x0,y0,color,opacity); cimg_init_scanline(color,opacity); const float nr1 = cimg::abs(r1), nr2 = cimg::abs(r2), nangle = (float)(angle*cimg::PI/180), u = (float)std::cos(nangle), v = (float)std::sin(nangle), rmax = cimg::max(nr1,nr2), l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2), l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2), a = l1*u*u + l2*v*v, b = u*v*(l1 - l2), c = l1*v*v + l2*u*u; const int yb = (int)std::sqrt(a*rmax*rmax/(a*c - b*b)), tymin = y0 - yb - 1, tymax = y0 + yb + 1, ymin = tymin<0?0:tymin, ymax = tymax>=height()?height() - 1:tymax; int oxmin = 0, oxmax = 0; bool first_line = true; for (int y = ymin; y<=ymax; ++y) { const float Y = y - y0 + (y0?(float)std::sqrt(delta)/a:0.0f, bY = b*Y/a, fxmin = x0 - 0.5f - bY - sdelta, fxmax = x0 + 0.5f - bY + sdelta; const int xmin = (int)fxmin, xmax = (int)fxmax; if (!pattern) cimg_draw_scanline(xmin,xmax,y,color,opacity,1); else { if (first_line) { if (y0 - yb>=0) cimg_draw_scanline(xmin,xmax,y,color,opacity,1); else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity); first_line = false; } else { if (xmin CImg& draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_circle(): Specified color is (null).", cimg_instance); cimg_init_scanline(color,opacity); if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this; if (y0>=0 && y0=0) { const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y; if (y1>=0 && y1=0 && y2=0 && y1=0 && y2 CImg& draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity, const unsigned int pattern) { cimg::unused(pattern); if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_circle(): Specified color is (null).", cimg_instance); if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this; if (!radius) return draw_point(x0,y0,color,opacity); draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity). draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity); if (radius==1) return *this; for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x=0) { f+=(ddFy+=2); --y; } ++x; ++(f+=(ddFx+=2)); if (x!=y + 1) { const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x, x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y; draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity). draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity); if (x!=y) draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity). draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity); } } return *this; } //! Draw an image. /** \param sprite Sprite image. \param x0 X-coordinate of the sprite position. \param y0 Y-coordinate of the sprite position. \param z0 Z-coordinate of the sprite position. \param c0 C-coordinate of the sprite position. \param opacity Drawing opacity. **/ template CImg& draw_image(const int x0, const int y0, const int z0, const int c0, const CImg& sprite, const float opacity=1) { if (is_empty() || !sprite) return *this; if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared()) return assign(sprite,false); const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); const int lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); const t *ptrs = sprite._data + (bx?-x0:0) + (by?-y0*(ulongT)sprite.width():0) + (bz?-z0*(ulongT)sprite.width()*sprite.height():0) + (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0); const ulongT offX = (ulongT)_width - lX, soffX = (ulongT)sprite._width - lX, offY = (ulongT)_width*(_height - lY), soffY = (ulongT)sprite._width*(sprite._height - lY), offZ = (ulongT)_width*_height*(_depth - lZ), soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (lX>0 && lY>0 && lZ>0 && lC>0) { T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); for (int v = 0; v=1) for (int x = 0; x& draw_image(const int x0, const int y0, const int z0, const int c0, const CImg& sprite, const float opacity=1) { if (is_empty() || !sprite) return *this; if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared()) return assign(sprite,false); const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); const int lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); const T *ptrs = sprite._data + (bx?-x0:0) + (by?-y0*(ulongT)sprite.width():0) + (bz?-z0*(ulongT)sprite.width()*sprite.height():0) + (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0); const ulongT offX = (ulongT)_width - lX, soffX = (ulongT)sprite._width - lX, offY = (ulongT)_width*(_height - lY), soffY = (ulongT)sprite._width*(sprite._height - lY), offZ = (ulongT)_width*_height*(_depth - lZ), soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ), slX = lX*sizeof(T); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); if (lX>0 && lY>0 && lZ>0 && lC>0) { T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); for (int v = 0; v=1) for (int y = 0; y CImg& draw_image(const int x0, const int y0, const int z0, const CImg& sprite, const float opacity=1) { return draw_image(x0,y0,z0,0,sprite,opacity); } //! Draw an image \overloading. template CImg& draw_image(const int x0, const int y0, const CImg& sprite, const float opacity=1) { return draw_image(x0,y0,0,sprite,opacity); } //! Draw an image \overloading. template CImg& draw_image(const int x0, const CImg& sprite, const float opacity=1) { return draw_image(x0,0,sprite,opacity); } //! Draw an image \overloading. template CImg& draw_image(const CImg& sprite, const float opacity=1) { return draw_image(0,sprite,opacity); } //! Draw a masked image. /** \param sprite Sprite image. \param mask Mask image. \param x0 X-coordinate of the sprite position in the image instance. \param y0 Y-coordinate of the sprite position in the image instance. \param z0 Z-coordinate of the sprite position in the image instance. \param c0 C-coordinate of the sprite position in the image instance. \param mask_max_value Maximum pixel value of the mask image \c mask. \param opacity Drawing opacity. \note - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite. - Dimensions along x,y and z of \p sprite and \p mask must be the same. **/ template CImg& draw_image(const int x0, const int y0, const int z0, const int c0, const CImg& sprite, const CImg& mask, const float opacity=1, const float mask_max_value=1) { if (is_empty() || !sprite || !mask) return *this; if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_max_value); if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_max_value); if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth) throw CImgArgumentException(_cimg_instance "draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have " "incompatible dimensions.", cimg_instance, sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data, mask._width,mask._height,mask._depth,mask._spectrum,mask._data); const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); const int lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); const ulongT coff = (bx?-x0:0) + (by?-y0*(ulongT)mask.width():0) + (bz?-z0*(ulongT)mask.width()*mask.height():0) + (bc?-c0*(ulongT)mask.width()*mask.height()*mask.depth():0), ssize = (ulongT)mask.width()*mask.height()*mask.depth()*mask.spectrum(); const ti *ptrs = sprite._data + coff; const tm *ptrm = mask._data + coff; const ulongT offX = (ulongT)_width - lX, soffX = (ulongT)sprite._width - lX, offY = (ulongT)_width*(_height - lY), soffY = (ulongT)sprite._width*(sprite._height - lY), offZ = (ulongT)_width*_height*(_depth - lZ), soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ); if (lX>0 && lY>0 && lZ>0 && lC>0) { T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); for (int c = 0; c CImg& draw_image(const int x0, const int y0, const int z0, const CImg& sprite, const CImg& mask, const float opacity=1, const float mask_max_value=1) { return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_max_value); } //! Draw a image \overloading. template CImg& draw_image(const int x0, const int y0, const CImg& sprite, const CImg& mask, const float opacity=1, const float mask_max_value=1) { return draw_image(x0,y0,0,sprite,mask,opacity,mask_max_value); } //! Draw a image \overloading. template CImg& draw_image(const int x0, const CImg& sprite, const CImg& mask, const float opacity=1, const float mask_max_value=1) { return draw_image(x0,0,sprite,mask,opacity,mask_max_value); } //! Draw an image. template CImg& draw_image(const CImg& sprite, const CImg& mask, const float opacity=1, const float mask_max_value=1) { return draw_image(0,sprite,mask,opacity,mask_max_value); } //! Draw a text string. /** \param x0 X-coordinate of the text in the image instance. \param y0 Y-coordinate of the text in the image instance. \param text Format of the text ('printf'-style format string). \param foreground_color Pointer to \c spectrum() consecutive values, defining the foreground drawing color. \param background_color Pointer to \c spectrum() consecutive values, defining the background drawing color. \param opacity Drawing opacity. \param font Font used for drawing text. **/ template CImg& draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity, const CImgList& font, ...) { if (!font) return *this; CImg tmp(2048); std::va_list ap; va_start(ap,font); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,false); } //! Draw a text string \overloading. /** \note A transparent background is used for the text. **/ template CImg& draw_text(const int x0, const int y0, const char *const text, const tc *const foreground_color, const int, const float opacity, const CImgList& font, ...) { if (!font) return *this; CImg tmp(2048); std::va_list ap; va_start(ap,font); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font,false); } //! Draw a text string \overloading. /** \note A transparent foreground is used for the text. **/ template CImg& draw_text(const int x0, const int y0, const char *const text, const int, const tc *const background_color, const float opacity, const CImgList& font, ...) { if (!font) return *this; CImg tmp(2048); std::va_list ap; va_start(ap,font); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font,false); } //! Draw a text string \overloading. /** \param x0 X-coordinate of the text in the image instance. \param y0 Y-coordinate of the text in the image instance. \param text Format of the text ('printf'-style format string). \param foreground_color Array of spectrum() values of type \c T, defining the foreground color (0 means 'transparent'). \param background_color Array of spectrum() values of type \c T, defining the background color (0 means 'transparent'). \param opacity Drawing opacity. \param font_height Height of the text font (exact match for 13,23,53,103, interpolated otherwise). **/ template CImg& draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; CImg tmp(2048); std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); const CImgList& font = CImgList::font(font_height,true); _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,true); return *this; } //! Draw a text string \overloading. template CImg& draw_text(const int x0, const int y0, const char *const text, const tc *const foreground_color, const int background_color=0, const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; cimg::unused(background_color); CImg tmp(2048); std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return draw_text(x0,y0,"%s",foreground_color,(const tc*)0,opacity,font_height,tmp._data); } //! Draw a text string \overloading. template CImg& draw_text(const int x0, const int y0, const char *const text, const int, const tc *const background_color, const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; CImg tmp(2048); std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return draw_text(x0,y0,"%s",(tc*)0,background_color,opacity,font_height,tmp._data); } template CImg& _draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity, const CImgList& font, const bool is_native_font) { if (!text) return *this; if (!font) throw CImgArgumentException(_cimg_instance "draw_text(): Empty specified font.", cimg_instance); const unsigned int text_length = (unsigned int)std::strlen(text); const bool _is_empty = is_empty(); if (_is_empty) { // If needed, pre-compute necessary size of the image int x = 0, y = 0, w = 0; unsigned char c = 0; for (unsigned int i = 0; iw) w = x; x = 0; break; case '\t' : x+=4*font[' ']._width; break; default : if (cw) w=x; y+=font[0]._height; } assign(x0 + w,y0 + y,1,is_native_font?1:font[0]._spectrum,0); } int x = x0, y = y0; for (unsigned int i = 0; i letter = font[c]; if (letter) { if (is_native_font && _spectrum>letter._spectrum) letter.resize(-100,-100,1,_spectrum,0,2); const unsigned int cmin = cimg::min(_spectrum,letter._spectrum); if (foreground_color) for (unsigned int c = 0; c CImg& draw_quiver(const CImg& flow, const t2 *const color, const float opacity=1, const unsigned int sampling=25, const float factor=-20, const bool is_arrow=true, const unsigned int pattern=~0U) { return draw_quiver(flow,CImg(color,_spectrum,1,1,1,true),opacity,sampling,factor,is_arrow,pattern); } //! Draw a 2d vector field, using a field of colors. /** \param flow Image of 2d vectors used as input data. \param color Image of spectrum()-D vectors corresponding to the color of each arrow. \param opacity Opacity of the drawing. \param sampling Length (in pixels) between each arrow. \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length). \param is_arrow Tells if arrows must be drawn, instead of oriented segments. \param pattern Used pattern to draw lines. \note Clipping is supported. **/ template CImg& draw_quiver(const CImg& flow, const CImg& color, const float opacity=1, const unsigned int sampling=25, const float factor=-20, const bool is_arrow=true, const unsigned int pattern=~0U) { if (is_empty()) return *this; if (!flow || flow._spectrum!=2) throw CImgArgumentException(_cimg_instance "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).", cimg_instance, flow._width,flow._height,flow._depth,flow._spectrum,flow._data); if (sampling<=0) throw CImgArgumentException(_cimg_instance "draw_quiver(): Invalid sampling value %g " "(should be >0)", cimg_instance, sampling); const bool colorfield = (color._width==flow._width && color._height==flow._height && color._depth==1 && color._spectrum==_spectrum); if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern); float vmax,fact; if (factor<=0) { float m, M = (float)flow.get_norm(2).max_min(m); vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M)); if (!vmax) vmax = 1; fact = -factor; } else { fact = factor; vmax = 1; } for (unsigned int y = sampling/2; y<_height; y+=sampling) for (unsigned int x = sampling/2; x<_width; x+=sampling) { const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height; float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax; if (is_arrow) { const int xx = (int)(x + u), yy = (int)(y + v); if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.0f,pattern); else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.0f,pattern); } else { if (colorfield) draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v), color.get_vector_at(X,Y)._data,opacity,pattern); else draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v), color._data,opacity,pattern); } } return *this; } //! Draw a labeled horizontal axis. /** \param values_x Values along the horizontal axis. \param y Y-coordinate of the horizontal axis in the image instance. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern Drawing pattern. \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). \param allow_zero Enable/disable the drawing of label '0' if found. **/ template CImg& draw_axis(const CImg& values_x, const int y, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const unsigned int font_height=13, const bool allow_zero=true) { if (is_empty()) return *this; const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height; const int siz = (int)values_x.size() - 1; CImg txt(32); CImg label; if (siz<=0) { // Degenerated case. draw_line(0,y,_width - 1,y,color,opacity,pattern); if (!siz) { cimg_snprintf(txt,txt._width,"%g",(double)*values_x); label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); const int _xt = (width() - label.width())/2, xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity); if (allow_zero || *txt!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } else { // Regular case. if (values_x[0]=width() - 2?width() - 3 - label.width():_xt; draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity); if (allow_zero || *txt!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } return *this; } //! Draw a labeled vertical axis. /** \param x X-coordinate of the vertical axis in the image instance. \param values_y Values along the Y-axis. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern Drawing pattern. \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). \param allow_zero Enable/disable the drawing of label '0' if found. **/ template CImg& draw_axis(const int x, const CImg& values_y, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const unsigned int font_height=13, const bool allow_zero=true) { if (is_empty()) return *this; int siz = (int)values_y.size() - 1; CImg txt(32); CImg label; if (siz<=0) { // Degenerated case. draw_line(x,0,x,_height - 1,color,opacity,pattern); if (!siz) { cimg_snprintf(txt,txt._width,"%g",(double)*values_y); label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); const int _yt = (height() - label.height())/2, yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt, _xt = x - 2 - label.width(), xt = _xt>=0?_xt:x + 3; draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity); if (allow_zero || *txt!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } else { // Regular case. if (values_y[0]=height()?height() - 1-label.height():_yt, _xt = x - 2 - label.width(), xt = _xt>=0?_xt:x + 3; draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity); if (allow_zero || *txt!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } return *this; } //! Draw labeled horizontal and vertical axes. /** \param values_x Values along the X-axis. \param values_y Values along the Y-axis. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern_x Drawing pattern for the X-axis. \param pattern_y Drawing pattern for the Y-axis. \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). \param allow_zero Enable/disable the drawing of label '0' if found. **/ template CImg& draw_axes(const CImg& values_x, const CImg& values_y, const tc *const color, const float opacity=1, const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U, const unsigned int font_height=13, const bool allow_zero=true) { if (is_empty()) return *this; const CImg nvalues_x(values_x._data,values_x.size(),1,1,1,true); const int sizx = (int)values_x.size() - 1, wm1 = width() - 1; if (sizx>=0) { float ox = (float)*nvalues_x; for (unsigned int x = sizx?1U:0U; x<_width; ++x) { const float nx = (float)nvalues_x._linear_atX((float)x*sizx/wm1); if (nx*ox<=0) { draw_axis(nx==0?x:x - 1,values_y,color,opacity,pattern_y,font_height,allow_zero); break; } ox = nx; } } const CImg nvalues_y(values_y._data,values_y.size(),1,1,1,true); const int sizy = (int)values_y.size() - 1, hm1 = height() - 1; if (sizy>0) { float oy = (float)nvalues_y[0]; for (unsigned int y = sizy?1U:0U; y<_height; ++y) { const float ny = (float)nvalues_y._linear_atX((float)y*sizy/hm1); if (ny*oy<=0) { draw_axis(values_x,ny==0?y:y - 1,color,opacity,pattern_x,font_height,allow_zero); break; } oy = ny; } } return *this; } //! Draw labeled horizontal and vertical axes \overloading. template CImg& draw_axes(const float x0, const float x1, const float y0, const float y1, const tc *const color, const float opacity=1, const int subdivisionx=-60, const int subdivisiony=-60, const float precisionx=0, const float precisiony=0, const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U, const unsigned int font_height=13) { if (is_empty()) return *this; const bool allow_zero = (x0*x1>0) || (y0*y1>0); const float dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0), px = dx<=0?1:precisionx==0?(float)std::pow(10.0,(int)std::log10(dx) - 2.0):precisionx, py = dy<=0?1:precisiony==0?(float)std::pow(10.0,(int)std::log10(dy) - 2.0):precisiony; if (x0!=x1 && y0!=y1) draw_axes(CImg::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px), CImg::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py), color,opacity,pattern_x,pattern_y,font_height,allow_zero); else if (x0==x1 && y0!=y1) draw_axis((int)x0,CImg::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py), color,opacity,pattern_y,font_height); else if (x0!=x1 && y0==y1) draw_axis(CImg::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px),(int)y0, color,opacity,pattern_x,font_height); return *this; } //! Draw 2d grid. /** \param values_x X-coordinates of the vertical lines. \param values_y Y-coordinates of the horizontal lines. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param pattern_x Drawing pattern for vertical lines. \param pattern_y Drawing pattern for horizontal lines. **/ template CImg& draw_grid(const CImg& values_x, const CImg& values_y, const tc *const color, const float opacity=1, const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) { if (is_empty()) return *this; if (values_x) cimg_foroff(values_x,x) { const int xi = (int)values_x[x]; if (xi>=0 && xi=0 && yi CImg& draw_grid(const float delta_x, const float delta_y, const float offsetx, const float offsety, const bool invertx, const bool inverty, const tc *const color, const float opacity=1, const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) { if (is_empty()) return *this; CImg seqx, seqy; if (delta_x!=0) { const float dx = delta_x>0?delta_x:_width*-delta_x/100; const unsigned int nx = (unsigned int)(_width/dx); seqx = CImg::sequence(1 + nx,0,(unsigned int)(dx*nx)); if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x) + offsetx,(float)_width); if (invertx) cimg_foroff(seqx,x) seqx(x) = _width - 1 - seqx(x); } if (delta_y!=0) { const float dy = delta_y>0?delta_y:_height*-delta_y/100; const unsigned int ny = (unsigned int)(_height/dy); seqy = CImg::sequence(1 + ny,0,(unsigned int)(dy*ny)); if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y) + offsety,(float)_height); if (inverty) cimg_foroff(seqy,y) seqy(y) = _height - 1 - seqy(y); } return draw_grid(seqx,seqy,color,opacity,pattern_x,pattern_y); } //! Draw 1d graph. /** \param data Image containing the graph values I = f(x). \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. \param plot_type Define the type of the plot: - 0 = No plot. - 1 = Plot using segments. - 2 = Plot using cubic splines. - 3 = Plot with bars. \param vertex_type Define the type of points: - 0 = No points. - 1 = Point. - 2 = Straight cross. - 3 = Diagonal cross. - 4 = Filled circle. - 5 = Outlined circle. - 6 = Square. - 7 = Diamond. \param ymin Lower bound of the y-range. \param ymax Upper bound of the y-range. \param pattern Drawing pattern. \note - if \c ymin==ymax==0, the y-range is computed automatically from the input samples. **/ template CImg& draw_graph(const CImg& data, const tc *const color, const float opacity=1, const unsigned int plot_type=1, const int vertex_type=1, const double ymin=0, const double ymax=0, const unsigned int pattern=~0U) { if (is_empty() || _height<=1) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_graph(): Specified color is (null).", cimg_instance); // Create shaded colors for displaying bar plots. CImg color1, color2; if (plot_type==3) { color1.assign(_spectrum); color2.assign(_spectrum); cimg_forC(*this,c) { color1[c] = (tc)cimg::min((float)cimg::type::max(),color[c]*1.2f); color2[c] = (tc)(color[c]*0.4f); } } // Compute min/max and normalization factors. const ulongT siz = data.size(), _siz1 = siz - (plot_type!=3?1:0), siz1 = _siz1?_siz1:1; const unsigned int _width1 = _width - (plot_type!=3?1:0), width1 = _width1?_width1:1; double m = ymin, M = ymax; if (ymin==ymax) m = (double)data.max_min(M); if (m==M) { --m; ++M; } const float ca = (float)(M-m)/(_height - 1); bool init_hatch = true; // Draw graph edges switch (plot_type%4) { case 1 : { // Segments int oX = 0, oY = (int)((data[0] - m)/ca); if (siz==1) { const int Y = (int)((*data - m)/ca); draw_line(0,Y,width() - 1,Y,color,opacity,pattern); } else { const float fx = (float)_width/siz1; for (ulongT off = 1; off ndata(data._data,siz,1,1,1,true); int oY = (int)((data[0] - m)/ca); cimg_forX(*this,x) { const int Y = (int)((ndata._cubic_atX((float)x*siz1/width1)-m)/ca); if (x>0) draw_line(x,oY,x + 1,Y,color,opacity,pattern,init_hatch); init_hatch = false; oY = Y; } } break; case 3 : { // Bars const int Y0 = (int)(-m/ca); const float fx = (float)_width/siz1; int oX = 0; cimg_foroff(data,off) { const int X = (int)((off + 1)*fx) - 1, Y = (int)((data[off] - m)/ca); draw_rectangle(oX,Y0,X,Y,color,opacity). draw_line(oX,Y,oX,Y0,color2.data(),opacity). draw_line(oX,Y0,X,Y0,Y<=Y0?color2.data():color1.data(),opacity). draw_line(X,Y,X,Y0,color1.data(),opacity). draw_line(oX,Y,X,Y,Y<=Y0?color1.data():color2.data(),opacity); oX = X + 1; } } break; default : break; // No edges } // Draw graph points const unsigned int wb2 = plot_type==3?_width1/(2*siz):0; const float fx = (float)_width1/siz1; switch (vertex_type%8) { case 1 : { // Point cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_point(X,Y,color,opacity); } } break; case 2 : { // Straight Cross cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_line(X - 3,Y,X + 3,Y,color,opacity).draw_line(X,Y - 3,X,Y + 3,color,opacity); } } break; case 3 : { // Diagonal Cross cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_line(X - 3,Y - 3,X + 3,Y + 3,color,opacity).draw_line(X - 3,Y + 3,X + 3,Y - 3,color,opacity); } } break; case 4 : { // Filled Circle cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_circle(X,Y,3,color,opacity); } } break; case 5 : { // Outlined circle cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_circle(X,Y,3,color,opacity,0U); } } break; case 6 : { // Square cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_rectangle(X - 3,Y - 3,X + 3,Y + 3,color,opacity,~0U); } } break; case 7 : { // Diamond cimg_foroff(data,off) { const int X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_line(X,Y - 4,X + 4,Y,color,opacity). draw_line(X + 4,Y,X,Y + 4,color,opacity). draw_line(X,Y + 4,X - 4,Y,color,opacity). draw_line(X - 4,Y,X,Y - 4,color,opacity); } } break; default : break; // No points } return *this; } //! Draw filled 3d region with the flood fill algorithm. /** \param x X-coordinate of the starting point of the region to fill. \param y Y-coordinate of the starting point of the region to fill. \param z Z-coordinate of the starting point of the region to fill. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param[out] region Image that will contain the mask of the filled region mask, as an output. \param sigma Tolerance concerning neighborhood values. \param opacity Opacity of the drawing. \param is_high_connexity Tells if 8-connexity must be used (only for 2d images). \return \c region is initialized with the binary mask of the filled region. **/ template CImg& draw_fill(const int x, const int y, const int z, const tc *const color, const float opacity, CImg& region, const float sigma=0, const bool is_high_connexity=false) { #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \ res = true; \ const T *reference_col = reference_color._data + _spectrum, *ptrs = data(x,y,z) + siz; \ for (unsigned int i = _spectrum; res && i; --i) { ptrs-=whd; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \ region(x,y,z) = (t)(res?1:noregion); \ } #define _cimg_draw_fill_set(x,y,z) { \ const tc *col = color; \ T *ptrd = data(x,y,z); \ if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } \ else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } \ } #define _cimg_draw_fill_insert(x,y,z) { \ if (posr1>=remaining._height) remaining.resize(3,remaining._height<<1,1,1,0); \ unsigned int *ptrr = remaining.data(0,posr1); \ *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \ } #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \ const unsigned int tx = x, ty = y, tz = z; \ _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \ } if (!color) throw CImgArgumentException(_cimg_instance "draw_fill(): Specified color is (null).", cimg_instance); region.assign(_width,_height,_depth,1,(t)0); if (x>=0 && x=0 && y=0 && z1); const CImg reference_color = get_vector_at(x,y,z); CImg remaining(3,512,1,1,0); remaining(0,0) = (unsigned int)x; remaining(1,0) = (unsigned int)y; remaining(2,0) = (unsigned int)z; unsigned int posr0 = 0, posr1 = 1; region(x,y,z) = (t)1; const t noregion = ((t)1==(t)2)?(t)0:(t)-1; if (is_3d) do { // 3d version of the filling algorithm const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++); if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; } bool cont, res; unsigned int nxc = xc; do { // X-backward _cimg_draw_fill_set(nxc,yc,zc); _cimg_draw_fill_test_neighbor(nxc,yc - 1,zc,yc!=0); _cimg_draw_fill_test_neighbor(nxc,yc + 1,zc,ycposr0); else do { // 2d version of the filling algorithm const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++); if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; } bool cont, res; unsigned int nxc = xc; do { // X-backward _cimg_draw_fill_set(nxc,yc,0); _cimg_draw_fill_test_neighbor(nxc,yc - 1,0,yc!=0); _cimg_draw_fill_test_neighbor(nxc,yc + 1,0,ycposr0); if (noregion) cimg_for(region,ptrd,t) if (*ptrd==noregion) *ptrd = (t)0; } return *this; } //! Draw filled 3d region with the flood fill algorithm \simplification. template CImg& draw_fill(const int x, const int y, const int z, const tc *const color, const float opacity=1, const float sigma=0, const bool is_high_connexity=false) { CImg tmp; return draw_fill(x,y,z,color,opacity,tmp,sigma,is_high_connexity); } //! Draw filled 2d region with the flood fill algorithm \simplification. template CImg& draw_fill(const int x, const int y, const tc *const color, const float opacity=1, const float sigma=0, const bool is_high_connexity=false) { CImg tmp; return draw_fill(x,y,0,color,opacity,tmp,sigma,is_high_connexity); } //! Draw a random plasma texture. /** \param alpha Alpha-parameter. \param beta Beta-parameter. \param scale Scale-parameter. \note Use the mid-point algorithm to render. **/ CImg& draw_plasma(const float alpha=1, const float beta=0, const unsigned int scale=8) { if (is_empty()) return *this; const int w = width(), h = height(); const Tfloat m = (Tfloat)cimg::type::min(), M = (Tfloat)cimg::type::max(); cimg_forZC(*this,z,c) { CImg ref = get_shared_slice(z,c); for (int delta = 1<1; delta>>=1) { const int delta2 = delta>>1; const float r = alpha*delta + beta; // Square step. for (int y0 = 0; y0M?M:val); } // Diamond steps. for (int y = -delta2; yM?M:val); } for (int y0 = 0; y0M?M:val); } for (int y = -delta2; yM?M:val); } } } return *this; } //! Draw a quadratic Mandelbrot or Julia 2d fractal. /** \param x0 X-coordinate of the upper-left pixel. \param y0 Y-coordinate of the upper-left pixel. \param x1 X-coordinate of the lower-right pixel. \param y1 Y-coordinate of the lower-right pixel. \param colormap Colormap. \param opacity Drawing opacity. \param z0r Real part of the upper-left fractal vertex. \param z0i Imaginary part of the upper-left fractal vertex. \param z1r Real part of the lower-right fractal vertex. \param z1i Imaginary part of the lower-right fractal vertex. \param iteration_max Maximum number of iterations for each estimated point. \param is_normalized_iteration Tells if iterations are normalized. \param is_julia_set Tells if the Mandelbrot or Julia set is rendered. \param param_r Real part of the Julia set parameter. \param param_i Imaginary part of the Julia set parameter. \note Fractal rendering is done by the Escape Time Algorithm. **/ template CImg& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1, const CImg& colormap, const float opacity=1, const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, const unsigned int iteration_max=255, const bool is_normalized_iteration=false, const bool is_julia_set=false, const double param_r=0, const double param_i=0) { if (is_empty()) return *this; CImg palette; if (colormap) palette.assign(colormap._data,colormap.size()/colormap._spectrum,1,1,colormap._spectrum,true); if (palette && palette._spectrum!=_spectrum) throw CImgArgumentException(_cimg_instance "draw_mandelbrot(): Instance and specified colormap (%u,%u,%u,%u,%p) have " "incompatible dimensions.", cimg_instance, colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)std::log(2.0); const int _x0 = x0<0?0:x0>=width()?width() - 1:x0, _y0 = y0<0?0:y0>=height()?height() - 1:y0, _x1 = x1<0?1:x1>=width()?width() - 1:x1, _y1 = y1<0?1:y1>=height()?height() - 1:y1; #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if ((1 + _x1 - _x0)*(1 + _y1 - _y0)>=2048) #endif for (int q = _y0; q<=_y1; ++q) for (int p = _x0; p<=_x1; ++p) { unsigned int iteration = 0; const double x = z0r + p*(z1r-z0r)/_width, y = z0i + q*(z1i-z0i)/_height; double zr, zi, cr, ci; if (is_julia_set) { zr = x; zi = y; cr = param_r; ci = param_i; } else { zr = param_r; zi = param_i; cr = x; ci = y; } for (iteration=1; zr*zr + zi*zi<=4 && iteration<=iteration_max; ++iteration) { const double temp = zr*zr - zi*zi + cr; zi = 2*zr*zi + ci; zr = temp; } if (iteration>iteration_max) { if (palette) { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette(0,c); else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(0,c)*nopacity + (*this)(p,q,0,c)*copacity); } else { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)0; else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)((*this)(p,q,0,c)*copacity); } } else if (is_normalized_iteration) { const float normz = (float)cimg::abs(zr*zr + zi*zi), niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2); if (palette) { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c); else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette._linear_atX(niteration,c)*nopacity + (*this)(p,q,0,c)*copacity); } else { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)niteration; else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(niteration*nopacity + (*this)(p,q,0,c)*copacity); } } else { if (palette) { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._atX(iteration,c); else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(iteration,c)*nopacity + (*this)(p,q,0,c)*copacity); } else { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)iteration; else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(iteration*nopacity + (*this)(p,q,0,c)*copacity); } } } return *this; } //! Draw a quadratic Mandelbrot or Julia 2d fractal \overloading. template CImg& draw_mandelbrot(const CImg& colormap, const float opacity=1, const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, const unsigned int iteration_max=255, const bool is_normalized_iteration=false, const bool is_julia_set=false, const double param_r=0, const double param_i=0) { return draw_mandelbrot(0,0,_width - 1,_height - 1,colormap,opacity, z0r,z0i,z1r,z1i,iteration_max,is_normalized_iteration,is_julia_set,param_r,param_i); } //! Draw a 1d gaussian function. /** \param xc X-coordinate of the gaussian center. \param sigma Standard variation of the gaussian distribution. \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_gaussian(const float xc, const float sigma, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (!color) throw CImgArgumentException(_cimg_instance "draw_gaussian(): Specified color is (null).", cimg_instance); const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth; const tc *col = color; cimg_forX(*this,x) { const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2); T *ptrd = data(x,0,0,0); if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } col-=_spectrum; } return *this; } //! Draw a 2d gaussian function. /** \param xc X-coordinate of the gaussian center. \param yc Y-coordinate of the gaussian center. \param tensor Covariance matrix (must be 2x2). \param color Pointer to \c spectrum() consecutive values, defining the drawing color. \param opacity Drawing opacity. **/ template CImg& draw_gaussian(const float xc, const float yc, const CImg& tensor, const tc *const color, const float opacity=1) { if (is_empty()) return *this; if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1) throw CImgArgumentException(_cimg_instance "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.", cimg_instance, tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); if (!color) throw CImgArgumentException(_cimg_instance "draw_gaussian(): Specified color is (null).", cimg_instance); typedef typename CImg::Tfloat tfloat; const CImg invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0); const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth; const tc *col = color; float dy = -yc; cimg_forY(*this,y) { float dx = -xc; cimg_forX(*this,x) { const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy); T *ptrd = data(x,y,0,0); if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } col-=_spectrum; ++dx; } ++dy; } return *this; } //! Draw a 2d gaussian function \overloading. template CImg& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv, const tc *const color, const float opacity=1) { const double a = r1*ru*ru + r2*rv*rv, b = (r1-r2)*ru*rv, c = r1*rv*rv + r2*ru*ru; const CImg tensor(2,2,1,1, a,b,b,c); return draw_gaussian(xc,yc,tensor,color,opacity); } //! Draw a 2d gaussian function \overloading. template CImg& draw_gaussian(const float xc, const float yc, const float sigma, const tc *const color, const float opacity=1) { return draw_gaussian(xc,yc,CImg::diagonal(sigma,sigma),color,opacity); } //! Draw a 3d gaussian function \overloading. template CImg& draw_gaussian(const float xc, const float yc, const float zc, const CImg& tensor, const tc *const color, const float opacity=1) { if (is_empty()) return *this; typedef typename CImg::Tfloat tfloat; if (tensor._width!=3 || tensor._height!=3 || tensor._depth!=1 || tensor._spectrum!=1) throw CImgArgumentException(_cimg_instance "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 3x3 matrix.", cimg_instance, tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); const CImg invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0); const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = 2*invT2(2,0), d = invT2(1,1), e = 2*invT2(2,1), f = invT2(2,2); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); const ulongT whd = (ulongT)_width*_height*_depth; const tc *col = color; cimg_forXYZ(*this,x,y,z) { const float dx = (x - xc), dy = (y - yc), dz = (z - zc), val = (float)std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz); T *ptrd = data(x,y,z,0); if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } col-=_spectrum; } return *this; } //! Draw a 3d gaussian function \overloading. template CImg& draw_gaussian(const float xc, const float yc, const float zc, const float sigma, const tc *const color, const float opacity=1) { return draw_gaussian(xc,yc,zc,CImg::diagonal(sigma,sigma,sigma),color,opacity); } //! Draw a 3d object. /** \param x0 X-coordinate of the 3d object position \param y0 Y-coordinate of the 3d object position \param z0 Z-coordinate of the 3d object position \param vertices Image Nx3 describing 3d point coordinates \param primitives List of P primitives \param colors List of P color (or textures) \param opacities Image or list of P opacities \param render_type d Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud) \param is_double_sided Tells if object faces have two sides or are oriented. \param focale length of the focale (0 for parallel projection) \param lightx X-coordinate of the light \param lighty Y-coordinate of the light \param lightz Z-coordinate of the light \param specular_lightness Amount of specular light. \param specular_shininess Shininess of the object **/ template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type, is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } //! Draw a 3d object \simplification. template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,1); } #ifdef cimg_use_board template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type, is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,1); } #endif //! Draw a 3d object \simplification. template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type, is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } //! Draw a 3d object \simplification. template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,1); } #ifdef cimg_use_board template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type, is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,1); } #endif //! Draw a 3d object \simplification. template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } //! Draw a 3d object \simplification. template CImg& draw_object3d(const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,zbuffer); } #ifdef cimg_use_board template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const unsigned int render_type=4, const bool is_double_sided=false, const float focale=700, const float lightx=0, const float lighty=0, const float lightz=-5e8, const float specular_lightness=0.2f, const float specular_shininess=0.1f) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,CImg::empty()); } template CImg& draw_object3d(LibBoard::Board& board, const float x0, const float y0, const float z0, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, CImg& zbuffer) { return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), render_type,is_double_sided,focale,lightx,lighty,lightz, specular_lightness,specular_shininess,zbuffer); } #endif template static float __draw_object3d(const CImgList& opacities, const unsigned int n_primitive, CImg& opacity) { if (n_primitive>=opacities._width || opacities[n_primitive].is_empty()) { opacity.assign(); return 1; } if (opacities[n_primitive].size()==1) { opacity.assign(); return opacities(n_primitive,0); } opacity.assign(opacities[n_primitive],true); return 1.0f; } template static float __draw_object3d(const CImg& opacities, const unsigned int n_primitive, CImg& opacity) { opacity.assign(); return n_primitive>=opacities._width?1.0f:(float)opacities[n_primitive]; } template static float ___draw_object3d(const CImgList& opacities, const unsigned int n_primitive) { return n_primitive static float ___draw_object3d(const CImg& opacities, const unsigned int n_primitive) { return n_primitive CImg& _draw_object3d(void *const pboard, CImg& zbuffer, const float X, const float Y, const float Z, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const to& opacities, const unsigned int render_type, const bool is_double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_lightness, const float specular_shininess, const float sprite_scale) { typedef typename cimg::superset2::type tpfloat; typedef typename to::value_type _to; if (is_empty() || !vertices || !primitives) return *this; CImg error_message(1024); if (!vertices.is_object3d(primitives,colors,opacities,false,error_message)) throw CImgArgumentException(_cimg_instance "draw_object3d(): Invalid specified 3d object (%u,%u) (%s).", cimg_instance,vertices._width,primitives._width,error_message.data()); #ifndef cimg_use_board if (pboard) return *this; #endif if (render_type==5) cimg::mutex(10); // Static variable used in this case, breaks thread-safety. const float nspec = 1 - (specular_lightness<0.0f?0.0f:(specular_lightness>1.0f?1.0f:specular_lightness)), nspec2 = 1 + (specular_shininess<0.0f?0.0f:specular_shininess), nsl1 = (nspec2 - 1)/cimg::sqr(nspec - 1), nsl2 = 1 - 2*nsl1*nspec, nsl3 = nspec2 - nsl1 - nsl2; // Create light texture for phong-like rendering. CImg light_texture; if (render_type==5) { if (colors._width>primitives._width) { static CImg default_light_texture; static const tc *lptr = 0; static tc ref_values[64] = { 0 }; const CImg& img = colors.back(); bool is_same_texture = (lptr==img._data); if (is_same_texture) for (unsigned int r = 0, j = 0; j<8; ++j) for (unsigned int i = 0; i<8; ++i) if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum)) { is_same_texture = false; break; } if (!is_same_texture || default_light_texture._spectrum<_spectrum) { (default_light_texture.assign(img,false)/=255).resize(-100,-100,1,_spectrum); lptr = colors.back().data(); for (unsigned int r = 0, j = 0; j<8; ++j) for (unsigned int i = 0; i<8; ++i) ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum); } light_texture.assign(default_light_texture,true); } else { static CImg default_light_texture; static float olightx = 0, olighty = 0, olightz = 0, ospecular_shininess = 0; if (!default_light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shininess!=ospecular_shininess || default_light_texture._spectrum<_spectrum) { default_light_texture.assign(512,512); const float dlx = lightx - X, dly = lighty - Y, dlz = lightz - Z, nl = (float)std::sqrt(dlx*dlx + dly*dly + dlz*dlz), nlx = (default_light_texture._width - 1)/2*(1 + dlx/nl), nly = (default_light_texture._height - 1)/2*(1 + dly/nl), white[] = { 1 }; default_light_texture.draw_gaussian(nlx,nly,default_light_texture._width/3.0f,white); cimg_forXY(default_light_texture,x,y) { const float factor = default_light_texture(x,y); if (factor>nspec) default_light_texture(x,y) = cimg::min(2,nsl1*factor*factor + nsl2*factor + nsl3); } default_light_texture.resize(-100,-100,1,_spectrum); olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shininess = specular_shininess; } light_texture.assign(default_light_texture,true); } } // Compute 3d to 2d projection. CImg projections(vertices._width,2); tpfloat parallzmin = cimg::type::max(); const float absfocale = focale?cimg::abs(focale):0; if (absfocale) { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(projections.size()>4096) #endif cimg_forX(projections,l) { // Perspective projection const tpfloat x = (tpfloat)vertices(l,0), y = (tpfloat)vertices(l,1), z = (tpfloat)vertices(l,2); const tpfloat projectedz = z + Z + absfocale; projections(l,1) = Y + absfocale*y/projectedz; projections(l,0) = X + absfocale*x/projectedz; } } else { #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(projections.size()>4096) #endif cimg_forX(projections,l) { // Parallel projection const tpfloat x = (tpfloat)vertices(l,0), y = (tpfloat)vertices(l,1), z = (tpfloat)vertices(l,2); if (z visibles(primitives._width,1,1,1,~0U); CImg zrange(primitives._width); const tpfloat zmin = absfocale?(tpfloat)(1.5f - absfocale):cimg::type::min(); bool is_forward = zbuffer?true:false; #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(primitives.size()>4096) #endif cimglist_for(primitives,l) { const CImg& primitive = primitives[l]; switch (primitive.size()) { case 1 : { // Point CImg<_to> _opacity; __draw_object3d(opacities,l,_opacity); if (l<=colors.width() && (colors[l].size()!=_spectrum || _opacity)) is_forward = false; const unsigned int i0 = (unsigned int)primitive(0); const tpfloat z0 = Z + vertices(i0,2); if (z0>zmin) { visibles(l) = (unsigned int)l; zrange(l) = z0; } } break; case 5 : { // Sphere const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1); const tpfloat Xc = 0.5f*((float)vertices(i0,0) + (float)vertices(i1,0)), Yc = 0.5f*((float)vertices(i0,1) + (float)vertices(i1,1)), Zc = 0.5f*((float)vertices(i0,2) + (float)vertices(i1,2)), _zc = Z + Zc, zc = _zc + _focale, xc = X + Xc*(absfocale?absfocale/zc:1), yc = Y + Yc*(absfocale?absfocale/zc:1), radius = 0.5f*std::sqrt(cimg::sqr(vertices(i1,0) - vertices(i0,0)) + cimg::sqr(vertices(i1,1) - vertices(i0,1)) + cimg::sqr(vertices(i1,2) - vertices(i0,2)))*(absfocale?absfocale/zc:1), xm = xc - radius, ym = yc - radius, xM = xc + radius, yM = yc + radius; if (xM>=0 && xm<_width && yM>=0 && ym<_height && _zc>zmin) { visibles(l) = (unsigned int)l; zrange(l) = _zc; } is_forward = false; } break; case 2 : // Segment case 6 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1); const tpfloat x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2); tpfloat xm, xM, ym, yM; if (x0=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin) { visibles(l) = (unsigned int)l; zrange(l) = (z0 + z1)/2; } } break; case 3 : // Triangle case 9 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2); const tpfloat x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2), x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2); tpfloat xm, xM, ym, yM; if (x0xM) xM = x2; if (y0yM) yM = y2; if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) { const tpfloat d = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0); if (is_double_sided || d<0) { visibles(l) = (unsigned int)l; zrange(l) = (z0 + z1 + z2)/3; } } } break; case 4 : // Rectangle case 12 : { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2), i3 = (unsigned int)primitive(3); const tpfloat x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2), x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2), x3 = projections(i3,0), y3 = projections(i3,1), z3 = Z + vertices(i3,2); tpfloat xm, xM, ym, yM; if (x0xM) xM = x2; if (x3xM) xM = x3; if (y0yM) yM = y2; if (y3yM) yM = y3; if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) { const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0); if (is_double_sided || d<0) { visibles(l) = (unsigned int)l; zrange(l) = (z0 + z1 + z2 + z3)/4; } } } break; default : if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Invalid primitive[%u] with size %u " "(should have size 1,2,3,4,5,6,9 or 12).", cimg_instance, l,primitive.size()); } } // Force transparent primitives to be drawn last when zbuffer is activated // (and if object contains no spheres or sprites). if (is_forward) cimglist_for(primitives,l) if (___draw_object3d(opacities,l)!=1) zrange(l) = 2*zmax - zrange(l); // Sort only visibles primitives. unsigned int *p_visibles = visibles._data; tpfloat *p_zrange = zrange._data; const tpfloat *ptrz = p_zrange; cimg_for(visibles,ptr,unsigned int) { if (*ptr!=~0U) { *(p_visibles++) = *ptr; *(p_zrange++) = *ptrz; } ++ptrz; } const unsigned int nb_visibles = (unsigned int)(p_zrange - zrange._data); if (!nb_visibles) { if (render_type==5) cimg::mutex(10,0); return *this; } CImg permutations; CImg(zrange._data,nb_visibles,1,1,1,true).sort(permutations,is_forward); // Compute light properties CImg lightprops; switch (render_type) { case 3 : { // Flat Shading lightprops.assign(nb_visibles); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(nb_visibles>4096) #endif cimg_forX(lightprops,l) { const CImg& primitive = primitives(visibles(permutations(l))); const unsigned int psize = primitive.size(); if (psize==3 || psize==4 || psize==9 || psize==12) { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2); const tpfloat x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2), x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2), x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2), dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, nx = dy1*dz2 - dz1*dy2, ny = dz1*dx2 - dx1*dz2, nz = dx1*dy2 - dy1*dx2, norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), lx = X + (x0 + x1 + x2)/3 - lightx, ly = Y + (y0 + y1 + y2)/3 - lighty, lz = Z + (z0 + z1 + z2)/3 - lightz, nl = (tpfloat)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz), factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0); lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); } else lightprops[l] = 1; } } break; case 4 : // Gouraud Shading case 5 : { // Phong-Shading CImg vertices_normals(vertices._width,6,1,1,0); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(nb_visibles>4096) #endif for (unsigned int l = 0; l& primitive = primitives[visibles(l)]; const unsigned int psize = primitive.size(); const bool triangle_flag = (psize==3) || (psize==9), rectangle_flag = (psize==4) || (psize==12); if (triangle_flag || rectangle_flag) { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2), i3 = rectangle_flag?(unsigned int)primitive(3):0; const tpfloat x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2), x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2), x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2), dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, nnx = dy1*dz2 - dz1*dy2, nny = dz1*dx2 - dx1*dz2, nnz = dx1*dy2 - dy1*dx2, norm = (tpfloat)(1e-5f + std::sqrt(nnx*nnx + nny*nny + nnz*nnz)), nx = nnx/norm, ny = nny/norm, nz = nnz/norm; unsigned int ix = 0, iy = 1, iz = 2; if (is_double_sided && nz>0) { ix = 3; iy = 4; iz = 5; } vertices_normals(i0,ix)+=nx; vertices_normals(i0,iy)+=ny; vertices_normals(i0,iz)+=nz; vertices_normals(i1,ix)+=nx; vertices_normals(i1,iy)+=ny; vertices_normals(i1,iz)+=nz; vertices_normals(i2,ix)+=nx; vertices_normals(i2,iy)+=ny; vertices_normals(i2,iz)+=nz; if (rectangle_flag) { vertices_normals(i3,ix)+=nx; vertices_normals(i3,iy)+=ny; vertices_normals(i3,iz)+=nz; } } } if (is_double_sided) cimg_forX(vertices_normals,p) { const float nx0 = vertices_normals(p,0), ny0 = vertices_normals(p,1), nz0 = vertices_normals(p,2), nx1 = vertices_normals(p,3), ny1 = vertices_normals(p,4), nz1 = vertices_normals(p,5), n0 = nx0*nx0 + ny0*ny0 + nz0*nz0, n1 = nx1*nx1 + ny1*ny1 + nz1*nz1; if (n1>n0) { vertices_normals(p,0) = -nx1; vertices_normals(p,1) = -ny1; vertices_normals(p,2) = -nz1; } } if (render_type==4) { lightprops.assign(vertices._width); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(nb_visibles>4096) #endif cimg_forX(lightprops,l) { const tpfloat nx = vertices_normals(l,0), ny = vertices_normals(l,1), nz = vertices_normals(l,2), norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), lx = X + vertices(l,0) - lightx, ly = Y + vertices(l,1) - lighty, lz = Z + vertices(l,2) - lightz, nl = (tpfloat)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz), factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0); lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); } } else { const unsigned int lw2 = light_texture._width/2 - 1, lh2 = light_texture._height/2 - 1; lightprops.assign(vertices._width,2); #ifdef cimg_use_openmp #pragma omp parallel for cimg_openmp_if(nb_visibles>4096) #endif cimg_forX(lightprops,l) { const tpfloat nx = vertices_normals(l,0), ny = vertices_normals(l,1), nz = vertices_normals(l,2), norm = (tpfloat)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), nnx = nx/norm, nny = ny/norm; lightprops(l,0) = lw2*(1 + nnx); lightprops(l,1) = lh2*(1 + nny); } } } break; } // Draw visible primitives const CImg default_color(1,_spectrum,1,1,(tc)200); CImg<_to> _opacity; for (unsigned int l = 0; l& primitive = primitives[n_primitive]; const CImg &__color = n_primitive(), _color = (__color && __color.size()!=_spectrum && __color._spectrum<_spectrum)? __color.get_resize(-100,-100,-100,_spectrum,0):CImg(), &color = _color?_color:(__color?__color:default_color); const tc *const pcolor = color._data; const float opacity = __draw_object3d(opacities,n_primitive,_opacity); #ifdef cimg_use_board LibBoard::Board &board = *(LibBoard::Board*)pboard; #endif switch (primitive.size()) { case 1 : { // Colored point or sprite const unsigned int n0 = (unsigned int)primitive[0]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1); if (_opacity.is_empty()) { // Scalar opacity. if (color.size()==_spectrum) { // Colored point. draw_point(x0,y0,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.fillCircle((float)x0,height()-(float)y0,0); } #endif } else { // Sprite. const tpfloat z = Z + vertices(n0,2); const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1); const unsigned int _sw = (unsigned int)(color._width*factor), _sh = (unsigned int)(color._height*factor), sw = _sw?_sw:1, sh = _sh?_sh:1; const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2; if (sw<=3*_width/2 && sh<=3*_height/2 && (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 _sprite = (sw!=color._width || sh!=color._height)? color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), &sprite = _sprite?_sprite:color; draw_image(nx0,ny0,sprite,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128); board.setFillColor(LibBoard::Color::None); board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); } #endif } } } else { // Opacity mask. const tpfloat z = Z + vertices(n0,2); const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1); const unsigned int _sw = (unsigned int)(cimg::max(color._width,_opacity._width)*factor), _sh = (unsigned int)(cimg::max(color._height,_opacity._height)*factor), sw = _sw?_sw:1, sh = _sh?_sh:1; const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2; if (sw<=3*_width/2 && sh<=3*_height/2 && (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 _sprite = (sw!=color._width || sh!=color._height)? color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), &sprite = _sprite?_sprite:color; const CImg<_to> _nopacity = (sw!=_opacity._width || sh!=_opacity._height)? _opacity.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<_to>(), &nopacity = _nopacity?_nopacity:_opacity; draw_image(nx0,ny0,sprite,nopacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128); board.setFillColor(LibBoard::Color::None); board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); } #endif } } } break; case 2 : { // Colored line const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale; if (render_type) { if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity); else draw_line(x0,y0,x1,y1,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,x1,height() - (float)y1); } #endif } else { draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); } #endif } } break; case 5 : { // Colored sphere const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], is_wireframe = (unsigned int)primitive[2]; const float Xc = 0.5f*((float)vertices(n0,0) + (float)vertices(n1,0)), Yc = 0.5f*((float)vertices(n0,1) + (float)vertices(n1,1)), Zc = 0.5f*((float)vertices(n0,2) + (float)vertices(n1,2)), zc = Z + Zc + _focale, xc = X + Xc*(absfocale?absfocale/zc:1), yc = Y + Yc*(absfocale?absfocale/zc:1), radius = 0.5f*std::sqrt(cimg::sqr(vertices(n1,0) - vertices(n0,0)) + cimg::sqr(vertices(n1,1) - vertices(n0,1)) + cimg::sqr(vertices(n1,2) - vertices(n0,2)))*(absfocale?absfocale/zc:1); switch (render_type) { case 0 : draw_point((int)xc,(int)yc,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.fillCircle(xc,height() - yc,0); } #endif break; case 1 : draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.setFillColor(LibBoard::Color::None); board.drawCircle(xc,height() - yc,radius); } #endif break; default : if (is_wireframe) draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U); else draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); if (!is_wireframe) board.fillCircle(xc,height() - yc,radius); else { board.setFillColor(LibBoard::Color::None); board.drawCircle(xc,height() - yc,radius); } } #endif break; } } break; case 6 : { // Textured line if (!__color) { if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for line primitive [%u].", cimg_instance,n_primitive); } const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1]; const int tx0 = (int)primitive[2], ty0 = (int)primitive[3], tx1 = (int)primitive[4], ty1 = (int)primitive[5], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale; if (render_type) { if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity); else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); } #endif } else { draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); } #endif } } break; case 3 : { // Colored triangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale, z2 = vertices(n2,2) + Z + _focale; switch (render_type) { case 0 : draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).draw_point(x2,y2,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); board.drawCircle((float)x2,height() - (float)y2,0); } #endif break; case 1 : if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,pcolor,opacity). draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity); else draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x0,y0,x2,y2,pcolor,opacity). draw_line(x1,y1,x2,y2,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); } #endif break; case 2 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); } #endif break; case 3 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)); else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)); #ifdef cimg_use_board if (pboard) { const float lp = cimg::min(lightprops(l),1); board.setPenColorRGBi((unsigned char)(color[0]*lp), (unsigned char)(color[1]*lp), (unsigned char)(color[2]*lp), (unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); } #endif break; case 4 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor, lightprops(n0),lightprops(n1),lightprops(n2),opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), (float)x1,height() - (float)y1,lightprops(n1), (float)x2,height() - (float)y2,lightprops(n2)); } #endif break; case 5 : { const unsigned int lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1); if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity); #ifdef cimg_use_board if (pboard) { const float l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, (float)x1,height() - (float)y1,l1, (float)x2,height() - (float)y2,l2); } #endif } break; } } break; case 4 : { // Colored rectangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], n3 = (unsigned int)primitive[3]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale, z2 = vertices(n2,2) + Z + _focale, z3 = vertices(n3,2) + Z + _focale; switch (render_type) { case 0 : draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity). draw_point(x2,y2,pcolor,opacity).draw_point(x3,y3,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); board.drawCircle((float)x2,height() - (float)y2,0); board.drawCircle((float)x3,height() - (float)y3,0); } #endif break; case 1 : if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity). draw_line(zbuffer,x2,y2,z2,x3,y3,z3,pcolor,opacity).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,pcolor,opacity); else draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x1,y1,x2,y2,pcolor,opacity). draw_line(x2,y2,x3,y3,pcolor,opacity).draw_line(x3,y3,x0,y0,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); } #endif break; case 2 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity).draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); board.fillTriangle((float)x0,height() - (float)y0, (float)x2,height() - (float)y2, (float)x3,height() - (float)y3); } #endif break; case 3 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity,lightprops(l)); else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)). _draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity,lightprops(l)); #ifdef cimg_use_board if (pboard) { const float lp = cimg::min(lightprops(l),1); board.setPenColorRGBi((unsigned char)(color[0]*lp), (unsigned char)(color[1]*lp), (unsigned char)(color[2]*lp),(unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); board.fillTriangle((float)x0,height() - (float)y0, (float)x2,height() - (float)y2, (float)x3,height() - (float)y3); } #endif break; case 4 : { const float lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,lightprop0,lightprop1,lightprop2,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,lightprop0,lightprop2,lightprop3,opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprop0,lightprop1,lightprop2,opacity). draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,lightprop0,lightprop2,lightprop3,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, (float)x1,height() - (float)y1,lightprop1, (float)x2,height() - (float)y2,lightprop2); board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, (float)x2,height() - (float)y2,lightprop2, (float)x3,height() - (float)y3,lightprop3); } #endif } break; case 5 : { const unsigned int lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); #ifdef cimg_use_board if (pboard) { const float l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, (float)x1,height() - (float)y1,l1, (float)x2,height() - (float)y2,l2); board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, (float)x2,height() - (float)y2,l2, (float)x3,height() - (float)y3,l3); } #endif } break; } } break; case 9 : { // Textured triangle if (!__color) { if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for triangle primitive [%u].", cimg_instance,n_primitive); } const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2]; const int tx0 = (int)primitive[3], ty0 = (int)primitive[4], tx1 = (int)primitive[5], ty1 = (int)primitive[6], tx2 = (int)primitive[7], ty2 = (int)primitive[8], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale, z2 = vertices(n2,2) + Z + _focale; switch (render_type) { case 0 : draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); board.drawCircle((float)x2,height() - (float)y2,0); } #endif break; case 1 : if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity). draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity); else draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity). draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); } #endif break; case 2 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); } #endif break; case 3 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)); #ifdef cimg_use_board if (pboard) { const float lp = cimg::min(lightprops(l),1); board.setPenColorRGBi((unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); } #endif break; case 4 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, lightprops(n0),lightprops(n1),lightprops(n2),opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, lightprops(n0),lightprops(n1),lightprops(n2),opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), (float)x1,height() - (float)y1,lightprops(n1), (float)x2,height() - (float)y2,lightprops(n2)); } #endif break; case 5 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), opacity); #ifdef cimg_use_board if (pboard) { const float l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, (float)x1,height() - (float)y1,l1, (float)x2,height() - (float)y2,l2); } #endif break; } } break; case 12 : { // Textured quadrangle if (!__color) { if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for quadrangle primitive [%u].", cimg_instance,n_primitive); } const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], n3 = (unsigned int)primitive[3]; const int tx0 = (int)primitive[4], ty0 = (int)primitive[5], tx1 = (int)primitive[6], ty1 = (int)primitive[7], tx2 = (int)primitive[8], ty2 = (int)primitive[9], tx3 = (int)primitive[10], ty3 = (int)primitive[11], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); const float z0 = vertices(n0,2) + Z + _focale, z1 = vertices(n1,2) + Z + _focale, z2 = vertices(n2,2) + Z + _focale, z3 = vertices(n3,2) + Z + _focale; switch (render_type) { case 0 : draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity). draw_point(x3,y3,color.get_vector_at(tx3<=0?0:tx3>=color.width()?color.width() - 1:tx3, ty3<=0?0:ty3>=color.height()?color.height() - 1:ty3)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawCircle((float)x0,height() - (float)y0,0); board.drawCircle((float)x1,height() - (float)y1,0); board.drawCircle((float)x2,height() - (float)y2,0); board.drawCircle((float)x3,height() - (float)y3,0); } #endif break; case 1 : if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity). draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity). draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity); else draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity). draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity). draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); } #endif break; case 2 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity). draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); board.fillTriangle((float)x0,height() - (float)y0, (float)x2,height() - (float)y2, (float)x3,height() - (float)y3); } #endif break; case 3 : if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l)); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)). draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l)); #ifdef cimg_use_board if (pboard) { const float lp = cimg::min(lightprops(l),1); board.setPenColorRGBi((unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(opacity*255)); board.fillTriangle((float)x0,height() - (float)y0, (float)x1,height() - (float)y1, (float)x2,height() - (float)y2); board.fillTriangle((float)x0,height() - (float)y0, (float)x2,height() - (float)y2, (float)x3,height() - (float)y3); } #endif break; case 4 : { const float lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, lightprop0,lightprop1,lightprop2,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, lightprop0,lightprop2,lightprop3,opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, lightprop0,lightprop1,lightprop2,opacity). draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, lightprop0,lightprop2,lightprop3,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, (float)x1,height() - (float)y1,lightprop1, (float)x2,height() - (float)y2,lightprop2); board.fillGouraudTriangle((float)x0,height() -(float)y0,lightprop0, (float)x2,height() - (float)y2,lightprop2, (float)x3,height() - (float)y3,lightprop3); } #endif } break; case 5 : { const unsigned int lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); #ifdef cimg_use_board if (pboard) { const float l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, (float)x1,height() - (float)y1,l1, (float)x2,height() - (float)y2,l2); board.fillGouraudTriangle((float)x0,height() -(float)y0,l0, (float)x2,height() - (float)y2,l2, (float)x3,height() - (float)y3,l3); } #endif } break; } } break; } } if (render_type==5) cimg::mutex(10,0); return *this; } //@} //--------------------------- // //! \name Data Input //@{ //--------------------------- //! Launch simple interface to select a shape from an image. /** \param disp Display window to use. \param feature_type Type of feature to select. Can be { 0=point | 1=line | 2=rectangle | 3=ellipse }. \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images. **/ CImg& select(CImgDisplay &disp, const unsigned int feature_type=2, unsigned int *const XYZ=0, const bool exit_on_anykey=false) { return get_select(disp,feature_type,XYZ,exit_on_anykey).move_to(*this); } //! Simple interface to select a shape from an image \overloading. CImg& select(const char *const title, const unsigned int feature_type=2, unsigned int *const XYZ=0, const bool exit_on_anykey=false) { return get_select(title,feature_type,XYZ,exit_on_anykey).move_to(*this); } //! Simple interface to select a shape from an image \newinstance. CImg get_select(CImgDisplay &disp, const unsigned int feature_type=2, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { return _get_select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false); } //! Simple interface to select a shape from an image \newinstance. CImg get_select(const char *const title, const unsigned int feature_type=2, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { CImgDisplay disp; return _get_select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false); } CImg _get_select(CImgDisplay &disp, const char *const title, const unsigned int feature_type, unsigned int *const XYZ, const int origX, const int origY, const int origZ, const bool exit_on_anykey, const bool reset_view3d, const bool force_display_z_coord) const { if (is_empty()) return CImg(1,feature_type==0?3:6,1,1,-1); if (!disp) { disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); } else if (title) disp.set_title("%s",title); CImg thumb; if (width()>disp.screen_width() || height()>disp.screen_height()) { const double ratio = cimg::min((double)disp.screen_width()/width(),(double)disp.screen_height()/height()); get_resize(cimg::max(1,(int)(ratio*width())),cimg::max(1,(int)(ratio*height())),-100,-100).move_to(thumb); } const unsigned int old_normalization = disp.normalization(); bool old_is_resized = disp.is_resized(); disp._normalization = 0; disp.show().set_key(0).set_wheel().show_mouse(); static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; int area = 0, starting_area = 0, clicked_area = 0, phase = 0, X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width), Y0 = (int)((XYZ?XYZ[1]:(_height - 1)/2)%_height), Z0 = (int)((XYZ?XYZ[2]:(_depth - 1)/2)%_depth), X1 =-1, Y1 = -1, Z1 = -1, X3d = -1, Y3d = -1, oX3d = X3d, oY3d = -1, omx = -1, omy = -1; float X = -1, Y = -1, Z = -1; unsigned int old_button = 0, key = 0; bool shape_selected = false, text_down = false, visible_cursor = true; static CImg pose3d; static bool is_view3d = false, is_axes = true; if (reset_view3d) { pose3d.assign(); is_view3d = false; } CImg points3d, opacities3d, sel_opacities3d; CImgList primitives3d, sel_primitives3d; CImgList colors3d, sel_colors3d; CImg visu, visu0, view3d; CImg text(1024); *text = 0; while (!key && !disp.is_closed() && !shape_selected) { // Handle mouse motion and selection int mx = disp.mouse_x(), my = disp.mouse_y(); const float mX = mx<0?-1.0f:(float)mx*(width() + (depth()>1?depth():0))/disp.width(), mY = my<0?-1.0f:(float)my*(height() + (depth()>1?depth():0))/disp.height(); area = 0; if (mX>=0 && mY>=0 && mX=0 && mX=height()) { area = 2; X = mX; Z = mY - _height; Y = (float)(phase?Y1:Y0); } if (mY>=0 && mX>=width() && mY=width() && mY>=height()) area = 4; if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0; CImg filename(32); switch (key = disp.key()) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : #endif case 0 : case cimg::keyCTRLLEFT : key = 0; break; case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(1); key = 0; } break; case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(-1); key = 0; } break; case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { is_axes = !is_axes; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). _is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { is_view3d = !is_view3d; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); if (visu0) { (+visu0).draw_text(0,0," Saving snapshot... ",foreground_color,background_color,0.7f,13).display(disp); visu0.save(filename); (+visu0).draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data). display(disp); } disp.set_key(key,false); key = 0; } break; case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; std::FILE *file; do { #ifdef cimg_use_zlib cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); #else cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); #endif if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu0).draw_text(0,0," Saving instance... ",foreground_color,background_color,0.7f,13).display(disp); save(filename); (+visu0).draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data). display(disp); disp.set_key(key,false); key = 0; } break; } switch (area) { case 0 : // When mouse is out of image range. mx = my = -1; X = Y = Z = -1; break; case 1 : case 2 : case 3 : // When mouse is over the XY,XZ or YZ projections. if (disp.button()&1 && phase<2 && clicked_area==area) { // When selection has been started (1st step). if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign(); X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; } if (!(disp.button()&1) && phase>=2 && clicked_area!=area) { // When selection is at 2nd step (for volumes). switch (starting_area) { case 1 : if (Z1!=(int)Z) visu0.assign(); Z1 = (int)Z; break; case 2 : if (Y1!=(int)Y) visu0.assign(); Y1 = (int)Y; break; case 3 : if (X1!=(int)X) visu0.assign(); X1 = (int)X; break; } } if (disp.button()&2 && clicked_area==area) { // When moving through the image/volume. if (phase) { if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign(); X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; } else { if (_depth>1 && (X0!=(int)X || Y0!=(int)Y || Z0!=(int)Z)) visu0.assign(); X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z; } } if (disp.button()&4) { X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0; visu0.assign(); } if (disp.wheel()) { // When moving through the slices of the volume (with mouse wheel). if (_depth>1 && !disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT() && !disp.is_keySHIFTLEFT() && !disp.is_keySHIFTRIGHT() && !disp.is_keyALT() && !disp.is_keyALTGR()) { switch (area) { case 1 : if (phase) Z = (float)(Z1+=disp.wheel()); else Z = (float)(Z0+=disp.wheel()); visu0.assign(); break; case 2 : if (phase) Y = (float)(Y1+=disp.wheel()); else Y = (float)(Y0+=disp.wheel()); visu0.assign(); break; case 3 : if (phase) X = (float)(X1+=disp.wheel()); else X = (float)(X0+=disp.wheel()); visu0.assign(); break; } disp.set_wheel(); } else key = ~0U; } if ((disp.button()&1)!=old_button) { // When left button has just been pressed or released. switch (phase) { case 0 : if (area==clicked_area) { X0 = X1 = (int)X; Y0 = Y1 = (int)Y; Z0 = Z1 = (int)Z; starting_area = area; ++phase; } break; case 1 : if (area==starting_area) { X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; ++phase; } else if (!(disp.button()&1)) { X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = 0; visu0.assign(); } break; case 2 : ++phase; break; } old_button = disp.button()&1; } break; case 4 : // When mouse is over the 3d view. if (is_view3d && points3d) { X3d = mx - width()*disp.width()/(width() + (depth()>1?depth():0)); Y3d = my - height()*disp.height()/(height() + (depth()>1?depth():0)); if (oX3d<0) { oX3d = X3d; oY3d = Y3d; } // Left + right buttons: reset. if ((disp.button()&3)==3) { pose3d.assign(); view3d.assign(); oX3d = oY3d = X3d = Y3d = -1; } else if (disp.button()&1 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Left button: rotate. const float R = 0.45f*cimg::min(view3d._width,view3d._height), R2 = R*R, u0 = (float)(oX3d - view3d.width()/2), v0 = (float)(oY3d - view3d.height()/2), u1 = (float)(X3d - view3d.width()/2), v1 = (float)(Y3d - view3d.height()/2), n0 = (float)std::sqrt(u0*u0 + v0*v0), n1 = (float)std::sqrt(u1*u1 + v1*v1), nu0 = n0>R?(u0*R/n0):u0, nv0 = n0>R?(v0*R/n0):v0, nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)), nu1 = n1>R?(u1*R/n1):u1, nv1 = n1>R?(v1*R/n1):v1, nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)), u = nv0*nw1 - nw0*nv1, v = nw0*nu1 - nu0*nw1, w = nv0*nu1 - nu0*nv1, n = (float)std::sqrt(u*u + v*v + w*w), alpha = (float)std::asin(n/R2); pose3d.draw_image(CImg::rotation_matrix(u,v,w,alpha)*pose3d.get_crop(0,0,2,2)); view3d.assign(); } else if (disp.button()&2 && pose3d && oY3d!=Y3d) { // Right button: zoom. pose3d(3,2)-=(oY3d - Y3d)*1.5f; view3d.assign(); } if (disp.wheel()) { // Wheel: zoom pose3d(3,2)-=disp.wheel()*15; view3d.assign(); disp.set_wheel(); } if (disp.button()&4 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Middle button: shift. pose3d(3,0)-=oX3d - X3d; pose3d(3,1)-=oY3d - Y3d; view3d.assign(); } oX3d = X3d; oY3d = Y3d; } mx = my = -1; X = Y = Z = -1; break; } if (phase) { if (!feature_type) shape_selected = phase?true:false; else { if (_depth>1) shape_selected = (phase==3)?true:false; else shape_selected = (phase==2)?true:false; } } if (X0<0) X0 = 0; if (X0>=width()) X0 = width() - 1; if (Y0<0) Y0 = 0; if (Y0>=height()) Y0 = height() - 1; if (Z0<0) Z0 = 0; if (Z0>=depth()) Z0 = depth() - 1; if (X1<1) X1 = 0; if (X1>=width()) X1 = width() - 1; if (Y1<0) Y1 = 0; if (Y1>=height()) Y1 = height() - 1; if (Z1<0) Z1 = 0; if (Z1>=depth()) Z1 = depth() - 1; // Draw visualization image on the display if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) { if (!visu0) { // Create image of projected planes. if (thumb) thumb.__get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); else __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); visu0.resize(disp); view3d.assign(); points3d.assign(); } if (is_view3d && _depth>1 && !view3d) { // Create 3d view for volumetric images. const unsigned int _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width + _depth),1,1), _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height + _depth),1,1), x3d = _x3d>=visu0._width?visu0._width - 1:_x3d, y3d = _y3d>=visu0._height?visu0._height - 1:_y3d; CImg(1,2,1,1,64,128).resize(visu0._width - x3d,visu0._height - y3d,1,visu0._spectrum,3). move_to(view3d); if (!points3d) { get_projections3d(primitives3d,colors3d,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0,true).move_to(points3d); points3d.append(CImg(8,3,1,1, 0,_width - 1,_width - 1,0,0,_width - 1,_width - 1,0, 0,0,_height - 1,_height - 1,0,0,_height - 1,_height - 1, 0,0,0,0,_depth - 1,_depth - 1,_depth - 1,_depth - 1),'x'); CImg::vector(12,13).move_to(primitives3d); CImg::vector(13,14).move_to(primitives3d); CImg::vector(14,15).move_to(primitives3d); CImg::vector(15,12).move_to(primitives3d); CImg::vector(16,17).move_to(primitives3d); CImg::vector(17,18).move_to(primitives3d); CImg::vector(18,19).move_to(primitives3d); CImg::vector(19,16).move_to(primitives3d); CImg::vector(12,16).move_to(primitives3d); CImg::vector(13,17).move_to(primitives3d); CImg::vector(14,18).move_to(primitives3d); CImg::vector(15,19).move_to(primitives3d); colors3d.insert(12,CImg::vector(255,255,255)); opacities3d.assign(primitives3d.width(),1,1,1,0.5f); if (!phase) { opacities3d[0] = opacities3d[1] = opacities3d[2] = 0.8f; sel_primitives3d.assign(); sel_colors3d.assign(); sel_opacities3d.assign(); } else { if (feature_type==2) { points3d.append(CImg(8,3,1,1, X0,X1,X1,X0,X0,X1,X1,X0, Y0,Y0,Y1,Y1,Y0,Y0,Y1,Y1, Z0,Z0,Z0,Z0,Z1,Z1,Z1,Z1),'x'); sel_primitives3d.assign(); CImg::vector(20,21).move_to(sel_primitives3d); CImg::vector(21,22).move_to(sel_primitives3d); CImg::vector(22,23).move_to(sel_primitives3d); CImg::vector(23,20).move_to(sel_primitives3d); CImg::vector(24,25).move_to(sel_primitives3d); CImg::vector(25,26).move_to(sel_primitives3d); CImg::vector(26,27).move_to(sel_primitives3d); CImg::vector(27,24).move_to(sel_primitives3d); CImg::vector(20,24).move_to(sel_primitives3d); CImg::vector(21,25).move_to(sel_primitives3d); CImg::vector(22,26).move_to(sel_primitives3d); CImg::vector(23,27).move_to(sel_primitives3d); } else { points3d.append(CImg(2,3,1,1, X0,X1, Y0,Y1, Z0,Z1),'x'); sel_primitives3d.assign(CImg::vector(20,21)); } sel_colors3d.assign(sel_primitives3d._width,CImg::vector(255,255,255)); sel_opacities3d.assign(sel_primitives3d._width,1,1,1,0.8f); } points3d.shift_object3d(-0.5f*(_width - 1),-0.5f*(_height - 1),-0.5f*(_depth - 1)).resize_object3d(); points3d*=0.75f*cimg::min(view3d._width,view3d._height); } if (!pose3d) CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose3d); CImg zbuffer3d(view3d._width,view3d._height,1,1,0); const CImg rotated_points3d = pose3d.get_crop(0,0,2,2)*points3d; if (sel_primitives3d) view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width, pose3d(3,1) + 0.5f*view3d._height, pose3d(3,2), rotated_points3d,sel_primitives3d,sel_colors3d,sel_opacities3d, 2,true,500,0,0,0,0,0,zbuffer3d); view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width, pose3d(3,1) + 0.5f*view3d._height, pose3d(3,2), rotated_points3d,primitives3d,colors3d,opacities3d, 2,true,500,0,0,0,0,0,zbuffer3d); visu0.draw_image(x3d,y3d,view3d); } visu = visu0; if (X<0 || Y<0 || Z<0) { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }} else { if (is_axes) { if (visible_cursor) { disp.hide_mouse(); visible_cursor = false; }} else { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }} const int d = (depth()>1)?depth():0; int _X = (int)X, _Y = (int)Y, _Z = (int)Z, w = disp.width(), W = width() + d, h = disp.height(), H = height() + d, _xp = (int)(_X*(float)w/W), xp = _xp + ((int)(_xp*(float)W/w)!=_X?1:0), _yp = (int)(_Y*(float)h/H), yp = _yp + ((int)(_yp*(float)H/h)!=_Y?1:0), _xn = (int)((_X + 1.0f)*w/W - 1), xn = _xn + ((int)((_xn + 1.0f)*W/w)!=_X + 1?1:0), _yn = (int)((_Y + 1.0f)*h/H - 1), yn = _yn + ((int)((_yn + 1.0f)*H/h)!=_Y + 1?1:0), _zxp = (int)((_Z + width())*(float)w/W), zxp = _zxp + ((int)(_zxp*(float)W/w)!=_Z + width()?1:0), _zyp = (int)((_Z + height())*(float)h/H), zyp = _zyp + ((int)(_zyp*(float)H/h)!=_Z + height()?1:0), _zxn = (int)((_Z + width() + 1.0f)*w/W - 1), zxn = _zxn + ((int)((_zxn + 1.0f)*W/w)!=_Z + width() + 1?1:0), _zyn = (int)((_Z + height() + 1.0f)*h/H - 1), zyn = _zyn + ((int)((_zyn + 1.0f)*H/h)!=_Z + height() + 1?1:0), _xM = (int)(width()*(float)w/W - 1), xM = _xM + ((int)((_xM + 1.0f)*W/w)!=width()?1:0), _yM = (int)(height()*(float)h/H - 1), yM = _yM + ((int)((_yM + 1.0f)*H/h)!=height()?1:0), xc = (xp + xn)/2, yc = (yp + yn)/2, zxc = (zxp + zxn)/2, zyc = (zyp + zyn)/2, xf = (int)(X*w/W), yf = (int)(Y*h/H), zxf = (int)((Z + width())*w/W), zyf = (int)((Z + height())*h/H); if (is_axes) { // Draw axes. visu.draw_line(0,yf,visu.width() - 1,yf,foreground_color,0.7f,0xFF00FF00). draw_line(0,yf,visu.width() - 1,yf,background_color,0.7f,0x00FF00FF). draw_line(xf,0,xf,visu.height() - 1,foreground_color,0.7f,0xFF00FF00). draw_line(xf,0,xf,visu.height() - 1,background_color,0.7f,0x00FF00FF); if (_depth>1) visu.draw_line(zxf,0,zxf,yM,foreground_color,0.7f,0xFF00FF00). draw_line(zxf,0,zxf,yM,background_color,0.7f,0x00FF00FF). draw_line(0,zyf,xM,zyf,foreground_color,0.7f,0xFF00FF00). draw_line(0,zyf,xM,zyf,background_color,0.7f,0x00FF00FF); } // Draw box cursor. if (xn - xp>=4 && yn - yp>=4) visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f). draw_rectangle(xp,yp,xn,yn,foreground_color,1,0xAAAAAAAA). draw_rectangle(xp,yp,xn,yn,background_color,1,0x55555555); if (_depth>1) { if (yn - yp>=4 && zxn - zxp>=4) visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f). draw_rectangle(zxp,yp,zxn,yn,foreground_color,1,0xAAAAAAAA). draw_rectangle(zxp,yp,zxn,yn,background_color,1,0x55555555); if (xn - xp>=4 && zyn - zyp>=4) visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f). draw_rectangle(xp,zyp,xn,zyn,foreground_color,1,0xAAAAAAAA). draw_rectangle(xp,zyp,xn,zyn,background_color,1,0x55555555); } // Draw selection. if (phase) { const int _xp0 = (int)(X0*(float)w/W), xp0 = _xp0 + ((int)(_xp0*(float)W/w)!=X0?1:0), _yp0 = (int)(Y0*(float)h/H), yp0 = _yp0 + ((int)(_yp0*(float)H/h)!=Y0?1:0), _xn0 = (int)((X0 + 1.0f)*w/W - 1), xn0 = _xn0 + ((int)((_xn0 + 1.0f)*W/w)!=X0 + 1?1:0), _yn0 = (int)((Y0 + 1.0f)*h/H - 1), yn0 = _yn0 + ((int)((_yn0 + 1.0f)*H/h)!=Y0 + 1?1:0), _zxp0 = (int)((Z0 + width())*(float)w/W), zxp0 = _zxp0 + ((int)(_zxp0*(float)W/w)!=Z0 + width()?1:0), _zyp0 = (int)((Z0 + height())*(float)h/H), zyp0 = _zyp0 + ((int)(_zyp0*(float)H/h)!=Z0 + height()?1:0), _zxn0 = (int)((Z0 + width() + 1.0f)*w/W - 1), zxn0 = _zxn0 + ((int)((_zxn0 + 1.0f)*W/w)!=Z0 + width() + 1?1:0), _zyn0 = (int)((Z0 + height() + 1.0f)*h/H - 1), zyn0 = _zyn0 + ((int)((_zyn0 + 1.0f)*H/h)!=Z0 + height() + 1?1:0), xc0 = (xp0 + xn0)/2, yc0 = (yp0 + yn0)/2, zxc0 = (zxp0 + zxn0)/2, zyc0 = (zyp0 + zyn0)/2; switch (feature_type) { case 1 : { visu.draw_arrow(xc0,yc0,xc,yc,background_color,0.9f,30,5,0x55555555). draw_arrow(xc0,yc0,xc,yc,foreground_color,0.9f,30,5,0xAAAAAAAA); if (d) { visu.draw_arrow(zxc0,yc0,zxc,yc,background_color,0.9f,30,5,0x55555555). draw_arrow(zxc0,yc0,zxc,yc,foreground_color,0.9f,30,5,0xAAAAAAAA). draw_arrow(xc0,zyc0,xc,zyc,background_color,0.9f,30,5,0x55555555). draw_arrow(xc0,zyc0,xc,zyc,foreground_color,0.9f,30,5,0xAAAAAAAA); } } break; case 2 : { visu.draw_rectangle(X0=0 && my<13) text_down = true; else if (my>=visu.height() - 13) text_down = false; if (!feature_type || !phase) { if (X>=0 && Y>=0 && Z>=0 && X1 || force_display_z_coord) cimg_snprintf(text,text._width," Point (%d,%d,%d) = [ ",origX + (int)X,origY + (int)Y,origZ + (int)Z); else cimg_snprintf(text,text._width," Point (%d,%d) = [ ",origX + (int)X,origY + (int)Y); char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512; for (unsigned int c = 0; c<_spectrum && ctext::format(), cimg::type::format((*this)((int)X,(int)Y,(int)Z,c))); ctext = text._data + std::strlen(text); *(ctext++) = ' '; *ctext = 0; } std::strcpy(text._data + std::strlen(text),"] "); } } else switch (feature_type) { case 1 : { const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = std::sqrt(dX*dX + dY*dY + dZ*dZ); if (_depth>1 || force_display_z_coord) cimg_snprintf(text,text._width," Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g ", origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,norm); else cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Norm = %g ", origX + X0,origY + Y0,origX + X1,origY + Y1,norm); } break; case 2 : if (_depth>1 || force_display_z_coord) cimg_snprintf(text,text._width," Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d) ", origX + (X01 || force_display_z_coord) cimg_snprintf(text,text._width," Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d) ", origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1, 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1)); else cimg_snprintf(text,text._width," Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d) ", origX + X0,origY + Y0,origX + X1,origY + Y1, 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1)); } if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.height() - 13:0,text,foreground_color,background_color,0.7f,13); } disp.display(visu).wait(); } else if (!shape_selected) disp.wait(); if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); } omx = mx; omy = my; if (!exit_on_anykey && key && key!=cimg::keyESC && (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { key = 0; } } // Return result. CImg res(1,feature_type==0?3:6,1,1,-1); if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; } if (shape_selected) { if (feature_type==2) { if (X0>X1) cimg::swap(X0,X1); if (Y0>Y1) cimg::swap(Y0,Y1); if (Z0>Z1) cimg::swap(Z0,Z1); } if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1; switch (feature_type) { case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break; case 3 : res[3] = cimg::abs(X1 - X0); res[4] = cimg::abs(Y1 - Y0); res[5] = cimg::abs(Z1 - Z0); // keep no break here! default : res[0] = X0; res[1] = Y0; res[2] = Z0; } } if (!exit_on_anykey || !(disp.button()&4)) disp.set_button(); if (!visible_cursor) disp.show_mouse(); disp._normalization = old_normalization; disp._is_resized = old_is_resized; if (key!=~0U) disp.set_key(key); return res; } // Return a visualizable uchar8 image for display routines. CImg __get_select(const CImgDisplay& disp, const int normalization, const int x, const int y, const int z) const { if (is_empty()) return CImg(1,1,1,1,0); const CImg crop = get_shared_channels(0,cimg::min(2,spectrum() - 1)); CImg img2d; if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d); else CImg(crop,false).move_to(img2d); // Check for inf and NaN values. if (cimg::type::is_float() && normalization) { bool is_inf = false, is_nan = false; cimg_for(img2d,ptr,Tuchar) if (cimg::type::is_inf(*ptr)) { is_inf = true; break; } else if (cimg::type::is_nan(*ptr)) { is_nan = true; break; } if (is_inf || is_nan) { Tint m0 = (Tint)cimg::type::max(), M0 = (Tint)cimg::type::min(); if (!normalization) { m0 = 0; M0 = 255; } else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; } else cimg_for(img2d,ptr,Tuchar) if (!cimg::type::is_inf(*ptr) && !cimg::type::is_nan(*ptr)) { if (*ptr<(Tuchar)m0) m0 = *ptr; if (*ptr>(Tuchar)M0) M0 = *ptr; } const T val_minf = (T)(normalization==1 || normalization==3?m0 - (M0 - m0)*20 - 1:m0), val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0); if (is_nan) cimg_for(img2d,ptr,Tuchar) if (cimg::type::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values. if (is_inf) cimg_for(img2d,ptr,Tuchar) if (cimg::type::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values. } } switch (normalization) { case 1 : img2d.normalize(0,255); break; case 2 : { const float m = disp._min, M = disp._max; (img2d-=m)*=255.0f/(M - m>0?M - m:1); } break; case 3 : if (cimg::type::is_float()) img2d.normalize(0,255); else { const float m = (float)cimg::type::min(), M = (float)cimg::type::max(); (img2d-=m)*=255.0f/(M - m>0?M - m:1); } break; } if (img2d.spectrum()==2) img2d.channels(0,2); return img2d; } //! Select sub-graph in a graph. CImg get_select_graph(CImgDisplay &disp, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0, const bool exit_on_anykey=false) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "select_graph(): Empty instance.", cimg_instance); if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0). set_title("CImg<%s>",pixel_type()); const ulongT siz = (ulongT)_width*_height*_depth; const unsigned int old_normalization = disp.normalization(); disp.show().set_button().set_wheel()._normalization = 0; double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax; if (nymin==nymax) { nymin = (Tfloat)min_max(nymax); const double dy = nymax - nymin; nymin-=dy/20; nymax+=dy/20; } if (nymin==nymax) { --nymin; ++nymax; } if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; } static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 }; static const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; static unsigned int odimv = 0; static CImg colormap; if (odimv!=_spectrum) { odimv = _spectrum; colormap = CImg(3,_spectrum,1,1,120).noise(70,1); if (_spectrum==1) { colormap[0] = colormap[1] = 120; colormap[2] = 200; } else { colormap(0,0) = 220; colormap(1,0) = 10; colormap(2,0) = 10; if (_spectrum>1) { colormap(0,1) = 10; colormap(1,1) = 220; colormap(2,1) = 10; } if (_spectrum>2) { colormap(0,2) = 10; colormap(1,2) = 10; colormap(2,2) = 220; } } } CImg visu0, visu, graph, text, axes; int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2; const unsigned int one = plot_type==3?0U:1U; unsigned int okey = 0, obutton = 0; CImg message(1024); CImg_3x3(I,unsigned char); for (bool selected = false; !selected && !disp.is_closed() && !okey && !disp.wheel(); ) { const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); const unsigned int key = disp.key(), button = disp.button(); // Generate graph representation. if (!visu0) { visu0.assign(disp.width(),disp.height(),1,3,220); const int gdimx = disp.width() - 32, gdimy = disp.height() - 32; if (gdimx>0 && gdimy>0) { graph.assign(gdimx,gdimy,1,3,255); if (siz<32) { if (siz>1) graph.draw_grid(gdimx/(float)(siz - one),gdimy/(float)(siz - one),0,0, false,true,black,0.2f,0x33333333,0x33333333); } else graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333); cimg_forC(*this,c) graph.draw_graph(get_shared_channel(c),&colormap(0,c),(plot_type!=3 || _spectrum==1)?1:0.6f, plot_type,vertex_type,nymax,nymin); axes.assign(gdimx,gdimy,1,1,0); const float dx = (float)cimg::abs(nxmax - nxmin), dy = (float)cimg::abs(nymax - nymin), px = (float)std::pow(10.0,(int)std::log10(dx?dx:1) - 2.0), py = (float)std::pow(10.0,(int)std::log10(dy?dy:1) - 2.0); const CImg seqx = dx<=0?CImg::vector(nxmin): CImg::sequence(1 + gdimx/60,nxmin,one?nxmax:nxmin + (nxmax - nxmin)*(siz + 1)/siz).round(px), seqy = CImg::sequence(1 + gdimy/60,nymax,nymin).round(py); const bool allow_zero = (nxmin*nxmax>0) || (nymin*nymax>0); axes.draw_axes(seqx,seqy,white,1,~0U,~0U,13,allow_zero); if (nymin>0) axes.draw_axis(seqx,gdimy - 1,gray,1,~0U,13,allow_zero); if (nymax<0) axes.draw_axis(seqx,0,gray,1,~0U,13,allow_zero); if (nxmin>0) axes.draw_axis(0,seqy,gray,1,~0U,13,allow_zero); if (nxmax<0) axes.draw_axis(gdimx - 1,seqy,gray,1,~0U,13,allow_zero); cimg_for3x3(axes,x,y,0,0,I,unsigned char) if (Icc) { if (Icc==255) cimg_forC(graph,c) graph(x,y,c) = 0; else cimg_forC(graph,c) graph(x,y,c) = (unsigned char)(2*graph(x,y,c)/3); } else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forC(graph,c) graph(x,y,c) = (unsigned char)((graph(x,y,c) + 511)/3); visu0.draw_image(16,16,graph); visu0.draw_line(15,15,16 + gdimx,15,gray2).draw_line(16 + gdimx,15,16 + gdimx,16 + gdimy,gray2). draw_line(16 + gdimx,16 + gdimy,15,16 + gdimy,white).draw_line(15,16 + gdimy,15,15,white); } else graph.assign(); text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1,13).resize(-100,-100,1,3); visu0.draw_image((visu0.width() - text.width())/2,visu0.height() - 14,~text); text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1,13).rotate(-90).resize(-100,-100,1,3); visu0.draw_image(1,(visu0.height() - text.height())/2,~text); visu.assign(); } // Generate and display current view. if (!visu) { visu.assign(visu0); if (graph && x0>=0 && x1>=0) { const int nx0 = x0<=x1?x0:x1, nx1 = x0<=x1?x1:x0, ny0 = y0<=y1?y0:y1, ny1 = y0<=y1?y1:y0, sx0 = (int)(16 + nx0*(visu.width() - 32)/cimg::max(1U,siz - one)), sx1 = (int)(15 + (nx1 + 1)*(visu.width() - 32)/cimg::max(1U,siz - one)), sy0 = 16 + ny0, sy1 = 16 + ny1; if (y0>=0 && y1>=0) visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU); else visu.draw_rectangle(sx0,0,sx1,visu.height() - 17,gray,0.5f). draw_line(sx0,16,sx0,visu.height() - 17,black,0.5f,0xCCCCCCCCU). draw_line(sx1,16,sx1,visu.height() - 17,black,0.5f,0xCCCCCCCCU); } if (mouse_x>=16 && mouse_y>=16 && mouse_x=7) cimg_snprintf(message,message._width,"Value[%u:%g] = ( %g %g %g ... %g %g %g )",x,cx, (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2), (double)(*this)(x,0,0,_spectrum - 4),(double)(*this)(x,0,0,_spectrum - 3), (double)(*this)(x,0,0,_spectrum - 1)); else { cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx); cimg_forC(*this,c) cimg_sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); cimg_sprintf(message._data + std::strlen(message),")"); } if (x0>=0 && x1>=0) { const unsigned int nx0 = (unsigned int)(x0<=x1?x0:x1), nx1 = (unsigned int)(x0<=x1?x1:x0), ny0 = (unsigned int)(y0<=y1?y0:y1), ny1 = (unsigned int)(y0<=y1?y1:y0); const double cx0 = nxmin + nx0*(nxmax - nxmin)/cimg::max(1U,siz - 1), cx1 = nxmin + (nx1 + one)*(nxmax - nxmin)/cimg::max(1U,siz - 1), cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32), cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32); if (y0>=0 && y1>=0) cimg_sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", x0,cx0,cy0,x1 + one,cx1,cy1); else cimg_sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", x0,cx0,x1 + one,cx1); } text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3); visu.draw_image((visu.width() - text.width())/2,1,~text); } visu.display(disp); } // Test keys. CImg filename(32); switch (okey = key) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : #endif case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : okey = 0; break; case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). _is_resized = true; disp.set_key(key,false); okey = 0; } break; case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; disp.set_key(key,false); okey = 0; } break; case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(CImgDisplay::screen_width()/2, CImgDisplay::screen_height()/2,1),false)._is_resized = true; disp.set_key(key,false); okey = 0; } break; case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; disp.set_key(key,false); okey = 0; } break; case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; if (visu || visu0) { CImg &screen = visu?visu:visu0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp); screen.save(filename); (+screen).draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename._data).display(disp); } disp.set_key(key,false); okey = 0; } break; case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; if (visu || visu0) { CImg &screen = visu?visu:visu0; std::FILE *file; do { #ifdef cimg_use_zlib cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); #else cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); #endif if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+screen).draw_text(0,0," Saving instance... ",black,gray,1,13).display(disp); save(filename); (+screen).draw_text(0,0," Instance '%s' saved. ",black,gray,1,13,filename._data).display(disp); } disp.set_key(key,false); okey = 0; } break; } // Handle mouse motion and mouse buttons if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) { visu.assign(); if (disp.mouse_x()>=0 && disp.mouse_y()>=0) { const int mx = (mouse_x - 16)*(int)(siz - one)/(disp.width() - 32), cx = mx<0?0:(mx>=(int)(siz - one)?(int)(siz - 1 - one):mx), my = mouse_y - 16, cy = my<=0?0:(my>=(disp.height() - 32)?(disp.height() - 32):my); if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; } } else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; } } else if (obutton) { x1 = x1>=0?cx:-1; y1 = y1>=0?cy:-1; selected = true; } } else if (!button && obutton) selected = true; obutton = button; omouse_x = mouse_x; omouse_y = mouse_y; } if (disp.is_resized()) { disp.resize(false); visu0.assign(); } if (visu && visu0) disp.wait(); if (!exit_on_anykey && okey && okey!=cimg::keyESC && (okey!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { disp.set_key(key,false); okey = 0; } } disp._normalization = old_normalization; if (x1>=0 && x1(4,1,1,1,x0,y0,x1>=0?x1 + (int)one:-1,y1); } //! Load image from a file. /** \param filename Filename, as a C-string. \note The extension of \c filename defines the file format. If no filename extension is provided, CImg::get_load() will try to load the file as a .cimg or .cimgz file. **/ CImg& load(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load(): Specified filename is (null).", cimg_instance); if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { CImg filename_local(256); load(cimg::load_network(filename,filename_local)); std::remove(filename_local); return *this; } const char *const ext = cimg::split_filename(filename); const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { #ifdef cimg_load_plugin cimg_load_plugin(filename); #endif #ifdef cimg_load_plugin1 cimg_load_plugin1(filename); #endif #ifdef cimg_load_plugin2 cimg_load_plugin2(filename); #endif #ifdef cimg_load_plugin3 cimg_load_plugin3(filename); #endif #ifdef cimg_load_plugin4 cimg_load_plugin4(filename); #endif #ifdef cimg_load_plugin5 cimg_load_plugin5(filename); #endif #ifdef cimg_load_plugin6 cimg_load_plugin6(filename); #endif #ifdef cimg_load_plugin7 cimg_load_plugin7(filename); #endif #ifdef cimg_load_plugin8 cimg_load_plugin8(filename); #endif // Ascii formats if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename); else if (!cimg::strcasecmp(ext,"dlm") || !cimg::strcasecmp(ext,"txt")) load_dlm(filename); // 2d binary formats else if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename); else if (!cimg::strcasecmp(ext,"jpg") || !cimg::strcasecmp(ext,"jpeg") || !cimg::strcasecmp(ext,"jpe") || !cimg::strcasecmp(ext,"jfif") || !cimg::strcasecmp(ext,"jif")) load_jpeg(filename); else if (!cimg::strcasecmp(ext,"png")) load_png(filename); else if (!cimg::strcasecmp(ext,"ppm") || !cimg::strcasecmp(ext,"pgm") || !cimg::strcasecmp(ext,"pnm") || !cimg::strcasecmp(ext,"pbm") || !cimg::strcasecmp(ext,"pnk")) load_pnm(filename); else if (!cimg::strcasecmp(ext,"pfm")) load_pfm(filename); else if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); else if (!cimg::strcasecmp(ext,"exr")) load_exr(filename); else if (!cimg::strcasecmp(ext,"cr2") || !cimg::strcasecmp(ext,"crw") || !cimg::strcasecmp(ext,"dcr") || !cimg::strcasecmp(ext,"mrw") || !cimg::strcasecmp(ext,"nef") || !cimg::strcasecmp(ext,"orf") || !cimg::strcasecmp(ext,"pix") || !cimg::strcasecmp(ext,"ptx") || !cimg::strcasecmp(ext,"raf") || !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename); else if (!cimg::strcasecmp(ext,"gif")) load_gif_external(filename); // 3d binary formats else if (!cimg::strcasecmp(ext,"dcm") || !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename); else if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"nii")) load_analyze(filename); else if (!cimg::strcasecmp(ext,"par") || !cimg::strcasecmp(ext,"rec")) load_parrec(filename); else if (!cimg::strcasecmp(ext,"mnc")) load_minc2(filename); else if (!cimg::strcasecmp(ext,"inr")) load_inr(filename); else if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename); else if (!cimg::strcasecmp(ext,"cimg") || !cimg::strcasecmp(ext,"cimgz") || !*ext) return load_cimg(filename); // Archive files else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); // Image sequences else if (!cimg::strcasecmp(ext,"avi") || !cimg::strcasecmp(ext,"mov") || !cimg::strcasecmp(ext,"asf") || !cimg::strcasecmp(ext,"divx") || !cimg::strcasecmp(ext,"flv") || !cimg::strcasecmp(ext,"mpg") || !cimg::strcasecmp(ext,"m1v") || !cimg::strcasecmp(ext,"m2v") || !cimg::strcasecmp(ext,"m4v") || !cimg::strcasecmp(ext,"mjp") || !cimg::strcasecmp(ext,"mp4") || !cimg::strcasecmp(ext,"mkv") || !cimg::strcasecmp(ext,"mpe") || !cimg::strcasecmp(ext,"movie") || !cimg::strcasecmp(ext,"ogm") || !cimg::strcasecmp(ext,"ogg") || !cimg::strcasecmp(ext,"ogv") || !cimg::strcasecmp(ext,"qt") || !cimg::strcasecmp(ext,"rm") || !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || !cimg::strcasecmp(ext,"mpeg")) load_video(filename); else throw CImgIOException("CImg<%s>::load()", pixel_type()); } catch (CImgIOException&) { std::FILE *file = 0; try { file = cimg::fopen(filename,"rb"); } catch (CImgIOException&) { cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load(): Failed to open file '%s'.", cimg_instance, filename); } try { const char *const f_type = cimg::ftype(file,filename); std::fclose(file); if (!cimg::strcasecmp(f_type,"pnm")) load_pnm(filename); else if (!cimg::strcasecmp(f_type,"pfm")) load_pfm(filename); else if (!cimg::strcasecmp(f_type,"bmp")) load_bmp(filename); else if (!cimg::strcasecmp(f_type,"inr")) load_inr(filename); else if (!cimg::strcasecmp(f_type,"jpg")) load_jpeg(filename); else if (!cimg::strcasecmp(f_type,"pan")) load_pandore(filename); else if (!cimg::strcasecmp(f_type,"png")) load_png(filename); else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); else if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); else if (!cimg::strcasecmp(f_type,"dcm")) load_medcon_external(filename); else throw CImgIOException("CImg<%s>::load()", pixel_type()); } catch (CImgIOException&) { try { load_other(filename); } catch (CImgIOException&) { cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load(): Failed to recognize format of file '%s'.", cimg_instance, filename); } } } cimg::exception_mode(omode); return *this; } //! Load image from a file \newinstance. static CImg get_load(const char *const filename) { return CImg().load(filename); } //! Load image from an ascii file. /** \param filename Filename, as a C -string. **/ CImg& load_ascii(const char *const filename) { return _load_ascii(0,filename); } //! Load image from an ascii file \inplace. static CImg get_load_ascii(const char *const filename) { return CImg().load_ascii(filename); } //! Load image from an ascii file \overloading. CImg& load_ascii(std::FILE *const file) { return _load_ascii(file,0); } //! Loadimage from an ascii file \newinstance. static CImg get_load_ascii(std::FILE *const file) { return CImg().load_ascii(file); } CImg& _load_ascii(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_ascii(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg line(256); *line = 0; int err = std::fscanf(nfile,"%255[^\n]",line._data); unsigned int dx = 0, dy = 1, dz = 1, dc = 1; cimg_sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dc); err = std::fscanf(nfile,"%*[^0-9.eEinfa+-]"); if (!dx || !dy || !dz || !dc) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_ascii(): Invalid ascii header in file '%s', image dimensions are set " "to (%u,%u,%u,%u).", cimg_instance, filename?filename:"(FILE*)",dx,dy,dz,dc); } assign(dx,dy,dz,dc); const ulongT siz = size(); ulongT off = 0; double val; T *ptr = _data; for (err = 1, off = 0; off& load_dlm(const char *const filename) { return _load_dlm(0,filename); } //! Load image from a DLM file \newinstance. static CImg get_load_dlm(const char *const filename) { return CImg().load_dlm(filename); } //! Load image from a DLM file \overloading. CImg& load_dlm(std::FILE *const file) { return _load_dlm(file,0); } //! Load image from a DLM file \newinstance. static CImg get_load_dlm(std::FILE *const file) { return CImg().load_dlm(file); } CImg& _load_dlm(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_dlm(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); CImg delimiter(256), tmp(256); *delimiter = *tmp = 0; unsigned int cdx = 0, dx = 0, dy = 0; int err = 0; double val; assign(256,256,1,1,0); while ((err = std::fscanf(nfile,"%lf%255[^0-9eEinfa.+-]",&val,delimiter._data))>0) { if (err>0) (*this)(cdx++,dy) = (T)val; if (cdx>=_width) resize(3*_width/2,_height,1,1,0); char c = 0; if (!cimg_sscanf(delimiter,"%255[^\n]%c",tmp._data,&c) || c=='\n') { dx = cimg::max(cdx,dx); if (++dy>=_height) resize(_width,3*_height/2,1,1,0); cdx = 0; } } if (cdx && err==1) { dx = cdx; ++dy; } if (!dx || !dy) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_dlm(): Invalid DLM file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } resize(dx,dy,1,1,0); if (!file) cimg::fclose(nfile); return *this; } //! Load image from a BMP file. /** \param filename Filename, as a C-string. **/ CImg& load_bmp(const char *const filename) { return _load_bmp(0,filename); } //! Load image from a BMP file \newinstance. static CImg get_load_bmp(const char *const filename) { return CImg().load_bmp(filename); } //! Load image from a BMP file \overloading. CImg& load_bmp(std::FILE *const file) { return _load_bmp(file,0); } //! Load image from a BMP file \newinstance. static CImg get_load_bmp(std::FILE *const file) { return CImg().load_bmp(file); } CImg& _load_bmp(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_bmp(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg header(54); cimg::fread(header._data,54,nfile); if (*header!='B' || header[1]!='M') { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_bmp(): Invalid BMP file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } // Read header and pixel buffer int file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24), offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24), header_size = header[0x0E] + (header[0x0F]<<8) + (header[0x10]<<16) + (header[0x11]<<24), dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24), dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24), compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24), nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24), bpp = header[0x1C] + (header[0x1D]<<8); if (!file_size || file_size==offset) { cimg::fseek(nfile,0,SEEK_END); file_size = (int)cimg::ftell(nfile); cimg::fseek(nfile,54,SEEK_SET); } if (header_size>40) cimg::fseek(nfile,header_size - 40,SEEK_CUR); const int cimg_iobuffer = 24*1024*1024, dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2?1:0)):(dx*bpp/8)), align_bytes = (4 - dx_bytes%4)%4, buf_size = cimg::min(cimg::abs(dy)*(dx_bytes + align_bytes),file_size - offset); CImg colormap; if (bpp<16) { if (!nb_colors) nb_colors = 1<0) cimg::fseek(nfile,xoffset,SEEK_CUR); CImg buffer; if (buf_size=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } unsigned char mask = 0x80, val = 0; cimg_forX(*this,x) { if (mask==0x80) val = *(ptrs++); const unsigned char *col = (unsigned char*)(colormap._data + (val&mask?1:0)); (*this)(x,y,2) = (T)*(col++); (*this)(x,y,1) = (T)*(col++); (*this)(x,y,0) = (T)*(col++); mask = cimg::ror(mask); } ptrs+=align_bytes; } } break; case 4 : { // 16 colors for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } unsigned char mask = 0xF0, val = 0; cimg_forX(*this,x) { if (mask==0xF0) val = *(ptrs++); const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4)); const unsigned char *col = (unsigned char*)(colormap._data + color); (*this)(x,y,2) = (T)*(col++); (*this)(x,y,1) = (T)*(col++); (*this)(x,y,0) = (T)*(col++); mask = cimg::ror(mask,4); } ptrs+=align_bytes; } } break; case 8 : { // 256 colors for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } cimg_forX(*this,x) { const unsigned char *col = (unsigned char*)(colormap._data + *(ptrs++)); (*this)(x,y,2) = (T)*(col++); (*this)(x,y,1) = (T)*(col++); (*this)(x,y,0) = (T)*(col++); } ptrs+=align_bytes; } } break; case 16 : { // 16 bits colors for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } cimg_forX(*this,x) { const unsigned char c1 = *(ptrs++), c2 = *(ptrs++); const unsigned short col = (unsigned short)(c1|(c2<<8)); (*this)(x,y,2) = (T)(col&0x1F); (*this)(x,y,1) = (T)((col>>5)&0x1F); (*this)(x,y,0) = (T)((col>>10)&0x1F); } ptrs+=align_bytes; } } break; case 24 : { // 24 bits colors for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } cimg_forX(*this,x) { (*this)(x,y,2) = (T)*(ptrs++); (*this)(x,y,1) = (T)*(ptrs++); (*this)(x,y,0) = (T)*(ptrs++); } ptrs+=align_bytes; } } break; case 32 : { // 32 bits colors for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); cimg::fseek(nfile,align_bytes,SEEK_CUR); } cimg_forX(*this,x) { (*this)(x,y,2) = (T)*(ptrs++); (*this)(x,y,1) = (T)*(ptrs++); (*this)(x,y,0) = (T)*(ptrs++); ++ptrs; } ptrs+=align_bytes; } } break; } if (dy<0) mirror('y'); if (!file) cimg::fclose(nfile); return *this; } //! Load image from a JPEG file. /** \param filename Filename, as a C-string. **/ CImg& load_jpeg(const char *const filename) { return _load_jpeg(0,filename); } //! Load image from a JPEG file \newinstance. static CImg get_load_jpeg(const char *const filename) { return CImg().load_jpeg(filename); } //! Load image from a JPEG file \overloading. CImg& load_jpeg(std::FILE *const file) { return _load_jpeg(file,0); } //! Load image from a JPEG file \newinstance. static CImg get_load_jpeg(std::FILE *const file) { return CImg().load_jpeg(file); } // Custom error handler for libjpeg. #ifdef cimg_use_jpeg struct _cimg_error_mgr { struct jpeg_error_mgr original; jmp_buf setjmp_buffer; char message[JMSG_LENGTH_MAX]; }; typedef struct _cimg_error_mgr *_cimg_error_ptr; METHODDEF(void) _cimg_jpeg_error_exit(j_common_ptr cinfo) { _cimg_error_ptr c_err = (_cimg_error_ptr) cinfo->err; // Return control to the setjmp point (*cinfo->err->format_message)(cinfo,c_err->message); jpeg_destroy(cinfo); // Clean memory and temp files. longjmp(c_err->setjmp_buffer,1); } #endif CImg& _load_jpeg(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_jpeg(): Specified filename is (null).", cimg_instance); #ifndef cimg_use_jpeg if (file) throw CImgIOException(_cimg_instance "load_jpeg(): Unable to load data from '(FILE*)' unless libjpeg is enabled.", cimg_instance); else return load_other(filename); #else std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); struct jpeg_decompress_struct cinfo; struct _cimg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.original); jerr.original.error_exit = _cimg_jpeg_error_exit; if (setjmp(jerr.setjmp_buffer)) { // JPEG error if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_jpeg(): Error message returned by libjpeg: %s.", cimg_instance,jerr.message); } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo,nfile); jpeg_read_header(&cinfo,TRUE); jpeg_start_decompress(&cinfo); if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) { if (!file) { cimg::fclose(nfile); return load_other(filename); } else throw CImgIOException(_cimg_instance "load_jpeg(): Failed to load JPEG data from file '%s'.", cimg_instance,filename?filename:"(FILE*)"); } CImg buffer(cinfo.output_width*cinfo.output_components); JSAMPROW row_pointer[1]; try { assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); } catch (...) { if (!file) cimg::fclose(nfile); throw; } T *ptr_r = _data, *ptr_g = _data + 1UL*_width*_height, *ptr_b = _data + 2UL*_width*_height, *ptr_a = _data + 3UL*_width*_height; while (cinfo.output_scanline // This is experimental code, not much tested, use with care. CImg& load_magick(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_magick(): Specified filename is (null).", cimg_instance); #ifdef cimg_use_magick Magick::Image image(filename); const unsigned int W = image.size().width(), H = image.size().height(); switch (image.type()) { case Magick::PaletteMatteType : case Magick::TrueColorMatteType : case Magick::ColorSeparationType : { assign(W,H,1,4); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); for (ulongT off = (ulongT)W*H; off; --off) { *(ptr_r++) = (T)(pixels->red); *(ptr_g++) = (T)(pixels->green); *(ptr_b++) = (T)(pixels->blue); *(ptr_a++) = (T)(pixels->opacity); ++pixels; } } break; case Magick::PaletteType : case Magick::TrueColorType : { assign(W,H,1,3); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); for (ulongT off = (ulongT)W*H; off; --off) { *(ptr_r++) = (T)(pixels->red); *(ptr_g++) = (T)(pixels->green); *(ptr_b++) = (T)(pixels->blue); ++pixels; } } break; case Magick::GrayscaleMatteType : { assign(W,H,1,2); T *ptr_r = data(0,0,0,0), *ptr_a = data(0,0,0,1); Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); for (ulongT off = (ulongT)W*H; off; --off) { *(ptr_r++) = (T)(pixels->red); *(ptr_a++) = (T)(pixels->opacity); ++pixels; } } break; default : { assign(W,H,1,1); T *ptr_r = data(0,0,0,0); Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); for (ulongT off = (ulongT)W*H; off; --off) { *(ptr_r++) = (T)(pixels->red); ++pixels; } } } return *this; #else throw CImgIOException(_cimg_instance "load_magick(): Unable to load file '%s' unless libMagick++ is enabled.", cimg_instance, filename); #endif } //! Load image from a file, using Magick++ library \newinstance. static CImg get_load_magick(const char *const filename) { return CImg().load_magick(filename); } //! Load image from a PNG file. /** \param filename Filename, as a C-string. **/ CImg& load_png(const char *const filename) { return _load_png(0,filename); } //! Load image from a PNG file \newinstance. static CImg get_load_png(const char *const filename) { return CImg().load_png(filename); } //! Load image from a PNG file \overloading. CImg& load_png(std::FILE *const file) { return _load_png(file,0); } //! Load image from a PNG file \newinstance. static CImg get_load_png(std::FILE *const file) { return CImg().load_png(file); } // (Note: Most of this function has been written by Eric Fausett) CImg& _load_png(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_png(): Specified filename is (null).", cimg_instance); #ifndef cimg_use_png if (file) throw CImgIOException(_cimg_instance "load_png(): Unable to load data from '(FILE*)' unless libpng is enabled.", cimg_instance); else return load_other(filename); #else // Open file and check for PNG validity const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'. std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb"); unsigned char pngCheck[8] = { 0 }; cimg::fread(pngCheck,8,(std::FILE*)nfile); if (png_sig_cmp(pngCheck,0,8)) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_png(): Invalid PNG file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } // Setup PNG structures for read png_voidp user_error_ptr = 0; png_error_ptr user_error_fn = 0, user_warning_fn = 0; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn); if (!png_ptr) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_png(): Failed to initialize 'png_ptr' structure for file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0); throw CImgIOException(_cimg_instance "load_png(): Failed to initialize 'info_ptr' structure for file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0); throw CImgIOException(_cimg_instance "load_png(): Failed to initialize 'end_info' structure for file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } // Error handling callback for png file reading if (setjmp(png_jmpbuf(png_ptr))) { if (!file) cimg::fclose((std::FILE*)nfile); png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); throw CImgIOException(_cimg_instance "load_png(): Encountered unknown fatal error in libpng for file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_init_io(png_ptr, nfile); png_set_sig_bytes(png_ptr, 8); // Get PNG Header Info up to data block png_read_info(png_ptr,info_ptr); png_uint_32 W, H; int bit_depth, color_type, interlace_type; bool is_gray = false; png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,(int*)0,(int*)0); // Transforms to unify image data if (color_type==PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; bit_depth = 8; } if (color_type==PNG_COLOR_TYPE_GRAY && bit_depth<8) { png_set_expand_gray_1_2_4_to_8(png_ptr); is_gray = true; bit_depth = 8; } if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); color_type |= PNG_COLOR_MASK_ALPHA; } if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); color_type |= PNG_COLOR_MASK_COLOR; is_gray = true; } if (color_type==PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr,0xffffU,PNG_FILLER_AFTER); png_read_update_info(png_ptr,info_ptr); if (bit_depth!=8 && bit_depth!=16) { if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0); throw CImgIOException(_cimg_instance "load_png(): Invalid bit depth %u in file '%s'.", cimg_instance, bit_depth,nfilename?nfilename:"(FILE*)"); } const int byte_depth = bit_depth>>3; // Allocate Memory for Image Read png_bytep *const imgData = new png_bytep[H]; for (unsigned int row = 0; row& load_pnm(const char *const filename) { return _load_pnm(0,filename); } //! Load image from a PNM file \newinstance. static CImg get_load_pnm(const char *const filename) { return CImg().load_pnm(filename); } //! Load image from a PNM file \overloading. CImg& load_pnm(std::FILE *const file) { return _load_pnm(file,0); } //! Load image from a PNM file \newinstance. static CImg get_load_pnm(std::FILE *const file) { return CImg().load_pnm(file); } CImg& _load_pnm(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_pnm(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); unsigned int ppm_type, W, H, D = 1, colormax = 255; CImg item(16384,1,1,1,0); int err, rval, gval, bval; const longT cimg_iobuffer = (longT)24*1024*1024; while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if (cimg_sscanf(item," P%u",&ppm_type)!=1) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pnm(): PNM header not found in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if ((err=cimg_sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } if (ppm_type!=1 && ppm_type!=4) { if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) { while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if (cimg_sscanf(item,"%u",&colormax)!=1) cimg::warn(_cimg_instance "load_pnm(): COLORMAX field is undefined in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } else { colormax = D; D = 1; } } std::fgetc(nfile); switch (ppm_type) { case 1 : { // 2d b&w ascii. assign(W,H,1,1); T* ptrd = _data; cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)(rval?0:255); else break; } } break; case 2 : { // 2d grey ascii. assign(W,H,1,1); T* ptrd = _data; cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)rval; else break; } } break; case 3 : { // 2d color ascii. assign(W,H,1,3); T *ptrd = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); cimg_forXY(*this,x,y) { if (std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(ptrd++) = (T)rval; *(ptr_g++) = (T)gval; *(ptr_b++) = (T)bval; } else break; } } break; case 4 : { // 2d b&w binary (support 3D PINK extension). CImg raw; assign(W,H,D,1); T *ptrd = data(0,0,0,0); unsigned int w = 0, h = 0, d = 0; for (longT to_read = (longT)((W/8 + (W%8?1:0))*H*D); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const unsigned char *ptrs = raw._data; unsigned char mask = 0, val = 0; for (ulongT off = (ulongT)raw._width; off || mask; mask>>=1) { if (!mask) { if (off--) val = *(ptrs++); mask = 128; } *(ptrd++) = (T)((val&mask)?0:255); if (++w==W) { w = 0; mask = 0; if (++h==H) { h = 0; if (++d==D) break; }} } } } break; case 5 : case 7 : { // 2d/3d grey binary (support 3D PINK extension). if (colormax<256) { // 8 bits. CImg raw; assign(W,H,D,1); T *ptrd = data(0,0,0,0); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const unsigned char *ptrs = raw._data; for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); } } else { // 16 bits. CImg raw; assign(W,H,D,1); T *ptrd = data(0,0,0,0); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer/2)); cimg::fread(raw._data,raw._width,nfile); if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); to_read-=raw._width; const unsigned short *ptrs = raw._data; for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); } } } break; case 6 : { // 2d color binary. if (colormax<256) { // 8 bits. CImg raw; assign(W,H,1,3); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const unsigned char *ptrs = raw._data; for (ulongT off = (ulongT)raw._width/3; off; --off) { *(ptr_r++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_b++) = (T)*(ptrs++); } } } else { // 16 bits. CImg raw; assign(W,H,1,3); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer/2)); cimg::fread(raw._data,raw._width,nfile); if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); to_read-=raw._width; const unsigned short *ptrs = raw._data; for (ulongT off = (ulongT)raw._width/3; off; --off) { *(ptr_r++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_b++) = (T)*(ptrs++); } } } } break; case 8 : { // 2d/3d grey binary with int32 integers (PINK extension). CImg raw; assign(W,H,D,1); T *ptrd = data(0,0,0,0); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const int *ptrs = raw._data; for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); } } break; case 9 : { // 2d/3d grey binary with float values (PINK extension). CImg raw; assign(W,H,D,1); T *ptrd = data(0,0,0,0); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const float *ptrs = raw._data; for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); } } break; default : assign(); if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pnm(): PNM type 'P%d' found, but type is not supported.", cimg_instance, filename?filename:"(FILE*)",ppm_type); } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a PFM file. /** \param filename Filename, as a C-string. **/ CImg& load_pfm(const char *const filename) { return _load_pfm(0,filename); } //! Load image from a PFM file \newinstance. static CImg get_load_pfm(const char *const filename) { return CImg().load_pfm(filename); } //! Load image from a PFM file \overloading. CImg& load_pfm(std::FILE *const file) { return _load_pfm(file,0); } //! Load image from a PFM file \newinstance. static CImg get_load_pfm(std::FILE *const file) { return CImg().load_pfm(file); } CImg& _load_pfm(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_pfm(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); char pfm_type; CImg item(16384,1,1,1,0); int W = 0, H = 0, err = 0; double scale = 0; while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if (cimg_sscanf(item," P%c",&pfm_type)!=1) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pfm(): PFM header not found in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if ((err=cimg_sscanf(item," %d %d",&W,&H))<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } if (err==2) { while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); if (cimg_sscanf(item,"%lf",&scale)!=1) cimg::warn(_cimg_instance "load_pfm(): SCALE field is undefined in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } std::fgetc(nfile); const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness(); if (is_color) { assign(W,H,1,3,0); CImg buf(3*W); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); cimg_forY(*this,y) { cimg::fread(buf._data,3*W,nfile); if (is_inverted) cimg::invert_endianness(buf._data,3*W); const float *ptrs = buf._data; cimg_forX(*this,x) { *(ptr_r++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_b++) = (T)*(ptrs++); } } } else { assign(W,H,1,1,0); CImg buf(W); T *ptrd = data(0,0,0,0); cimg_forY(*this,y) { cimg::fread(buf._data,W,nfile); if (is_inverted) cimg::invert_endianness(buf._data,W); const float *ptrs = buf._data; cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++); } } if (!file) cimg::fclose(nfile); return mirror('y'); // Most of the .pfm files are flipped along the y-axis. } //! Load image from a RGB file. /** \param filename Filename, as a C-string. \param dimw Width of the image buffer. \param dimh Height of the image buffer. **/ CImg& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { return _load_rgb(0,filename,dimw,dimh); } //! Load image from a RGB file \newinstance. static CImg get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { return CImg().load_rgb(filename,dimw,dimh); } //! Load image from a RGB file \overloading. CImg& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { return _load_rgb(file,0,dimw,dimh); } //! Load image from a RGB file \newinstance. static CImg get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { return CImg().load_rgb(file,dimw,dimh); } CImg& _load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_rgb(): Specified filename is (null).", cimg_instance); if (!dimw || !dimh) return assign(); const longT cimg_iobuffer = (longT)24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg raw; assign(dimw,dimh,1,3); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const unsigned char *ptrs = raw._data; for (ulongT off = raw._width/3UL; off; --off) { *(ptr_r++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_b++) = (T)*(ptrs++); } } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a RGBA file. /** \param filename Filename, as a C-string. \param dimw Width of the image buffer. \param dimh Height of the image buffer. **/ CImg& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { return _load_rgba(0,filename,dimw,dimh); } //! Load image from a RGBA file \newinstance. static CImg get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { return CImg().load_rgba(filename,dimw,dimh); } //! Load image from a RGBA file \overloading. CImg& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { return _load_rgba(file,0,dimw,dimh); } //! Load image from a RGBA file \newinstance. static CImg get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { return CImg().load_rgba(file,dimw,dimh); } CImg& _load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_rgba(): Specified filename is (null).", cimg_instance); if (!dimw || !dimh) return assign(); const longT cimg_iobuffer = (longT)24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg raw; assign(dimw,dimh,1,4); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); for (longT to_read = (longT)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer)); cimg::fread(raw._data,raw._width,nfile); to_read-=raw._width; const unsigned char *ptrs = raw._data; for (ulongT off = raw._width/4UL; off; --off) { *(ptr_r++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_b++) = (T)*(ptrs++); *(ptr_a++) = (T)*(ptrs++); } } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a TIFF file. /** \param filename Filename, as a C-string. \param first_frame First frame to read (for multi-pages tiff). \param last_frame Last frame to read (for multi-pages tiff). \param step_frame Step value of frame reading. \note - libtiff support is enabled by defining the precompilation directive \c cimg_use_tif. - When libtiff is enabled, 2D and 3D (multipage) several channel per pixel are supported for char,uchar,short,ushort,float and \c double pixel types. - If \c cimg_use_tif is not defined at compile time the function uses CImg& load_other(const char*). **/ CImg& load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, float *const voxel_size=0, CImg *const description=0) { if (!filename) throw CImgArgumentException(_cimg_instance "load_tiff(): Specified filename is (null).", cimg_instance); const unsigned int nfirst_frame = first_frame1) throw CImgArgumentException(_cimg_instance "load_tiff(): Unable to read sub-images from file '%s' unless libtiff is enabled.", cimg_instance, filename); return load_other(filename); #else TIFF *tif = TIFFOpen(filename,"r"); if (tif) { unsigned int nb_images = 0; do ++nb_images; while (TIFFReadDirectory(tif)); if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) cimg::warn(_cimg_instance "load_tiff(): File '%s' contains %u image(s) while specified frame range is [%u,%u] (step %u).", cimg_instance, filename,nb_images,nfirst_frame,nlast_frame,nstep_frame); if (nfirst_frame>=nb_images) return assign(); if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; TIFFSetDirectory(tif,0); CImg frame; for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) { frame._load_tiff(tif,l,voxel_size,description); if (l==nfirst_frame) assign(frame._width,frame._height,1 + (nlast_frame - nfirst_frame)/nstep_frame,frame._spectrum); if (frame._width>_width || frame._height>_height || frame._spectrum>_spectrum) resize(cimg::max(frame._width,_width), cimg::max(frame._height,_height),-100, cimg::max(frame._spectrum,_spectrum),0); draw_image(0,0,(l - nfirst_frame)/nstep_frame,frame); } TIFFClose(tif); } else throw CImgIOException(_cimg_instance "load_tiff(): Failed to open file '%s'.", cimg_instance, filename); return *this; #endif } //! Load image from a TIFF file \newinstance. static CImg get_load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, float *const voxel_size=0, CImg *const description=0) { return CImg().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description); } // (Original contribution by Jerome Boulanger). #ifdef cimg_use_tiff template void _load_tiff_tiled_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) { t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); if (buf) { for (unsigned int row = 0; row void _load_tiff_tiled_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) { t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); if (buf) { for (unsigned int vv = 0; vv void _load_tiff_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) { t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); if (buf) { uint32 row, rowsperstrip = (uint32)-1; TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); for (row = 0; rowny?ny - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgIOException(_cimg_instance "load_tiff(): Invalid strip in file '%s'.", cimg_instance, TIFFFileName(tif)); } const t *ptr = buf; for (unsigned int rr = 0; rr void _load_tiff_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) { t *buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); if (buf) { uint32 row, rowsperstrip = (uint32)-1; TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); for (unsigned int vv = 0; vvny?ny - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, vv); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgIOException(_cimg_instance "load_tiff(): Invalid strip in file '%s'.", cimg_instance, TIFFFileName(tif)); } const t *ptr = buf; for (unsigned int rr = 0;rr& _load_tiff(TIFF *const tif, const unsigned int directory, float *const voxel_size, CImg *const description) { if (!TIFFSetDirectory(tif,directory)) return assign(); uint16 samplesperpixel = 1, bitspersample = 8, photo = 0; uint16 sampleformat = 1; uint32 nx = 1, ny = 1; const char *const filename = TIFFFileName(tif); const bool is_spp = (bool)TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel); TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx); TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny); TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat); TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample); TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo); if (voxel_size) { const char *s_description = 0; float vx = 0, vy = 0, vz = 0; if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) { const char *s_desc = std::strstr(s_description,"VX="); if (s_desc && cimg_sscanf(s_desc,"VX=%f VY=%f VZ=%f",&vx,&vy,&vz)==3) { // CImg format. voxel_size[0] = vx; voxel_size[1] = vy; voxel_size[2] = vz; } s_desc = std::strstr(s_description,"spacing="); if (s_desc && cimg_sscanf(s_desc,"spacing=%f",&vz)==1) { // fiji format. voxel_size[2] = vz; } } TIFFGetField(tif,TIFFTAG_XRESOLUTION,voxel_size); TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size + 1); voxel_size[0] = 1.0f/voxel_size[0]; voxel_size[1] = 1.0f/voxel_size[1]; } if (description) { const char *s_description = 0; if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) CImg::string(s_description).move_to(*description); } const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel; assign(nx,ny,1,spectrum); if ((photo>=3 && sampleformat==1 && (bitspersample==4 || bitspersample==8) && (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) || (bitspersample==1 && samplesperpixel==1)) { // Special case for unsigned color images. uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32)); if (!raster) { _TIFFfree(raster); TIFFClose(tif); throw CImgException(_cimg_instance "load_tiff(): Failed to allocate memory (%s) for file '%s'.", cimg_instance, cimg::strbuffersize(nx*ny*sizeof(uint32)),filename); } TIFFReadRGBAImage(tif,nx,ny,raster,0); switch (spectrum) { case 1 : cimg_forXY(*this,x,y) (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); break; case 3 : cimg_forXY(*this,x,y) { (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]); (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]); } break; case 4 : cimg_forXY(*this,x,y) { (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]); } break; } _TIFFfree(raster); } else { // Other cases. uint16 config; TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config); if (TIFFIsTiled(tif)) { uint32 tw = 1, th = 1; TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw); TIFFGetField(tif,TIFFTAG_TILELENGTH,&th); if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { case 8 : { if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); } break; case 16 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); break; case 32 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); break; } else switch (bitspersample) { case 8 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); break; case 16 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); break; case 32 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); break; } } else { if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { case 8 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); else _load_tiff_contig(tif,samplesperpixel,nx,ny); break; case 16 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); else _load_tiff_contig(tif,samplesperpixel,nx,ny); break; case 32 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig(tif,samplesperpixel,nx,ny); else _load_tiff_contig(tif,samplesperpixel,nx,ny); break; } else switch (bitspersample) { case 8 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); else _load_tiff_separate(tif,samplesperpixel,nx,ny); break; case 16 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); else _load_tiff_separate(tif,samplesperpixel,nx,ny); break; case 32 : if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate(tif,samplesperpixel,nx,ny); else _load_tiff_separate(tif,samplesperpixel,nx,ny); break; } } } return *this; } #endif //! Load image from a MINC2 file. /** \param filename Filename, as a C-string. **/ // (Original code by Haz-Edine Assemlal). CImg& load_minc2(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_minc2(): Specified filename is (null).", cimg_instance); #ifndef cimg_use_minc2 return load_other(filename); #else minc::minc_1_reader rdr; rdr.open(filename); assign(rdr.ndim(1)?rdr.ndim(1):1, rdr.ndim(2)?rdr.ndim(2):1, rdr.ndim(3)?rdr.ndim(3):1, rdr.ndim(4)?rdr.ndim(4):1); if(typeid(T)==typeid(unsigned char)) rdr.setup_read_byte(); else if(typeid(T)==typeid(int)) rdr.setup_read_int(); else if(typeid(T)==typeid(double)) rdr.setup_read_double(); else rdr.setup_read_float(); minc::load_standard_volume(rdr, this->_data); return *this; #endif } //! Load image from a MINC2 file \newinstance. static CImg get_load_minc2(const char *const filename) { return CImg().load_analyze(filename); } //! Load image from an ANALYZE7.5/NIFTI file. /** \param filename Filename, as a C-string. \param[out] voxel_size Pointer to the three voxel sizes read from the file. **/ CImg& load_analyze(const char *const filename, float *const voxel_size=0) { return _load_analyze(0,filename,voxel_size); } //! Load image from an ANALYZE7.5/NIFTI file \newinstance. static CImg get_load_analyze(const char *const filename, float *const voxel_size=0) { return CImg().load_analyze(filename,voxel_size); } //! Load image from an ANALYZE7.5/NIFTI file \overloading. CImg& load_analyze(std::FILE *const file, float *const voxel_size=0) { return _load_analyze(file,0,voxel_size); } //! Load image from an ANALYZE7.5/NIFTI file \newinstance. static CImg get_load_analyze(std::FILE *const file, float *const voxel_size=0) { return CImg().load_analyze(file,voxel_size); } CImg& _load_analyze(std::FILE *const file, const char *const filename, float *const voxel_size=0) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_analyze(): Specified filename is (null).", cimg_instance); std::FILE *nfile_header = 0, *nfile = 0; if (!file) { CImg body(1024); const char *const ext = cimg::split_filename(filename,body); if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file. nfile_header = cimg::fopen(filename,"rb"); cimg_sprintf(body._data + std::strlen(body),".img"); nfile = cimg::fopen(body,"rb"); } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file. nfile = cimg::fopen(filename,"rb"); cimg_sprintf(body._data + std::strlen(body),".hdr"); nfile_header = cimg::fopen(body,"rb"); } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file. } else nfile_header = nfile = file; // File is a Niftii file. if (!nfile || !nfile_header) throw CImgIOException(_cimg_instance "load_analyze(): Invalid Analyze7.5 or NIFTI header in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); // Read header. bool endian = false; unsigned int header_size; cimg::fread(&header_size,1,nfile_header); if (!header_size) throw CImgIOException(_cimg_instance "load_analyze(): Invalid zero-size header in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); } unsigned char *const header = new unsigned char[header_size]; cimg::fread(header + 4,header_size - 4,nfile_header); if (!file && nfile_header!=nfile) cimg::fclose(nfile_header); if (endian) { cimg::invert_endianness((short*)(header + 40),5); cimg::invert_endianness((short*)(header + 70),1); cimg::invert_endianness((short*)(header + 72),1); cimg::invert_endianness((float*)(header + 76),4); cimg::invert_endianness((float*)(header + 112),1); } unsigned short *dim = (unsigned short*)(header + 40), dimx = 1, dimy = 1, dimz = 1, dimv = 1; if (!dim[0]) cimg::warn(_cimg_instance "load_analyze(): File '%s' defines an image with zero dimensions.", cimg_instance, filename?filename:"(FILE*)"); if (dim[0]>4) cimg::warn(_cimg_instance "load_analyze(): File '%s' defines an image with %u dimensions, reading only the 4 first.", cimg_instance, filename?filename:"(FILE*)",dim[0]); if (dim[0]>=1) dimx = dim[1]; if (dim[0]>=2) dimy = dim[2]; if (dim[0]>=3) dimz = dim[3]; if (dim[0]>=4) dimv = dim[4]; float scalefactor = *(float*)(header + 112); if (scalefactor==0) scalefactor=1; const unsigned short datatype = *(unsigned short*)(header + 70); if (voxel_size) { const float *vsize = (float*)(header + 76); voxel_size[0] = vsize[1]; voxel_size[1] = vsize[2]; voxel_size[2] = vsize[3]; } delete[] header; // Read pixel data. assign(dimx,dimy,dimz,dimv); switch (datatype) { case 2 : { unsigned char *const buffer = new unsigned char[(size_t)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 4 : { short *const buffer = new short[(size_t)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 8 : { int *const buffer = new int[(size_t)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 16 : { float *const buffer = new float[(size_t)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 64 : { double *const buffer = new double[(size_t)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; default : if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_analyze(): Unable to load datatype %d in file '%s'", cimg_instance, datatype,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a .cimg[z] file. /** \param filename Filename, as a C-string. \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg& load_cimg(const char *const filename, const char axis='z', const float align=0) { CImgList list; list.load_cimg(filename); if (list._width==1) return list[0].move_to(*this); return assign(list.get_append(axis,align)); } //! Load image from a .cimg[z] file \newinstance static CImg get_load_cimg(const char *const filename, const char axis='z', const float align=0) { return CImg().load_cimg(filename,axis,align); } //! Load image from a .cimg[z] file \overloading. CImg& load_cimg(std::FILE *const file, const char axis='z', const float align=0) { CImgList list; list.load_cimg(file); if (list._width==1) return list[0].move_to(*this); return assign(list.get_append(axis,align)); } //! Load image from a .cimg[z] file \newinstance static CImg get_load_cimg(std::FILE *const file, const char axis='z', const float align=0) { return CImg().load_cimg(file,axis,align); } //! Load sub-images of a .cimg file. /** \param filename Filename, as a C-string. \param n0 Starting frame. \param n1 Ending frame (~0U for max). \param x0 X-coordinate of the starting sub-image vertex. \param y0 Y-coordinate of the starting sub-image vertex. \param z0 Z-coordinate of the starting sub-image vertex. \param c0 C-coordinate of the starting sub-image vertex. \param x1 X-coordinate of the ending sub-image vertex (~0U for max). \param y1 Y-coordinate of the ending sub-image vertex (~0U for max). \param z1 Z-coordinate of the ending sub-image vertex (~0U for max). \param c1 C-coordinate of the ending sub-image vertex (~0U for max). \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg& load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, const char axis='z', const float align=0) { CImgList list; list.load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); if (list._width==1) return list[0].move_to(*this); return assign(list.get_append(axis,align)); } //! Load sub-images of a .cimg file \newinstance. static CImg get_load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, const char axis='z', const float align=0) { return CImg().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); } //! Load sub-images of a .cimg file \overloading. CImg& load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, const char axis='z', const float align=0) { CImgList list; list.load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); if (list._width==1) return list[0].move_to(*this); return assign(list.get_append(axis,align)); } //! Load sub-images of a .cimg file \newinstance. static CImg get_load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, const char axis='z', const float align=0) { return CImg().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); } //! Load image from an INRIMAGE-4 file. /** \param filename Filename, as a C-string. \param[out] voxel_size Pointer to the three voxel sizes read from the file. **/ CImg& load_inr(const char *const filename, float *const voxel_size=0) { return _load_inr(0,filename,voxel_size); } //! Load image from an INRIMAGE-4 file \newinstance. static CImg get_load_inr(const char *const filename, float *const voxel_size=0) { return CImg().load_inr(filename,voxel_size); } //! Load image from an INRIMAGE-4 file \overloading. CImg& load_inr(std::FILE *const file, float *const voxel_size=0) { return _load_inr(file,0,voxel_size); } //! Load image from an INRIMAGE-4 file \newinstance. static CImg get_load_inr(std::FILE *const file, float *voxel_size=0) { return CImg().load_inr(file,voxel_size); } static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) { CImg item(1024), tmp1(64), tmp2(64); *item = *tmp1 = *tmp2 = 0; out[0] = std::fscanf(file,"%63s",item._data); out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) throw CImgIOException("CImg<%s>::load_inr(): INRIMAGE-4 header not found.", pixel_type()); while (std::fscanf(file," %63[^\n]%*c",item._data)!=EOF && std::strncmp(item,"##}",3)) { cimg_sscanf(item," XDIM%*[^0-9]%d",out); cimg_sscanf(item," YDIM%*[^0-9]%d",out + 1); cimg_sscanf(item," ZDIM%*[^0-9]%d",out + 2); cimg_sscanf(item," VDIM%*[^0-9]%d",out + 3); cimg_sscanf(item," PIXSIZE%*[^0-9]%d",out + 6); if (voxel_size) { cimg_sscanf(item," VX%*[^0-9.+-]%f",voxel_size); cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1); cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2); } if (cimg_sscanf(item," CPU%*[ =]%s",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,"sun",3)?0:1; switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1._data,tmp2._data)) { case 0 : break; case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,tmp1._width - 1); case 1 : if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; if (out[4]>=0) break; default : throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.", pixel_type(), tmp2._data); } } if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) throw CImgIOException("CImg<%s>::load_inr(): Invalid dimensions (%d,%d,%d,%d) defined in header.", pixel_type(), out[0],out[1],out[2],out[3]); if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::load_inr(): Incomplete pixel type defined in header.", pixel_type()); if(out[6]<0) throw CImgIOException("CImg<%s>::load_inr(): Incomplete PIXSIZE field defined in header.", pixel_type()); if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr(): Big/Little Endian coding type undefined in header.", pixel_type()); } CImg& _load_inr(std::FILE *const file, const char *const filename, float *const voxel_size) { #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \ if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ Ts *xval, *const val = new Ts[(size_t)fopt[0]*fopt[3]]; \ cimg_forYZ(*this,y,z) { \ cimg::fread(val,fopt[0]*fopt[3],nfile); \ if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \ xval = val; cimg_forX(*this,x) cimg_forC(*this,c) (*this)(x,y,z,c) = (T)*(xval++); \ } \ delete[] val; \ loaded = true; \ } if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_inr(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); int fopt[8], endian=cimg::endianness()?1:0; bool loaded = false; if (voxel_size) voxel_size[0] = voxel_size[1] = voxel_size[2] = 1; _load_inr_header(nfile,fopt,voxel_size); assign(fopt[0],fopt[1],fopt[2],fopt[3]); _cimg_load_inr_case(0,0,8,unsigned char); _cimg_load_inr_case(0,1,8,char); _cimg_load_inr_case(0,0,16,unsigned short); _cimg_load_inr_case(0,1,16,short); _cimg_load_inr_case(0,0,32,unsigned int); _cimg_load_inr_case(0,1,32,int); _cimg_load_inr_case(1,0,32,float); _cimg_load_inr_case(1,1,32,float); _cimg_load_inr_case(1,0,64,double); _cimg_load_inr_case(1,1,64,double); if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_inr(): Unknown pixel type defined in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a EXR file. /** \param filename Filename, as a C-string. **/ CImg& load_exr(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_exr(): Specified filename is (null).", cimg_instance); #ifndef cimg_use_openexr return load_other(filename); #else Imf::RgbaInputFile file(filename); Imath::Box2i dw = file.dataWindow(); const int inwidth = dw.max.x - dw.min.x + 1, inheight = dw.max.y - dw.min.y + 1; Imf::Array2D pixels; pixels.resizeErase(inheight,inwidth); file.setFrameBuffer(&pixels[0][0] - dw.min.x - dw.min.y*inwidth, 1, inwidth); file.readPixels(dw.min.y, dw.max.y); assign(inwidth,inheight,1,4); T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); cimg_forXY(*this,x,y) { *(ptr_r++) = (T)pixels[y][x].r; *(ptr_g++) = (T)pixels[y][x].g; *(ptr_b++) = (T)pixels[y][x].b; *(ptr_a++) = (T)pixels[y][x].a; } return *this; #endif } //! Load image from a EXR file \newinstance. static CImg get_load_exr(const char *const filename) { return CImg().load_exr(filename); } //! Load image from a PANDORE-5 file. /** \param filename Filename, as a C-string. **/ CImg& load_pandore(const char *const filename) { return _load_pandore(0,filename); } //! Load image from a PANDORE-5 file \newinstance. static CImg get_load_pandore(const char *const filename) { return CImg().load_pandore(filename); } //! Load image from a PANDORE-5 file \overloading. CImg& load_pandore(std::FILE *const file) { return _load_pandore(file,0); } //! Load image from a PANDORE-5 file \newinstance. static CImg get_load_pandore(std::FILE *const file) { return CImg().load_pandore(file); } CImg& _load_pandore(std::FILE *const file, const char *const filename) { #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \ cimg::fread(dims,nbdim,nfile); \ if (endian) cimg::invert_endianness(dims,nbdim); \ assign(nwidth,nheight,ndepth,ndim); \ const size_t siz = size(); \ stype *buffer = new stype[siz]; \ cimg::fread(buffer,siz,nfile); \ if (endian) cimg::invert_endianness(buffer,siz); \ T *ptrd = _data; \ cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \ buffer-=siz; \ delete[] buffer #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \ if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \ else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \ else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \ else throw CImgIOException(_cimg_instance \ "load_pandore(): Unknown pixel datatype in file '%s'.", \ cimg_instance, \ filename?filename:"(FILE*)"); } if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_pandore(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg header(32); cimg::fread(header._data,12,nfile); if (cimg::strncasecmp("PANDORE",header,7)) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pandore(): PANDORE header not found in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } unsigned int imageid, dims[8] = { 0 }; int ptbuf[4] = { 0 }; cimg::fread(&imageid,1,nfile); const bool endian = imageid>255; if (endian) cimg::invert_endianness(imageid); cimg::fread(header._data,20,nfile); switch (imageid) { case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; case 3 : _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break; case 4 : _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break; case 5 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break; case 6 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break; case 7 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break; case 8 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break; case 9 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break; case 10 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break; case 11 : { // Region 1d cimg::fread(dims,3,nfile); if (endian) cimg::invert_endianness(dims,3); assign(dims[1],1,1,1); const unsigned siz = size(); if (dims[2]<256) { unsigned char *buffer = new unsigned char[siz]; cimg::fread(buffer,siz,nfile); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { if (dims[2]<65536) { unsigned short *buffer = new unsigned short[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { unsigned int *buffer = new unsigned int[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } } } break; case 12 : { // Region 2d cimg::fread(dims,4,nfile); if (endian) cimg::invert_endianness(dims,4); assign(dims[2],dims[1],1,1); const size_t siz = size(); if (dims[3]<256) { unsigned char *buffer = new unsigned char[siz]; cimg::fread(buffer,siz,nfile); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { if (dims[3]<65536) { unsigned short *buffer = new unsigned short[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { unsigned int *buffer = new unsigned int[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } } } break; case 13 : { // Region 3d cimg::fread(dims,5,nfile); if (endian) cimg::invert_endianness(dims,5); assign(dims[3],dims[2],dims[1],1); const size_t siz = size(); if (dims[4]<256) { unsigned char *buffer = new unsigned char[siz]; cimg::fread(buffer,siz,nfile); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { if (dims[4]<65536) { unsigned short *buffer = new unsigned short[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } else { unsigned int *buffer = new unsigned int[siz]; cimg::fread(buffer,siz,nfile); if (endian) cimg::invert_endianness(buffer,siz); T *ptrd = _data; cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); buffer-=siz; delete[] buffer; } } } break; case 16 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break; case 17 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break; case 18 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break; case 19 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break; case 20 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break; case 21 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break; case 22 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break; case 23 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); case 24 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break; case 25 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break; case 26 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break; case 27 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break; case 28 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break; case 29 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break; case 30 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1); break; case 31 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break; case 32 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4); break; case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; case 34 : { // Points 1d cimg::fread(ptbuf,1,nfile); if (endian) cimg::invert_endianness(ptbuf,1); assign(1); (*this)(0) = (T)ptbuf[0]; } break; case 35 : { // Points 2d cimg::fread(ptbuf,2,nfile); if (endian) cimg::invert_endianness(ptbuf,2); assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0]; } break; case 36 : { // Points 3d cimg::fread(ptbuf,3,nfile); if (endian) cimg::invert_endianness(ptbuf,3); assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0]; } break; default : if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pandore(): Unable to load data with ID_type %u in file '%s'.", cimg_instance, imageid,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; } //! Load image from a PAR-REC (Philips) file. /** \param filename Filename, as a C-string. \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg& load_parrec(const char *const filename, const char axis='c', const float align=0) { CImgList list; list.load_parrec(filename); if (list._width==1) return list[0].move_to(*this); return assign(list.get_append(axis,align)); } //! Load image from a PAR-REC (Philips) file \newinstance. static CImg get_load_parrec(const char *const filename, const char axis='c', const float align=0) { return CImg().load_parrec(filename,axis,align); } //! Load image from a raw binary file. /** \param filename Filename, as a C-string. \param size_x Width of the image buffer. \param size_y Height of the image buffer. \param size_z Depth of the image buffer. \param size_c Spectrum of the image buffer. \param is_multiplexed Tells if the image values are multiplexed along the C-axis. \param invert_endianness Tells if the endianness of the image buffer must be inverted. \param offset Starting offset of the read in the specified file. **/ CImg& load_raw(const char *const filename, const unsigned int size_x=0, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_multiplexed=false, const bool invert_endianness=false, const ulongT offset=0) { return _load_raw(0,filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); } //! Load image from a raw binary file \newinstance. static CImg get_load_raw(const char *const filename, const unsigned int size_x=0, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_multiplexed=false, const bool invert_endianness=false, const ulongT offset=0) { return CImg().load_raw(filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); } //! Load image from a raw binary file \overloading. CImg& load_raw(std::FILE *const file, const unsigned int size_x=0, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_multiplexed=false, const bool invert_endianness=false, const ulongT offset=0) { return _load_raw(file,0,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); } //! Load image from a raw binary file \newinstance. static CImg get_load_raw(std::FILE *const file, const unsigned int size_x=0, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1, const bool is_multiplexed=false, const bool invert_endianness=false, const ulongT offset=0) { return CImg().load_raw(file,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); } CImg& _load_raw(std::FILE *const file, const char *const filename, const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const bool is_multiplexed, const bool invert_endianness, const ulongT offset) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_raw(): Specified filename is (null).", cimg_instance); if (cimg::is_directory(filename)) throw CImgArgumentException(_cimg_instance "load_raw(): Specified filename '%s' is a directory.", cimg_instance,filename); ulongT siz = (ulongT)size_x*size_y*size_z*size_c; unsigned int _size_x = size_x, _size_y = size_y, _size_z = size_z, _size_c = size_c; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); if (!siz) { // Retrieve file size. const longT fpos = cimg::ftell(nfile); if (fpos<0) throw CImgArgumentException(_cimg_instance "load_raw(): Cannot determine size of input file '%s'.", cimg_instance,filename?filename:"(FILE*)"); cimg::fseek(nfile,0,SEEK_END); siz = cimg::ftell(nfile)/sizeof(T); _size_y = (unsigned int)siz; _size_x = _size_z = _size_c = 1; cimg::fseek(nfile,fpos,SEEK_SET); } cimg::fseek(nfile,offset,SEEK_SET); assign(_size_x,_size_y,_size_z,_size_c,0); if (siz && (!is_multiplexed || size_c==1)) { cimg::fread(_data,siz,nfile); if (invert_endianness) cimg::invert_endianness(_data,siz); } else if (siz) { CImg buf(1,1,1,_size_c); cimg_forXYZ(*this,x,y,z) { cimg::fread(buf._data,_size_c,nfile); if (invert_endianness) cimg::invert_endianness(buf._data,_size_c); set_vector_at(buf,x,y,z); } } if (!file) cimg::fclose(nfile); return *this; } //! Load image sequence from a YUV file. /** \param filename Filename, as a C-string. \param size_x Width of the frames. \param size_y Height of the frames. \param first_frame Index of the first frame to read. \param last_frame Index of the last frame to read. \param step_frame Step value for frame reading. \param yuv2rgb Tells if the YUV to RGB transform must be applied. \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. **/ CImg& load_yuv(const char *const filename, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return get_load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this); } //! Load image sequence from a YUV file \newinstance. static CImg get_load_yuv(const char *const filename, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return CImgList().load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis); } //! Load image sequence from a YUV file \overloading. CImg& load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return get_load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this); } //! Load image sequence from a YUV file \newinstance. static CImg get_load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return CImgList().load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis); } //! Load 3d object from a .OFF file. /** \param[out] primitives Primitives data of the 3d object. \param[out] colors Colors data of the 3d object. \param filename Filename, as a C-string. **/ template CImg& load_off(CImgList& primitives, CImgList& colors, const char *const filename) { return _load_off(primitives,colors,0,filename); } //! Load 3d object from a .OFF file \newinstance. template static CImg get_load_off(CImgList& primitives, CImgList& colors, const char *const filename) { return CImg().load_off(primitives,colors,filename); } //! Load 3d object from a .OFF file \overloading. template CImg& load_off(CImgList& primitives, CImgList& colors, std::FILE *const file) { return _load_off(primitives,colors,file,0); } //! Load 3d object from a .OFF file \newinstance. template static CImg get_load_off(CImgList& primitives, CImgList& colors, std::FILE *const file) { return CImg().load_off(primitives,colors,file); } template CImg& _load_off(CImgList& primitives, CImgList& colors, std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException(_cimg_instance "load_off(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0; CImg line(256); *line = 0; int err; // Skip comments, and read magic string OFF do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_off(): OFF header not found in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); if ((err = cimg_sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_off(): Invalid number of vertices or primitives specified in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); } // Read points data assign(nb_points,3); float X = 0, Y = 0, Z = 0; cimg_forX(*this,l) { do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); if ((err = cimg_sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_off(): Failed to read vertex %u/%u in file '%s'.", cimg_instance, l + 1,nb_points,filename?filename:"(FILE*)"); } (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z; } // Read primitive data primitives.assign(); colors.assign(); bool stop_flag = false; while (!stop_flag) { float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f; unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0; *line = 0; if ((err = std::fscanf(nfile,"%u",&prim))!=1) stop_flag = true; else { ++nb_read; switch (prim) { case 1 : { if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line._data))<2) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 2 : { if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line._data))<2) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 3 : { if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line._data))<3) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i2,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 4 : { if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line._data))<4) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 5 : { if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line._data))<5) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i4,i3).move_to(primitives); colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); ++nb_primitives; } } break; case 6 : { if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line._data))<6) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i5,i4,i3).move_to(primitives); colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); ++nb_primitives; } } break; case 7 : { if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line._data))<7) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i4,i3,i1).move_to(primitives); CImg::vector(i0,i6,i5,i4).move_to(primitives); CImg::vector(i3,i2,i1).move_to(primitives); colors.insert(3,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); ++(++nb_primitives); } } break; case 8 : { if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line._data))<7) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, nb_read,nb_primitives,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } else { err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i5,i4,i3).move_to(primitives); CImg::vector(i0,i7,i6,i5).move_to(primitives); colors.insert(3,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); ++(++nb_primitives); } } break; default : cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u (%u vertices) from file '%s'.", cimg_instance, nb_read,nb_primitives,prim,filename?filename:"(FILE*)"); err = std::fscanf(nfile,"%*[^\n] "); } } } if (!file) cimg::fclose(nfile); if (primitives._width!=nb_primitives) cimg::warn(_cimg_instance "load_off(): Only %u/%u primitives read from file '%s'.", cimg_instance, primitives._width,nb_primitives,filename?filename:"(FILE*)"); return *this; } //! Load image sequence from a video file, using OpenCV library. /** \param filename Filename, as a C-string. \param first_frame Index of the first frame to read. \param last_frame Index of the last frame to read. \param step_frame Step value for frame reading. **/ CImg& load_video(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const char axis='z', const float align=0) { return get_load_video(filename,first_frame,last_frame,step_frame,axis,align).move_to(*this); } //! Load image sequence from a video file, using OpenCV library \newinstance. static CImg get_load_video(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const char axis='z', const float align=0) { return CImgList().load_video(filename,first_frame,last_frame,step_frame).get_append(axis,align); } //! Load image sequence using FFMPEG's external tool 'ffmpeg'. /** \param filename Filename, as a C-string. \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg& load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) { return get_load_ffmpeg_external(filename,axis,align).move_to(*this); } //! Load image sequence using FFMPEG's external tool 'ffmpeg' \newinstance. static CImg get_load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) { return CImgList().load_ffmpeg_external(filename).get_append(axis,align); } //! Load gif file, using Imagemagick or GraphicsMagicks's external tools. /** \param filename Filename, as a C-string. \param use_graphicsmagick Tells if GraphicsMagick's tool 'gm' is used instead of ImageMagick's tool 'convert'. \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg& load_gif_external(const char *const filename, const char axis='z', const float align=0) { return get_load_gif_external(filename,axis,align).move_to(*this); } //! Load gif file, using ImageMagick or GraphicsMagick's external tool 'convert' \newinstance. static CImg get_load_gif_external(const char *const filename, const char axis='z', const float align=0) { return CImgList().load_gif_external(filename).get_append(axis,align); } //! Load image using GraphicsMagick's external tool 'gm'. /** \param filename Filename, as a C-string. **/ CImg& load_graphicsmagick_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_graphicsmagick_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 cimg_snprintf(command,command._width,"%s convert \"%s\" pnm:-", cimg::graphicsmagick_path(),s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.", cimg_instance, filename); } pclose(file); return *this; } #endif do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.pnm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s\"", cimg::graphicsmagick_path(),s_filename.data(), CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::graphicsmagick_path()); if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.", cimg_instance, filename); } else cimg::fclose(file); load_pnm(filename_tmp); std::remove(filename_tmp); return *this; } //! Load image using GraphicsMagick's external tool 'gm' \newinstance. static CImg get_load_graphicsmagick_external(const char *const filename) { return CImg().load_graphicsmagick_external(filename); } //! Load gzipped image file, using external tool 'gunzip'. /** \param filename Filename, as a C-string. **/ CImg& load_gzip_external(const char *const filename) { if (!filename) throw CImgIOException(_cimg_instance "load_gzip_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256), body(256); const char *const ext = cimg::split_filename(filename,body), *const ext2 = cimg::split_filename(body,0); std::FILE *file = 0; do { if (!cimg::strcasecmp(ext,"gz")) { if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gunzip_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_gzip_external(): Failed to load file '%s' with external command 'gunzip'.", cimg_instance, filename); } else cimg::fclose(file); load(filename_tmp); std::remove(filename_tmp); return *this; } //! Load gzipped image file, using external tool 'gunzip' \newinstance. static CImg get_load_gzip_external(const char *const filename) { return CImg().load_gzip_external(filename); } //! Load image using ImageMagick's external tool 'convert'. /** \param filename Filename, as a C-string. **/ CImg& load_imagemagick_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_imagemagick_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 cimg_snprintf(command,command._width,"%s%s \"%s\" pnm:-", cimg::imagemagick_path(), !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_imagemagick_external(): Failed to load file '%s' with " "external command 'convert'.", cimg_instance, filename); } pclose(file); return *this; } #endif do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.pnm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s%s \"%s\" \"%s\"", cimg::imagemagick_path(), !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", s_filename.data(),CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::imagemagick_path()); if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_imagemagick_external(): Failed to load file '%s' with external command 'convert'.", cimg_instance, filename); } else cimg::fclose(file); load_pnm(filename_tmp); std::remove(filename_tmp); return *this; } //! Load image using ImageMagick's external tool 'convert' \newinstance. static CImg get_load_imagemagick_external(const char *const filename) { return CImg().load_imagemagick_external(filename); } //! Load image from a DICOM file, using XMedcon's external tool 'medcon'. /** \param filename Filename, as a C-string. **/ CImg& load_medcon_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_medcon_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256), body(256); cimg::fclose(cimg::fopen(filename,"r")); std::FILE *file = 0; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s -w -c anlz -o \"%s\" -f \"%s\"", cimg::medcon_path(), CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); cimg::split_filename(filename_tmp,body); cimg_snprintf(command,command._width,"%s.hdr",body._data); file = std::fopen(command,"rb"); if (!file) { cimg_snprintf(command,command._width,"m000-%s.hdr",body._data); file = std::fopen(command,"rb"); if (!file) { throw CImgIOException(_cimg_instance "load_medcon_external(): Failed to load file '%s' with external command 'medcon'.", cimg_instance, filename); } } cimg::fclose(file); load_analyze(command); std::remove(command); cimg::split_filename(command,body); cimg_snprintf(command,command._width,"%s.img",body._data); std::remove(command); return *this; } //! Load image from a DICOM file, using XMedcon's external tool 'medcon' \newinstance. static CImg get_load_medcon_external(const char *const filename) { return CImg().load_medcon_external(filename); } //! Load image from a RAW Color Camera file, using external tool 'dcraw'. /** \param filename Filename, as a C-string. **/ CImg& load_dcraw_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_dcraw_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\"", cimg::dcraw_path(),s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", cimg_instance, filename); } pclose(file); return *this; } #endif do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\" > \"%s\"", cimg::dcraw_path(),s_filename.data(),CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::dcraw_path()); if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", cimg_instance, filename); } else cimg::fclose(file); load_pnm(filename_tmp); std::remove(filename_tmp); return *this; } //! Load image from a RAW Color Camera file, using external tool 'dcraw' \newinstance. static CImg get_load_dcraw_external(const char *const filename) { return CImg().load_dcraw_external(filename); } //! Load image from a camera stream, using OpenCV. /** \param camera_index Index of the camera to capture images from. \param skip_frames Number of frames to skip before the capture. \param release_camera Tells if the camera ressource must be released at the end of the method. **/ CImg& load_camera(const unsigned int camera_index=0, const unsigned int skip_frames=0, const bool release_camera=true, const unsigned int capture_width=0, const unsigned int capture_height=0) { #ifdef cimg_use_opencv if (camera_index>99) throw CImgArgumentException(_cimg_instance "load_camera(): Invalid request for camera #%u " "(no more than 100 cameras can be managed simultaneously).", cimg_instance, camera_index); static CvCapture *capture[100] = { 0 }; static unsigned int capture_w[100], capture_h[100]; if (release_camera) { cimg::mutex(9); if (capture[camera_index]) cvReleaseCapture(&(capture[camera_index])); capture[camera_index] = 0; capture_w[camera_index] = capture_h[camera_index] = 0; cimg::mutex(9,0); return *this; } if (!capture[camera_index]) { cimg::mutex(9); capture[camera_index] = cvCreateCameraCapture(camera_index); capture_w[camera_index] = 0; capture_h[camera_index] = 0; cimg::mutex(9,0); if (!capture[camera_index]) { throw CImgIOException(_cimg_instance "load_camera(): Failed to initialize camera #%u.", cimg_instance, camera_index); } } cimg::mutex(9); if (capture_width!=capture_w[camera_index]) { cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_WIDTH,capture_width); capture_w[camera_index] = capture_width; } if (capture_height!=capture_h[camera_index]) { cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_HEIGHT,capture_height); capture_h[camera_index] = capture_height; } const IplImage *img = 0; for (unsigned int i = 0; iwidthStep - 3*img->width); assign(img->width,img->height,1,3); const unsigned char* ptrs = (unsigned char*)img->imageData; T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); if (step>0) cimg_forY(*this,y) { cimg_forX(*this,x) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); } ptrs+=step; } else for (ulongT siz = (ulongT)img->width*img->height; siz; --siz) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); } } cimg::mutex(9,0); return *this; #else cimg::unused(camera_index,skip_frames,release_camera,capture_width,capture_height); throw CImgIOException(_cimg_instance "load_camera(): This function requires the OpenCV library to run " "(macro 'cimg_use_opencv' must be defined).", cimg_instance); #endif } //! Load image from a camera stream, using OpenCV \newinstance. static CImg get_load_camera(const unsigned int camera_index=0, const unsigned int skip_frames=0, const bool release_camera=true, const unsigned int capture_width=0, const unsigned int capture_height=0) { return CImg().load_camera(camera_index,skip_frames,release_camera,capture_width,capture_height); } //! Load image using various non-native ways. /** \param filename Filename, as a C-string. **/ CImg& load_other(const char *const filename) { if (!filename) throw CImgArgumentException(_cimg_instance "load_other(): Specified filename is (null).", cimg_instance); const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { load_magick(filename); } catch (CImgException&) { try { load_imagemagick_external(filename); } catch (CImgException&) { try { load_graphicsmagick_external(filename); } catch (CImgException&) { try { load_cimg(filename); } catch (CImgException&) { try { std::fclose(cimg::fopen(filename,"rb")); } catch (CImgException&) { cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_other(): Failed to open file '%s'.", cimg_instance, filename); } cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_other(): Failed to recognize format of file '%s'.", cimg_instance, filename); } } } } cimg::exception_mode(omode); return *this; } //! Load image using various non-native ways \newinstance. static CImg get_load_other(const char *const filename) { return CImg().load_other(filename); } //@} //--------------------------- // //! \name Data Output //@{ //--------------------------- //! Display information about the image data. /** \param title Name for the considered image. \param display_stats Tells to compute and display image statistics. **/ const CImg& print(const char *const title=0, const bool display_stats=true) const { int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0; CImg st; if (!is_empty() && display_stats) { st = get_stats(); xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7]; xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11]; } const ulongT siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1, mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1; CImg _title(64); if (!title) cimg_snprintf(_title,_title._width,"CImg<%s>",pixel_type()); std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p", cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, cimg::t_bold,cimg::t_normal,(void*)this, cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum, mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), mdisp==0?"b":(mdisp==1?"Kio":"Mio"), cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); if (_data) std::fprintf(cimg::output(),"..%p (%s) = [ ",(void*)((char*)end() - 1),_is_shared?"shared":"non-shared"); else std::fprintf(cimg::output()," (%s) = [ ",_is_shared?"shared":"non-shared"); if (!is_empty()) cimg_foroff(*this,off) { std::fprintf(cimg::output(),cimg::type::format(),cimg::type::format(_data[off])); if (off!=siz1) std::fprintf(cimg::output(),"%s",off%_width==width1?" ; ":" "); if (off==7 && siz>16) { off = siz1 - 8; std::fprintf(cimg::output(),"... "); } } if (!is_empty() && display_stats) std::fprintf(cimg::output(), " ], %smin%s = %g, %smax%s = %g, %smean%s = %g, %sstd%s = %g, %scoords_min%s = (%u,%u,%u,%u), " "%scoords_max%s = (%u,%u,%u,%u).\n", cimg::t_bold,cimg::t_normal,st[0], cimg::t_bold,cimg::t_normal,st[1], cimg::t_bold,cimg::t_normal,st[2], cimg::t_bold,cimg::t_normal,std::sqrt(st[3]), cimg::t_bold,cimg::t_normal,xm,ym,zm,vm, cimg::t_bold,cimg::t_normal,xM,yM,zM,vM); else std::fprintf(cimg::output(),"%s].\n",is_empty()?"":" "); std::fflush(cimg::output()); return *this; } //! Display image into a CImgDisplay window. /** \param disp Display window. **/ const CImg& display(CImgDisplay& disp) const { disp.display(*this); return *this; } //! Display image into a CImgDisplay window, in an interactive way. /** \param disp Display window. \param display_info Tells if image information are displayed on the standard output. **/ const CImg& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { return _display(disp,0,display_info,XYZ,exit_on_anykey,false); } //! Display image into an interactive window. /** \param title Window title \param display_info Tells if image information are displayed on the standard output. **/ const CImg& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { CImgDisplay disp; return _display(disp,title,display_info,XYZ,exit_on_anykey,false); } const CImg& _display(CImgDisplay &disp, const char *const title, const bool display_info, unsigned int *const XYZ, const bool exit_on_anykey, const bool exit_on_simpleclick) const { unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0; int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1, old_mouse_x = -1, old_mouse_y = -1; if (!disp) { disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); else disp.set_title("%s",title); } else if (title) disp.set_title("%s",title); disp.show().flush(); const CImg dtitle = CImg::string(disp.title()); if (display_info) print(dtitle); CImg zoom; for (bool reset_view = true, resize_disp = false, is_first_select = true; !key && !disp.is_closed(); ) { if (reset_view) { if (XYZ) { _XYZ[0] = XYZ[0]; _XYZ[1] = XYZ[1]; _XYZ[2] = XYZ[2]; } else { _XYZ[0] = (unsigned int)(x0 + x1)/2; _XYZ[1] = (unsigned int)(y0 + y1)/2; _XYZ[2] = (unsigned int)(z0 + z1)/2; } x0 = 0; y0 = 0; z0 = 0; x1 = width() - 1; y1 = height() - 1; z1 = depth() - 1; oldw = disp._width; oldh = disp._height; reset_view = false; } if (!x0 && !y0 && !z0 && x1==width() - 1 && y1==height() - 1 && z1==depth() - 1) { if (is_empty()) zoom.assign(1,1,1,1,0); else zoom.assign(); } else zoom = get_crop(x0,y0,z0,x1,y1,z1); const unsigned int dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0, tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U); if (!is_empty() && !disp.is_fullscreen() && resize_disp) { const unsigned int ttw = tw*disp.width()/oldw, tth = th*disp.height()/oldh, dM = cimg::max(ttw,tth), diM = (unsigned int)cimg::max(disp.width(),disp.height()), imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM); disp.set_fullscreen(false).resize(cimg_fitscreen(imgw,imgh,1),false); resize_disp = false; } oldw = tw; oldh = th; bool go_up = false, go_down = false, go_left = false, go_right = false, go_inc = false, go_dec = false, go_in = false, go_out = false, go_in_center = false; const CImg& visu = zoom?zoom:*this; disp.set_title("%s",dtitle._data); if (_width>1 && visu._width==1) disp.set_title("%s | x=%u",disp._title,x0); if (_height>1 && visu._height==1) disp.set_title("%s | y=%u",disp._title,y0); if (_depth>1 && visu._depth==1) disp.set_title("%s | z=%u",disp._title,z0); if (!is_first_select) { _XYZ[0] = (unsigned int)(x1 - x0)/2; _XYZ[1] = (unsigned int)(y1 - y0)/2; _XYZ[2] = (unsigned int)(z1 - z0)/2; } disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y; const CImg selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1); old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y; is_first_select = false; if (disp.wheel()) { if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { go_down = !(go_up = disp.wheel()>0); } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { go_left = !(go_right = disp.wheel()>0); } else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) { go_out = !(go_in = disp.wheel()>0); go_in_center = false; } disp.set_wheel(); } const int sx0 = selection(0), sy0 = selection(1), sz0 = selection(2), sx1 = selection(3), sy1 = selection(4), sz1 = selection(5); if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) { x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0; if (sx0==sx1 && sy0==sy1 && sz0==sz1) { if (exit_on_simpleclick && (!zoom || is_empty())) break; else reset_view = true; } resize_disp = true; } else switch (key = disp.key()) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : #endif case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : #if cimg_OS!=2 case cimg::keyALTGR : #endif case cimg::keyALT : key = 0; break; case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) { // Special mode: play stack of frames const unsigned int w1 = visu._width*disp.width()/(visu._width + (visu._depth>1?visu._depth:0)), h1 = visu._height*disp.height()/(visu._height + (visu._depth>1?visu._depth:0)); float frame_timing = 5; bool is_stopped = false; disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0; for (unsigned int timer = 0; !key && !disp.is_closed() && !disp.button(); ) { if (disp.is_resized()) disp.resize(false); if (!timer) { visu.get_slice((int)_XYZ[2]).display(disp.set_title("%s | z=%d",dtitle.data(),_XYZ[2])); (++_XYZ[2])%=visu._depth; } if (!is_stopped) { if (++timer>(unsigned int)frame_timing) timer = 0; } else timer = ~0U; if (disp.wheel()) { frame_timing-=disp.wheel()/3.0f; disp.set_wheel(); } switch (key = disp.key()) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : #endif case cimg::keyCTRLLEFT : key = 0; break; case cimg::keyPAGEUP : frame_timing-=0.3f; key = 0; break; case cimg::keyPAGEDOWN : frame_timing+=0.3f; key = 0; break; case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break; case cimg::keyARROWLEFT : case cimg::keyARROWUP : is_stopped = true; timer = 0; key = 0; break; case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : is_stopped = true; (_XYZ[2]+=visu._depth - 2)%=visu._depth; timer = 0; key = 0; break; case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false); disp.set_key(key,false); key = 0; } break; case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false).set_key(key,false); key = 0; } break; case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(_width,_height,_depth),false).set_key(key,false); key = 0; } break; case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.resize(disp.screen_width(),disp.screen_height(),false). toggle_fullscreen().set_key(key,false); key = 0; } break; } frame_timing = frame_timing<1?1:(frame_timing>39?39:frame_timing); disp.wait(20); } const unsigned int w2 = (visu._width + (visu._depth>1?visu._depth:0))*disp.width()/visu._width, h2 = (visu._height + (visu._depth>1?visu._depth:0))*disp.height()/visu._height; disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(dtitle.data()).set_key().set_button().set_wheel(); key = 0; } break; case cimg::keyHOME : reset_view = resize_disp = true; key = 0; break; case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break; case cimg::keyPADSUB : go_out = true; key = 0; break; case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break; case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break; case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break; case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break; case cimg::keyPAD7 : go_up = go_left = true; key = 0; break; case cimg::keyPAD9 : go_up = go_right = true; key = 0; break; case cimg::keyPAD1 : go_down = go_left = true; key = 0; break; case cimg::keyPAD3 : go_down = go_right = true; key = 0; break; case cimg::keyPAGEUP : go_inc = true; key = 0; break; case cimg::keyPAGEDOWN : go_dec = true; key = 0; break; } if (go_in) { const int mx = go_in_center?disp.width()/2:disp.mouse_x(), my = go_in_center?disp.height()/2:disp.mouse_y(), mX = mx*(width() + (depth()>1?depth():0))/disp.width(), mY = my*(height() + (depth()>1?depth():0))/disp.height(); int X = (int)_XYZ[0], Y = (int)_XYZ[1], Z = (int)_XYZ[2]; if (mX=height()) { X = x0 + mX*(1 + x1 - x0)/width(); Z = z0 + (mY - height())*(1 + z1 - z0)/depth(); Y = (int)_XYZ[1]; } if (mX>=width() && mY4) { x0 = X - 3*(X - x0)/4; x1 = X + 3*(x1 - X)/4; } if (y1 - y0>4) { y0 = Y - 3*(Y - y0)/4; y1 = Y + 3*(y1 - Y)/4; } if (z1 - z0>4) { z0 = Z - 3*(Z - z0)/4; z1 = Z + 3*(z1 - Z)/4; } } if (go_out) { const int delta_x = (x1 - x0)/8, delta_y = (y1 - y0)/8, delta_z = (z1 - z0)/8, ndelta_x = delta_x?delta_x:(_width>1?1:0), ndelta_y = delta_y?delta_y:(_height>1?1:0), ndelta_z = delta_z?delta_z:(_depth>1?1:0); x0-=ndelta_x; y0-=ndelta_y; z0-=ndelta_z; x1+=ndelta_x; y1+=ndelta_y; z1+=ndelta_z; if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; } if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; } if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; } if (x1>=width()) { x0-=(x1 - width() + 1); x1 = width() - 1; if (x0<0) x0 = 0; } if (y1>=height()) { y0-=(y1 - height() + 1); y1 = height() - 1; if (y0<0) y0 = 0; } if (z1>=depth()) { z0-=(z1 - depth() + 1); z1 = depth() - 1; if (z0<0) z0 = 0; } } if (go_left) { const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0); if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; } else { x1-=x0; x0 = 0; } } if (go_right) { const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0); if (x1+ndelta1?1:0); if (y0 - ndelta>=0) { y0-=ndelta; y1-=ndelta; } else { y1-=y0; y0 = 0; } } if (go_down) { const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1?1:0); if (y1+ndelta1?1:0); if (z0 - ndelta>=0) { z0-=ndelta; z1-=ndelta; } else { z1-=z0; z0 = 0; } } if (go_dec) { const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1?1:0); if (z1+ndelta const CImg& display_object3d(CImgDisplay& disp, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const to& opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static, render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const to& opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { CImgDisplay disp; return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static, render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(CImgDisplay &disp, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(disp,vertices,primitives,colors,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(title,vertices,primitives,colors,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(CImgDisplay &disp, const CImg& vertices, const CImgList& primitives, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(disp,vertices,primitives,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, const CImg& vertices, const CImgList& primitives, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(title,vertices,primitives,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(CImgDisplay &disp, const CImg& vertices, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(disp,vertices,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, const CImg& vertices, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, const float light_x=0, const float light_y=0, const float light_z=-5e8f, const float specular_lightness=0.2f, const float specular_shininess=0.1f, const bool display_axes=true, float *const pose_matrix=0, const bool exit_on_anykey=false) const { return display_object3d(title,vertices,CImgList(),centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } template const CImg& _display_object3d(CImgDisplay& disp, const char *const title, const CImg& vertices, const CImgList& primitives, const CImgList& colors, const to& opacities, const bool centering, const int render_static, const int render_motion, const bool is_double_sided, const float focale, const float light_x, const float light_y, const float light_z, const float specular_lightness, const float specular_shininess, const bool display_axes, float *const pose_matrix, const bool exit_on_anykey) const { typedef typename cimg::superset::type tpfloat; // Check input arguments if (is_empty()) { if (disp) return CImg(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0). _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); else return CImg(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2, CImgDisplay::screen_height()/2,1), 1,(colors && colors[0].size()==1)?1:3,3). _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } else { if (disp) disp.resize(*this,false); } CImg error_message(1024); if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) throw CImgArgumentException(_cimg_instance "display_object3d(): Invalid specified 3d object (%u,%u) (%s).", cimg_instance,vertices._width,primitives._width,error_message.data()); if (vertices._width && !primitives) { CImgList nprimitives(vertices._width,1,1,1,1); cimglist_for(nprimitives,l) nprimitives(l,0) = (tf)l; return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix,exit_on_anykey); } if (!disp) { disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); if (!title) disp.set_title("CImg<%s> (%u vertices, %u primitives)", pixel_type(),vertices._width,primitives._width); } else if (title) disp.set_title("%s",title); // Init 3d objects and compute object statistics CImg pose, rotated_vertices(vertices._width,3), bbox_vertices, rotated_bbox_vertices, axes_vertices, rotated_axes_vertices, bbox_opacities, axes_opacities; CImgList bbox_primitives, axes_primitives; CImgList reverse_primitives; CImgList bbox_colors, bbox_colors2, axes_colors; unsigned int ns_width = 0, ns_height = 0; int _is_double_sided = (int)is_double_sided; bool ndisplay_axes = display_axes; const CImg background_color(1,1,1,_spectrum,0), foreground_color(1,1,1,_spectrum,255); float Xoff = 0, Yoff = 0, Zoff = 0, sprite_scale = 1, xm = 0, xM = vertices?vertices.get_shared_row(0).max_min(xm):0, ym = 0, yM = vertices?vertices.get_shared_row(1).max_min(ym):0, zm = 0, zM = vertices?vertices.get_shared_row(2).max_min(zm):0; const float delta = cimg::max(xM - xm,yM - ym,zM - zm); rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1, xm,xM,xM,xm,xm,xM,xM,xm, ym,ym,yM,yM,ym,ym,yM,yM, zm,zm,zm,zm,zM,zM,zM,zM); bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6); bbox_colors.assign(6,_spectrum,1,1,1,background_color[0]); bbox_colors2.assign(6,_spectrum,1,1,1,foreground_color[0]); bbox_opacities.assign(bbox_colors._width,1,1,1,0.3f); rotated_axes_vertices = axes_vertices.assign(7,3,1,1, 0,20,0,0,22,-6,-6, 0,0,20,0,-6,22,-6, 0,0,0,20,0,0,22); axes_opacities.assign(3,1,1,1,1); axes_colors.assign(3,_spectrum,1,1,1,foreground_color[0]); axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3); // Begin user interaction loop CImg visu0(*this), visu; CImg zbuffer(visu0.width(),visu0.height(),1,1,0); bool init_pose = true, clicked = false, redraw = true; unsigned int key = 0; int x0 = 0, y0 = 0, x1 = 0, y1 = 0, nrender_static = render_static, nrender_motion = render_motion; disp.show().flush(); while (!disp.is_closed() && !key) { // Init object pose if (init_pose) { const float ratio = delta>0?(2.0f*cimg::min(disp.width(),disp.height())/(3.0f*delta)):1, dx = (xM + xm)/2, dy = (yM + ym)/2, dz = (zM + zm)/2; if (centering) CImg(4,3,1,1, ratio,0.,0.,-ratio*dx, 0.,ratio,0.,-ratio*dy, 0.,0.,ratio,-ratio*dz).move_to(pose); else CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose); if (pose_matrix) { CImg pose0(pose_matrix,4,3,1,1,false); pose0.resize(4,4,1,1,0); pose.resize(4,4,1,1,0); pose0(3,3) = pose(3,3) = 1; (pose0*pose).get_crop(0,0,3,2).move_to(pose); Xoff = pose_matrix[12]; Yoff = pose_matrix[13]; Zoff = pose_matrix[14]; sprite_scale = pose_matrix[15]; } else { Xoff = Yoff = Zoff = 0; sprite_scale = 1; } init_pose = false; redraw = true; } // Rotate and draw 3d object if (redraw) { const float r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0), r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1), r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2); if ((clicked && nrender_motion>=0) || (!clicked && nrender_static>=0)) cimg_forX(vertices,l) { const float x = (float)vertices(l,0), y = (float)vertices(l,1), z = (float)vertices(l,2); rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30; rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31; rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32; } else cimg_forX(bbox_vertices,l) { const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2); rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30; rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31; rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32; } // Draw objects //#ifdef cimg_use_openmp // const bool render_with_zbuffer = true; //#else const bool render_with_zbuffer = !clicked && nrender_static>0; //#endif visu = visu0; if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0)) visu.draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale). draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale); else visu._draw_object3d((void*)0,render_with_zbuffer?zbuffer.fill(0):CImg::empty(), Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static,_is_double_sided==1,focale, width()/2.0f + light_x,height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess,sprite_scale); // Draw axes if (ndisplay_axes) { const float n = (float)std::sqrt(1e-8 + r00*r00 + r01*r01 + r02*r02), _r00 = r00/n, _r10 = r10/n, _r20 = r20/n, _r01 = r01/n, _r11 = r11/n, _r21 = r21/n, _r02 = r01/n, _r12 = r12/n, _r22 = r22/n, Xaxes = 25, Yaxes = visu._height - 38.0f; cimg_forX(axes_vertices,l) { const float x = axes_vertices(l,0), y = axes_vertices(l,1), z = axes_vertices(l,2); rotated_axes_vertices(l,0) = _r00*x + _r10*y + _r20*z; rotated_axes_vertices(l,1) = _r01*x + _r11*y + _r21*z; rotated_axes_vertices(l,2) = _r02*x + _r12*y + _r22*z; } axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.0f; axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.0f; axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f; visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives, axes_colors,axes_opacities,1,false,focale). draw_text((int)(Xaxes + rotated_axes_vertices(4,0)), (int)(Yaxes + rotated_axes_vertices(4,1)), "X",axes_colors[0]._data,0,axes_opacities(0,0),13). draw_text((int)(Xaxes + rotated_axes_vertices(5,0)), (int)(Yaxes + rotated_axes_vertices(5,1)), "Y",axes_colors[1]._data,0,axes_opacities(1,0),13). draw_text((int)(Xaxes + rotated_axes_vertices(6,0)), (int)(Yaxes + rotated_axes_vertices(6,1)), "Z",axes_colors[2]._data,0,axes_opacities(2,0),13); } visu.display(disp); if (!clicked || nrender_motion==nrender_static) redraw = false; } // Handle user interaction disp.wait(); if ((disp.button() || disp.wheel()) && disp.mouse_x()>=0 && disp.mouse_y()>=0) { redraw = true; if (!clicked) { x0 = x1 = disp.mouse_x(); y0 = y1 = disp.mouse_y(); if (!disp.wheel()) clicked = true; } else { x1 = disp.mouse_x(); y1 = disp.mouse_y(); } if (disp.button()&1) { const float R = 0.45f*cimg::min(disp.width(),disp.height()), R2 = R*R, u0 = (float)(x0 - disp.width()/2), v0 = (float)(y0 - disp.height()/2), u1 = (float)(x1 - disp.width()/2), v1 = (float)(y1 - disp.height()/2), n0 = (float)std::sqrt(u0*u0 + v0*v0), n1 = (float)std::sqrt(u1*u1 + v1*v1), nu0 = n0>R?(u0*R/n0):u0, nv0 = n0>R?(v0*R/n0):v0, nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)), nu1 = n1>R?(u1*R/n1):u1, nv1 = n1>R?(v1*R/n1):v1, nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)), u = nv0*nw1 - nw0*nv1, v = nw0*nu1 - nu0*nw1, w = nv0*nu1 - nu0*nv1, n = (float)std::sqrt(u*u + v*v + w*w), alpha = (float)std::asin(n/R2); (CImg::rotation_matrix(u,v,w,alpha)*pose).move_to(pose); x0 = x1; y0 = y1; } if (disp.button()&2) { if (focale>0) Zoff-=(y0 - y1)*focale/400; else { const float s = std::exp((y0 - y1)/400.0f); pose*=s; sprite_scale*=s; } x0 = x1; y0 = y1; } if (disp.wheel()) { if (focale>0) Zoff-=disp.wheel()*focale/20; else { const float s = std::exp(disp.wheel()/20.0f); pose*=s; sprite_scale*=s; } disp.set_wheel(); } if (disp.button()&4) { Xoff+=(x1 - x0); Yoff+=(y1 - y0); x0 = x1; y0 = y1; } if ((disp.button()&1) && (disp.button()&2)) { init_pose = true; disp.set_button(); x0 = x1; y0 = y1; pose = CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0); } } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; } CImg filename(32); switch (key = disp.key()) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : #endif case 0 : case cimg::keyCTRLLEFT : key = 0; break; case cimg::keyD: if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). _is_resized = true; disp.set_key(key,false); key = 0; } break; case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; disp.set_key(key,false); key = 0; } break; case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; disp.set_key(key,false); key = 0; } break; case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { if (!ns_width || !ns_height || ns_width>(unsigned int)disp.screen_width() || ns_height>(unsigned int)disp.screen_height()) { ns_width = disp.screen_width()*3U/4; ns_height = disp.screen_height()*3U/4; } if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false); else { ns_width = disp._width; ns_height = disp._height; disp.resize(disp.screen_width(),disp.screen_height(),false); } disp.toggle_fullscreen()._is_resized = true; disp.set_key(key,false); key = 0; } break; case cimg::keyT : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Switch single/double-sided primitives. if (--_is_double_sided==-2) _is_double_sided = 1; if (_is_double_sided>=0) reverse_primitives.assign(); else primitives.get_reverse_object3d().move_to(reverse_primitives); disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyZ : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Enable/disable Z-buffer if (zbuffer) zbuffer.assign(); else zbuffer.assign(visu0.width(),visu0.height(),1,1,0); disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Show/hide 3d axes. ndisplay_axes = !ndisplay_axes; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF1 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to points. nrender_motion = (nrender_static==0 && nrender_motion!=0)?0:-1; nrender_static = 0; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF2 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to lines. nrender_motion = (nrender_static==1 && nrender_motion!=1)?1:-1; nrender_static = 1; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF3 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat. nrender_motion = (nrender_static==2 && nrender_motion!=2)?2:-1; nrender_static = 2; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF4 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat-shaded. nrender_motion = (nrender_static==3 && nrender_motion!=3)?3:-1; nrender_static = 3; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF5 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to gouraud-shaded. nrender_motion = (nrender_static==4 && nrender_motion!=4)?4:-1; nrender_static = 4; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyF6 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to phong-shaded. nrender_motion = (nrender_static==5 && nrender_motion!=5)?5:-1; nrender_static = 5; disp.set_key(key,false); key = 0; redraw = true; } break; case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu).draw_text(0,0," Saving snapshot... ", foreground_color._data,background_color._data,0.7f,13).display(disp); visu.save(filename); (+visu).draw_text(0,0," Snapshot '%s' saved. ", foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); disp.set_key(key,false); key = 0; } break; case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.off",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu).draw_text(0,0," Saving object... ", foreground_color._data,background_color._data,0.7f,13).display(disp); vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename); (+visu).draw_text(0,0," Object '%s' saved. ", foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); disp.set_key(key,false); key = 0; } break; case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file static unsigned int snap_number = 0; std::FILE *file; do { #ifdef cimg_use_zlib cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); #else cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); #endif if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu).draw_text(0,0," Saving object... ", foreground_color._data,background_color._data,0.7f,13).display(disp); vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities). save(filename); (+visu).draw_text(0,0," Object '%s' saved. ", foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); disp.set_key(key,false); key = 0; } break; #ifdef cimg_use_board case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.eps",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu).draw_text(0,0," Saving EPS snapshot... ", foreground_color._data,background_color._data,0.7f,13).display(disp); LibBoard::Board board; (+visu)._draw_object3d(&board,zbuffer.fill(0), Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static, _is_double_sided==1,focale, visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess, sprite_scale); board.saveEPS(filename); (+visu).draw_text(0,0," Object '%s' saved. ", foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); disp.set_key(key,false); key = 0; } break; case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.svg",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu).draw_text(0,0," Saving SVG snapshot... ", foreground_color._data,background_color._data,0.7f,13).display(disp); LibBoard::Board board; (+visu)._draw_object3d(&board,zbuffer.fill(0), Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static, _is_double_sided==1,focale, visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess, sprite_scale); board.saveSVG(filename); (+visu).draw_text(0,0," Object '%s' saved. ", foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); disp.set_key(key,false); key = 0; } break; #endif } if (disp.is_resized()) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width(),disp.height()); redraw = true; } if (!exit_on_anykey && key && key!=cimg::keyESC && (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { key = 0; } } if (pose_matrix) { std::memcpy(pose_matrix,pose._data,12*sizeof(float)); pose_matrix[12] = Xoff; pose_matrix[13] = Yoff; pose_matrix[14] = Zoff; pose_matrix[15] = sprite_scale; } disp.set_button().set_key(key); return *this; } //! Display 1d graph in an interactive window. /** \param disp Display window. \param plot_type Plot type. Can be { 0=points | 1=segments | 2=splines | 3=bars }. \param vertex_type Vertex type. \param labelx Title for the horizontal axis, as a C-string. \param xmin Minimum value along the X-axis. \param xmax Maximum value along the X-axis. \param labely Title for the vertical axis, as a C-string. \param ymin Minimum value along the X-axis. \param ymax Maximum value along the X-axis. **/ const CImg& display_graph(CImgDisplay &disp, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0, const bool exit_on_anykey=false) const { return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); } //! Display 1d graph in an interactive window \overloading. const CImg& display_graph(const char *const title=0, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0, const bool exit_on_anykey=false) const { CImgDisplay disp; return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); } const CImg& _display_graph(CImgDisplay &disp, const char *const title=0, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0, const bool exit_on_anykey=false) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "display_graph(): Empty instance.", cimg_instance); if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0). set_title(title?"%s":"CImg<%s>",title?title:pixel_type()); const ulongT siz = (ulongT)_width*_height*_depth, siz1 = cimg::max(1U,siz - 1); const unsigned int old_normalization = disp.normalization(); disp.show().flush()._normalization = 0; double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax; if (nxmin==nxmax) { nxmin = 0; nxmax = siz1; } int x0 = 0, x1 = width()*height()*depth() - 1, key = 0; for (bool reset_view = true; !key && !disp.is_closed(); ) { if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; } CImg zoom(x1 - x0 + 1,1,1,spectrum()); cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg(data(x0,0,0,c),x1 - x0 + 1,1,1,1,true); if (y0==y1) { y0 = zoom.min_max(y1); const double dy = y1 - y0; y0-=dy/20; y1+=dy/20; } if (y0==y1) { --y0; ++y1; } const CImg selection = zoom.get_select_graph(disp,plot_type,vertex_type, labelx, nxmin + x0*(nxmax - nxmin)/siz1, nxmin + x1*(nxmax - nxmin)/siz1, labely,y0,y1,true); const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); if (selection[0]>=0) { if (selection[2]<0) reset_view = true; else { x1 = x0 + selection[2]; x0+=selection[0]; if (selection[1]>=0 && selection[3]>=0) { y0 = y1 - selection[3]*(y1 - y0)/(disp.height() - 32); y1-=selection[1]*(y1 - y0)/(disp.height() - 32); } } } else { bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false; switch (key = (int)disp.key()) { case cimg::keyHOME : reset_view = true; key = 0; disp.set_key(); break; case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break; case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break; case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key(); break; case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key(); break; case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break; case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break; case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break; case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break; case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break; case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break; } if (disp.wheel()) { if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0); else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0); else go_out = !(go_in = disp.wheel()>0); key = 0; } if (go_in) { const int xsiz = x1 - x0, mx = (mouse_x - 16)*xsiz/(disp.width() - 32), cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx)); if (x1 - x0>4) { x0 = cx - 7*(cx - x0)/8; x1 = cx + 7*(x1 - cx)/8; if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { const double ysiz = y1 - y0, my = (mouse_y - 16)*ysiz/(disp.height() - 32), cy = y1 - (my<0?0:(my>=ysiz?ysiz:my)); y0 = cy - 7*(cy - y0)/8; y1 = cy + 7*(y1 - cy)/8; } else y0 = y1 = 0; } } if (go_out) { if (x0>0 || x1<(int)siz1) { const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1?1:0); const double ndelta_y = (y1 - y0)/8; x0-=ndelta_x; x1+=ndelta_x; y0-=ndelta_y; y1+=ndelta_y; if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz1; } if (x1>=(int)siz) { x0-=(x1 - siz1); x1 = (int)siz1; if (x0<0) x0 = 0; } } } if (go_left) { const int delta = (x1 - x0)/5, ndelta = delta?delta:1; if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; } else { x1-=x0; x0 = 0; } go_left = false; } if (go_right) { const int delta = (x1 - x0)/5, ndelta = delta?delta:1; if (x1 + ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; } else { x0+=(siz1 - x1); x1 = (int)siz1; } go_right = false; } if (go_up) { const double delta = (y1 - y0)/10, ndelta = delta?delta:1; y0+=ndelta; y1+=ndelta; go_up = false; } if (go_down) { const double delta = (y1 - y0)/10, ndelta = delta?delta:1; y0-=ndelta; y1-=ndelta; go_down = false; } } if (!exit_on_anykey && key && key!=(int)cimg::keyESC && (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { disp.set_key(key,false); key = 0; } } disp._normalization = old_normalization; return *this; } //! Save image as a file. /** \param filename Filename, as a C-string. \param number When positive, represents an index added to the filename. Otherwise, no number is added. \param digits Number of digits used for adding the number to the filename. \note - The used file format is defined by the file extension in the filename \p filename. - Parameter \p number can be used to add a 6-digit number to the filename before saving. **/ const CImg& save(const char *const filename, const int number=-1, const unsigned int digits=6) const { if (!filename) throw CImgArgumentException(_cimg_instance "save(): Specified filename is (null).", cimg_instance); // Do not test for empty instances, since .cimg format is able to manage empty instances. const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); CImg nfilename(1024); const char *const fn = is_stdout?filename:(number>=0)?cimg::number_filename(filename,number,digits,nfilename): filename; #ifdef cimg_save_plugin cimg_save_plugin(fn); #endif #ifdef cimg_save_plugin1 cimg_save_plugin1(fn); #endif #ifdef cimg_save_plugin2 cimg_save_plugin2(fn); #endif #ifdef cimg_save_plugin3 cimg_save_plugin3(fn); #endif #ifdef cimg_save_plugin4 cimg_save_plugin4(fn); #endif #ifdef cimg_save_plugin5 cimg_save_plugin5(fn); #endif #ifdef cimg_save_plugin6 cimg_save_plugin6(fn); #endif #ifdef cimg_save_plugin7 cimg_save_plugin7(fn); #endif #ifdef cimg_save_plugin8 cimg_save_plugin8(fn); #endif // Ascii formats if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn); else if (!cimg::strcasecmp(ext,"dlm") || !cimg::strcasecmp(ext,"txt")) return save_dlm(fn); else if (!cimg::strcasecmp(ext,"cpp") || !cimg::strcasecmp(ext,"hpp") || !cimg::strcasecmp(ext,"h") || !cimg::strcasecmp(ext,"c")) return save_cpp(fn); // 2d binary formats else if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn); else if (!cimg::strcasecmp(ext,"jpg") || !cimg::strcasecmp(ext,"jpeg") || !cimg::strcasecmp(ext,"jpe") || !cimg::strcasecmp(ext,"jfif") || !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn); else if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn); else if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn); else if (!cimg::strcasecmp(ext,"png")) return save_png(fn); else if (!cimg::strcasecmp(ext,"pgm") || !cimg::strcasecmp(ext,"ppm") || !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn); else if (!cimg::strcasecmp(ext,"pnk")) return save_pnk(fn); else if (!cimg::strcasecmp(ext,"pfm")) return save_pfm(fn); else if (!cimg::strcasecmp(ext,"exr")) return save_exr(fn); else if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); // 3d binary formats else if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false); else if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn); else if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"nii")) return save_analyze(fn); else if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn); else if (!cimg::strcasecmp(ext,"mnc")) return save_minc2(fn); else if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn); else if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn); // Archive files else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); // Image sequences else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true); else if (!cimg::strcasecmp(ext,"avi") || !cimg::strcasecmp(ext,"mov") || !cimg::strcasecmp(ext,"asf") || !cimg::strcasecmp(ext,"divx") || !cimg::strcasecmp(ext,"flv") || !cimg::strcasecmp(ext,"mpg") || !cimg::strcasecmp(ext,"m1v") || !cimg::strcasecmp(ext,"m2v") || !cimg::strcasecmp(ext,"m4v") || !cimg::strcasecmp(ext,"mjp") || !cimg::strcasecmp(ext,"mp4") || !cimg::strcasecmp(ext,"mkv") || !cimg::strcasecmp(ext,"mpe") || !cimg::strcasecmp(ext,"movie") || !cimg::strcasecmp(ext,"ogm") || !cimg::strcasecmp(ext,"ogg") || !cimg::strcasecmp(ext,"ogv") || !cimg::strcasecmp(ext,"qt") || !cimg::strcasecmp(ext,"rm") || !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); return save_other(fn); } //! Save image as an ascii file. /** \param filename Filename, as a C-string. **/ const CImg& save_ascii(const char *const filename) const { return _save_ascii(0,filename); } //! Save image as an ascii file \overloading. const CImg& save_ascii(std::FILE *const file) const { return _save_ascii(file,0); } const CImg& _save_ascii(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_ascii(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); std::fprintf(nfile,"%u %u %u %u\n",_width,_height,_depth,_spectrum); const T* ptrs = _data; cimg_forYZC(*this,y,z,c) { cimg_forX(*this,x) std::fprintf(nfile,"%.16g ",(double)*(ptrs++)); std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a .cpp source file. /** \param filename Filename, as a C-string. **/ const CImg& save_cpp(const char *const filename) const { return _save_cpp(0,filename); } //! Save image as a .cpp source file \overloading. const CImg& save_cpp(std::FILE *const file) const { return _save_cpp(file,0); } const CImg& _save_cpp(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_cpp(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); CImg varname(1024); *varname = 0; if (filename) cimg_sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname._data); if (!*varname) cimg_snprintf(varname,varname._width,"unnamed"); std::fprintf(nfile, "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n" "%s data_%s[] = { %s\n ", varname._data,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname._data, is_empty()?"};":""); if (!is_empty()) for (ulongT off = 0, siz = size() - 1; off<=siz; ++off) { std::fprintf(nfile,cimg::type::format(),cimg::type::format((*this)[off])); if (off==siz) std::fprintf(nfile," };\n"); else if (!((off + 1)%16)) std::fprintf(nfile,",\n "); else std::fprintf(nfile,", "); } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a DLM file. /** \param filename Filename, as a C-string. **/ const CImg& save_dlm(const char *const filename) const { return _save_dlm(0,filename); } //! Save image as a DLM file \overloading. const CImg& save_dlm(std::FILE *const file) const { return _save_dlm(file,0); } const CImg& _save_dlm(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_dlm(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_dlm(): Instance is volumetric, values along Z will be unrolled in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (_spectrum>1) cimg::warn(_cimg_instance "save_dlm(): Instance is multispectral, values along C will be unrolled in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); const T* ptrs = _data; cimg_forYZC(*this,y,z,c) { cimg_forX(*this,x) std::fprintf(nfile,"%.16g%s",(double)*(ptrs++),(x==width() - 1)?"":","); std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a BMP file. /** \param filename Filename, as a C-string. **/ const CImg& save_bmp(const char *const filename) const { return _save_bmp(0,filename); } //! Save image as a BMP file \overloading. const CImg& save_bmp(std::FILE *const file) const { return _save_bmp(file,0); } const CImg& _save_bmp(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_bmp(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_bmp(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (_spectrum>3) cimg::warn(_cimg_instance "save_bmp(): Instance is multispectral, only the three first channels will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); CImg header(54,1,1,1,0); unsigned char align_buf[4] = { 0 }; const unsigned int align = (4 - (3*_width)%4)%4, buf_size = (3*_width + align)*height(), file_size = 54 + buf_size; header[0] = 'B'; header[1] = 'M'; header[0x02] = file_size&0xFF; header[0x03] = (file_size>>8)&0xFF; header[0x04] = (file_size>>16)&0xFF; header[0x05] = (file_size>>24)&0xFF; header[0x0A] = 0x36; header[0x0E] = 0x28; header[0x12] = _width&0xFF; header[0x13] = (_width>>8)&0xFF; header[0x14] = (_width>>16)&0xFF; header[0x15] = (_width>>24)&0xFF; header[0x16] = _height&0xFF; header[0x17] = (_height>>8)&0xFF; header[0x18] = (_height>>16)&0xFF; header[0x19] = (_height>>24)&0xFF; header[0x1A] = 1; header[0x1B] = 0; header[0x1C] = 24; header[0x1D] = 0; header[0x22] = buf_size&0xFF; header[0x23] = (buf_size>>8)&0xFF; header[0x24] = (buf_size>>16)&0xFF; header[0x25] = (buf_size>>24)&0xFF; header[0x27] = 0x1; header[0x2B] = 0x1; cimg::fwrite(header._data,54,nfile); const T *ptr_r = data(0,_height - 1,0,0), *ptr_g = (_spectrum>=2)?data(0,_height - 1,0,1):0, *ptr_b = (_spectrum>=3)?data(0,_height - 1,0,2):0; switch (_spectrum) { case 1 : { cimg_forY(*this,y) { cimg_forX(*this,x) { const unsigned char val = (unsigned char)*(ptr_r++); std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile); } cimg::fwrite(align_buf,align,nfile); ptr_r-=2*_width; } } break; case 2 : { cimg_forY(*this,y) { cimg_forX(*this,x) { std::fputc(0,nfile); std::fputc((unsigned char)(*(ptr_g++)),nfile); std::fputc((unsigned char)(*(ptr_r++)),nfile); } cimg::fwrite(align_buf,align,nfile); ptr_r-=2*_width; ptr_g-=2*_width; } } break; default : { cimg_forY(*this,y) { cimg_forX(*this,x) { std::fputc((unsigned char)(*(ptr_b++)),nfile); std::fputc((unsigned char)(*(ptr_g++)),nfile); std::fputc((unsigned char)(*(ptr_r++)),nfile); } cimg::fwrite(align_buf,align,nfile); ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width; } } } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a JPEG file. /** \param filename Filename, as a C-string. \param quality Image quality (in %) **/ const CImg& save_jpeg(const char *const filename, const unsigned int quality=100) const { return _save_jpeg(0,filename,quality); } //! Save image as a JPEG file \overloading. const CImg& save_jpeg(std::FILE *const file, const unsigned int quality=100) const { return _save_jpeg(file,0,quality); } const CImg& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_jpeg(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_jpeg(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); #ifndef cimg_use_jpeg if (!file) return save_other(filename,quality); else throw CImgIOException(_cimg_instance "save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.", cimg_instance); #else unsigned int dimbuf = 0; J_COLOR_SPACE colortype = JCS_RGB; switch (_spectrum) { case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break; case 2 : dimbuf = 3; colortype = JCS_RGB; break; case 3 : dimbuf = 3; colortype = JCS_RGB; break; default : dimbuf = 4; colortype = JCS_CMYK; break; } // Call libjpeg functions struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); jpeg_stdio_dest(&cinfo,nfile); cinfo.image_width = _width; cinfo.image_height = _height; cinfo.input_components = dimbuf; cinfo.in_color_space = colortype; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE); jpeg_start_compress(&cinfo,TRUE); JSAMPROW row_pointer[1]; CImg buffer(_width*dimbuf); while (cinfo.next_scanline& save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_magick(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } #ifdef cimg_use_magick double stmin, stmax = (double)max_min(stmin); if (_depth>1) cimg::warn(_cimg_instance "save_magick(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename); if (_spectrum>3) cimg::warn(_cimg_instance "save_magick(): Instance is multispectral, only the three first channels will be " "saved in file '%s'.", cimg_instance, filename); if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) cimg::warn(_cimg_instance "save_magick(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", cimg_instance, filename,stmin,stmax); Magick::Image image(Magick::Geometry(_width,_height),"black"); image.type(Magick::TrueColorType); image.depth(bytes_per_pixel?(8*bytes_per_pixel):(stmax>=256?16:8)); const T *ptr_r = data(0,0,0,0), *ptr_g = _spectrum>1?data(0,0,0,1):0, *ptr_b = _spectrum>2?data(0,0,0,2):0; Magick::PixelPacket *pixels = image.getPixels(0,0,_width,_height); switch (_spectrum) { case 1 : // Scalar images for (ulongT off = (ulongT)_width*_height; off; --off) { pixels->red = pixels->green = pixels->blue = (Magick::Quantum)*(ptr_r++); ++pixels; } break; case 2 : // RG images for (ulongT off = (ulongT)_width*_height; off; --off) { pixels->red = (Magick::Quantum)*(ptr_r++); pixels->green = (Magick::Quantum)*(ptr_g++); pixels->blue = 0; ++pixels; } break; default : // RGB images for (ulongT off = (ulongT)_width*_height; off; --off) { pixels->red = (Magick::Quantum)*(ptr_r++); pixels->green = (Magick::Quantum)*(ptr_g++); pixels->blue = (Magick::Quantum)*(ptr_b++); ++pixels; } } image.syncPixels(); image.write(filename); return *this; #else cimg::unused(bytes_per_pixel); throw CImgIOException(_cimg_instance "save_magick(): Unable to save file '%s' unless libMagick++ is enabled.", cimg_instance, filename); #endif } //! Save image as a PNG file. /** \param filename Filename, as a C-string. \param bytes_per_pixel Force the number of bytes per pixels for the saving, when possible. **/ const CImg& save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const { return _save_png(0,filename,bytes_per_pixel); } //! Save image as a PNG file \overloading. const CImg& save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { return _save_png(file,0,bytes_per_pixel); } const CImg& _save_png(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_png(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } #ifndef cimg_use_png cimg::unused(bytes_per_pixel); if (!file) return save_other(filename); else throw CImgIOException(_cimg_instance "save_png(): Unable to save data in '(*FILE)' unless libpng is enabled.", cimg_instance); #else const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'. std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb"); volatile double stmin, stmax = (double)max_min(stmin); if (_depth>1) cimg::warn(_cimg_instance "save_png(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename); if (_spectrum>4) cimg::warn(_cimg_instance "save_png(): Instance is multispectral, only the three first channels will be saved in file '%s'.", cimg_instance, filename); if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) cimg::warn(_cimg_instance "save_png(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", cimg_instance, filename,stmin,stmax); // Setup PNG structures for write png_voidp user_error_ptr = 0; png_error_ptr user_error_fn = 0, user_warning_fn = 0; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn); if(!png_ptr){ if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "save_png(): Failed to initialize 'png_ptr' structure when saving file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "save_png(): Failed to initialize 'info_ptr' structure when saving file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_init_io(png_ptr, nfile); const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8); int color_type; switch (spectrum()) { case 1 : color_type = PNG_COLOR_TYPE_GRAY; break; case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3 : color_type = PNG_COLOR_TYPE_RGB; break; default : color_type = PNG_COLOR_TYPE_RGB_ALPHA; } const int interlace_type = PNG_INTERLACE_NONE; const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; const int filter_method = PNG_FILTER_TYPE_DEFAULT; png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method); png_write_info(png_ptr,info_ptr); const int byte_depth = bit_depth>>3; const int numChan = spectrum()>4?4:spectrum(); const int pixel_bit_depth_flag = numChan * (bit_depth - 1); // Allocate Memory for Image Save and Fill pixel data png_bytep *const imgData = new png_byte*[_height]; for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width]; const T *pC0 = data(0,0,0,0); switch (pixel_bit_depth_flag) { case 7 : { // Gray 8-bit cimg_forY(*this,y) { unsigned char *ptrd = imgData[y]; cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++); } } break; case 14 : { // Gray w/ Alpha 8-bit const T *pC1 = data(0,0,0,1); cimg_forY(*this,y) { unsigned char *ptrd = imgData[y]; cimg_forX(*this,x) { *(ptrd++) = (unsigned char)*(pC0++); *(ptrd++) = (unsigned char)*(pC1++); } } } break; case 21 : { // RGB 8-bit const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); cimg_forY(*this,y) { unsigned char *ptrd = imgData[y]; cimg_forX(*this,x) { *(ptrd++) = (unsigned char)*(pC0++); *(ptrd++) = (unsigned char)*(pC1++); *(ptrd++) = (unsigned char)*(pC2++); } } } break; case 28 : { // RGB x/ Alpha 8-bit const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); cimg_forY(*this,y){ unsigned char *ptrd = imgData[y]; cimg_forX(*this,x){ *(ptrd++) = (unsigned char)*(pC0++); *(ptrd++) = (unsigned char)*(pC1++); *(ptrd++) = (unsigned char)*(pC2++); *(ptrd++) = (unsigned char)*(pC3++); } } } break; case 15 : { // Gray 16-bit cimg_forY(*this,y){ unsigned short *ptrd = (unsigned short*)(imgData[y]); cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++); if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width); } } break; case 30 : { // Gray w/ Alpha 16-bit const T *pC1 = data(0,0,0,1); cimg_forY(*this,y){ unsigned short *ptrd = (unsigned short*)(imgData[y]); cimg_forX(*this,x) { *(ptrd++) = (unsigned short)*(pC0++); *(ptrd++) = (unsigned short)*(pC1++); } if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width); } } break; case 45 : { // RGB 16-bit const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); cimg_forY(*this,y) { unsigned short *ptrd = (unsigned short*)(imgData[y]); cimg_forX(*this,x) { *(ptrd++) = (unsigned short)*(pC0++); *(ptrd++) = (unsigned short)*(pC1++); *(ptrd++) = (unsigned short)*(pC2++); } if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width); } } break; case 60 : { // RGB w/ Alpha 16-bit const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); cimg_forY(*this,y) { unsigned short *ptrd = (unsigned short*)(imgData[y]); cimg_forX(*this,x) { *(ptrd++) = (unsigned short)*(pC0++); *(ptrd++) = (unsigned short)*(pC1++); *(ptrd++) = (unsigned short)*(pC2++); *(ptrd++) = (unsigned short)*(pC3++); } if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width); } } break; default : if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.", cimg_instance, nfilename?nfilename:"(FILE*)"); } png_write_image(png_ptr,imgData); png_write_end(png_ptr,info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); // Deallocate Image Write Memory cimg_forY(*this,n) delete[] imgData[n]; delete[] imgData; if (!file) cimg::fclose(nfile); return *this; #endif } //! Save image as a PNM file. /** \param filename Filename, as a C-string. \param bytes_per_pixel Force the number of bytes per pixels for the saving. **/ const CImg& save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const { return _save_pnm(0,filename,bytes_per_pixel); } //! Save image as a PNM file \overloading. const CImg& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { return _save_pnm(file,0,bytes_per_pixel); } const CImg& _save_pnm(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_pnm(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } double stmin, stmax = (double)max_min(stmin); if (_depth>1) cimg::warn(_cimg_instance "save_pnm(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (_spectrum>3) cimg::warn(_cimg_instance "save_pnm(): Instance is multispectral, only the three first channels will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) cimg::warn(_cimg_instance "save_pnm(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", cimg_instance, stmin,stmax,filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const T *ptr_r = data(0,0,0,0), *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; const ulongT buf_size = cimg::min((ulongT)1024*1024,(ulongT)_width*_height*(_spectrum==1?1UL:3UL)); std::fprintf(nfile,"P%c\n%u %u\n%u\n", (_spectrum==1?'5':'6'),_width,_height,stmax<256?255:(stmax<4096?4095:65535)); switch (_spectrum) { case 1 : { // Scalar image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); unsigned char *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } else { // Binary PGM 16 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); unsigned short *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++); if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } } break; case 2 : { // RG image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size/3); unsigned char *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (unsigned char)*(ptr_r++); *(ptrd++) = (unsigned char)*(ptr_g++); *(ptrd++) = 0; } cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } else { // Binary PPM 16 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size/3); unsigned short *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (unsigned short)*(ptr_r++); *(ptrd++) = (unsigned short)*(ptr_g++); *(ptrd++) = 0; } if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } } break; default : { // RGB image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size/3); unsigned char *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (unsigned char)*(ptr_r++); *(ptrd++) = (unsigned char)*(ptr_g++); *(ptrd++) = (unsigned char)*(ptr_b++); } cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } else { // Binary PPM 16 bits CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size/3); unsigned short *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (unsigned short)*(ptr_r++); *(ptrd++) = (unsigned short)*(ptr_g++); *(ptrd++) = (unsigned short)*(ptr_b++); } if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } } } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a PNK file. /** \param filename Filename, as a C-string. **/ const CImg& save_pnk(const char *const filename) const { return _save_pnk(0,filename); } //! Save image as a PNK file \overloading. const CImg& save_pnk(std::FILE *const file) const { return _save_pnk(file,0); } const CImg& _save_pnk(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_pnk(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_spectrum>1) cimg::warn(_cimg_instance "save_pnk(): Instance is multispectral, only the first channel will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); const ulongT buf_size = cimg::min((ulongT)1024*1024,(ulongT)_width*_height*_depth); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const T *ptr = data(0,0,0,0); if (!cimg::type::is_float() && sizeof(T)==1 && _depth<2) // Can be saved as regular PNM file. _save_pnm(file,filename,0); else if (!cimg::type::is_float() && sizeof(T)==1) { // Save as extended P5 file: Binary byte-valued 3d. std::fprintf(nfile,"P5\n%u %u %u\n255\n",_width,_height,_depth); CImg buf(buf_size); for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); unsigned char *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr++); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } else if (!cimg::type::is_float()) { // Save as P8: Binary int32-valued 3d. if (_depth>1) std::fprintf(nfile,"P8\n%u %u %u\n%d\n",_width,_height,_depth,(int)max()); else std::fprintf(nfile,"P8\n%u %u\n%d\n",_width,_height,(int)max()); CImg buf(buf_size); for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); int *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (int)*(ptr++); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } else { // Save as P9: Binary float-valued 3d. if (_depth>1) std::fprintf(nfile,"P9\n%u %u %u\n%g\n",_width,_height,_depth,(double)max()); else std::fprintf(nfile,"P9\n%u %u\n%g\n",_width,_height,(double)max()); CImg buf(buf_size); for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); float *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr++); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a PFM file. /** \param filename Filename, as a C-string. **/ const CImg& save_pfm(const char *const filename) const { get_mirror('y')._save_pfm(0,filename); return *this; } //! Save image as a PFM file \overloading. const CImg& save_pfm(std::FILE *const file) const { get_mirror('y')._save_pfm(file,0); return *this; } const CImg& _save_pfm(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_pfm(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_pfm(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); if (_spectrum>3) cimg::warn(_cimg_instance "save_pfm(): image instance is multispectral, only the three first channels will be saved " "in file '%s'.", cimg_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const T *ptr_r = data(0,0,0,0), *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; const unsigned int buf_size = cimg::min(1024*1024U,_width*_height*(_spectrum==1?1:3)); std::fprintf(nfile,"P%c\n%u %u\n1.0\n", (_spectrum==1?'f':'F'),_width,_height); switch (_spectrum) { case 1 : { // Scalar image CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const ulongT N = cimg::min((ulongT)to_write,buf_size); float *ptrd = buf._data; for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr_r++); if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,N,nfile); to_write-=N; } } break; case 2 : { // RG image CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); float *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (float)*(ptr_r++); *(ptrd++) = (float)*(ptr_g++); *(ptrd++) = 0; } if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } break; default : { // RGB image CImg buf(buf_size); for (longT to_write = (longT)width()*height(); to_write>0; ) { const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); float *ptrd = buf._data; for (ulongT i = N; i>0; --i) { *(ptrd++) = (float)*(ptr_r++); *(ptrd++) = (float)*(ptr_g++); *(ptrd++) = (float)*(ptr_b++); } if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); cimg::fwrite(buf._data,3*N,nfile); to_write-=N; } } } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a RGB file. /** \param filename Filename, as a C-string. **/ const CImg& save_rgb(const char *const filename) const { return _save_rgb(0,filename); } //! Save image as a RGB file \overloading. const CImg& save_rgb(std::FILE *const file) const { return _save_rgb(file,0); } const CImg& _save_rgb(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_rgb(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_spectrum!=3) cimg::warn(_cimg_instance "save_rgb(): image instance has not exactly 3 channels, for file '%s'.", cimg_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const ulongT wh = (ulongT)_width*_height; unsigned char *const buffer = new unsigned char[3*wh], *nbuffer = buffer; const T *ptr1 = data(0,0,0,0), *ptr2 = _spectrum>1?data(0,0,0,1):0, *ptr3 = _spectrum>2?data(0,0,0,2):0; switch (_spectrum) { case 1 : { // Scalar image for (ulongT k = 0; k& save_rgba(const char *const filename) const { return _save_rgba(0,filename); } //! Save image as a RGBA file \overloading. const CImg& save_rgba(std::FILE *const file) const { return _save_rgba(file,0); } const CImg& _save_rgba(std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_rgba(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if (_spectrum!=4) cimg::warn(_cimg_instance "save_rgba(): image instance has not exactly 4 channels, for file '%s'.", cimg_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const ulongT wh = (ulongT)_width*_height; unsigned char *const buffer = new unsigned char[4*wh], *nbuffer = buffer; const T *ptr1 = data(0,0,0,0), *ptr2 = _spectrum>1?data(0,0,0,1):0, *ptr3 = _spectrum>2?data(0,0,0,2):0, *ptr4 = _spectrum>3?data(0,0,0,3):0; switch (_spectrum) { case 1 : { // Scalar images for (ulongT k = 0; k{ 0=None | 1=LZW | 2=JPEG }. \note - libtiff support is enabled by defining the precompilation directive \c cimg_use_tif. - When libtiff is enabled, 2D and 3D (multipage) several channel per pixel are supported for char,uchar,short,ushort,float and \c double pixel types. - If \c cimg_use_tif is not defined at compile time the function uses CImg&save_other(const char*). **/ const CImg& save_tiff(const char *const filename, const unsigned int compression_type=0, const float *const voxel_size=0, const char *const description=0, const bool use_bigtiff=true) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_tiff(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } #ifdef cimg_use_tiff const bool _use_bigtiff = use_bigtiff && sizeof(ulongT)>=8 && size()*sizeof(T)>=1UL<<31; // No bigtiff for small images. TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4"); if (tif) { cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description); TIFFClose(tif); } else throw CImgIOException(_cimg_instance "save_tiff(): Failed to open file '%s' for writing.", cimg_instance, filename); return *this; #else cimg::unused(compression_type,voxel_size,description,use_bigtiff); return save_other(filename); #endif } #ifdef cimg_use_tiff #define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \ const typed foo = (typed)0; return _save_tiff(tif,directory,z,foo,compression_type,voxel_size,description); } // [internal] Save a plane into a tiff file template const CImg& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const t& pixel_t, const unsigned int compression_type, const float *const voxel_size, const char *const description) const { if (is_empty() || !tif || pixel_t) return *this; const char *const filename = TIFFFileName(tif); uint32 rowsperstrip = (uint32)-1; uint16 spp = _spectrum, bpp = sizeof(t)*8, photometric; if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB; else photometric = PHOTOMETRIC_MINISBLACK; TIFFSetDirectory(tif,directory); TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,_width); TIFFSetField(tif,TIFFTAG_IMAGELENGTH,_height); if (voxel_size) { const float vx = voxel_size[0], vy = voxel_size[1], vz = voxel_size[2]; TIFFSetField(tif,TIFFTAG_RESOLUTIONUNIT,RESUNIT_NONE); TIFFSetField(tif,TIFFTAG_XRESOLUTION,1.0f/vx); TIFFSetField(tif,TIFFTAG_YRESOLUTION,1.0f/vy); CImg s_description(256); cimg_snprintf(s_description,s_description._width,"VX=%g VY=%g VZ=%g spacing=%g",vx,vy,vz,vz); TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,s_description.data()); } if (description) TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,description); TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT); TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp); if (cimg::type::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3); else if (cimg::type::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1); else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2); TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp); TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric); TIFFSetField(tif,TIFFTAG_COMPRESSION,compression_type==2?COMPRESSION_JPEG: compression_type==1?COMPRESSION_LZW:COMPRESSION_NONE); rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip); TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip); TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB); TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg"); t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); if (buf) { for (unsigned int row = 0; row<_height; row+=rowsperstrip) { uint32 nrow = (row + rowsperstrip>_height?_height - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif,row,0); tsize_t i = 0; for (unsigned int rr = 0; rr& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const unsigned int compression_type, const float *const voxel_size, const char *const description) const { _cimg_save_tiff("bool",unsigned char,compression_type); _cimg_save_tiff("unsigned char",unsigned char,compression_type); _cimg_save_tiff("char",char,compression_type); _cimg_save_tiff("unsigned short",unsigned short,compression_type); _cimg_save_tiff("short",short,compression_type); _cimg_save_tiff("unsigned int",unsigned int,compression_type); _cimg_save_tiff("int",int,compression_type); _cimg_save_tiff("unsigned int64",unsigned int,compression_type); _cimg_save_tiff("int64",int,compression_type); _cimg_save_tiff("float",float,compression_type); _cimg_save_tiff("double",float,compression_type); const char *const filename = TIFFFileName(tif); throw CImgInstanceException(_cimg_instance "save_tiff(): Unsupported pixel type '%s' for file '%s'.", cimg_instance, pixel_type(),filename?filename:"(FILE*)"); return *this; } #endif //! Save image as a MINC2 file. /** \param filename Filename, as a C-string. \param imitate_file If non-zero, reference filename, as a C-string, to borrow header from. **/ const CImg& save_minc2(const char *const filename, const char *const imitate_file=0) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_minc2(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } #ifndef cimg_use_minc2 cimg::unused(imitate_file); return save_other(filename); #else minc::minc_1_writer wtr; if (imitate_file) wtr.open(filename, imitate_file); else { minc::minc_info di; if(width()) di.push_back(minc::dim_info(width(),width()*0.5,-1,minc::dim_info::DIM_X)); if(height()) di.push_back(minc::dim_info(height(),height()*0.5,-1,minc::dim_info::DIM_Y)); if(depth()) di.push_back(minc::dim_info(depth(),depth()*0.5,-1,minc::dim_info::DIM_Z)); if(spectrum()) di.push_back(minc::dim_info(spectrum(),spectrum()*0.5,-1,minc::dim_info::DIM_TIME)); wtr.open(filename,di,1,NC_FLOAT,0); } if(typeid(T)==typeid(unsigned char)) wtr.setup_write_byte(); else if(typeid(T)==typeid(int)) wtr.setup_write_int(); else if(typeid(T)==typeid(double)) wtr.setup_write_double(); else wtr.setup_write_float(); minc::save_standard_volume(wtr, this->_data); return *this; #endif } //! Save image as an ANALYZE7.5 or NIFTI file. /** \param filename Filename, as a C-string. \param voxel_size Pointer to 3 consecutive values that tell about the voxel sizes along the X,Y and Z dimensions. **/ const CImg& save_analyze(const char *const filename, const float *const voxel_size=0) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_analyze(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } std::FILE *file; CImg header(348,1,1,1,0), hname(1024), iname(1024); const char *const ext = cimg::split_filename(filename); short datatype = -1; if (!*ext) { cimg_snprintf(hname,hname._width,"%s.hdr",filename); cimg_snprintf(iname,iname._width,"%s.img",filename); } if (!cimg::strncasecmp(ext,"hdr",3)) { std::strcpy(hname,filename); std::strncpy(iname,filename,iname._width - 1); cimg_sprintf(iname._data + std::strlen(iname) - 3,"img"); } if (!cimg::strncasecmp(ext,"img",3)) { std::strcpy(hname,filename); std::strncpy(iname,filename,iname._width - 1); cimg_sprintf(hname._data + std::strlen(iname) - 3,"hdr"); } if (!cimg::strncasecmp(ext,"nii",3)) { std::strncpy(hname,filename,hname._width - 1); *iname = 0; } int *const iheader = (int*)header._data; *iheader = 348; std::strcpy(header._data + 4,"CImg"); std::strcpy(header._data + 14," "); ((short*)&(header[36]))[0] = 4096; ((char*)&(header[38]))[0] = 114; ((short*)&(header[40]))[0] = 4; ((short*)&(header[40]))[1] = (short)_width; ((short*)&(header[40]))[2] = (short)_height; ((short*)&(header[40]))[3] = (short)_depth; ((short*)&(header[40]))[4] = (short)_spectrum; if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4; if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4; if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"unsigned int64")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"int64")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16; if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64; if (datatype<0) throw CImgIOException(_cimg_instance "save_analyze(): Unsupported pixel type '%s' for file '%s'.", cimg_instance, pixel_type(),filename); ((short*)&(header[70]))[0] = datatype; ((short*)&(header[72]))[0] = sizeof(T); ((float*)&(header[112]))[0] = 1; ((float*)&(header[76]))[0] = 0; if (voxel_size) { ((float*)&(header[76]))[1] = voxel_size[0]; ((float*)&(header[76]))[2] = voxel_size[1]; ((float*)&(header[76]))[3] = voxel_size[2]; } else ((float*)&(header[76]))[1] = ((float*)&(header[76]))[2] = ((float*)&(header[76]))[3] = 1; file = cimg::fopen(hname,"wb"); cimg::fwrite(header._data,348,file); if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } cimg::fwrite(_data,size(),file); cimg::fclose(file); return *this; } //! Save image as a .cimg file. /** \param filename Filename, as a C-string. \param is_compressed Tells if the file contains compressed image data. **/ const CImg& save_cimg(const char *const filename, const bool is_compressed=false) const { CImgList(*this,true).save_cimg(filename,is_compressed); return *this; } //! Save image as a .cimg file \overloading. const CImg& save_cimg(std::FILE *const file, const bool is_compressed=false) const { CImgList(*this,true).save_cimg(file,is_compressed); return *this; } //! Save image as a sub-image into an existing .cimg file. /** \param filename Filename, as a C-string. \param n0 Index of the image inside the file. \param x0 X-coordinate of the sub-image location. \param y0 Y-coordinate of the sub-image location. \param z0 Z-coordinate of the sub-image location. \param c0 C-coordinate of the sub-image location. **/ const CImg& save_cimg(const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0) const { CImgList(*this,true).save_cimg(filename,n0,x0,y0,z0,c0); return *this; } //! Save image as a sub-image into an existing .cimg file \overloading. const CImg& save_cimg(std::FILE *const file, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0) const { CImgList(*this,true).save_cimg(file,n0,x0,y0,z0,c0); return *this; } //! Save blank image as a .cimg file. /** \param filename Filename, as a C-string. \param dx Width of the image. \param dy Height of the image. \param dz Depth of the image. \param dc Number of channels of the image. \note - All pixel values of the saved image are set to \c 0. - Use this method to save large images without having to instanciate and allocate them. **/ static void save_empty_cimg(const char *const filename, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1) { return CImgList::save_empty_cimg(filename,1,dx,dy,dz,dc); } //! Save blank image as a .cimg file \overloading. /** Same as save_empty_cimg(const char *,unsigned int,unsigned int,unsigned int,unsigned int) with a file stream argument instead of a filename string. **/ static void save_empty_cimg(std::FILE *const file, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1) { return CImgList::save_empty_cimg(file,1,dx,dy,dz,dc); } //! Save image as an INRIMAGE-4 file. /** \param filename Filename, as a C-string. \param voxel_size Pointer to 3 values specifying the voxel sizes along the X,Y and Z dimensions. **/ const CImg& save_inr(const char *const filename, const float *const voxel_size=0) const { return _save_inr(0,filename,voxel_size); } //! Save image as an INRIMAGE-4 file \overloading. const CImg& save_inr(std::FILE *const file, const float *const voxel_size=0) const { return _save_inr(file,0,voxel_size); } const CImg& _save_inr(std::FILE *const file, const char *const filename, const float *const voxel_size) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_inr(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } int inrpixsize = -1; const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; } if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; } if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; } if (inrpixsize<=0) throw CImgIOException(_cimg_instance "save_inr(): Unsupported pixel type '%s' for file '%s'", cimg_instance, pixel_type(),filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); CImg header(257); int err = cimg_snprintf(header,header._width,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n", _width,_height,_depth,_spectrum); if (voxel_size) err+=cimg_sprintf(header._data + err,"VX=%g\nVY=%g\nVZ=%g\n", voxel_size[0],voxel_size[1],voxel_size[2]); err+=cimg_sprintf(header._data + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm"); std::memset(header._data + err,'\n',252 - err); std::memcpy(header._data + 252,"##}\n",4); cimg::fwrite(header._data,256,nfile); cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile); if (!file) cimg::fclose(nfile); return *this; } //! Save image as an OpenEXR file. /** \param filename Filename, as a C-string. \note The OpenEXR file format is described here. **/ const CImg& save_exr(const char *const filename) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_exr(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_exr(): Instance is volumetric, only the first slice will be saved in file '%s'.", cimg_instance, filename); #ifndef cimg_use_openexr return save_other(filename); #else Imf::Rgba *const ptrd0 = new Imf::Rgba[(size_t)_width*_height], *ptrd = ptrd0, rgba; switch (_spectrum) { case 1 : { // Grayscale image. for (const T *ptr_r = data(), *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_rPandore file specifications for more information). **/ const CImg& save_pandore(const char *const filename, const unsigned int colorspace=0) const { return _save_pandore(0,filename,colorspace); } //! Save image as a Pandore-5 file \overloading. /** Same as save_pandore(const char *,unsigned int) const with a file stream argument instead of a filename string. **/ const CImg& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const { return _save_pandore(file,0,colorspace); } unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const { unsigned int nbdims = 0; if (id==2 || id==3 || id==4) { dims[0] = 1; dims[1] = _width; nbdims = 2; } if (id==5 || id==6 || id==7) { dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; } if (id==8 || id==9 || id==10) { dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; } if (id==16 || id==17 || id==18) { dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; } if (id==19 || id==20 || id==21) { dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; } if (id==22 || id==23 || id==25) { dims[0] = _spectrum; dims[1] = _width; nbdims = 2; } if (id==26 || id==27 || id==29) { dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; } if (id==30 || id==31 || id==33) { dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; } return nbdims; } const CImg& _save_pandore(std::FILE *const file, const char *const filename, const unsigned int colorspace) const { #define __cimg_save_pandore_case(dtype) \ dtype *buffer = new dtype[size()]; \ const T *ptrs = _data; \ cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \ buffer-=size(); \ cimg::fwrite(buffer,size(),nfile); \ delete[] buffer #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \ if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && \ (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \ unsigned int *iheader = (unsigned int*)(header + 12); \ nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ cimg::fwrite(header,36,nfile); \ if (sizeof(unsigned long)==4) { CImg ndims(5); \ for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ else if (sizeof(unsigned int)==4) { CImg ndims(5); \ for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ else if (sizeof(unsigned short)==4) { CImg ndims(5); \ for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ else throw CImgIOException(_cimg_instance \ "save_pandore(): Unsupported datatype for file '%s'.",\ cimg_instance, \ filename?filename:"(FILE*)"); \ if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ __cimg_save_pandore_case(unsigned char); \ } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \ else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \ else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \ else throw CImgIOException(_cimg_instance \ "save_pandore(): Unsupported datatype for file '%s'.",\ cimg_instance, \ filename?filename:"(FILE*)"); \ } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \ else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \ else throw CImgIOException(_cimg_instance \ "save_pandore(): Unsupported datatype for file '%s'.",\ cimg_instance, \ filename?filename:"(FILE*)"); \ } \ saved = true; \ } if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_pandore(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, 0,0,0,0,'C','I','m','g',0,0,0,0,0, 'N','o',' ','d','a','t','e',0,0,0,0 }; unsigned int nbdims, dims[5] = { 0 }; bool saved = false; _cimg_save_pandore_case(1,1,1,"unsigned char",2); _cimg_save_pandore_case(1,1,1,"char",3); _cimg_save_pandore_case(1,1,1,"unsigned short",3); _cimg_save_pandore_case(1,1,1,"short",3); _cimg_save_pandore_case(1,1,1,"unsigned int",3); _cimg_save_pandore_case(1,1,1,"int",3); _cimg_save_pandore_case(1,1,1,"unsigned int64",3); _cimg_save_pandore_case(1,1,1,"int64",3); _cimg_save_pandore_case(1,1,1,"float",4); _cimg_save_pandore_case(1,1,1,"double",4); _cimg_save_pandore_case(0,1,1,"unsigned char",5); _cimg_save_pandore_case(0,1,1,"char",6); _cimg_save_pandore_case(0,1,1,"unsigned short",6); _cimg_save_pandore_case(0,1,1,"short",6); _cimg_save_pandore_case(0,1,1,"unsigned int",6); _cimg_save_pandore_case(0,1,1,"int",6); _cimg_save_pandore_case(0,1,1,"unsigned int64",6); _cimg_save_pandore_case(0,1,1,"int64",6); _cimg_save_pandore_case(0,1,1,"float",7); _cimg_save_pandore_case(0,1,1,"double",7); _cimg_save_pandore_case(0,0,1,"unsigned char",8); _cimg_save_pandore_case(0,0,1,"char",9); _cimg_save_pandore_case(0,0,1,"unsigned short",9); _cimg_save_pandore_case(0,0,1,"short",9); _cimg_save_pandore_case(0,0,1,"unsigned int",9); _cimg_save_pandore_case(0,0,1,"int",9); _cimg_save_pandore_case(0,0,1,"unsigned int64",9); _cimg_save_pandore_case(0,0,1,"int64",9); _cimg_save_pandore_case(0,0,1,"float",10); _cimg_save_pandore_case(0,0,1,"double",10); _cimg_save_pandore_case(0,1,3,"unsigned char",16); _cimg_save_pandore_case(0,1,3,"char",17); _cimg_save_pandore_case(0,1,3,"unsigned short",17); _cimg_save_pandore_case(0,1,3,"short",17); _cimg_save_pandore_case(0,1,3,"unsigned int",17); _cimg_save_pandore_case(0,1,3,"int",17); _cimg_save_pandore_case(0,1,3,"unsigned int64",17); _cimg_save_pandore_case(0,1,3,"int64",17); _cimg_save_pandore_case(0,1,3,"float",18); _cimg_save_pandore_case(0,1,3,"double",18); _cimg_save_pandore_case(0,0,3,"unsigned char",19); _cimg_save_pandore_case(0,0,3,"char",20); _cimg_save_pandore_case(0,0,3,"unsigned short",20); _cimg_save_pandore_case(0,0,3,"short",20); _cimg_save_pandore_case(0,0,3,"unsigned int",20); _cimg_save_pandore_case(0,0,3,"int",20); _cimg_save_pandore_case(0,0,3,"unsigned int64",20); _cimg_save_pandore_case(0,0,3,"int64",20); _cimg_save_pandore_case(0,0,3,"float",21); _cimg_save_pandore_case(0,0,3,"double",21); _cimg_save_pandore_case(1,1,0,"unsigned char",22); _cimg_save_pandore_case(1,1,0,"char",23); _cimg_save_pandore_case(1,1,0,"unsigned short",23); _cimg_save_pandore_case(1,1,0,"short",23); _cimg_save_pandore_case(1,1,0,"unsigned int",23); _cimg_save_pandore_case(1,1,0,"int",23); _cimg_save_pandore_case(1,1,0,"unsigned int64",23); _cimg_save_pandore_case(1,1,0,"int64",23); _cimg_save_pandore_case(1,1,0,"float",25); _cimg_save_pandore_case(1,1,0,"double",25); _cimg_save_pandore_case(0,1,0,"unsigned char",26); _cimg_save_pandore_case(0,1,0,"char",27); _cimg_save_pandore_case(0,1,0,"unsigned short",27); _cimg_save_pandore_case(0,1,0,"short",27); _cimg_save_pandore_case(0,1,0,"unsigned int",27); _cimg_save_pandore_case(0,1,0,"int",27); _cimg_save_pandore_case(0,1,0,"unsigned int64",27); _cimg_save_pandore_case(0,1,0,"int64",27); _cimg_save_pandore_case(0,1,0,"float",29); _cimg_save_pandore_case(0,1,0,"double",29); _cimg_save_pandore_case(0,0,0,"unsigned char",30); _cimg_save_pandore_case(0,0,0,"char",31); _cimg_save_pandore_case(0,0,0,"unsigned short",31); _cimg_save_pandore_case(0,0,0,"short",31); _cimg_save_pandore_case(0,0,0,"unsigned int",31); _cimg_save_pandore_case(0,0,0,"int",31); _cimg_save_pandore_case(0,0,0,"unsigned int64",31); _cimg_save_pandore_case(0,0,0,"int64",31); _cimg_save_pandore_case(0,0,0,"float",33); _cimg_save_pandore_case(0,0,0,"double",33); if (!file) cimg::fclose(nfile); return *this; } //! Save image as a raw data file. /** \param filename Filename, as a C-string. \param is_multiplexed Tells if the image channels are stored in a multiplexed way (\c true) or not (\c false). \note The .raw format does not store the image dimensions in the output file, so you have to keep track of them somewhere to be able to read the file correctly afterwards. **/ const CImg& save_raw(const char *const filename, const bool is_multiplexed=false) const { return _save_raw(0,filename,is_multiplexed); } //! Save image as a raw data file \overloading. /** Same as save_raw(const char *,bool) const with a file stream argument instead of a filename string. **/ const CImg& save_raw(std::FILE *const file, const bool is_multiplexed=false) const { return _save_raw(file,0,is_multiplexed); } const CImg& _save_raw(std::FILE *const file, const char *const filename, const bool is_multiplexed) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_raw(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); if (!is_multiplexed) cimg::fwrite(_data,size(),nfile); else { CImg buf(_spectrum); cimg_forXYZ(*this,x,y,z) { cimg_forC(*this,c) buf[c] = (*this)(x,y,z,c); cimg::fwrite(buf._data,_spectrum,nfile); } } if (!file) cimg::fclose(nfile); return *this; } //! Save image as a .yuv video file. /** \param filename Filename, as a C-string. \param is_rgb Tells if pixel values of the instance image are RGB-coded (\c true) or YUV-coded (\c false). \note Each slice of the instance image is considered to be a single frame of the output video file. **/ const CImg& save_yuv(const char *const filename, const bool is_rgb=true) const { get_split('z').save_yuv(filename,is_rgb); return *this; } //! Save image as a .yuv video file \overloading. /** Same as save_yuv(const char*,bool) const with a file stream argument instead of a filename string. **/ const CImg& save_yuv(std::FILE *const file, const bool is_rgb=true) const { get_split('z').save_yuv(file,is_rgb); return *this; } //! Save 3d object as an Object File Format (.off) file. /** \param filename Filename, as a C-string. \param primitives List of 3d object primitives. \param colors List of 3d object colors. \note - Instance image contains the vertices data of the 3d object. - Textured, transparent or sphere-shaped primitives cannot be managed by the .off file format. Such primitives will be lost or simplified during file saving. - The .off file format is described here. **/ template const CImg& save_off(const CImgList& primitives, const CImgList& colors, const char *const filename) const { return _save_off(primitives,colors,0,filename); } //! Save 3d object as an Object File Format (.off) file \overloading. /** Same as save_off(const CImgList&,const CImgList&,const char*) const with a file stream argument instead of a filename string. **/ template const CImg& save_off(const CImgList& primitives, const CImgList& colors, std::FILE *const file) const { return _save_off(primitives,colors,file,0); } template const CImg& _save_off(const CImgList& primitives, const CImgList& colors, std::FILE *const file, const char *const filename) const { if (!file && !filename) throw CImgArgumentException(_cimg_instance "save_off(): Specified filename is (null).", cimg_instance); if (is_empty()) throw CImgInstanceException(_cimg_instance "save_off(): Empty instance, for file '%s'.", cimg_instance, filename?filename:"(FILE*)"); CImgList opacities; CImg error_message(1024); if (!is_object3d(primitives,colors,opacities,true,error_message)) throw CImgInstanceException(_cimg_instance "save_off(): Invalid specified 3d object, for file '%s' (%s).", cimg_instance, filename?filename:"(FILE*)",error_message.data()); const CImg default_color(1,3,1,1,200); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); unsigned int supported_primitives = 0; cimglist_for(primitives,l) if (primitives[l].size()!=5) ++supported_primitives; std::fprintf(nfile,"OFF\n%u %u %u\n",_width,supported_primitives,3*primitives._width); cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n", (float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2))); cimglist_for(primitives,l) { const CImg& color = l1?color[1]:r)/255.0f, b = (csiz>2?color[2]:g)/255.0f; switch (psiz) { case 1 : std::fprintf(nfile,"1 %u %f %f %f\n", (unsigned int)primitives(l,0),r,g,b); break; case 2 : std::fprintf(nfile,"2 %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; case 3 : std::fprintf(nfile,"3 %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,2), (unsigned int)primitives(l,1),r,g,b); break; case 4 : std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,3), (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break; case 5 : std::fprintf(nfile,"2 %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; case 6 : { const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3); const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; std::fprintf(nfile,"2 %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),rt,gt,bt); } break; case 9 : { const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4); const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; std::fprintf(nfile,"3 %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,2), (unsigned int)primitives(l,1),rt,gt,bt); } break; case 12 : { const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5); const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,3), (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),rt,gt,bt); } break; } } if (!file) cimg::fclose(nfile); return *this; } //! Save volumetric image as a video, using the OpenCV library. /** \param filename Filename to write data to. \param fps Number of frames per second. \param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs). \param keep_open Tells if the video writer associated to the specified filename must be kept open or not (to allow frames to be added in the same file afterwards). **/ const CImg& save_video(const char *const filename, const unsigned int fps=25, const char *codec=0, const bool keep_open=false) const { if (is_empty()) { CImgList().save_video(filename,fps,codec,keep_open); return *this; } CImgList list; get_split('z').move_to(list); list.save_video(filename,fps,codec,keep_open); return *this; } //! Save volumetric image as a video, using ffmpeg external binary. /** \param filename Filename, as a C-string. \param fps Video framerate. \param codec Video codec, as a C-string. \param bitrate Video bitrate. \note - Each slice of the instance image is considered to be a single frame of the output video file. - This method uses \c ffmpeg, an external executable binary provided by FFmpeg. It must be installed for the method to succeed. **/ const CImg& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, const char *const codec=0, const unsigned int bitrate=2048) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_ffmpeg_external(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } CImgList list; get_split('z').move_to(list); list.save_ffmpeg_external(filename,fps,codec,bitrate); return *this; } //! Save image using gzip external binary. /** \param filename Filename, as a C-string. \note This method uses \c gzip, an external executable binary provided by gzip. It must be installed for the method to succeed. **/ const CImg& save_gzip_external(const char *const filename) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_gzip_external(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } CImg command(1024), filename_tmp(256), body(256); const char *ext = cimg::split_filename(filename,body), *ext2 = cimg::split_filename(body,0); std::FILE *file; do { if (!cimg::strcasecmp(ext,"gz")) { if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); save(filename_tmp); cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gzip_path(), CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimg_instance "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.", cimg_instance, filename); else cimg::fclose(file); std::remove(filename_tmp); return *this; } //! Save image using GraphicsMagick's external binary. /** \param filename Filename, as a C-string. \param quality Image quality (expressed in percent), when the file format supports it. \note This method uses \c gm, an external executable binary provided by GraphicsMagick. It must be installed for the method to succeed. **/ const CImg& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_graphicsmagick_external(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_other(): File '%s', saving a volumetric image with an external call to " "GraphicsMagick only writes the first image slice.", cimg_instance,filename); #ifdef cimg_use_png #define _cimg_sge_ext1 "png" #define _cimg_sge_ext2 "png" #else #define _cimg_sge_ext1 "pgm" #define _cimg_sge_ext2 "ppm" #endif CImg command(1024), filename_tmp(256); std::FILE *file; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(), _spectrum==1?_cimg_sge_ext1:_cimg_sge_ext2); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); #ifdef cimg_use_png save_png(filename_tmp); #else save_pnm(filename_tmp); #endif cimg_snprintf(command,command._width,"%s convert -quality %u \"%s\" \"%s\"", cimg::graphicsmagick_path(),quality, CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimg_instance "save_graphicsmagick_external(): Failed to save file '%s' with external command 'gm'.", cimg_instance, filename); if (file) cimg::fclose(file); std::remove(filename_tmp); return *this; } //! Save image using ImageMagick's external binary. /** \param filename Filename, as a C-string. \param quality Image quality (expressed in percent), when the file format supports it. \note This method uses \c convert, an external executable binary provided by ImageMagick. It must be installed for the method to succeed. **/ const CImg& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_imagemagick_external(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_other(): File '%s', saving a volumetric image with an external call to " "ImageMagick only writes the first image slice.", cimg_instance,filename); #ifdef cimg_use_png #define _cimg_sie_ext1 "png" #define _cimg_sie_ext2 "png" #else #define _cimg_sie_ext1 "pgm" #define _cimg_sie_ext2 "ppm" #endif CImg command(1024), filename_tmp(256); std::FILE *file; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",cimg::temporary_path(), cimg_file_separator,cimg::filenamerand(),_spectrum==1?_cimg_sie_ext1:_cimg_sie_ext2); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); #ifdef cimg_use_png save_png(filename_tmp); #else save_pnm(filename_tmp); #endif cimg_snprintf(command,command._width,"%s -quality %u \"%s\" \"%s\"", cimg::imagemagick_path(),quality, CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimg_instance "save_imagemagick_external(): Failed to save file '%s' with external command 'convert'.", cimg_instance, filename); if (file) cimg::fclose(file); std::remove(filename_tmp); return *this; } //! Save image as a Dicom file. /** \param filename Filename, as a C-string. \note This method uses \c medcon, an external executable binary provided by (X)Medcon. It must be installed for the method to succeed. **/ const CImg& save_medcon_external(const char *const filename) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_medcon_external(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } CImg command(1024), filename_tmp(256), body(256); std::FILE *file; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); save_analyze(filename_tmp); cimg_snprintf(command,command._width,"%s -w -c dicom -o \"%s\" -f \"%s\"", cimg::medcon_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); std::remove(filename_tmp); cimg::split_filename(filename_tmp,body); cimg_snprintf(filename_tmp,filename_tmp._width,"%s.img",body._data); std::remove(filename_tmp); file = std::fopen(filename,"rb"); if (!file) { cimg_snprintf(command,command._width,"m000-%s",filename); file = std::fopen(command,"rb"); if (!file) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "save_medcon_external(): Failed to save file '%s' with external command 'medcon'.", cimg_instance, filename); } } cimg::fclose(file); std::rename(command,filename); return *this; } // Save image for non natively supported formats. /** \param filename Filename, as a C-string. \param quality Image quality (expressed in percent), when the file format supports it. \note - The filename extension tells about the desired file format. - This method tries to save the instance image as a file, using external tools from ImageMagick or GraphicsMagick. At least one of these tool must be installed for the method to succeed. - It is recommended to use the generic method save(const char*, int) const instead, as it can handle some file formats natively. **/ const CImg& save_other(const char *const filename, const unsigned int quality=100) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_other(): Specified filename is (null).", cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } if (_depth>1) cimg::warn(_cimg_instance "save_other(): File '%s', saving a volumetric image with an external call to " "ImageMagick or GraphicsMagick only writes the first image slice.", cimg_instance,filename); const unsigned int omode = cimg::exception_mode(); bool is_saved = true; cimg::exception_mode(0); try { save_magick(filename); } catch (CImgException&) { try { save_imagemagick_external(filename,quality); } catch (CImgException&) { try { save_graphicsmagick_external(filename,quality); } catch (CImgException&) { is_saved = false; } } } cimg::exception_mode(omode); if (!is_saved) throw CImgIOException(_cimg_instance "save_other(): Failed to save file '%s'. Format is not natively supported, " "and no external commands succeeded.", cimg_instance, filename); return *this; } //! Serialize a CImg instance into a raw CImg buffer. /** \param is_compressed tells if zlib compression must be used for serialization (this requires 'cimg_use_zlib' been enabled). **/ CImg get_serialize(const bool is_compressed=false) const { return CImgList(*this,true).get_serialize(is_compressed); } // [internal] Return a 40x38 color logo of a 'danger' item. static CImg _logo40x38() { CImg res(40,38,1,3); const unsigned char *ptrs = cimg::logo40x38; T *ptr1 = res.data(0,0,0,0), *ptr2 = res.data(0,0,0,1), *ptr3 = res.data(0,0,0,2); for (ulongT off = 0; off<(ulongT)res._width*res._height;) { const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++); for (unsigned int l = 0; l structure # # # #------------------------------------------ */ //! Represent a list of images CImg. template struct CImgList { unsigned int _width, _allocated_width; CImg *_data; //! Simple iterator type, to loop through each image of a list. /** \note - The \c CImgList::iterator type is defined as a CImg*. - You may use it like this: \code CImgList<> list; // Assuming this image list is not empty. for (CImgList<>::iterator it = list.begin(); it* iterator; //! Simple const iterator type, to loop through each image of a \c const list instance. /** \note - The \c CImgList::const_iterator type is defined to be a const CImg*. - Similar to CImgList::iterator, but for constant list instances. **/ typedef const CImg* const_iterator; //! Pixel value type. /** Refer to the pixels value type of the images in the list. \note - The \c CImgList::value_type type of a \c CImgList is defined to be a \c T. It is then similar to CImg::value_type. - \c CImgList::value_type is actually not used in %CImg methods. It has been mainly defined for compatibility with STL naming conventions. **/ typedef T value_type; // Define common types related to template type T. typedef typename cimg::superset::type Tbool; typedef typename cimg::superset::type Tuchar; typedef typename cimg::superset::type Tchar; typedef typename cimg::superset::type Tushort; typedef typename cimg::superset::type Tshort; typedef typename cimg::superset::type Tuint; typedef typename cimg::superset::type Tint; typedef typename cimg::superset::type Tulong; typedef typename cimg::superset::type Tlong; typedef typename cimg::superset::type Tfloat; typedef typename cimg::superset::type Tdouble; typedef typename cimg::last::type boolT; typedef typename cimg::last::type ucharT; typedef typename cimg::last::type charT; typedef typename cimg::last::type ushortT; typedef typename cimg::last::type shortT; typedef typename cimg::last::type uintT; typedef typename cimg::last::type intT; typedef typename cimg::last::type ulongT; typedef typename cimg::last::type longT; typedef typename cimg::last::type uint64T; typedef typename cimg::last::type int64T; typedef typename cimg::last::type floatT; typedef typename cimg::last::type doubleT; //@} //--------------------------- // //! \name Plugins //@{ //--------------------------- #ifdef cimglist_plugin #include cimglist_plugin #endif #ifdef cimglist_plugin1 #include cimglist_plugin1 #endif #ifdef cimglist_plugin2 #include cimglist_plugin2 #endif #ifdef cimglist_plugin3 #include cimglist_plugin3 #endif #ifdef cimglist_plugin4 #include cimglist_plugin4 #endif #ifdef cimglist_plugin5 #include cimglist_plugin5 #endif #ifdef cimglist_plugin6 #include cimglist_plugin6 #endif #ifdef cimglist_plugin7 #include cimglist_plugin7 #endif #ifdef cimglist_plugin8 #include cimglist_plugin8 #endif //@} //-------------------------------------------------------- // //! \name Constructors / Destructor / Instance Management //@{ //-------------------------------------------------------- //! Destructor. /** Destroy current list instance. \note - Any allocated buffer is deallocated. - Destroying an empty list does nothing actually. **/ ~CImgList() { delete[] _data; } //! Default constructor. /** Construct a new empty list instance. \note - An empty list has no pixel data and its dimension width() is set to \c 0, as well as its image buffer pointer data(). - An empty list may be reassigned afterwards, with the family of the assign() methods. In all cases, the type of pixels stays \c T. **/ CImgList(): _width(0),_allocated_width(0),_data(0) {} //! Construct list containing empty images. /** \param n Number of empty images. \note Useful when you know by advance the number of images you want to manage, as it will allocate the right amount of memory for the list, without needs for reallocation (that may occur when starting from an empty list and inserting several images in it). **/ explicit CImgList(const unsigned int n):_width(n) { if (n) _data = new CImg[_allocated_width = cimg::max(16UL,cimg::nearest_pow2(n))]; else { _allocated_width = 0; _data = 0; } } //! Construct list containing images of specified size. /** \param n Number of images. \param width Width of images. \param height Height of images. \param depth Depth of images. \param spectrum Number of channels of images. \note Pixel values are not initialized and may probably contain garbage. **/ CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int spectrum=1): _width(0),_allocated_width(0),_data(0) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum); } //! Construct list containing images of specified size, and initialize pixel values. /** \param n Number of images. \param width Width of images. \param height Height of images. \param depth Depth of images. \param spectrum Number of channels of images. \param val Initialization value for images pixels. **/ CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const T& val): _width(0),_allocated_width(0),_data(0) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum,val); } //! Construct list containing images of specified size, and initialize pixel values from a sequence of integers. /** \param n Number of images. \param width Width of images. \param height Height of images. \param depth Depth of images. \param spectrum Number of channels of images. \param val0 First value of the initializing integers sequence. \param val1 Second value of the initializing integers sequence. \warning You must specify at least width*height*depth*spectrum values in your argument list, or you will probably segfault. **/ CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...): _width(0),_allocated_width(0),_data(0) { #define _CImgList_stdarg(t) { \ assign(n,width,height,depth,spectrum); \ const ulongT siz = (ulongT)width*height*depth*spectrum, nsiz = siz*n; \ T *ptrd = _data->_data; \ va_list ap; \ va_start(ap,val1); \ for (ulongT l = 0, s = 0, i = 0; iwidth*height*depth*spectrum values in your argument list, or you will probably segfault. **/ CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...): _width(0),_allocated_width(0),_data(0) { _CImgList_stdarg(double); } //! Construct list containing copies of an input image. /** \param n Number of images. \param img Input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of \c img. **/ template CImgList(const unsigned int n, const CImg& img, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(n); cimglist_apply(*this,assign)(img,is_shared); } //! Construct list from one image. /** \param img Input image to copy in the constructed list. \param is_shared Tells if the element of the list is a shared or non-shared copy of \c img. **/ template explicit CImgList(const CImg& img, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(1); _data[0].assign(img,is_shared); } //! Construct list from two images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(2); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); } //! Construct list from three images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(3); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); } //! Construct list from four images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param img4 Fourth input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(4); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); } //! Construct list from five images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param img4 Fourth input image to copy in the constructed list. \param img5 Fifth input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(5); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); } //! Construct list from six images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param img4 Fourth input image to copy in the constructed list. \param img5 Fifth input image to copy in the constructed list. \param img6 Sixth input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(6); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); } //! Construct list from seven images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param img4 Fourth input image to copy in the constructed list. \param img5 Fifth input image to copy in the constructed list. \param img6 Sixth input image to copy in the constructed list. \param img7 Seventh input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(7); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); _data[6].assign(img7,is_shared); } //! Construct list from eight images. /** \param img1 First input image to copy in the constructed list. \param img2 Second input image to copy in the constructed list. \param img3 Third input image to copy in the constructed list. \param img4 Fourth input image to copy in the constructed list. \param img5 Fifth input image to copy in the constructed list. \param img6 Sixth input image to copy in the constructed list. \param img7 Seventh input image to copy in the constructed list. \param img8 Eighth input image to copy in the constructed list. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const bool is_shared=false): _width(0),_allocated_width(0),_data(0) { assign(8); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared); } //! Construct list copy. /** \param list Input list to copy. \note The shared state of each element of the constructed list is kept the same as in \c list. **/ template CImgList(const CImgList& list):_width(0),_allocated_width(0),_data(0) { assign(list._width); cimglist_for(*this,l) _data[l].assign(list[l],false); } //! Construct list copy \specialization. CImgList(const CImgList& list):_width(0),_allocated_width(0),_data(0) { assign(list._width); cimglist_for(*this,l) _data[l].assign(list[l],list[l]._is_shared); } //! Construct list copy, and force the shared state of the list elements. /** \param list Input list to copy. \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. **/ template CImgList(const CImgList& list, const bool is_shared):_width(0),_allocated_width(0),_data(0) { assign(list._width); cimglist_for(*this,l) _data[l].assign(list[l],is_shared); } //! Construct list by reading the content of a file. /** \param filename Filename, as a C-string. **/ explicit CImgList(const char *const filename):_width(0),_allocated_width(0),_data(0) { assign(filename); } //! Construct list from the content of a display window. /** \param disp Display window to get content from. \note Constructed list contains a single image only. **/ explicit CImgList(const CImgDisplay& disp):_width(0),_allocated_width(0),_data(0) { assign(disp); } //! Return a list with elements being shared copies of images in the list instance. /** \note list2 = list1.get_shared() is equivalent to list2.assign(list1,true). **/ CImgList get_shared() { CImgList res(_width); cimglist_for(*this,l) res[l].assign(_data[l],true); return res; } //! Return a list with elements being shared copies of images in the list instance \const. const CImgList get_shared() const { CImgList res(_width); cimglist_for(*this,l) res[l].assign(_data[l],true); return res; } //! Destructor \inplace. /** \see CImgList(). **/ CImgList& assign() { delete[] _data; _width = _allocated_width = 0; _data = 0; return *this; } //! Destructor \inplace. /** Equivalent to assign(). \note Only here for compatibility with STL naming conventions. **/ CImgList& clear() { return assign(); } //! Construct list containing empty images \inplace. /** \see CImgList(unsigned int). **/ CImgList& assign(const unsigned int n) { if (!n) return assign(); if (_allocated_width(n<<2)) { delete[] _data; _data = new CImg[_allocated_width=cimg::max(16UL,cimg::nearest_pow2(n))]; } _width = n; return *this; } //! Construct list containing images of specified size \inplace. /** \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int). **/ CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int spectrum=1) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum); return *this; } //! Construct list containing images of specified size, and initialize pixel values \inplace. /** \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const T). **/ CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const T& val) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum,val); return *this; } //! Construct list with images of specified size, and initialize pixel values from a sequence of integers \inplace. /** \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const int, const int, ...). **/ CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...) { _CImgList_stdarg(int); return *this; } //! Construct list with images of specified size, and initialize pixel values from a sequence of doubles \inplace. /** \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const double, const double, ...). **/ CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...) { _CImgList_stdarg(double); return *this; } //! Construct list containing copies of an input image \inplace. /** \see CImgList(unsigned int, const CImg&, bool). **/ template CImgList& assign(const unsigned int n, const CImg& img, const bool is_shared=false) { assign(n); cimglist_apply(*this,assign)(img,is_shared); return *this; } //! Construct list from one image \inplace. /** \see CImgList(const CImg&, bool). **/ template CImgList& assign(const CImg& img, const bool is_shared=false) { assign(1); _data[0].assign(img,is_shared); return *this; } //! Construct list from two images \inplace. /** \see CImgList(const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const bool is_shared=false) { assign(2); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); return *this; } //! Construct list from three images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const bool is_shared=false) { assign(3); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); return *this; } //! Construct list from four images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const bool is_shared=false) { assign(4); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); return *this; } //! Construct list from five images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const bool is_shared=false) { assign(5); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); return *this; } //! Construct list from six images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const bool is_shared=false) { assign(6); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); return *this; } //! Construct list from seven images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const bool is_shared=false) { assign(7); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); _data[6].assign(img7,is_shared); return *this; } //! Construct list from eight images \inplace. /** \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, bool). **/ template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const bool is_shared=false) { assign(8); _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared); return *this; } //! Construct list as a copy of an existing list and force the shared state of the list elements \inplace. /** \see CImgList(const CImgList&, bool is_shared). **/ template CImgList& assign(const CImgList& list, const bool is_shared=false) { cimg::unused(is_shared); assign(list._width); cimglist_for(*this,l) _data[l].assign(list[l],false); return *this; } //! Construct list as a copy of an existing list and force shared state of elements \inplace \specialization. CImgList& assign(const CImgList& list, const bool is_shared=false) { if (this==&list) return *this; CImgList res(list._width); cimglist_for(res,l) res[l].assign(list[l],is_shared); return res.move_to(*this); } //! Construct list by reading the content of a file \inplace. /** \see CImgList(const char *const). **/ CImgList& assign(const char *const filename) { return load(filename); } //! Construct list from the content of a display window \inplace. /** \see CImgList(const CImgDisplay&). **/ CImgList& assign(const CImgDisplay &disp) { return assign(CImg(disp)); } //! Transfer the content of the list instance to another list. /** \param list Destination list. \note When returning, the current list instance is empty and the initial content of \c list is destroyed. **/ template CImgList& move_to(CImgList& list) { list.assign(_width); bool is_one_shared_element = false; cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared; if (is_one_shared_element) cimglist_for(*this,l) list[l].assign(_data[l]); else cimglist_for(*this,l) _data[l].move_to(list[l]); assign(); return list; } //! Transfer the content of the list instance at a specified position in another list. /** \param list Destination list. \param pos Index of the insertion in the list. \note When returning, the list instance is empty and the initial content of \c list is preserved (only images indexes may be modified). **/ template CImgList& move_to(CImgList& list, const unsigned int pos) { if (is_empty()) return list; const unsigned int npos = pos>list._width?list._width:pos; list.insert(_width,npos); bool is_one_shared_element = false; cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared; if (is_one_shared_element) cimglist_for(*this,l) list[npos + l].assign(_data[l]); else cimglist_for(*this,l) _data[l].move_to(list[npos + l]); assign(); return list; } //! Swap all fields between two list instances. /** \param list List to swap fields with. \note Can be used to exchange the content of two lists in a fast way. **/ CImgList& swap(CImgList& list) { cimg::swap(_width,list._width,_allocated_width,list._allocated_width); cimg::swap(_data,list._data); return list; } //! Return a reference to an empty list. /** \note Can be used to define default values in a function taking a CImgList as an argument. \code void f(const CImgList& list=CImgList::empty()); \endcode **/ static CImgList& empty() { static CImgList _empty; return _empty.assign(); } //! Return a reference to an empty list \const. static const CImgList& const_empty() { static const CImgList _empty; return _empty; } //@} //------------------------------------------ // //! \name Overloaded Operators //@{ //------------------------------------------ //! Return a reference to one image element of the list. /** \param pos Indice of the image element. **/ CImg& operator()(const unsigned int pos) { #if cimg_verbosity>=3 if (pos>=_width) { cimg::warn(_cimglist_instance "operator(): Invalid image request, at position [%u].", cimglist_instance, pos); return *_data; } #endif return _data[pos]; } //! Return a reference to one image of the list. /** \param pos Indice of the image element. **/ const CImg& operator()(const unsigned int pos) const { return const_cast*>(this)->operator()(pos); } //! Return a reference to one pixel value of one image of the list. /** \param pos Indice of the image element. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list(n,x,y,z,c) is equivalent to list[n](x,y,z,c). **/ T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { return (*this)[pos](x,y,z,c); } //! Return a reference to one pixel value of one image of the list \const. const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { return (*this)[pos](x,y,z,c); } //! Return pointer to the first image of the list. /** \note Images in a list are stored as a buffer of \c CImg. **/ operator CImg*() { return _data; } //! Return pointer to the first image of the list \const. operator const CImg*() const { return _data; } //! Construct list from one image \inplace. /** \param img Input image to copy in the constructed list. \note list = img; is equivalent to list.assign(img);. **/ template CImgList& operator=(const CImg& img) { return assign(img); } //! Construct list from another list. /** \param list Input list to copy. \note list1 = list2 is equivalent to list1.assign(list2);. **/ template CImgList& operator=(const CImgList& list) { return assign(list); } //! Construct list from another list \specialization. CImgList& operator=(const CImgList& list) { return assign(list); } //! Construct list by reading the content of a file \inplace. /** \see CImgList(const char *const). **/ CImgList& operator=(const char *const filename) { return assign(filename); } //! Construct list from the content of a display window \inplace. /** \see CImgList(const CImgDisplay&). **/ CImgList& operator=(const CImgDisplay& disp) { return assign(disp); } //! Return a non-shared copy of a list. /** \note +list is equivalent to CImgList(list,false). It forces the copy to have non-shared elements. **/ CImgList operator+() const { return CImgList(*this,false); } //! Return a copy of the list instance, where image \c img has been inserted at the end. /** \param img Image inserted at the end of the instance copy. \note Define a convenient way to create temporary lists of images, as in the following code: \code (img1,img2,img3,img4).display("My four images"); \endcode **/ template CImgList& operator,(const CImg& img) { return insert(img); } //! Return a copy of the list instance, where image \c img has been inserted at the end \const. template CImgList operator,(const CImg& img) const { return (+*this).insert(img); } //! Return a copy of the list instance, where all elements of input list \c list have been inserted at the end. /** \param list List inserted at the end of the instance copy. **/ template CImgList& operator,(const CImgList& list) { return insert(list); } //! Return a copy of the list instance, where all elements of input \c list have been inserted at the end \const. template CImgList& operator,(const CImgList& list) const { return (+*this).insert(list); } //! Return image corresponding to the appending of all images of the instance list along specified axis. /** \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \note list>'x' is equivalent to list.get_append('x'). **/ CImg operator>(const char axis) const { return get_append(axis,0); } //! Return list corresponding to the splitting of all images of the instance list along specified axis. /** \param axis Axis used for image splitting. \note list<'x' is equivalent to list.get_split('x'). **/ CImgList operator<(const char axis) const { return get_split(axis); } //@} //------------------------------------- // //! \name Instance Characteristics //@{ //------------------------------------- //! Return the type of image pixel values as a C string. /** Return a \c char* string containing the usual type name of the image pixel values (i.e. a stringified version of the template parameter \c T). \note - The returned string may contain spaces (as in \c "unsigned char"). - If the pixel type \c T does not correspond to a registered type, the string "unknown" is returned. **/ static const char* pixel_type() { return cimg::type::string(); } //! Return the size of the list, i.e. the number of images contained in it. /** \note Similar to size() but returns result as a (signed) integer. **/ int width() const { return (int)_width; } //! Return the size of the list, i.e. the number of images contained in it. /** \note Similar to width() but returns result as an unsigned integer. **/ unsigned int size() const { return _width; } //! Return pointer to the first image of the list. /** \note Images in a list are stored as a buffer of \c CImg. **/ CImg *data() { return _data; } //! Return pointer to the first image of the list \const. const CImg *data() const { return _data; } //! Return pointer to the pos-th image of the list. /** \param pos Indice of the image element to access. \note list.data(n); is equivalent to list.data + n;. **/ #if cimg_verbosity>=3 CImg *data(const unsigned int pos) { if (pos>=size()) cimg::warn(_cimglist_instance "data(): Invalid pointer request, at position [%u].", cimglist_instance, pos); return _data + pos; } const CImg *data(const unsigned int l) const { return const_cast*>(this)->data(l); } #else CImg *data(const unsigned int l) { return _data + l; } //! Return pointer to the pos-th image of the list \const. const CImg *data(const unsigned int l) const { return _data + l; } #endif //! Return iterator to the first image of the list. /** **/ iterator begin() { return _data; } //! Return iterator to the first image of the list \const. const_iterator begin() const { return _data; } //! Return iterator to one position after the last image of the list. /** **/ iterator end() { return _data + _width; } //! Return iterator to one position after the last image of the list \const. const_iterator end() const { return _data + _width; } //! Return reference to the first image of the list. /** **/ CImg& front() { return *_data; } //! Return reference to the first image of the list \const. const CImg& front() const { return *_data; } //! Return a reference to the last image of the list. /** **/ const CImg& back() const { return *(_data + _width - 1); } //! Return a reference to the last image of the list \const. CImg& back() { return *(_data + _width - 1); } //! Return pos-th image of the list. /** \param pos Indice of the image element to access. **/ CImg& at(const int pos) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "at(): Empty instance.", cimglist_instance); return _data[pos<0?0:pos>=(int)_width?(int)_width - 1:pos]; } //! Access to pixel value with Dirichlet boundary conditions. /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZC(p,x,y,z,c); is equivalent to list[p].atXYZC(x,y,z,c);. **/ T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXYZC(x,y,z,c,out_value); } //! Access to pixel value with Dirichlet boundary conditions \const. T atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXYZC(x,y,z,c,out_value); } //! Access to pixel value with Neumann boundary conditions. /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list.atNXYZC(p,x,y,z,c); is equivalent to list[p].atXYZC(x,y,z,c);. **/ T& atNXYZC(const int pos, const int x, const int y, const int z, const int c) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXYZC(): Empty instance.", cimglist_instance); return _atNXYZC(pos,x,y,z,c); } //! Access to pixel value with Neumann boundary conditions \const. T atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXYZC(): Empty instance.", cimglist_instance); return _atNXYZC(pos,x,y,z,c); } T& _atNXYZC(const int pos, const int x, const int y, const int z, const int c) { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c); } T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c); } //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y,\c z). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXYZ(x,y,z,c,out_value); } //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y,\c z) \const. T atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXYZ(x,y,z,c,out_value); } //! Access to pixel value with Neumann boundary conditions for the 4 first coordinates (\c pos, \c x,\c y,\c z). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXYZ(): Empty instance.", cimglist_instance); return _atNXYZ(pos,x,y,z,c); } //! Access to pixel value with Neumann boundary conditions for the 4 first coordinates (\c pos, \c x,\c y,\c z) \const. T atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXYZ(): Empty instance.", cimglist_instance); return _atNXYZ(pos,x,y,z,c); } T& _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c); } T _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atXY(x,y,z,c,out_value); } //! Access to pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y) \const. T atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXY(x,y,z,c,out_value); } //! Access to pixel value with Neumann boundary conditions for the 3 first coordinates (\c pos, \c x,\c y). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXY(): Empty instance.", cimglist_instance); return _atNXY(pos,x,y,z,c); } //! Access to pixel value with Neumann boundary conditions for the 3 first coordinates (\c pos, \c x,\c y) \const. T atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNXY(): Empty instance.", cimglist_instance); return _atNXY(pos,x,y,z,c); } T& _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c); } T _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\c pos,\c x). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):_data[pos].atX(x,y,z,c,out_value); } //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\c pos,\c x) \const. T atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atX(x,y,z,c,out_value); } //! Access to pixel value with Neumann boundary conditions for the 2 first coordinates (\c pos, \c x). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNX(): Empty instance.", cimglist_instance); return _atNX(pos,x,y,z,c); } //! Access to pixel value with Neumann boundary conditions for the 2 first coordinates (\c pos, \c x) \const. T atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atNX(): Empty instance.", cimglist_instance); return _atNX(pos,x,y,z,c); } T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c); } T _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the first coordinate (\c pos). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):(*this)(pos,x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the first coordinate (\c pos) \const. T atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { return (pos<0 || pos>=(int)_width)?out_value:(*this)(pos,x,y,z,c); } //! Return pixel value with Neumann boundary conditions for the first coordinate (\c pos). /** \param pos Indice of the image element to access. \param x X-coordinate of the pixel value. \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atN(): Empty instance.", cimglist_instance); return _atN(pos,x,y,z,c); } //! Return pixel value with Neumann boundary conditions for the first coordinate (\c pos) \const. T atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "atN(): Empty instance.", cimglist_instance); return _atN(pos,x,y,z,c); } T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c); } T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c); } //! Return a C-string containing the values of all images in the instance list. /** \param separator Character separator set between consecutive pixel values. \param max_size Maximum size of the returned string. \note The result is returne as a CImg image whose pixel buffer contains the desired C-string. **/ CImg value_string(const char separator=',', const unsigned int max_size=0) const { if (is_empty()) return CImg(1,1,1,1,0); CImgList items; for (unsigned int l = 0; l<_width - 1; ++l) { CImg item = _data[l].value_string(separator,0); item.back() = separator; item.move_to(items); } _data[_width - 1].value_string(separator,0).move_to(items); CImg res; (items>'x').move_to(res); if (max_size) { res.crop(0,max_size); res(max_size) = 0; } return res; } //@} //------------------------------------- // //! \name Instance Checking //@{ //------------------------------------- //! Return \c true if list is empty. /** **/ bool is_empty() const { return (!_data || !_width); } //! Test if number of image elements is equal to specified value. /** \param size_n Number of image elements to test. **/ bool is_sameN(const unsigned int size_n) const { return _width==size_n; } //! Test if number of image elements is equal between two images lists. /** \param list Input list to compare with. **/ template bool is_sameN(const CImgList& list) const { return is_sameN(list._width); } // Define useful functions to check list dimensions. // (cannot be documented because macro-generated). #define _cimglist_def_is_same1(axis) \ bool is_same##axis(const unsigned int val) const { \ bool res = true; \ for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(val); return res; \ } \ bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \ return is_sameN(n) && is_same##axis(val); \ } \ #define _cimglist_def_is_same2(axis1,axis2) \ bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \ bool res = true; \ for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2(val1,val2); return res; \ } \ bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \ return is_sameN(n) && is_same##axis1##axis2(val1,val2); \ } \ #define _cimglist_def_is_same3(axis1,axis2,axis3) \ bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, \ const unsigned int val3) const { \ bool res = true; \ for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2##axis3(val1,val2,val3); \ return res; \ } \ bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, \ const unsigned int val2, const unsigned int val3) const { \ return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \ } \ #define _cimglist_def_is_same(axis) \ template bool is_same##axis(const CImg& img) const { \ bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(img); return res; \ } \ template bool is_same##axis(const CImgList& list) const { \ const unsigned int lmin = cimg::min(_width,list._width); \ bool res = true; for (unsigned int l = 0; l bool is_sameN##axis(const unsigned int n, const CImg& img) const { \ return (is_sameN(n) && is_same##axis(img)); \ } \ template bool is_sameN##axis(const CImgList& list) const { \ return (is_sameN(list) && is_same##axis(list)); \ } _cimglist_def_is_same(XY) _cimglist_def_is_same(XZ) _cimglist_def_is_same(XC) _cimglist_def_is_same(YZ) _cimglist_def_is_same(YC) _cimglist_def_is_same(XYZ) _cimglist_def_is_same(XYC) _cimglist_def_is_same(YZC) _cimglist_def_is_same(XYZC) _cimglist_def_is_same1(X) _cimglist_def_is_same1(Y) _cimglist_def_is_same1(Z) _cimglist_def_is_same1(C) _cimglist_def_is_same2(X,Y) _cimglist_def_is_same2(X,Z) _cimglist_def_is_same2(X,C) _cimglist_def_is_same2(Y,Z) _cimglist_def_is_same2(Y,C) _cimglist_def_is_same2(Z,C) _cimglist_def_is_same3(X,Y,Z) _cimglist_def_is_same3(X,Y,C) _cimglist_def_is_same3(X,Z,C) _cimglist_def_is_same3(Y,Z,C) //! Test if dimensions of each image of the list match specified arguments. /** \param dx Checked image width. \param dy Checked image height. \param dz Checked image depth. \param dc Checked image spectrum. **/ bool is_sameXYZC(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) const { bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_sameXYZC(dx,dy,dz,dc); return res; } //! Test if list dimensions match specified arguments. /** \param n Number of images in the list. \param dx Checked image width. \param dy Checked image height. \param dz Checked image depth. \param dc Checked image spectrum. **/ bool is_sameNXYZC(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) const { return is_sameN(n) && is_sameXYZC(dx,dy,dz,dc); } //! Test if list contains one particular pixel location. /** \param n Index of the image whom checked pixel value belong to. \param x X-coordinate of the checked pixel value. \param y Y-coordinate of the checked pixel value. \param z Z-coordinate of the checked pixel value. \param c C-coordinate of the checked pixel value. **/ bool containsNXYZC(const int n, const int x=0, const int y=0, const int z=0, const int c=0) const { if (is_empty()) return false; return n>=0 && n<(int)_width && x>=0 && x<_data[n].width() && y>=0 && y<_data[n].height() && z>=0 && z<_data[n].depth() && c>=0 && c<_data[n].spectrum(); } //! Test if list contains image with specified indice. /** \param n Index of the checked image. **/ bool containsN(const int n) const { if (is_empty()) return false; return n>=0 && n<(int)_width; } //! Test if one image of the list contains the specified referenced value. /** \param pixel Reference to pixel value to test. \param[out] n Index of image containing the pixel value, if test succeeds. \param[out] x X-coordinate of the pixel value, if test succeeds. \param[out] y Y-coordinate of the pixel value, if test succeeds. \param[out] z Z-coordinate of the pixel value, if test succeeds. \param[out] c C-coordinate of the pixel value, if test succeeds. \note If true, set coordinates (n,x,y,z,c). **/ template bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& c) const { if (is_empty()) return false; cimglist_for(*this,l) if (_data[l].contains(pixel,x,y,z,c)) { n = (t)l; return true; } return false; } //! Test if one of the image list contains the specified referenced value. /** \param pixel Reference to pixel value to test. \param[out] n Index of image containing the pixel value, if test succeeds. \param[out] x X-coordinate of the pixel value, if test succeeds. \param[out] y Y-coordinate of the pixel value, if test succeeds. \param[out] z Z-coordinate of the pixel value, if test succeeds. \note If true, set coordinates (n,x,y,z). **/ template bool contains(const T& pixel, t& n, t& x, t&y, t& z) const { t c; return contains(pixel,n,x,y,z,c); } //! Test if one of the image list contains the specified referenced value. /** \param pixel Reference to pixel value to test. \param[out] n Index of image containing the pixel value, if test succeeds. \param[out] x X-coordinate of the pixel value, if test succeeds. \param[out] y Y-coordinate of the pixel value, if test succeeds. \note If true, set coordinates (n,x,y). **/ template bool contains(const T& pixel, t& n, t& x, t&y) const { t z, c; return contains(pixel,n,x,y,z,c); } //! Test if one of the image list contains the specified referenced value. /** \param pixel Reference to pixel value to test. \param[out] n Index of image containing the pixel value, if test succeeds. \param[out] x X-coordinate of the pixel value, if test succeeds. \note If true, set coordinates (n,x). **/ template bool contains(const T& pixel, t& n, t& x) const { t y, z, c; return contains(pixel,n,x,y,z,c); } //! Test if one of the image list contains the specified referenced value. /** \param pixel Reference to pixel value to test. \param[out] n Index of image containing the pixel value, if test succeeds. \note If true, set coordinates (n). **/ template bool contains(const T& pixel, t& n) const { t x, y, z, c; return contains(pixel,n,x,y,z,c); } //! Test if one of the image list contains the specified referenced value. /** \param pixel Reference to pixel value to test. **/ bool contains(const T& pixel) const { unsigned int n, x, y, z, c; return contains(pixel,n,x,y,z,c); } //! Test if the list contains the image 'img'. /** \param img Reference to image to test. \param[out] n Index of image in the list, if test succeeds. \note If true, returns the position (n) of the image in the list. **/ template bool contains(const CImg& img, t& n) const { if (is_empty()) return false; const CImg *const ptr = &img; cimglist_for(*this,i) if (_data + i==ptr) { n = (t)i; return true; } return false; } //! Test if the list contains the image img. /** \param img Reference to image to test. **/ bool contains(const CImg& img) const { unsigned int n; return contains(img,n); } //@} //------------------------------------- // //! \name Mathematical Functions //@{ //------------------------------------- //! Return a reference to the minimum pixel value of the instance list. /** **/ T& min() { if (is_empty()) throw CImgInstanceException(_cimglist_instance "min(): Empty instance.", cimglist_instance); T *ptr_min = _data->_data; T min_value = *ptr_min; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) if (*ptrs_data; T min_value = *ptr_min; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) if (*ptrs_data; T max_value = *ptr_max; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); } return *ptr_max; } //! Return a reference to the maximum pixel value of the instance list \const. const T& max() const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "max(): Empty instance.", cimglist_instance); const T *ptr_max = _data->_data; T max_value = *ptr_max; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); } return *ptr_max; } //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well. /** \param[out] max_val Value of the maximum value found. **/ template T& min_max(t& max_val) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "min_max(): Empty instance.", cimglist_instance); T *ptr_min = _data->_data; T min_value = *ptr_min, max_value = min_value; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) { const T val = *ptrs; if (valmax_value) max_value = val; } } max_val = (t)max_value; return *ptr_min; } //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well \const. /** \param[out] max_val Value of the maximum value found. **/ template const T& min_max(t& max_val) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "min_max(): Empty instance.", cimglist_instance); const T *ptr_min = _data->_data; T min_value = *ptr_min, max_value = min_value; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) { const T val = *ptrs; if (valmax_value) max_value = val; } } max_val = (t)max_value; return *ptr_min; } //! Return a reference to the minimum pixel value of the instance list and return the minimum value as well. /** \param[out] min_val Value of the minimum value found. **/ template T& max_min(t& min_val) { if (is_empty()) throw CImgInstanceException(_cimglist_instance "max_min(): Empty instance.", cimglist_instance); T *ptr_max = _data->_data; T min_value = *ptr_max, max_value = min_value; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) { const T val = *ptrs; if (val>max_value) { max_value = val; ptr_max = ptrs; } if (val const T& max_min(t& min_val) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "max_min(): Empty instance.", cimglist_instance); const T *ptr_max = _data->_data; T min_value = *ptr_max, max_value = min_value; cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_for(img,ptrs,T) { const T val = *ptrs; if (val>max_value) { max_value = val; ptr_max = ptrs; } if (val CImgList& insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) { const unsigned int npos = pos==~0U?_width:pos; if (npos>_width) throw CImgArgumentException(_cimglist_instance "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) " "at position %u.", cimglist_instance, img._width,img._height,img._depth,img._spectrum,img._data,npos); if (is_shared) throw CImgArgumentException(_cimglist_instance "insert(): Invalid insertion request of specified shared image " "CImg<%s>(%u,%u,%u,%u,%p) at position %u (pixel types are different).", cimglist_instance, img.pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data,npos); CImg *const new_data = (++_width>_allocated_width)?new CImg[_allocated_width?(_allocated_width<<=1): (_allocated_width=16)]:0; if (!_data) { // Insert new element into empty list. _data = new_data; *_data = img; } else { if (new_data) { // Insert with re-allocation. if (npos) std::memcpy(new_data,_data,sizeof(CImg)*npos); if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); std::memset(_data,0,sizeof(CImg)*(_width - 1)); delete[] _data; _data = new_data; } else if (npos!=_width - 1) // Insert without re-allocation. std::memmove(_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; _data[npos]._data = 0; _data[npos] = img; } return *this; } //! Insert a copy of the image \c img into the current image list, at position \c pos \specialization. CImgList& insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) { const unsigned int npos = pos==~0U?_width:pos; if (npos>_width) throw CImgArgumentException(_cimglist_instance "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) " "at position %u.", cimglist_instance, img._width,img._height,img._depth,img._spectrum,img._data,npos); CImg *const new_data = (++_width>_allocated_width)?new CImg[_allocated_width?(_allocated_width<<=1): (_allocated_width=16)]:0; if (!_data) { // Insert new element into empty list. _data = new_data; if (is_shared && img) { _data->_width = img._width; _data->_height = img._height; _data->_depth = img._depth; _data->_spectrum = img._spectrum; _data->_is_shared = true; _data->_data = img._data; } else *_data = img; } else { if (new_data) { // Insert with re-allocation. if (npos) std::memcpy(new_data,_data,sizeof(CImg)*npos); if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); if (is_shared && img) { new_data[npos]._width = img._width; new_data[npos]._height = img._height; new_data[npos]._depth = img._depth; new_data[npos]._spectrum = img._spectrum; new_data[npos]._is_shared = true; new_data[npos]._data = img._data; } else { new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0; new_data[npos]._data = 0; new_data[npos] = img; } std::memset(_data,0,sizeof(CImg)*(_width - 1)); delete[] _data; _data = new_data; } else { // Insert without re-allocation. if (npos!=_width - 1) std::memmove(_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); if (is_shared && img) { _data[npos]._width = img._width; _data[npos]._height = img._height; _data[npos]._depth = img._depth; _data[npos]._spectrum = img._spectrum; _data[npos]._is_shared = true; _data[npos]._data = img._data; } else { _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; _data[npos]._data = 0; _data[npos] = img; } } } return *this; } //! Insert a copy of the image \c img into the current image list, at position \c pos \newinstance. template CImgList get_insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) const { return (+*this).insert(img,pos,is_shared); } //! Insert n empty images img into the current image list, at position \p pos. /** \param n Number of empty images to insert. \param pos Index of the insertion. **/ CImgList& insert(const unsigned int n, const unsigned int pos=~0U) { CImg empty; if (!n) return *this; const unsigned int npos = pos==~0U?_width:pos; for (unsigned int i = 0; i get_insert(const unsigned int n, const unsigned int pos=~0U) const { return (+*this).insert(n,pos); } //! Insert \c n copies of the image \c img into the current image list, at position \c pos. /** \param n Number of image copies to insert. \param img Image to insert by copy. \param pos Index of the insertion. \param is_shared Tells if inserted images are shared copies of \c img or not. **/ template CImgList& insert(const unsigned int n, const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) { if (!n) return *this; const unsigned int npos = pos==~0U?_width:pos; insert(img,npos,is_shared); for (unsigned int i = 1; i CImgList get_insert(const unsigned int n, const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) const { return (+*this).insert(n,img,pos,is_shared); } //! Insert a copy of the image list \c list into the current image list, starting from position \c pos. /** \param list Image list to insert. \param pos Index of the insertion. \param is_shared Tells if inserted images are shared copies of images of \c list or not. **/ template CImgList& insert(const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) { const unsigned int npos = pos==~0U?_width:pos; if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos + l,is_shared); else insert(CImgList(list),npos,is_shared); return *this; } //! Insert a copy of the image list \c list into the current image list, starting from position \c pos \newinstance. template CImgList get_insert(const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) const { return (+*this).insert(list,pos,is_shared); } //! Insert n copies of the list \c list at position \c pos of the current list. /** \param n Number of list copies to insert. \param list Image list to insert. \param pos Index of the insertion. \param is_shared Tells if inserted images are shared copies of images of \c list or not. **/ template CImgList& insert(const unsigned int n, const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) { if (!n) return *this; const unsigned int npos = pos==~0U?_width:pos; for (unsigned int i = 0; i CImgList get_insert(const unsigned int n, const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) const { return (+*this).insert(n,list,pos,is_shared); } //! Remove all images between from indexes. /** \param pos1 Starting index of the removal. \param pos2 Ending index of the removal. **/ CImgList& remove(const unsigned int pos1, const unsigned int pos2) { const unsigned int npos1 = pos1=_width) throw CImgArgumentException(_cimglist_instance "remove(): Invalid remove request at positions %u->%u.", cimglist_instance, npos1,tpos2); else { if (tpos2>=_width) throw CImgArgumentException(_cimglist_instance "remove(): Invalid remove request at positions %u->%u.", cimglist_instance, npos1,tpos2); for (unsigned int k = npos1; k<=npos2; ++k) _data[k].assign(); const unsigned int nb = 1 + npos2 - npos1; if (!(_width-=nb)) return assign(); if (_width>(_allocated_width>>2) || _allocated_width<=16) { // Removing items without reallocation. if (npos1!=_width) std::memmove(_data + npos1,_data + npos2 + 1,sizeof(CImg)*(_width - npos1)); std::memset(_data + _width,0,sizeof(CImg)*nb); } else { // Removing items with reallocation. _allocated_width>>=2; while (_allocated_width>16 && _width<(_allocated_width>>1)) _allocated_width>>=1; CImg *const new_data = new CImg[_allocated_width]; if (npos1) std::memcpy(new_data,_data,sizeof(CImg)*npos1); if (npos1!=_width) std::memcpy(new_data + npos1,_data + npos2 + 1,sizeof(CImg)*(_width - npos1)); if (_width!=_allocated_width) std::memset(new_data + _width,0,sizeof(CImg)*(_allocated_width - _width)); std::memset(_data,0,sizeof(CImg)*(_width + nb)); delete[] _data; _data = new_data; } } return *this; } //! Remove all images between from indexes \newinstance. CImgList get_remove(const unsigned int pos1, const unsigned int pos2) const { return (+*this).remove(pos1,pos2); } //! Remove image at index \c pos from the image list. /** \param pos Index of the image to remove. **/ CImgList& remove(const unsigned int pos) { return remove(pos,pos); } //! Remove image at index \c pos from the image list \newinstance. CImgList get_remove(const unsigned int pos) const { return (+*this).remove(pos); } //! Remove last image. /** **/ CImgList& remove() { return remove(_width - 1); } //! Remove last image \newinstance. CImgList get_remove() const { return (+*this).remove(); } //! Reverse list order. CImgList& reverse() { for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width - 1 - l]); return *this; } //! Reverse list order \newinstance. CImgList get_reverse() const { return (+*this).reverse(); } //! Return a sublist. /** \param pos0 Starting index of the sublist. \param pos1 Ending index of the sublist. **/ CImgList& images(const unsigned int pos0, const unsigned int pos1) { return get_images(pos0,pos1).move_to(*this); } //! Return a sublist \newinstance. CImgList get_images(const unsigned int pos0, const unsigned int pos1) const { if (pos0>pos1 || pos1>=_width) throw CImgArgumentException(_cimglist_instance "images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); CImgList res(pos1 - pos0 + 1); cimglist_for(res,l) res[l].assign(_data[pos0 + l]); return res; } //! Return a shared sublist. /** \param pos0 Starting index of the sublist. \param pos1 Ending index of the sublist. **/ CImgList get_shared_images(const unsigned int pos0, const unsigned int pos1) { if (pos0>pos1 || pos1>=_width) throw CImgArgumentException(_cimglist_instance "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); CImgList res(pos1 - pos0 + 1); cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); return res; } //! Return a shared sublist \newinstance. const CImgList get_shared_images(const unsigned int pos0, const unsigned int pos1) const { if (pos0>pos1 || pos1>=_width) throw CImgArgumentException(_cimglist_instance "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); CImgList res(pos1 - pos0 + 1); cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); return res; } //! Return a single image which is the appending of all images of the current CImgList instance. /** \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ CImg get_append(const char axis, const float align=0) const { if (is_empty()) return CImg(); if (_width==1) return +((*this)[0]); unsigned int dx = 0, dy = 0, dz = 0, dc = 0, pos = 0; CImg res; switch (cimg::uncase(axis)) { case 'x' : { // Along the X-axis. cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) { dx+=img._width; dy = cimg::max(dy,img._height); dz = cimg::max(dz,img._depth); dc = cimg::max(dc,img._spectrum); } } res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) res.draw_image(pos, (int)(align*(dy - img._height)), (int)(align*(dz - img._depth)), (int)(align*(dc - img._spectrum)), img); pos+=img._width; } } break; case 'y' : { // Along the Y-axis. cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) { dx = cimg::max(dx,img._width); dy+=img._height; dz = cimg::max(dz,img._depth); dc = cimg::max(dc,img._spectrum); } } res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) res.draw_image((int)(align*(dx - img._width)), pos, (int)(align*(dz - img._depth)), (int)(align*(dc - img._spectrum)), img); pos+=img._height; } } break; case 'z' : { // Along the Z-axis. cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) { dx = cimg::max(dx,img._width); dy = cimg::max(dy,img._height); dz+=img._depth; dc = cimg::max(dc,img._spectrum); } } res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) res.draw_image((int)(align*(dx - img._width)), (int)(align*(dy - img._height)), pos, (int)(align*(dc - img._spectrum)), img); pos+=img._depth; } } break; default : { // Along the C-axis. cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) { dx = cimg::max(dx,img._width); dy = cimg::max(dy,img._height); dz = cimg::max(dz,img._depth); dc+=img._spectrum; } } res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) res.draw_image((int)(align*(dx - img._width)), (int)(align*(dy - img._height)), (int)(align*(dz - img._depth)), pos, img); pos+=img._spectrum; } } } return res; } //! Return a list where each image has been split along the specified axis. /** \param axis Axis to split images along. \param nb Number of spliting parts for each image. **/ CImgList& split(const char axis, const int nb=-1) { return get_split(axis,nb).move_to(*this); } //! Return a list where each image has been split along the specified axis \newinstance. CImgList get_split(const char axis, const int nb=-1) const { CImgList res; cimglist_for(*this,l) _data[l].get_split(axis,nb).move_to(res,~0U); return res; } //! Insert image at the end of the list. /** \param img Image to insert. **/ template CImgList& push_back(const CImg& img) { return insert(img); } //! Insert image at the front of the list. /** \param img Image to insert. **/ template CImgList& push_front(const CImg& img) { return insert(img,0); } //! Insert list at the end of the current list. /** \param list List to insert. **/ template CImgList& push_back(const CImgList& list) { return insert(list); } //! Insert list at the front of the current list. /** \param list List to insert. **/ template CImgList& push_front(const CImgList& list) { return insert(list,0); } //! Remove last image. /** **/ CImgList& pop_back() { return remove(_width - 1); } //! Remove first image. /** **/ CImgList& pop_front() { return remove(0); } //! Remove image pointed by iterator. /** \param iter Iterator pointing to the image to remove. **/ CImgList& erase(const iterator iter) { return remove(iter - _data); } //@} //---------------------------------- // //! \name Data Input //@{ //---------------------------------- //! Display a simple interactive interface to select images or sublists. /** \param disp Window instance to display selection and user interface. \param feature_type Can be \c false to select a single image, or \c true to select a sublist. \param axis Axis along whom images are appended for visualization. \param align Alignment setting when images have not all the same size. \return A one-column vector containing the selected image indexes. **/ CImg get_select(CImgDisplay &disp, const bool feature_type=true, const char axis='x', const float align=0, const bool exit_on_anykey=false) const { return _get_select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false); } //! Display a simple interactive interface to select images or sublists. /** \param title Title of a new window used to display selection and user interface. \param feature_type Can be \c false to select a single image, or \c true to select a sublist. \param axis Axis along whom images are appended for visualization. \param align Alignment setting when images have not all the same size. \return A one-column vector containing the selected image indexes. **/ CImg get_select(const char *const title, const bool feature_type=true, const char axis='x', const float align=0, const bool exit_on_anykey=false) const { CImgDisplay disp; return _get_select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false); } CImg _get_select(CImgDisplay &disp, const char *const title, const bool feature_type, const char axis, const float align, const bool exit_on_anykey, const unsigned int orig, const bool resize_disp, const bool exit_on_rightbutton, const bool exit_on_wheel) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "select(): Empty instance.", cimglist_instance); // Create image correspondence table and get list dimensions for visualization. CImgList _indices; unsigned int max_width = 0, max_height = 0, sum_width = 0, sum_height = 0; cimglist_for(*this,l) { const CImg& img = _data[l]; const unsigned int w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); if (w>max_width) max_width = w; if (h>max_height) max_height = h; sum_width+=w; sum_height+=h; if (axis=='x') CImg(w,1,1,1,(unsigned int)l).move_to(_indices); else CImg(h,1,1,1,(unsigned int)l).move_to(_indices); } const CImg indices0 = _indices>'x'; // Create display window. if (!disp) { if (axis=='x') disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:0,1); else disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:0,1); if (!title) disp.set_title("CImgList<%s> (%u)",pixel_type(),_width); } else if (title) disp.set_title("%s",title); if (resize_disp) { if (axis=='x') disp.resize(cimg_fitscreen(sum_width,max_height,1),false); else disp.resize(cimg_fitscreen(max_width,sum_height,1),false); } const unsigned int old_normalization = disp.normalization(); bool old_is_resized = disp.is_resized(); disp._normalization = 0; disp.show().set_key(0); static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; // Enter event loop. CImg visu0, visu; CImg indices; CImg positions(_width,4,1,1,-1); int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1; bool is_clicked = false, is_selected = false, text_down = false, update_display = true; unsigned int key = 0; while (!is_selected && !disp.is_closed() && !key) { // Create background image. if (!visu0) { visu0.assign(disp._width,disp._height,1,3,0); visu.assign(); (indices0.get_resize(axis=='x'?visu0._width:visu0._height,1)).move_to(indices); unsigned int ind = 0; if (axis=='x') for (unsigned int x = 0; x onexone(1,1,1,1,0), &src = _data[ind]?_data[ind]:onexone; CImg res; src.__get_select(disp,old_normalization,(src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2). move_to(res); const unsigned int h = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,true); res.resize(x - x0,cimg::max(32U,h*disp._height/max_height),1,res._spectrum==1?3:-100); positions(ind,0) = positions(ind,2) = (int)x0; positions(ind,1) = positions(ind,3) = (int)(align*(visu0.height() - res.height())); positions(ind,2)+=res._width; positions(ind,3)+=res._height - 1; visu0.draw_image(positions(ind,0),positions(ind,1),res); } else for (unsigned int y = 0; y &src = _data[ind]; const CImg img2d = src._depth>1?src.get_projections2d((src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2): cimg::type::string()==cimg::type::string()?src.get_shared():src; CImg res = old_normalization==1 || (old_normalization==3 && cimg::type::string()!=cimg::type::string())? CImg(img2d.get_normalize(0,255)): CImg(img2d); if (res._spectrum>3) res.channels(0,2); const unsigned int w = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,false); res.resize(cimg::max(32U,w*disp._width/max_width),y - y0,1,res._spectrum==1?3:-100); positions(ind,0) = positions(ind,2) = (int)(align*(visu0.width() - res.width())); positions(ind,1) = positions(ind,3) = (int)y0; positions(ind,2)+=res._width - 1; positions(ind,3)+=res._height; visu0.draw_image(positions(ind,0),positions(ind,1),res); } if (axis=='x') --positions(ind,2); else --positions(ind,3); update_display = true; } if (!visu || oindice0!=indice0 || oindice1!=indice1) { if (indice0>=0 && indice1>=0) { visu.assign(visu0,false); const int indm = cimg::min(indice0,indice1), indM = cimg::max(indice0,indice1); for (int ind = indm; ind<=indM; ++ind) if (positions(ind,0)>=0) { visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3), background_color,0.2f); if ((axis=='x' && positions(ind,2) - positions(ind,0)>=8) || (axis!='x' && positions(ind,3) - positions(ind,1)>=8)) visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3), foreground_color,0.9f,0xAAAAAAAA); } const int yt = (int)text_down?visu.height() - 13:0; if (is_clicked) visu.draw_text(0,yt," Images #%u - #%u, Size = %u", foreground_color,background_color,0.7f,13, orig + indm,orig + indM,indM - indm + 1); else visu.draw_text(0,yt," Image #%u (%u,%u,%u,%u)",foreground_color,background_color,0.7f,13, orig + indice0, _data[indice0]._width, _data[indice0]._height, _data[indice0]._depth, _data[indice0]._spectrum); update_display = true; } else visu.assign(); } if (!visu) { visu.assign(visu0,true); update_display = true; } if (update_display) { visu.display(disp); update_display = false; } disp.wait(); // Manage user events. const int xm = disp.mouse_x(), ym = disp.mouse_y(); int indice = -1; if (xm>=0) { indice = (int)indices(axis=='x'?xm:ym); if (disp.button()&1) { if (!is_clicked) { is_clicked = true; oindice0 = indice0; indice0 = indice; } oindice1 = indice1; indice1 = indice; if (!feature_type) is_selected = true; } else { if (!is_clicked) { oindice0 = oindice1 = indice0; indice0 = indice1 = indice; } else is_selected = true; } } else { if (is_clicked) { if (!(disp.button()&1)) { is_clicked = is_selected = false; indice0 = indice1 = -1; } else indice1 = -1; } else indice0 = indice1 = -1; } if (disp.button()&4) { is_clicked = is_selected = false; indice0 = indice1 = -1; } if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; } if (disp.wheel() && exit_on_wheel) is_selected = true; CImg filename(32); switch (key = disp.key()) { #if cimg_OS!=2 case cimg::keyCTRLRIGHT : #endif case 0 : case cimg::keyCTRLLEFT : key = 0; break; case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). _is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(cimg_fitscreen(axis=='x'?sum_width:max_width,axis=='x'?max_height:sum_height,1),false). _is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; disp.set_key(key,false); key = 0; visu0.assign(); } break; case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; std::FILE *file; do { cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); if (visu0) { (+visu0).draw_text(0,0," Saving snapshot... ", foreground_color,background_color,0.7f,13).display(disp); visu0.save(filename); (+visu0).draw_text(0,0," Snapshot '%s' saved. ", foreground_color,background_color,0.7f,13,filename._data).display(disp); } disp.set_key(key,false).wait(); key = 0; } break; case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { static unsigned int snap_number = 0; std::FILE *file; do { #ifdef cimg_use_zlib cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); #else cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); #endif if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); } while (file); (+visu0).draw_text(0,0," Saving instance... ", foreground_color,background_color,0.7f,13).display(disp); save(filename); (+visu0).draw_text(0,0," Instance '%s' saved. ", foreground_color,background_color,0.7f,13,filename._data).display(disp); disp.set_key(key,false).wait(); key = 0; } break; } if (disp.is_resized()) { disp.resize(false); visu0.assign(); } if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }} else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }} if (!exit_on_anykey && key && key!=cimg::keyESC && (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { key = 0; } } CImg res(1,2,1,1,-1); if (is_selected) { if (feature_type) res.fill(cimg::min(indice0,indice1),cimg::max(indice0,indice1)); else res.fill(indice0); } if (!(disp.button()&2)) disp.set_button(); disp._normalization = old_normalization; disp._is_resized = old_is_resized; disp.set_key(key); return res; } //! Load a list from a file. /** \param filename Filename to read data from. **/ CImgList& load(const char *const filename) { if (!filename) throw CImgArgumentException(_cimglist_instance "load(): Specified filename is (null).", cimglist_instance); if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { CImg filename_local(256); load(cimg::load_network(filename,filename_local)); std::remove(filename_local); return *this; } const bool is_stdin = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { #ifdef cimglist_load_plugin cimglist_load_plugin(filename); #endif #ifdef cimglist_load_plugin1 cimglist_load_plugin1(filename); #endif #ifdef cimglist_load_plugin2 cimglist_load_plugin2(filename); #endif #ifdef cimglist_load_plugin3 cimglist_load_plugin3(filename); #endif #ifdef cimglist_load_plugin4 cimglist_load_plugin4(filename); #endif #ifdef cimglist_load_plugin5 cimglist_load_plugin5(filename); #endif #ifdef cimglist_load_plugin6 cimglist_load_plugin6(filename); #endif #ifdef cimglist_load_plugin7 cimglist_load_plugin7(filename); #endif #ifdef cimglist_load_plugin8 cimglist_load_plugin8(filename); #endif if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); else if (!cimg::strcasecmp(ext,"gif")) load_gif_external(filename); else if (!cimg::strcasecmp(ext,"cimg") || !cimg::strcasecmp(ext,"cimgz") || !*ext) load_cimg(filename); else if (!cimg::strcasecmp(ext,"rec") || !cimg::strcasecmp(ext,"par")) load_parrec(filename); else if (!cimg::strcasecmp(ext,"avi") || !cimg::strcasecmp(ext,"mov") || !cimg::strcasecmp(ext,"asf") || !cimg::strcasecmp(ext,"divx") || !cimg::strcasecmp(ext,"flv") || !cimg::strcasecmp(ext,"mpg") || !cimg::strcasecmp(ext,"m1v") || !cimg::strcasecmp(ext,"m2v") || !cimg::strcasecmp(ext,"m4v") || !cimg::strcasecmp(ext,"mjp") || !cimg::strcasecmp(ext,"mp4") || !cimg::strcasecmp(ext,"mkv") || !cimg::strcasecmp(ext,"mpe") || !cimg::strcasecmp(ext,"movie") || !cimg::strcasecmp(ext,"ogm") || !cimg::strcasecmp(ext,"ogg") || !cimg::strcasecmp(ext,"ogv") || !cimg::strcasecmp(ext,"qt") || !cimg::strcasecmp(ext,"rm") || !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || !cimg::strcasecmp(ext,"mpeg")) load_video(filename); else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); else throw CImgIOException("CImgList<%s>::load()", pixel_type()); } catch (CImgIOException&) { std::FILE *file = 0; if (!is_stdin) try { file = cimg::fopen(filename,"rb"); } catch (CImgIOException&) { cimg::exception_mode(omode); throw CImgIOException(_cimglist_instance "load(): Failed to open file '%s'.", cimglist_instance, filename); } try { if (!is_stdin) { const char *const f_type = cimg::ftype(file,filename); std::fclose(file); if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); else throw CImgIOException("CImgList<%s>::load()", pixel_type()); } else throw CImgIOException("CImgList<%s>::load()", pixel_type()); } catch (CImgIOException&) { assign(1); try { _data->load(filename); } catch (CImgIOException&) { cimg::exception_mode(omode); throw CImgIOException(_cimglist_instance "load(): Failed to recognize format of file '%s'.", cimglist_instance, filename); } } } cimg::exception_mode(omode); return *this; } //! Load a list from a file \newinstance. static CImgList get_load(const char *const filename) { return CImgList().load(filename); } //! Load a list from a .cimg file. /** \param filename Filename to read data from. **/ CImgList& load_cimg(const char *const filename) { return _load_cimg(0,filename); } //! Load a list from a .cimg file \newinstance. static CImgList get_load_cimg(const char *const filename) { return CImgList().load_cimg(filename); } //! Load a list from a .cimg file. /** \param file File to read data from. **/ CImgList& load_cimg(std::FILE *const file) { return _load_cimg(file,0); } //! Load a list from a .cimg file \newinstance. static CImgList get_load_cimg(std::FILE *const file) { return CImgList().load_cimg(file); } CImgList& _load_cimg(std::FILE *const file, const char *const filename) { #ifdef cimg_use_zlib #define _cimgz_load_cimg_case(Tss) { \ Bytef *const cbuf = new Bytef[csiz]; \ cimg::fread(cbuf,csiz,nfile); \ raw.assign(W,H,D,C); \ uLongf destlen = (ulongT)raw.size()*sizeof(Tss); \ uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \ delete[] cbuf; \ if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ raw.move_to(img); \ } #else #define _cimgz_load_cimg_case(Tss) \ throw CImgIOException(_cimglist_instance \ "load_cimg(): Unable to load compressed data from file '%s' unless zlib is enabled.", \ cimglist_instance, \ filename?filename:"(FILE*)"); #endif #define _cimg_load_cimg_case(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; \ W = H = D = C = 0; csiz = 0; \ if ((err = cimg_sscanf(tmp,"%u %u %u %u #%lu",&W,&H,&D,&C,&csiz))<4) \ throw CImgIOException(_cimglist_instance \ "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'.", \ cimglist_instance, \ W,H,D,C,l,filename?filename:("(FILE*)")); \ if (W*H*D*C>0) { \ CImg raw; \ CImg &img = _data[l]; \ if (err==5) _cimgz_load_cimg_case(Tss) \ else { \ img.assign(W,H,D,C); \ T *ptrd = img._data; \ for (ulongT to_read = img.size(); to_read; ) { \ raw.assign((unsigned int)cimg::min(to_read,cimg_iobuffer)); \ cimg::fread(raw._data,raw._width,nfile); \ if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ const Tss *ptrs = raw._data; \ for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ to_read-=raw._width; \ } \ } \ } \ } \ loaded = true; \ } if (!filename && !file) throw CImgArgumentException(_cimglist_instance "load_cimg(): Specified filename is (null).", cimglist_instance); const ulongT cimg_iobuffer = (ulongT)24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool loaded = false, endian = cimg::endianness(); CImg tmp(256), str_pixeltype(256), str_endian(256); *tmp = *str_pixeltype = *str_endian = 0; unsigned int j, N = 0, W, H, D, C; ulongT csiz; int i, err; do { j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; } while (*tmp=='#' && i>=0); err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]", &N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_cimg(): CImg header not found in file '%s'.", cimglist_instance, filename?filename:"(FILE*)"); } if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; assign(N); _cimg_load_cimg_case("bool",bool); _cimg_load_cimg_case("unsigned_char",unsigned char); _cimg_load_cimg_case("uchar",unsigned char); _cimg_load_cimg_case("char",char); _cimg_load_cimg_case("unsigned_short",unsigned short); _cimg_load_cimg_case("ushort",unsigned short); _cimg_load_cimg_case("short",short); _cimg_load_cimg_case("unsigned_int",unsigned int); _cimg_load_cimg_case("uint",unsigned int); _cimg_load_cimg_case("int",int); _cimg_load_cimg_case("unsigned_long",ulongT); _cimg_load_cimg_case("ulong",ulongT); _cimg_load_cimg_case("long",longT); _cimg_load_cimg_case("unsigned_int64",uint64T); _cimg_load_cimg_case("uint64",uint64T); _cimg_load_cimg_case("int64",int64T); _cimg_load_cimg_case("float",float); _cimg_load_cimg_case("double",double); if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_cimg(): Unsupported pixel type '%s' for file '%s'.", cimglist_instance, str_pixeltype._data,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; } //! Load a sublist list from a (non compressed) .cimg file. /** \param filename Filename to read data from. \param n0 Starting index of images to read (~0U for max). \param n1 Ending index of images to read (~0U for max). \param x0 Starting X-coordinates of image regions to read. \param y0 Starting Y-coordinates of image regions to read. \param z0 Starting Z-coordinates of image regions to read. \param c0 Starting C-coordinates of image regions to read. \param x1 Ending X-coordinates of image regions to read (~0U for max). \param y1 Ending Y-coordinates of image regions to read (~0U for max). \param z1 Ending Z-coordinates of image regions to read (~0U for max). \param c1 Ending C-coordinates of image regions to read (~0U for max). **/ CImgList& load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { return _load_cimg(0,filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); } //! Load a sublist list from a (non compressed) .cimg file \newinstance. static CImgList get_load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { return CImgList().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); } //! Load a sub-image list from a (non compressed) .cimg file \overloading. CImgList& load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { return _load_cimg(file,0,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); } //! Load a sub-image list from a (non compressed) .cimg file \newinstance. static CImgList get_load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { return CImgList().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); } CImgList& _load_cimg(std::FILE *const file, const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { #define _cimg_load_cimg_case2(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l<=nn1; ++l) { \ j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \ W = H = D = C = 0; \ if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ throw CImgIOException(_cimglist_instance \ "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ cimglist_instance, \ W,H,D,C,l,filename?filename:"(FILE*)"); \ if (W*H*D*C>0) { \ if (l=W || ny0>=H || nz0>=D || nc0>=C) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ else { \ const unsigned int \ _nx1 = nx1==~0U?W - 1:nx1, \ _ny1 = ny1==~0U?H - 1:ny1, \ _nz1 = nz1==~0U?D - 1:nz1, \ _nc1 = nc1==~0U?C - 1:nc1; \ if (_nx1>=W || _ny1>=H || _nz1>=D || _nc1>=C) \ throw CImgArgumentException(_cimglist_instance \ "load_cimg(): Invalid specified coordinates " \ "[%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " \ "because image [%u] in file '%s' has size (%u,%u,%u,%u).", \ cimglist_instance, \ n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,l,filename?filename:"(FILE*)",W,H,D,C); \ CImg raw(1 + _nx1 - nx0); \ CImg &img = _data[l - nn0]; \ img.assign(1 + _nx1 - nx0,1 + _ny1 - ny0,1 + _nz1 - nz0,1 + _nc1 - nc0); \ T *ptrd = img._data; \ ulongT skipvb = nc0*W*H*D*sizeof(Tss); \ if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \ for (unsigned int c = 1 + _nc1 - nc0; c; --c) { \ const ulongT skipzb = nz0*W*H*sizeof(Tss); \ if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \ for (unsigned int z = 1 + _nz1 - nz0; z; --z) { \ const ulongT skipyb = ny0*W*sizeof(Tss); \ if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \ for (unsigned int y = 1 + _ny1 - ny0; y; --y) { \ const ulongT skipxb = nx0*sizeof(Tss); \ if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \ cimg::fread(raw._data,raw._width,nfile); \ if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ const Tss *ptrs = raw._data; \ for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ const ulongT skipxe = (W - 1 - _nx1)*sizeof(Tss); \ if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \ } \ const ulongT skipye = (H - 1 - _ny1)*W*sizeof(Tss); \ if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \ } \ const ulongT skipze = (D - 1 - _nz1)*W*H*sizeof(Tss); \ if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \ } \ const ulongT skipve = (C - 1 - _nc1)*W*H*D*sizeof(Tss); \ if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \ } \ } \ } \ loaded = true; \ } if (!filename && !file) throw CImgArgumentException(_cimglist_instance "load_cimg(): Specified filename is (null).", cimglist_instance); unsigned int nn0 = cimg::min(n0,n1), nn1 = cimg::max(n0,n1), nx0 = cimg::min(x0,x1), nx1 = cimg::max(x0,x1), ny0 = cimg::min(y0,y1), ny1 = cimg::max(y0,y1), nz0 = cimg::min(z0,z1), nz1 = cimg::max(z0,z1), nc0 = cimg::min(c0,c1), nc1 = cimg::max(c0,c1); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool loaded = false, endian = cimg::endianness(); CImg tmp(256), str_pixeltype(256), str_endian(256); *tmp = *str_pixeltype = *str_endian = 0; unsigned int j, N, W, H, D, C; int i, err; j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]", &N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_cimg(): CImg header not found in file '%s'.", cimglist_instance, filename?filename:"(FILE*)"); } if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; nn1 = n1==~0U?N - 1:n1; if (nn1>=N) throw CImgArgumentException(_cimglist_instance "load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " "because file '%s' contains only %u images.", cimglist_instance, n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,filename?filename:"(FILE*)",N); assign(1 + nn1 - n0); _cimg_load_cimg_case2("bool",bool); _cimg_load_cimg_case2("unsigned_char",unsigned char); _cimg_load_cimg_case2("uchar",unsigned char); _cimg_load_cimg_case2("char",char); _cimg_load_cimg_case2("unsigned_short",unsigned short); _cimg_load_cimg_case2("ushort",unsigned short); _cimg_load_cimg_case2("short",short); _cimg_load_cimg_case2("unsigned_int",unsigned int); _cimg_load_cimg_case2("uint",unsigned int); _cimg_load_cimg_case2("int",int); _cimg_load_cimg_case2("unsigned_long",ulongT); _cimg_load_cimg_case2("ulong",ulongT); _cimg_load_cimg_case2("long",longT); _cimg_load_cimg_case2("unsigned_int64",uint64T); _cimg_load_cimg_case2("uint64",uint64T); _cimg_load_cimg_case2("int64",int64T); _cimg_load_cimg_case2("float",float); _cimg_load_cimg_case2("double",double); if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_cimg(): Unsupported pixel type '%s' for file '%s'.", cimglist_instance, str_pixeltype._data,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; } //! Load a list from a PAR/REC (Philips) file. /** \param filename Filename to read data from. **/ CImgList& load_parrec(const char *const filename) { if (!filename) throw CImgArgumentException(_cimglist_instance "load_parrec(): Specified filename is (null).", cimglist_instance); CImg body(1024), filenamepar(1024), filenamerec(1024); *body = *filenamepar = *filenamerec = 0; const char *const ext = cimg::split_filename(filename,body); if (!std::strcmp(ext,"par")) { std::strncpy(filenamepar,filename,filenamepar._width - 1); cimg_snprintf(filenamerec,filenamerec._width,"%s.rec",body._data); } if (!std::strcmp(ext,"PAR")) { std::strncpy(filenamepar,filename,filenamepar._width - 1); cimg_snprintf(filenamerec,filenamerec._width,"%s.REC",body._data); } if (!std::strcmp(ext,"rec")) { std::strncpy(filenamerec,filename,filenamerec._width - 1); cimg_snprintf(filenamepar,filenamepar._width,"%s.par",body._data); } if (!std::strcmp(ext,"REC")) { std::strncpy(filenamerec,filename,filenamerec._width - 1); cimg_snprintf(filenamepar,filenamepar._width,"%s.PAR",body._data); } std::FILE *file = cimg::fopen(filenamepar,"r"); // Parse header file CImgList st_slices; CImgList st_global; CImg line(256); *line = 0; int err; do { err = std::fscanf(file,"%255[^\n]%*c",line._data); } while (err!=EOF && (*line=='#' || *line=='.')); do { unsigned int sn,size_x,size_y,pixsize; float rs,ri,ss; err = std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&size_x,&size_y,&ri,&rs,&ss); if (err==7) { CImg::vector((float)sn,(float)pixsize,(float)size_x,(float)size_y,ri,rs,ss,0).move_to(st_slices); unsigned int i; for (i = 0; i::vector(size_x,size_y,sn).move_to(st_global); else { CImg &vec = st_global[i]; if (size_x>vec[0]) vec[0] = size_x; if (size_y>vec[1]) vec[1] = size_y; vec[2] = sn; } st_slices[st_slices._width - 1][7] = (float)i; } } while (err==7); // Read data std::FILE *file2 = cimg::fopen(filenamerec,"rb"); cimglist_for(st_global,l) { const CImg& vec = st_global[l]; CImg(vec[0],vec[1],vec[2]).move_to(*this); } cimglist_for(st_slices,l) { const CImg& vec = st_slices[l]; const unsigned int sn = (unsigned int)vec[0] - 1, pixsize = (unsigned int)vec[1], size_x = (unsigned int)vec[2], size_y = (unsigned int)vec[3], imn = (unsigned int)vec[7]; const float ri = vec[4], rs = vec[5], ss = vec[6]; switch (pixsize) { case 8 : { CImg buf(size_x,size_y); cimg::fread(buf._data,size_x*size_y,file2); if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); CImg& img = (*this)[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; case 16 : { CImg buf(size_x,size_y); cimg::fread(buf._data,size_x*size_y,file2); if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); CImg& img = (*this)[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; case 32 : { CImg buf(size_x,size_y); cimg::fread(buf._data,size_x*size_y,file2); if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); CImg& img = (*this)[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; default : cimg::fclose(file); cimg::fclose(file2); throw CImgIOException(_cimglist_instance "load_parrec(): Unsupported %d-bits pixel type for file '%s'.", cimglist_instance, pixsize,filename); } } cimg::fclose(file); cimg::fclose(file2); if (!_width) throw CImgIOException(_cimglist_instance "load_parrec(): Failed to recognize valid PAR-REC data in file '%s'.", cimglist_instance, filename); return *this; } //! Load a list from a PAR/REC (Philips) file \newinstance. static CImgList get_load_parrec(const char *const filename) { return CImgList().load_parrec(filename); } //! Load a list from a YUV image sequence file. /** \param filename Filename to read data from. \param size_x Width of the images. \param size_y Height of the images. \param first_frame Index of first image frame to read. \param last_frame Index of last image frame to read. \param step_frame Step applied between each frame. \param yuv2rgb Apply YUV to RGB transformation during reading. **/ CImgList& load_yuv(const char *const filename, const unsigned int size_x, const unsigned int size_y, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true) { return _load_yuv(0,filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb); } //! Load a list from a YUV image sequence file \newinstance. static CImgList get_load_yuv(const char *const filename, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true) { return CImgList().load_yuv(filename,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb); } //! Load a list from an image sequence YUV file \overloading. CImgList& load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true) { return _load_yuv(file,0,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb); } //! Load a list from an image sequence YUV file \newinstance. static CImgList get_load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true) { return CImgList().load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb); } CImgList& _load_yuv(std::FILE *const file, const char *const filename, const unsigned int size_x, const unsigned int size_y, const unsigned int first_frame, const unsigned int last_frame, const unsigned int step_frame, const bool yuv2rgb) { if (!filename && !file) throw CImgArgumentException(_cimglist_instance "load_yuv(): Specified filename is (null).", cimglist_instance); if (size_x%2 || size_y%2) throw CImgArgumentException(_cimglist_instance "load_yuv(): Invalid odd XY dimensions %ux%u in file '%s'.", cimglist_instance, size_x,size_y,filename?filename:"(FILE*)"); if (!size_x || !size_y) throw CImgArgumentException(_cimglist_instance "load_yuv(): Invalid sequence size (%u,%u) in file '%s'.", cimglist_instance, size_x,size_y,filename?filename:"(FILE*)"); const unsigned int nfirst_frame = first_frame tmp(size_x,size_y,1,3), UV(size_x/2,size_y/2,1,2); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool stop_flag = false; int err; if (nfirst_frame) { err = cimg::fseek(nfile,nfirst_frame*(size_x*size_y + size_x*size_y/2),SEEK_CUR); if (err) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_yuv(): File '%s' doesn't contain frame number %u.", cimglist_instance, filename?filename:"(FILE*)",nfirst_frame); } } unsigned int frame; for (frame = nfirst_frame; !stop_flag && frame<=nlast_frame; frame+=nstep_frame) { tmp.fill(0); // *TRY* to read the luminance part, do not replace by cimg::fread! err = (int)std::fread((void*)(tmp._data),1,(ulongT)tmp._width*tmp._height,nfile); if (err!=(int)(tmp._width*tmp._height)) { stop_flag = true; if (err>0) cimg::warn(_cimglist_instance "load_yuv(): File '%s' contains incomplete data or given image dimensions " "(%u,%u) are incorrect.", cimglist_instance, filename?filename:"(FILE*)",size_x,size_y); } else { UV.fill(0); // *TRY* to read the luminance part, do not replace by cimg::fread! err = (int)std::fread((void*)(UV._data),1,(size_t)(UV.size()),nfile); if (err!=(int)(UV.size())) { stop_flag = true; if (err>0) cimg::warn(_cimglist_instance "load_yuv(): File '%s' contains incomplete data or given image dimensions (%u,%u) " "are incorrect.", cimglist_instance, filename?filename:"(FILE*)",size_x,size_y); } else { cimg_forXY(UV,x,y) { const int x2 = x*2, y2 = y*2; tmp(x2,y2,1) = tmp(x2 + 1,y2,1) = tmp(x2,y2 + 1,1) = tmp(x2 + 1,y2 + 1,1) = UV(x,y,0); tmp(x2,y2,2) = tmp(x2 + 1,y2,2) = tmp(x2,y2 + 1,2) = tmp(x2 + 1,y2 + 1,2) = UV(x,y,1); } if (yuv2rgb) tmp.YCbCrtoRGB(); insert(tmp); if (nstep_frame>1) cimg::fseek(nfile,(nstep_frame - 1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR); } } } if (stop_flag && nlast_frame!=~0U && frame!=nlast_frame) cimg::warn(_cimglist_instance "load_yuv(): Frame %d not reached since only %u frames were found in file '%s'.", cimglist_instance, nlast_frame,frame - 1,filename?filename:"(FILE*)"); if (!file) cimg::fclose(nfile); return *this; } //! Load an image from a video file, using OpenCV library. /** \param filename Filename, as a C-string. \param first_frame Index of the first frame to read. \param last_frame Index of the last frame to read. \param step_frame Step value for frame reading. \note If step_frame==0, the current video stream is forced to be released (without any frames read). **/ CImgList& load_video(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1) { #ifndef cimg_use_opencv if (first_frame || last_frame!=~0U || step_frame>1) throw CImgArgumentException(_cimglist_instance "load_video() : File '%s', arguments 'first_frame', 'last_frame' " "and 'step_frame' can be only set when using OpenCV " "(-Dcimg_use_opencv must be enabled).", cimglist_instance,filename); return load_ffmpeg_external(filename); #else static CvCapture *captures[32] = { 0 }; static CImgList filenames(32); static CImg positions(32,1,1,1,0); static int last_used_index = -1; // Detect if a video capture already exists for the specified filename. cimg::mutex(9); int index = -1; if (filename) { if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) { index = last_used_index; } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) { index = l; break; } } else index = last_used_index; cimg::mutex(9,0); // Release stream if needed. if (!step_frame || (index>=0 && positions[index]>first_frame)) { if (index>=0) { cimg::mutex(9); cvReleaseCapture(&captures[index]); captures[index] = 0; filenames[index].assign(); positions[index] = 0; if (last_used_index==index) last_used_index = -1; index = -1; cimg::mutex(9,0); } else if (filename) cimg::warn(_cimglist_instance "load_video() : File '%s', no opened video stream associated with filename found.", cimglist_instance,filename); else cimg::warn(_cimglist_instance "load_video() : No opened video stream found.", cimglist_instance,filename); if (!step_frame) return *this; } // Find empty slot for capturing video stream. if (index<0) { if (!filename) throw CImgArgumentException(_cimglist_instance "load_video(): No already open video reader found. You must specify a " "non-(null) filename argument for the first call.", cimglist_instance); else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); } if (index<0) throw CImgIOException(_cimglist_instance "load_video(): File '%s', no video reader slots available. " "You have to release some of your previously opened videos.", cimglist_instance,filename); cimg::mutex(9); captures[index] = cvCaptureFromFile(filename); CImg::string(filename).move_to(filenames[index]); positions[index] = 0; cimg::mutex(9,0); if (!captures[index]) { filenames[index].assign(); std::fclose(cimg::fopen(filename,"rb")); // Check file availability. throw CImgIOException(_cimglist_instance "load_video(): File '%s', unable to detect format of video file.", cimglist_instance,filename); } } cimg::mutex(9); const unsigned int nb_frames = (unsigned int)cimg::max(0.,cvGetCaptureProperty(captures[index], CV_CAP_PROP_FRAME_COUNT)); cimg::mutex(9,0); assign(); // Skip frames if necessary. unsigned int &pos = positions[index]; while (pos frame(src->width,src->height,1,3); const int step = (int)(src->widthStep - 3*src->width); const unsigned char* ptrs = (unsigned char*)src->imageData; T *ptr_r = frame.data(0,0,0,0), *ptr_g = frame.data(0,0,0,1), *ptr_b = frame.data(0,0,0,2); if (step>0) cimg_forY(frame,y) { cimg_forX(frame,x) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); } ptrs+=step; } else for (ulongT siz = (ulongT)src->width*src->height; siz; --siz) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); } frame.move_to(*this); ++pos; bool skip_failed = false; for (unsigned int i = 1; i=nb_frames)) { // Close video stream when necessary. cimg::mutex(9); cvReleaseCapture(&captures[index]); captures[index] = 0; filenames[index].assign(); positions[index] = 0; index = -1; cimg::mutex(9,0); } cimg::mutex(9); last_used_index = index; cimg::mutex(9,0); return *this; #endif } //! Load an image from a video file, using OpenCV library \newinstance. static CImgList get_load_video(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1) { return CImgList().load_video(filename,first_frame,last_frame,step_frame); } //! Load an image from a video file using the external tool 'ffmpeg'. /** \param filename Filename to read data from. **/ CImgList& load_ffmpeg_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimglist_instance "load_ffmpeg_external(): Specified filename is (null).", cimglist_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256), filename_tmp2(256); std::FILE *file = 0; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%%6d.ppm",filename_tmp._data); #if cimg_OS!=2 cimg_snprintf(command,command._width,"%s -i \"%s\" \"%s\" >/dev/null 2>&1", cimg::ffmpeg_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp2)._system_strescape().data()); #else cimg_snprintf(command,command._width,"\"%s -i \"%s\" \"%s\"\" >NUL 2>&1", cimg::ffmpeg_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp2)._system_strescape().data()); #endif cimg::system(command,0); const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); assign(); unsigned int i = 1; for (bool stop_flag = false; !stop_flag; ++i) { cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,i); CImg img; try { img.load_pnm(filename_tmp2); } catch (CImgException&) { stop_flag = true; } if (img) { img.move_to(*this); std::remove(filename_tmp2); } } cimg::exception_mode(omode); if (is_empty()) throw CImgIOException(_cimglist_instance "load_ffmpeg_external(): Failed to open file '%s' with external command 'ffmpeg'.", cimglist_instance, filename); return *this; } //! Load an image from a video file using the external tool 'ffmpeg' \newinstance. static CImgList get_load_ffmpeg_external(const char *const filename) { return CImgList().load_ffmpeg_external(filename); } //! Load gif file, using ImageMagick or GraphicsMagick's external tools. /** \param filename Filename to read data from. \param use_graphicsmagick Tells if GraphicsMagick's tool 'gm' is used instead of ImageMagick's tool 'convert'. **/ CImgList& load_gif_external(const char *const filename) { if (!filename) throw CImgArgumentException(_cimglist_instance "load_gif_external(): Specified filename is (null).", cimglist_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. if (!_load_gif_external(filename,false)) if (!_load_gif_external(filename,true)) try { assign(CImg().load_other(filename)); } catch (CImgException&) { assign(); } if (is_empty()) throw CImgIOException(_cimglist_instance "load_gif_external(): Failed to open file '%s'.", cimglist_instance,filename); return *this; } CImgList& _load_gif_external(const char *const filename, const bool use_graphicsmagick=false) { CImg command(1024), filename_tmp(256), filename_tmp2(256); std::FILE *file = 0; do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.0",filename_tmp._data); else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-0.png",filename_tmp._data); if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); #if cimg_OS!=2 if (use_graphicsmagick) cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s.png\" >/dev/null 2>&1", cimg::graphicsmagick_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); else cimg_snprintf(command,command._width,"%s \"%s\" \"%s.png\" >/dev/null 2>&1", cimg::imagemagick_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); #else if (use_graphicsmagick) cimg_snprintf(command,command._width,"\"%s convert \"%s\" \"%s.png\"\" >NUL 2>&1", cimg::graphicsmagick_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); else cimg_snprintf(command,command._width,"\"%s \"%s\" \"%s.png\"\" >NUL 2>&1", cimg::imagemagick_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); #endif cimg::system(command,0); const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); assign(); // Try to read a single frame gif. cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png",filename_tmp._data); CImg img; try { img.load_png(filename_tmp2); } catch (CImgException&) { } if (img) { img.move_to(*this); std::remove(filename_tmp2); } else { // Try to read animated gif. unsigned int i = 0; for (bool stop_flag = false; !stop_flag; ++i) { if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.%u",filename_tmp._data,i); else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-%u.png",filename_tmp._data,i); CImg img; try { img.load_png(filename_tmp2); } catch (CImgException&) { stop_flag = true; } if (img) { img.move_to(*this); std::remove(filename_tmp2); } } } cimg::exception_mode(omode); return *this; } //! Load gif file, using ImageMagick or GraphicsMagick's external tools \newinstance. static CImgList get_load_gif_external(const char *const filename) { return CImgList().load_gif_external(filename); } //! Load a gzipped list, using external tool 'gunzip'. /** \param filename Filename to read data from. **/ CImgList& load_gzip_external(const char *const filename) { if (!filename) throw CImgIOException(_cimglist_instance "load_gzip_external(): Specified filename is (null).", cimglist_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. CImg command(1024), filename_tmp(256), body(256); const char *ext = cimg::split_filename(filename,body), *ext2 = cimg::split_filename(body,0); std::FILE *file = 0; do { if (!cimg::strcasecmp(ext,"gz")) { if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gunzip_path(), CImg::string(filename)._system_strescape().data(), CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimglist_instance "load_gzip_external(): Failed to open file '%s'.", cimglist_instance, filename); } else cimg::fclose(file); load(filename_tmp); std::remove(filename_tmp); return *this; } //! Load a gzipped list, using external tool 'gunzip' \newinstance. static CImgList get_load_gzip_external(const char *const filename) { return CImgList().load_gzip_external(filename); } //! Load a 3d object from a .OFF file. /** \param filename Filename to read data from. \param[out] primitives At return, contains the list of 3d object primitives. \param[out] colors At return, contains the list of 3d object colors. \return List of 3d object vertices. **/ template CImgList& load_off(const char *const filename, CImgList& primitives, CImgList& colors) { return get_load_off(filename,primitives,colors).move_to(*this); } //! Load a 3d object from a .OFF file \newinstance. template static CImgList get_load_off(const char *const filename, CImgList& primitives, CImgList& colors) { return CImg().load_off(filename,primitives,colors)<'x'; } //! Load images from a TIFF file. /** \param filename Filename to read data from. \param first_frame Index of first image frame to read. \param last_frame Index of last image frame to read. \param step_frame Step applied between each frame. **/ CImgList& load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, float *const voxel_size=0, CImg *const description=0) { const unsigned int nfirst_frame = first_frame::get_load_tiff(filename)); #else TIFF *tif = TIFFOpen(filename,"r"); if (tif) { unsigned int nb_images = 0; do ++nb_images; while (TIFFReadDirectory(tif)); if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) cimg::warn(_cimglist_instance "load_tiff(): Invalid specified frame range is [%u,%u] (step %u) since " "file '%s' contains %u image(s).", cimglist_instance, nfirst_frame,nlast_frame,nstep_frame,filename,nb_images); if (nfirst_frame>=nb_images) return assign(); if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; assign(1 + (nlast_frame - nfirst_frame)/nstep_frame); TIFFSetDirectory(tif,0); #if cimg_verbosity>=3 TIFFSetWarningHandler(0); TIFFSetErrorHandler(0); #endif cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,voxel_size,description); TIFFClose(tif); } else throw CImgIOException(_cimglist_instance "load_tiff(): Failed to open file '%s'.", cimglist_instance, filename); return *this; #endif } //! Load a multi-page TIFF file \newinstance. static CImgList get_load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, float *const voxel_size=0, CImg *const description=0) { return CImgList().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description); } //@} //---------------------------------- // //! \name Data Output //@{ //---------------------------------- //! Print information about the list on the standard output. /** \param title Label set to the information displayed. \param display_stats Tells if image statistics must be computed and displayed. **/ const CImgList& print(const char *const title=0, const bool display_stats=true) const { unsigned int msiz = 0; cimglist_for(*this,l) msiz+=_data[l].size(); msiz*=sizeof(T); const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U; CImg _title(64); if (!title) cimg_snprintf(_title,_title._width,"CImgList<%s>",pixel_type()); std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p", cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, cimg::t_bold,cimg::t_normal,(void*)this, cimg::t_bold,cimg::t_normal,_width,_allocated_width, mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), mdisp==0?"b":(mdisp==1?"Kio":"Mio"), cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); if (_data) std::fprintf(cimg::output(),"..%p.\n",(void*)((char*)end() - 1)); else std::fprintf(cimg::output(),".\n"); char tmp[16] = { 0 }; cimglist_for(*this,ll) { cimg_snprintf(tmp,sizeof(tmp),"[%d]",ll); std::fprintf(cimg::output()," "); _data[ll].print(tmp,display_stats); if (ll==3 && width()>8) { ll = width() - 5; std::fprintf(cimg::output()," ...\n"); } } std::fflush(cimg::output()); return *this; } //! Display the current CImgList instance in an existing CImgDisplay window (by reference). /** \param disp Reference to an existing CImgDisplay instance, where the current image list will be displayed. \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignmenet. \note This function displays the list images of the current CImgList instance into an existing CImgDisplay window. Images of the list are appended in a single temporarly image for visualization purposes. The function returns immediately. **/ const CImgList& display(CImgDisplay &disp, const char axis='x', const float align=0) const { disp.display(*this,axis,align); return *this; } //! Display the current CImgList instance in a new display window. /** \param disp Display window. \param display_info Tells if image information are displayed on the standard output. \param axis Alignment axis for images viewing. \param align Apending alignment. \note This function opens a new window with a specific title and displays the list images of the current CImgList instance into it. Images of the list are appended in a single temporarly image for visualization purposes. The function returns when a key is pressed or the display window is closed by the user. **/ const CImgList& display(CImgDisplay &disp, const bool display_info, const char axis='x', const float align=0, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { bool is_exit = false; return _display(disp,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); } //! Display the current CImgList instance in a new display window. /** \param title Title of the opening display window. \param display_info Tells if list information must be written on standard output. \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ const CImgList& display(const char *const title=0, const bool display_info=true, const char axis='x', const float align=0, unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { CImgDisplay disp; bool is_exit = false; return _display(disp,title,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); } const CImgList& _display(CImgDisplay &disp, const char *const title, const bool display_info, const char axis, const float align, unsigned int *const XYZ, const bool exit_on_anykey, const unsigned int orig, const bool is_first_call, bool &is_exit) const { if (is_empty()) throw CImgInstanceException(_cimglist_instance "display(): Empty instance.", cimglist_instance); if (!disp) { if (axis=='x') { unsigned int sum_width = 0, max_height = 0; cimglist_for(*this,l) { const CImg &img = _data[l]; const unsigned int w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); sum_width+=w; if (h>max_height) max_height = h; } disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:0,1); } else { unsigned int max_width = 0, sum_height = 0; cimglist_for(*this,l) { const CImg &img = _data[l]; const unsigned int w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); if (w>max_width) max_width = w; sum_height+=h; } disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:0,1); } if (!title) disp.set_title("CImgList<%s> (%u)",pixel_type(),_width); } else if (title) disp.set_title("%s",title); const CImg dtitle = CImg::string(disp.title()); if (display_info) print(disp.title()); disp.show().flush(); if (_width==1) { const unsigned int dw = disp._width, dh = disp._height; if (!is_first_call) disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false). set_title("%s (%ux%ux%ux%u)", dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum); _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call); if (disp.key()) is_exit = true; disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data()); } else { bool disp_resize = !is_first_call; while (!disp.is_closed() && !is_exit) { const CImg s = _get_select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true); disp_resize = true; if (s[0]<0) { // No selections done. if (disp.button()&2) { disp.flush(); break; } is_exit = true; } else if (disp.wheel()) { // Zoom in/out. const int wheel = disp.wheel(); disp.set_wheel(); if (!is_first_call && wheel<0) break; if (wheel>0 && _width>=4) { const unsigned int delta = cimg::max(1U,(unsigned int)cimg::round(0.3*_width)), ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta), ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta); if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,exit_on_anykey, orig + ind0,false,is_exit); } } else if (s[0]!=0 || s[1]!=width() - 1) get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,exit_on_anykey, orig + s[0],false,is_exit); } } return *this; } //! Save list into a file. /** \param filename Filename to write data to. \param number When positive, represents an index added to the filename. Otherwise, no number is added. \param digits Number of digits used for adding the number to the filename. **/ const CImgList& save(const char *const filename, const int number=-1, const unsigned int digits=6) const { if (!filename) throw CImgArgumentException(_cimglist_instance "save(): Specified filename is (null).", cimglist_instance); // Do not test for empty instances, since .cimg format is able to manage empty instances. const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); CImg nfilename(1024); const char *const fn = is_stdout?filename:number>=0?cimg::number_filename(filename,number,digits,nfilename): filename; #ifdef cimglist_save_plugin cimglist_save_plugin(fn); #endif #ifdef cimglist_save_plugin1 cimglist_save_plugin1(fn); #endif #ifdef cimglist_save_plugin2 cimglist_save_plugin2(fn); #endif #ifdef cimglist_save_plugin3 cimglist_save_plugin3(fn); #endif #ifdef cimglist_save_plugin4 cimglist_save_plugin4(fn); #endif #ifdef cimglist_save_plugin5 cimglist_save_plugin5(fn); #endif #ifdef cimglist_save_plugin6 cimglist_save_plugin6(fn); #endif #ifdef cimglist_save_plugin7 cimglist_save_plugin7(fn); #endif #ifdef cimglist_save_plugin8 cimglist_save_plugin8(fn); #endif if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false); else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true); else if (!cimg::strcasecmp(ext,"avi") || !cimg::strcasecmp(ext,"mov") || !cimg::strcasecmp(ext,"asf") || !cimg::strcasecmp(ext,"divx") || !cimg::strcasecmp(ext,"flv") || !cimg::strcasecmp(ext,"mpg") || !cimg::strcasecmp(ext,"m1v") || !cimg::strcasecmp(ext,"m2v") || !cimg::strcasecmp(ext,"m4v") || !cimg::strcasecmp(ext,"mjp") || !cimg::strcasecmp(ext,"mp4") || !cimg::strcasecmp(ext,"mkv") || !cimg::strcasecmp(ext,"mpe") || !cimg::strcasecmp(ext,"movie") || !cimg::strcasecmp(ext,"ogm") || !cimg::strcasecmp(ext,"ogg") || !cimg::strcasecmp(ext,"ogv") || !cimg::strcasecmp(ext,"qt") || !cimg::strcasecmp(ext,"rm") || !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); #ifdef cimg_use_tiff else if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); #endif else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); else { if (_width==1) _data[0].save(fn,-1); else cimglist_for(*this,l) { _data[l].save(fn,is_stdout?-1:l); if (is_stdout) std::fputc(EOF,stdout); } } return *this; } //! Tell if an image list can be saved as one single file. /** \param filename Filename, as a C-string. \return \c true if the file format supports multiple images, \c false otherwise. **/ static bool is_saveable(const char *const filename) { const char *const ext = cimg::split_filename(filename); if (!cimg::strcasecmp(ext,"cimgz") || #ifdef cimg_use_tiff !cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff") || #endif !cimg::strcasecmp(ext,"yuv") || !cimg::strcasecmp(ext,"avi") || !cimg::strcasecmp(ext,"mov") || !cimg::strcasecmp(ext,"asf") || !cimg::strcasecmp(ext,"divx") || !cimg::strcasecmp(ext,"flv") || !cimg::strcasecmp(ext,"mpg") || !cimg::strcasecmp(ext,"m1v") || !cimg::strcasecmp(ext,"m2v") || !cimg::strcasecmp(ext,"m4v") || !cimg::strcasecmp(ext,"mjp") || !cimg::strcasecmp(ext,"mp4") || !cimg::strcasecmp(ext,"mkv") || !cimg::strcasecmp(ext,"mpe") || !cimg::strcasecmp(ext,"movie") || !cimg::strcasecmp(ext,"ogm") || !cimg::strcasecmp(ext,"ogg") || !cimg::strcasecmp(ext,"ogv") || !cimg::strcasecmp(ext,"qt") || !cimg::strcasecmp(ext,"rm") || !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || !cimg::strcasecmp(ext,"mpeg")) return true; return false; } //! Save image sequence as a GIF animated file. /** \param filename Filename to write data to. \param fps Number of desired frames per second. \param nb_loops Number of loops (\c 0 for infinite looping). **/ const CImgList& save_gif_external(const char *const filename, const float fps=25, const unsigned int nb_loops=0) { CImg command(1024), filename_tmp(256), filename_tmp2(256); CImgList filenames; std::FILE *file = 0; #ifdef cimg_use_png #define _cimg_save_gif_ext "png" #else #define _cimg_save_gif_ext "ppm" #endif do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001." _cimg_save_gif_ext,filename_tmp._data); if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); cimglist_for(*this,l) { cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u." _cimg_save_gif_ext,filename_tmp._data,l + 1); CImg::string(filename_tmp2).move_to(filenames); if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save(filename_tmp2); else _data[l].save(filename_tmp2); } #if cimg_OS!=2 cimg_snprintf(command,command._width,"%s -delay %u -loop %u", cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops); CImg::string(command).move_to(filenames,0); cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1", CImg::string(filename)._system_strescape().data()); CImg::string(command).move_to(filenames); #else cimg_snprintf(command,command._width,"\"%s -delay %u -loop %u", cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops); CImg::string(command).move_to(filenames,0); cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1", CImg::string(filename)._system_strescape().data()); CImg::string(command).move_to(filenames); #endif CImg _command = filenames>'x'; cimg_for(_command,p,char) if (!*p) *p = ' '; _command.back() = 0; cimg::system(_command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimglist_instance "save_gif_external(): Failed to save file '%s' with external command 'convert'.", cimglist_instance, filename); else cimg::fclose(file); cimglist_for_in(*this,1,filenames._width - 1,l) std::remove(filenames[l]); return *this; } const CImgList& _save_yuv(std::FILE *const file, const char *const filename, const bool is_rgb) const { if (!file && !filename) throw CImgArgumentException(_cimglist_instance "save_yuv(): Specified filename is (null).", cimglist_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } if ((*this)[0].width()%2 || (*this)[0].height()%2) throw CImgInstanceException(_cimglist_instance "save_yuv(): Invalid odd instance dimensions (%u,%u) for file '%s'.", cimglist_instance, (*this)[0].width(),(*this)[0].height(), filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); cimglist_for(*this,l) { CImg YCbCr((*this)[l]); if (is_rgb) YCbCr.RGBtoYCbCr(); cimg::fwrite(YCbCr._data,(size_t)YCbCr._width*YCbCr._height,nfile); cimg::fwrite(YCbCr.get_resize(YCbCr._width/2, YCbCr._height/2,1,3,3).data(0,0,0,1), (size_t)YCbCr._width*YCbCr._height/2,nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save list as a YUV image sequence file. /** \param filename Filename to write data to. \param is_rgb Tells if the RGB to YUV conversion must be done for saving. **/ const CImgList& save_yuv(const char *const filename=0, const bool is_rgb=true) const { return _save_yuv(0,filename,is_rgb); } //! Save image sequence into a YUV file. /** \param file File to write data to. \param is_rgb Tells if the RGB to YUV conversion must be done for saving. **/ const CImgList& save_yuv(std::FILE *const file, const bool is_rgb=true) const { return _save_yuv(file,0,is_rgb); } const CImgList& _save_cimg(std::FILE *const file, const char *const filename, const bool is_compressed) const { if (!file && !filename) throw CImgArgumentException(_cimglist_instance "save_cimg(): Specified filename is (null).", cimglist_instance); #ifndef cimg_use_zlib if (is_compressed) cimg::warn(_cimglist_instance "save_cimg(): Unable to save compressed data in file '%s' unless zlib is enabled, " "saving them uncompressed.", cimglist_instance, filename?filename:"(FILE*)"); #endif std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype); else std::fprintf(nfile,"%u %s %s_endian\n",_width,ptype,etype); cimglist_for(*this,l) { const CImg& img = _data[l]; std::fprintf(nfile,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); if (img._data) { CImg tmp; if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } const CImg& ref = cimg::endianness()?tmp:img; bool failed_to_compress = true; if (is_compressed) { #ifdef cimg_use_zlib const ulongT siz = sizeof(T)*ref.size(); uLongf csiz = siz + siz/100 + 16; Bytef *const cbuf = new Bytef[csiz]; if (compress(cbuf,&csiz,(Bytef*)ref._data,siz)) cimg::warn(_cimglist_instance "save_cimg(): Failed to save compressed data for file '%s', saving them uncompressed.", cimglist_instance, filename?filename:"(FILE*)"); else { std::fprintf(nfile," #%lu\n",csiz); cimg::fwrite(cbuf,csiz,nfile); delete[] cbuf; failed_to_compress = false; } #endif } if (failed_to_compress) { // Write in a non-compressed way. std::fputc('\n',nfile); cimg::fwrite(ref._data,ref.size(),nfile); } } else std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save list into a .cimg file. /** \param filename Filename to write data to. \param is_compressed Tells if data compression must be enabled. **/ const CImgList& save_cimg(const char *const filename, const bool is_compressed=false) const { return _save_cimg(0,filename,is_compressed); } //! Save list into a .cimg file. /** \param file File to write data to. \param is_compressed Tells if data compression must be enabled. **/ const CImgList& save_cimg(std::FILE *file, const bool is_compressed=false) const { return _save_cimg(file,0,is_compressed); } const CImgList& _save_cimg(std::FILE *const file, const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0) const { #define _cimg_save_cimg_case(Ts,Tss) \ if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l0) { \ if (l=W || y0>=H || z0>=D || c0>=D) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ else { \ const CImg& img = (*this)[l - n0]; \ const T *ptrs = img._data; \ const unsigned int \ x1 = x0 + img._width - 1, \ y1 = y0 + img._height - 1, \ z1 = z0 + img._depth - 1, \ c1 = c0 + img._spectrum - 1, \ nx1 = x1>=W?W - 1:x1, \ ny1 = y1>=H?H - 1:y1, \ nz1 = z1>=D?D - 1:z1, \ nc1 = c1>=C?C - 1:c1; \ CImg raw(1 + nx1 - x0); \ const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \ if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \ for (unsigned int v = 1 + nc1 - c0; v; --v) { \ const unsigned int skipzb = z0*W*H*sizeof(Tss); \ if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \ for (unsigned int z = 1 + nz1 - z0; z; --z) { \ const unsigned int skipyb = y0*W*sizeof(Tss); \ if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \ for (unsigned int y = 1 + ny1 - y0; y; --y) { \ const unsigned int skipxb = x0*sizeof(Tss); \ if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \ raw.assign(ptrs, raw._width); \ ptrs+=img._width; \ if (endian) cimg::invert_endianness(raw._data,raw._width); \ cimg::fwrite(raw._data,raw._width,nfile); \ const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \ if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \ } \ const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \ if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \ } \ const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \ if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \ } \ const unsigned int skipve = (C - 1 - nc1)*W*H*D*sizeof(Tss); \ if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \ } \ } \ } \ saved = true; \ } if (!file && !filename) throw CImgArgumentException(_cimglist_instance "save_cimg(): Specified filename is (null).", cimglist_instance); if (is_empty()) throw CImgInstanceException(_cimglist_instance "save_cimg(): Empty instance, for file '%s'.", cimglist_instance, filename?filename:"(FILE*)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+"); bool saved = false, endian = cimg::endianness(); CImg tmp(256), str_pixeltype(256), str_endian(256); *tmp = *str_pixeltype = *str_endian = 0; unsigned int j, N, W, H, D, C; int i, err; j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "save_cimg(): CImg header not found in file '%s'.", cimglist_instance, filename?filename:"(FILE*)"); } if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; const unsigned int lmax = cimg::min(N,n0 + _width); _cimg_save_cimg_case("bool",bool); _cimg_save_cimg_case("unsigned_char",unsigned char); _cimg_save_cimg_case("uchar",unsigned char); _cimg_save_cimg_case("char",char); _cimg_save_cimg_case("unsigned_short",unsigned short); _cimg_save_cimg_case("ushort",unsigned short); _cimg_save_cimg_case("short",short); _cimg_save_cimg_case("unsigned_int",unsigned int); _cimg_save_cimg_case("uint",unsigned int); _cimg_save_cimg_case("int",int); _cimg_save_cimg_case("unsigned_int64",uint64T); _cimg_save_cimg_case("uint64",uint64T); _cimg_save_cimg_case("int64",int64T); _cimg_save_cimg_case("float",float); _cimg_save_cimg_case("double",double); if (!saved) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "save_cimg(): Unsupported data type '%s' for file '%s'.", cimglist_instance, filename?filename:"(FILE*)",str_pixeltype._data); } if (!file) cimg::fclose(nfile); return *this; } //! Insert the image instance into into an existing .cimg file, at specified coordinates. /** \param filename Filename to write data to. \param n0 Starting index of images to write. \param x0 Starting X-coordinates of image regions to write. \param y0 Starting Y-coordinates of image regions to write. \param z0 Starting Z-coordinates of image regions to write. \param c0 Starting C-coordinates of image regions to write. **/ const CImgList& save_cimg(const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0) const { return _save_cimg(0,filename,n0,x0,y0,z0,c0); } //! Insert the image instance into into an existing .cimg file, at specified coordinates. /** \param file File to write data to. \param n0 Starting index of images to write. \param x0 Starting X-coordinates of image regions to write. \param y0 Starting Y-coordinates of image regions to write. \param z0 Starting Z-coordinates of image regions to write. \param c0 Starting C-coordinates of image regions to write. **/ const CImgList& save_cimg(std::FILE *const file, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0) const { return _save_cimg(file,0,n0,x0,y0,z0,c0); } static void _save_empty_cimg(std::FILE *const file, const char *const filename, const unsigned int nb, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) { std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const ulongT siz = (ulongT)dx*dy*dz*dc*sizeof(T); std::fprintf(nfile,"%u %s\n",nb,pixel_type()); for (unsigned int i=nb; i; --i) { std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dc); for (ulongT off = siz; off; --off) std::fputc(0,nfile); } if (!file) cimg::fclose(nfile); } //! Save empty (non-compressed) .cimg file with specified dimensions. /** \param filename Filename to write data to. \param nb Number of images to write. \param dx Width of images in the written file. \param dy Height of images in the written file. \param dz Depth of images in the written file. \param dc Spectrum of images in the written file. **/ static void save_empty_cimg(const char *const filename, const unsigned int nb, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1) { return _save_empty_cimg(0,filename,nb,dx,dy,dz,dc); } //! Save empty .cimg file with specified dimensions. /** \param file File to write data to. \param nb Number of images to write. \param dx Width of images in the written file. \param dy Height of images in the written file. \param dz Depth of images in the written file. \param dc Spectrum of images in the written file. **/ static void save_empty_cimg(std::FILE *const file, const unsigned int nb, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1) { return _save_empty_cimg(file,0,nb,dx,dy,dz,dc); } //! Save list as a TIFF file. /** \param filename Filename to write data to. \param compression_type Compression mode used to write data. **/ const CImgList& save_tiff(const char *const filename, const unsigned int compression_type=0, const float *const voxel_size=0, const char *const description=0, const bool use_bigtiff=true) const { if (!filename) throw CImgArgumentException(_cimglist_instance "save_tiff(): Specified filename is (null).", cimglist_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } #ifndef cimg_use_tiff if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,use_bigtiff); else cimglist_for(*this,l) { CImg nfilename(1024); cimg::number_filename(filename,l,6,nfilename); _data[l].save_tiff(nfilename,compression_type,voxel_size,description,use_bigtiff); } #else ulongT siz = 0; cimglist_for(*this,l) siz+=_data[l].size(); const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images. TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4"); if (tif) { for (unsigned int dir = 0, l = 0; l<_width; ++l) { const CImg& img = (*this)[l]; cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description); } TIFFClose(tif); } else throw CImgIOException(_cimglist_instance "save_tiff(): Failed to open stream for file '%s'.", cimglist_instance, filename); #endif return *this; } //! Save list as a gzipped file, using external tool 'gzip'. /** \param filename Filename to write data to. **/ const CImgList& save_gzip_external(const char *const filename) const { if (!filename) throw CImgIOException(_cimglist_instance "save_gzip_external(): Specified filename is (null).", cimglist_instance); CImg command(1024), filename_tmp(256), body(256); const char *ext = cimg::split_filename(filename,body), *ext2 = cimg::split_filename(body,0); std::FILE *file; do { if (!cimg::strcasecmp(ext,"gz")) { if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); if (is_saveable(body)) { save(filename_tmp); cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gzip_path(), CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimglist_instance "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.", cimglist_instance, filename); else cimg::fclose(file); std::remove(filename_tmp); } else { CImg nfilename(1024); cimglist_for(*this,l) { cimg::number_filename(body,l,6,nfilename); if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); _data[l].save_gzip_external(nfilename); } } return *this; } //! Save image sequence, using the OpenCV library. /** \param filename Filename to write data to. \param fps Number of frames per second. \param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs). \param keep_open Tells if the video writer associated to the specified filename must be kept open or not (to allow frames to be added in the same file afterwards). **/ const CImgList& save_video(const char *const filename, const unsigned int fps=25, const char *codec=0, const bool keep_open=false) const { #ifndef cimg_use_opencv cimg::unused(codec,keep_open); return save_ffmpeg_external(filename,fps); #else static CvVideoWriter *writers[32] = { 0 }; static CImgList filenames(32); static CImg sizes(32,2,1,1,0); static int last_used_index = -1; // Detect if a video writer already exists for the specified filename. cimg::mutex(9); int index = -1; if (filename) { if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) { index = last_used_index; } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) { index = l; break; } } else index = last_used_index; cimg::mutex(9,0); // Find empty slot for capturing video stream. if (index<0) { if (!filename) throw CImgArgumentException(_cimglist_instance "save_video(): No already open video writer found. You must specify a " "non-(null) filename argument for the first call.", cimglist_instance); else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); } if (index<0) throw CImgIOException(_cimglist_instance "save_video(): File '%s', no video writer slots available. " "You have to release some of your previously opened videos.", cimglist_instance,filename); if (is_empty()) throw CImgInstanceException(_cimglist_instance "save_video(): Instance list is empty.", cimglist_instance); const unsigned int W = _data?_data[0]._width:0, H = _data?_data[0]._height:0; if (!W || !H) throw CImgInstanceException(_cimglist_instance "save_video(): Frame [0] is an empty image.", cimglist_instance); #define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x)) const char *const _codec = codec && *codec?codec:"mp4v", codec0 = _cimg_docase(_codec[0]), codec1 = _codec[0]?_cimg_docase(_codec[1]):0, codec2 = _codec[1]?_cimg_docase(_codec[2]):0, codec3 = _codec[2]?_cimg_docase(_codec[3]):0; cimg::mutex(9); writers[index] = cvCreateVideoWriter(filename,CV_FOURCC(codec0,codec1,codec2,codec3), fps,cvSize(W,H)); CImg::string(filename).move_to(filenames[index]); sizes(index,0) = W; sizes(index,1) = H; cimg::mutex(9,0); if (!writers[index]) throw CImgIOException(_cimglist_instance "save_video(): File '%s', unable to initialize video writer with codec '%c%c%c%c'.", cimglist_instance,filename, codec0,codec1,codec2,codec3); } if (!is_empty()) { const unsigned int W = sizes(index,0), H = sizes(index,1); cimg::mutex(9); IplImage *ipl = cvCreateImage(cvSize(W,H),8,3); cimglist_for(*this,l) { CImg &src = _data[l]; if (src.is_empty()) cimg::warn(_cimglist_instance "save_video(): Skip empty frame %d for file '%s'.", cimglist_instance,l,filename); if (src._depth>1 || src._spectrum>3) cimg::warn(_cimglist_instance "save_video(): Frame %u has incompatible dimension (%u,%u,%u,%u). " "Some image data may be ignored when writing frame into video file '%s'.", cimglist_instance,l,src._width,src._height,src._depth,src._spectrum,filename); if (src._width==W && src._height==H && src._spectrum==3) { const T *ptr_r = src.data(0,0,0,0), *ptr_g = src.data(0,0,0,1), *ptr_b = src.data(0,0,0,2); char *ptrd = ipl->imageData; cimg_forXY(src,x,y) { *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++); } } else { CImg _src(src,false); _src.channels(0,cimg::min(_src._spectrum - 1,2U)).resize(W,H); _src.resize(W,H,1,3,_src._spectrum==1?1:0); const unsigned char *ptr_r = _src.data(0,0,0,0), *ptr_g = _src.data(0,0,0,1), *ptr_b = _src.data(0,0,0,2); char *ptrd = ipl->imageData; cimg_forXY(_src,x,y) { *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++); } } cvWriteFrame(writers[index],ipl); } cvReleaseImage(&ipl); cimg::mutex(9,0); } cimg::mutex(9); if (!keep_open) { cvReleaseVideoWriter(&writers[index]); writers[index] = 0; filenames[index].assign(); sizes(index,0) = sizes(index,1) = 0; last_used_index = -1; } else last_used_index = index; cimg::mutex(9,0); return *this; #endif } //! Save image sequence, using the external tool 'ffmpeg'. /** \param filename Filename to write data to. \param fps Number of frames per second. \param codec Type of compression. \param bitrate Output bitrate **/ const CImgList& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, const char *const codec=0, const unsigned int bitrate=2048) const { if (!filename) throw CImgArgumentException(_cimglist_instance "save_ffmpeg_external(): Specified filename is (null).", cimglist_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } const char *const ext = cimg::split_filename(filename), *const _codec = codec?codec:!cimg::strcasecmp(ext,"flv")?"flv":"mpeg2video"; CImg command(1024), filename_tmp(256), filename_tmp2(256); CImgList filenames; std::FILE *file = 0; cimglist_for(*this,l) if (!_data[l].is_sameXYZ(_data[0])) throw CImgInstanceException(_cimglist_instance "save_ffmpeg_external(): Invalid instance dimensions for file '%s'.", cimglist_instance, filename); do { cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); cimglist_for(*this,l) { cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,l + 1); CImg::string(filename_tmp2).move_to(filenames); if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save_pnm(filename_tmp2); else _data[l].save_pnm(filename_tmp2); } #if cimg_OS!=2 cimg_snprintf(command,command._width,"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\" >/dev/null 2>&1", cimg::ffmpeg_path(), CImg::string(filename_tmp)._system_strescape().data(), _codec,bitrate,fps, CImg::string(filename)._system_strescape().data()); #else cimg_snprintf(command,command._width,"\"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\"\" >NUL 2>&1", cimg::ffmpeg_path(), CImg::string(filename_tmp)._system_strescape().data(), _codec,bitrate,fps, CImg::string(filename)._system_strescape().data()); #endif cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException(_cimglist_instance "save_ffmpeg_external(): Failed to save file '%s' with external command 'ffmpeg'.", cimglist_instance, filename); else cimg::fclose(file); cimglist_for(*this,l) std::remove(filenames[l]); return *this; } //! Serialize a CImgList instance into a raw CImg buffer. /** \param is_compressed tells if zlib compression must be used for serialization (this requires 'cimg_use_zlib' been enabled). **/ CImg get_serialize(const bool is_compressed=false) const { #ifndef cimg_use_zlib if (is_compressed) cimg::warn(_cimglist_instance "get_serialize(): Unable to compress data unless zlib is enabled, " "storing them uncompressed.", cimglist_instance); #endif CImgList stream; CImg tmpstr(128); const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; if (std::strstr(ptype,"unsigned")==ptype) cimg_snprintf(tmpstr,tmpstr._width,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype); else cimg_snprintf(tmpstr,tmpstr._width,"%u %s %s_endian\n",_width,ptype,etype); CImg::string(tmpstr,false).move_to(stream); cimglist_for(*this,l) { const CImg& img = _data[l]; cimg_snprintf(tmpstr,tmpstr._width,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); CImg::string(tmpstr,false).move_to(stream); if (img._data) { CImg tmp; if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } const CImg& ref = cimg::endianness()?tmp:img; bool failed_to_compress = true; if (is_compressed) { #ifdef cimg_use_zlib const ulongT siz = sizeof(T)*ref.size(); uLongf csiz = (ulongT)compressBound(siz); Bytef *const cbuf = new Bytef[csiz]; if (compress(cbuf,&csiz,(Bytef*)ref._data,siz)) cimg::warn(_cimglist_instance "get_serialize(): Failed to save compressed data, saving them uncompressed.", cimglist_instance); else { cimg_snprintf(tmpstr,tmpstr._width," #%lu\n",csiz); CImg::string(tmpstr,false).move_to(stream); CImg(cbuf,csiz).move_to(stream); delete[] cbuf; failed_to_compress = false; } #endif } if (failed_to_compress) { // Write in a non-compressed way. CImg::string("\n",false).move_to(stream); stream.insert(1); stream.back().assign((unsigned char*)ref._data,ref.size()*sizeof(T),1,1,1,true); } } else CImg::string("\n",false).move_to(stream); } cimglist_apply(stream,unroll)('y'); return stream>'y'; } //! Unserialize a CImg serialized buffer into a CImgList list. template static CImgList get_unserialize(const CImg& buffer) { #ifdef cimg_use_zlib #define _cimgz_unserialize_case(Tss) { \ Bytef *cbuf = (Bytef*)stream; \ if (sizeof(t)!=1 || cimg::type::string()==cimg::type::string()) { \ cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \ for (ulongT i = 0; i raw(W,H,D,C); \ uLongf destlen = raw.size()*sizeof(Tss); \ uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \ if (!is_bytef) delete[] cbuf; \ if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ raw.move_to(img); \ } #else #define _cimgz_unserialize_case(Tss) \ throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unable to unserialize compressed data " \ "unless zlib is enabled.", \ pixel_type()); #endif #define _cimg_unserialize_case(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l::unserialize(): Invalid specified size (%u,%u,%u,%u) for " \ "image #%u in serialized buffer.", \ pixel_type(),W,H,D,C,l); \ if (W*H*D*C>0) { \ CImg &img = res._data[l]; \ if (err==5) _cimgz_unserialize_case(Tss) \ else { \ if (sizeof(t)!=1) { \ CImg raw(W*sizeof(Tss),H,D,C); \ cimg_for(raw,p,unsigned char) *p = (unsigned char)*(stream++); \ img.assign((Tss*)raw._data,W,H,D,C); \ } else img.assign((Tss*)stream,W,H,D,C); \ if (endian!=cimg::endianness()) cimg::invert_endianness(img._data,img.size()); \ } \ } \ } \ loaded = true; \ } if (buffer.is_empty()) throw CImgArgumentException("CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).", pixel_type()); CImgList res; const t *stream = buffer._data, *const estream = buffer._data + buffer.size(); bool loaded = false, endian = cimg::endianness(), is_bytef = false; CImg tmp(256), str_pixeltype(256), str_endian(256); *tmp = *str_pixeltype = *str_endian = 0; unsigned int j, N = 0, W, H, D, C; ulongT csiz; int i, err; cimg::unused(is_bytef); do { j = 0; while ((i=(int)*stream)!='\n' && stream::get_unserialize(): CImg header not found in serialized buffer.", pixel_type()); if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; res.assign(N); _cimg_unserialize_case("bool",bool); _cimg_unserialize_case("unsigned_char",unsigned char); _cimg_unserialize_case("uchar",unsigned char); _cimg_unserialize_case("char",char); _cimg_unserialize_case("unsigned_short",unsigned short); _cimg_unserialize_case("ushort",unsigned short); _cimg_unserialize_case("short",short); _cimg_unserialize_case("unsigned_int",unsigned int); _cimg_unserialize_case("uint",unsigned int); _cimg_unserialize_case("int",int); _cimg_unserialize_case("unsigned_int64",uint64T); _cimg_unserialize_case("uint64",uint64T); _cimg_unserialize_case("int64",int64T); _cimg_unserialize_case("float",float); _cimg_unserialize_case("double",double); if (!loaded) throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined " "in serialized buffer.", pixel_type(),str_pixeltype._data); return res; } //@} //---------------------------------- // //! \name Others //@{ //---------------------------------- //! Crop font along the X-axis. /** **/ CImgList& crop_font() { return get_crop_font().move_to(*this); } //! Crop font along the X-axis \newinstance. /** **/ CImgList get_crop_font() const { CImgList res; cimglist_for(*this,l) { const CImg& letter = (*this)[l]; int xmin = letter.width(), xmax = 0; cimg_forXY(letter,x,y) if (letter(x,y)) { if (xxmax) xmax = x; } if (xmin>xmax) CImg(letter._width,letter._height,1,letter._spectrum,0).move_to(res); else letter.get_crop(xmin,0,xmax,letter._height - 1).move_to(res); } res[' '].resize(res['f']._width,-100,-100,-100,0); if (' ' + 256& font(const unsigned int font_height, const bool is_variable_width=true) { if (!font_height) return CImgList::const_empty(); cimg::mutex(11); // Decompress nearest base font data if needed. static const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 }; static const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 }, data_Ms[] = { 86,79,57,47 }; const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U; static CImg base_fonts[4]; CImg &base_font = base_fonts[data_ind]; if (!base_font) { const unsigned int w = data_widths[data_ind], h = data_heights[data_ind], M = data_Ms[data_ind]; base_font.assign(256*w,h); const char *data_font = data_fonts[data_ind]; unsigned char *ptrd = base_font; const unsigned char *const ptrde = base_font.end(); // Special case needed for 90x103 to avoid MS compiler limit with big strings. CImg data90x103; if (!data_font) { ((CImg(cimg::_data_font90x103[0], (unsigned int)std::strlen(cimg::_data_font90x103[0]),1,1,1,true), CImg(cimg::_data_font90x103[1], (unsigned int)std::strlen(cimg::_data_font90x103[1]) + 1,1,1,1,true))>'x'). move_to(data90x103); data_font = data90x103.data(); } // Uncompress font data (decode RLE). for (const char *ptrs = data_font; *ptrs; ++ptrs) { const int c = (int)(*ptrs - M - 32), v = c>=0?255:0, n = c>=0?c:-c; if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; } else { std::memset(ptrd,v,ptrde - ptrd); break; } } } // Find optimal font cache location to return. static CImgList fonts[16]; static bool is_variable_widths[16] = { 0 }; unsigned int ind = ~0U; for (int i = 0; i<16; ++i) if (!fonts[i] || (is_variable_widths[i]==is_variable_width && font_height==fonts[i][0]._height)) { ind = (unsigned int)i; break; // Found empty slot or cached font. } if (ind==~0U) { // No empty slots nor existing font in cache. std::memmove(fonts,fonts + 1,15*sizeof(CImgList)); std::memmove(is_variable_widths,is_variable_widths + 1,15*sizeof(bool)); std::memset(fonts + (ind=15),0,sizeof(CImgList)); // Free a slot in cache for new font. } CImgList &font = fonts[ind]; // Render requested font. if (!font) { const unsigned int padding_x = font_height<33U?1U:font_height<53U?2U:font_height<103U?3U:4U; is_variable_widths[ind] = is_variable_width; font = base_font.get_split('x',256); if (font_height!=font[0]._height) cimglist_for(font,l) font[l].resize(cimg::max(1U,font[l]._width*font_height/font[l]._height),font_height,-100,-100, font[0]._height>font_height?2:5); if (is_variable_width) font.crop_font(); cimglist_for(font,l) font[l].resize(font[l]._width + padding_x,-100,1,1,0,0,0.5); font.insert(256,0); cimglist_for_in(font,0,255,l) font[l].assign(font[l + 256]._width,font[l + 256]._height,1,3,1); } cimg::mutex(11,0); return font; } //! Compute a 1d Fast Fourier Transform, along specified axis. /** \param axis Axis along which the Fourier transform is computed. \param invert Tells if the direct (\c false) or inverse transform (\c true) is computed. **/ CImgList& FFT(const char axis, const bool invert=false) { if (is_empty()) return *this; if (_width==1) insert(1); if (_width>2) cimg::warn(_cimglist_instance "FFT(): Instance has more than 2 images", cimglist_instance); CImg::FFT(_data[0],_data[1],axis,invert); return *this; } //! Compute a 1-D Fast Fourier Transform, along specified axis \newinstance. CImgList get_FFT(const char axis, const bool invert=false) const { return CImgList(*this,false).FFT(axis,invert); } //! Compute a n-d Fast Fourier Transform. /** \param invert Tells if the direct (\c false) or inverse transform (\c true) is computed. **/ CImgList& FFT(const bool invert=false) { if (is_empty()) return *this; if (_width==1) insert(1); if (_width>2) cimg::warn(_cimglist_instance "FFT(): Instance has more than 2 images", cimglist_instance); CImg::FFT(_data[0],_data[1],invert); return *this; } //! Compute a n-d Fast Fourier Transform \newinstance. CImgList get_FFT(const bool invert=false) const { return CImgList(*this,false).FFT(invert); } //! Reverse primitives orientations of a 3d object. /** **/ CImgList& reverse_object3d() { cimglist_for(*this,l) { CImg& p = _data[l]; switch (p.size()) { case 2 : case 3: cimg::swap(p[0],p[1]); break; case 6 : cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break; case 9 : cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break; case 4 : cimg::swap(p[0],p[1],p[2],p[3]); break; case 12 : cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break; } } return *this; } //! Reverse primitives orientations of a 3d object \newinstance. CImgList get_reverse_object3d() const { return (+*this).reverse_object3d(); } //@} }; // struct CImgList { ... /* #--------------------------------------------- # # Completion of previously declared functions # #---------------------------------------------- */ namespace cimg { //! Get/set path to store temporary files. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path where temporary files can be saved. **/ inline const char* temporary_path(const char *const user_path, const bool reinit_path) { #define _cimg_test_temporary_path(p) \ if (!path_found) { \ cimg_snprintf(s_path,s_path.width(),"%s",p); \ cimg_snprintf(tmp,tmp._width,"%s%c%s",s_path.data(),cimg_file_separator,filename_tmp._data); \ if ((file=std::fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \ } static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; CImg tmp(1024), filename_tmp(256); std::FILE *file = 0; cimg_snprintf(filename_tmp,filename_tmp._width,"%s.tmp",cimg::filenamerand()); char *tmpPath = std::getenv("TMP"); if (!tmpPath) { tmpPath = std::getenv("TEMP"); winformat_string(tmpPath); } if (tmpPath) _cimg_test_temporary_path(tmpPath); #if cimg_OS==2 _cimg_test_temporary_path("C:\\WINNT\\Temp"); _cimg_test_temporary_path("C:\\WINDOWS\\Temp"); _cimg_test_temporary_path("C:\\Temp"); _cimg_test_temporary_path("C:"); _cimg_test_temporary_path("D:\\WINNT\\Temp"); _cimg_test_temporary_path("D:\\WINDOWS\\Temp"); _cimg_test_temporary_path("D:\\Temp"); _cimg_test_temporary_path("D:"); #else _cimg_test_temporary_path("/tmp"); _cimg_test_temporary_path("/var/tmp"); #endif if (!path_found) { *s_path = 0; std::strncpy(tmp,filename_tmp,tmp._width - 1); if ((file=std::fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } } if (!path_found) { cimg::mutex(7,0); throw CImgIOException("cimg::temporary_path(): Failed to locate path for writing temporary files.\n"); } } cimg::mutex(7,0); return s_path; } //! Get/set path to the Program Files/ directory (Windows only). /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the program files. **/ #if cimg_OS==2 inline const char* programfiles_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(MAX_PATH); *s_path = 0; // Note: in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). #if !defined(__INTEL_COMPILER) if (!SHGetSpecialFolderPathA(0,s_path,0x0026,false)) { const char *const pfPath = std::getenv("PROGRAMFILES"); if (pfPath) std::strncpy(s_path,pfPath,MAX_PATH - 1); else std::strcpy(s_path,"C:\\PROGRA~1"); } #else std::strcpy(s_path,"C:\\PROGRA~1"); #endif } cimg::mutex(7,0); return s_path; } #endif //! Get/set path to the ImageMagick's \c convert binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c convert binary. **/ inline const char* imagemagick_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 const char *const pf_path = programfiles_path(); if (!path_found) { std::strcpy(s_path,".\\convert.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"convert.exe"); #else if (!path_found) { std::strcpy(s_path,"./convert"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"convert"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the GraphicsMagick's \c gm binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c gm binary. **/ inline const char* graphicsmagick_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 const char *const pf_path = programfiles_path(); if (!path_found) { std::strcpy(s_path,".\\gm.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=10 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 9; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } for (int k = 32; k>=0 && !path_found; --k) { cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gm.exe"); #else if (!path_found) { std::strcpy(s_path,"./gm"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gm"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the XMedcon's \c medcon binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c medcon binary. **/ inline const char* medcon_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 const char *const pf_path = programfiles_path(); if (!path_found) { std::strcpy(s_path,".\\medcon.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) { cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.bat",pf_path); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) { cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.exe",pf_path); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) { std::strcpy(s_path,"C:\\XMedCon\\bin\\medcon.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"medcon.exe"); #else if (!path_found) { std::strcpy(s_path,"./medcon"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"medcon"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the FFMPEG's \c ffmpeg binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c ffmpeg binary. **/ inline const char *ffmpeg_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\ffmpeg.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"ffmpeg.exe"); #else if (!path_found) { std::strcpy(s_path,"./ffmpeg"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"ffmpeg"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the \c gzip binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c gzip binary. **/ inline const char *gzip_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\gzip.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gzip.exe"); #else if (!path_found) { std::strcpy(s_path,"./gzip"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gzip"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the \c gunzip binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c gunzip binary. **/ inline const char *gunzip_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\gunzip.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gunzip.exe"); #else if (!path_found) { std::strcpy(s_path,"./gunzip"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"gunzip"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the \c dcraw binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c dcraw binary. **/ inline const char *dcraw_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\dcraw.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"dcraw.exe"); #else if (!path_found) { std::strcpy(s_path,"./dcraw"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"dcraw"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the \c wget binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c wget binary. **/ inline const char *wget_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\wget.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"wget.exe"); #else if (!path_found) { std::strcpy(s_path,"./wget"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"wget"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } //! Get/set path to the \c curl binary. /** \param user_path Specified path, or \c 0 to get the path currently used. \param reinit_path Force path to be recalculated (may take some time). \return Path containing the \c curl binary. **/ inline const char *curl_path(const char *const user_path, const bool reinit_path) { static CImg s_path; cimg::mutex(7); if (reinit_path) s_path.assign(); if (user_path) { if (!s_path) s_path.assign(1024); std::strncpy(s_path,user_path,1023); } else if (!s_path) { s_path.assign(1024); bool path_found = false; std::FILE *file = 0; #if cimg_OS==2 if (!path_found) { std::strcpy(s_path,".\\curl.exe"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"curl.exe"); #else if (!path_found) { std::strcpy(s_path,"./curl"); if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } } if (!path_found) std::strcpy(s_path,"curl"); #endif winformat_string(s_path); } cimg::mutex(7,0); return s_path; } // [internal] Sorting function, used by cimg::files(). inline int _sort_files(const void* a, const void* b) { const CImg &sa = *(CImg*)a, &sb = *(CImg*)b; return std::strcmp(sa._data,sb._data); } //! Return list of files/directories in specified directory. /** \param path Path to the directory. Set to 0 for current directory. \param is_pattern Tell if specified path has a matching pattern in it. \param mode Output type, can be primary { 0=files only | 1=folders only | 2=files + folders }. \param include_path Tell if \c path must be included in resulting filenames. \return A list of filenames. **/ inline CImgList files(const char *const path, const bool is_pattern=false, const unsigned int mode=2, const bool include_path=false) { if (!path || !*path) return files("*",true,mode,include_path); CImgList res; // If path is a valid folder name, ignore argument 'is_pattern'. const bool _is_pattern = is_pattern && !cimg::is_directory(path); bool is_root = false, is_current = false; cimg::unused(is_root,is_current); // Clean format of input path. CImg pattern, _path = CImg::string(path); #if cimg_OS==2 for (char *ps = _path; *ps; ++ps) if (*ps=='\\') *ps='/'; #endif char *pd = _path; for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; } *pd = 0; unsigned int lp = (unsigned int)std::strlen(_path); if (!_is_pattern && lp && _path[lp - 1]=='/') { _path[lp - 1] = 0; --lp; #if cimg_OS!=2 is_root = !*_path; #endif } // Separate folder path and matching pattern. if (_is_pattern) { const unsigned int bpos = (unsigned int)(cimg::basename(_path,'/') - _path.data()); CImg::string(_path).move_to(pattern); if (bpos) { _path[bpos - 1] = 0; // End 'path' at last slash. #if cimg_OS!=2 is_root = !*_path; #endif } else { // No path to folder specified, assuming current folder. is_current = true; *_path = 0; } lp = (unsigned int)std::strlen(_path); } // Windows version. #if cimg_OS==2 if (!_is_pattern) { pattern.assign(lp + 3); std::memcpy(pattern,_path,lp); pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0; } WIN32_FIND_DATAA file_data; const HANDLE dir = FindFirstFileA(pattern.data(),&file_data); if (dir==INVALID_HANDLE_VALUE) return CImgList::const_empty(); do { const char *const filename = file_data.cFileName; if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { const unsigned int lf = (unsigned int)std::strlen(filename); const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) { if (include_path) { CImg full_filename((lp?lp+1:0) + lf + 1); if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; } std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1); full_filename.move_to(res); } else CImg(filename,lf + 1).move_to(res); } } } while (FindNextFileA(dir,&file_data)); FindClose(dir); // Unix version (posix). #else DIR *const dir = opendir(is_root?"/":is_current?".":_path.data()); if (!dir) return CImgList::const_empty(); struct dirent *ent; while ((ent=readdir(dir))!=0) { const char *const filename = ent->d_name; if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { const unsigned int lf = (unsigned int)std::strlen(filename); CImg full_filename(lp + lf + 2); if (!is_current) { full_filename.assign(lp + lf + 2); if (lp) std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; std::memcpy(full_filename._data + lp + 1,filename,lf + 1); } else full_filename.assign(filename,lf + 1); struct stat st; if (stat(full_filename,&st)==-1) continue; const bool is_directory = (st.st_mode & S_IFDIR)!=0; if ((!mode && !is_directory) || (mode==1 && is_directory) || mode==2) { if (include_path) { if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) full_filename.move_to(res); } else { if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) CImg(filename,lf + 1).move_to(res); } } } } closedir(dir); #endif // Sort resulting list by lexicographic order. if (res._width>=2) std::qsort(res._data,res._width,sizeof(CImg),_sort_files); return res; } //! Try to guess format from an image file. /** \param file Input file (can be \c 0 if \c filename is set). \param filename Filename, as a C-string (can be \c 0 if \c file is set). \return C-string containing the guessed file format, or \c 0 if nothing has been guessed. **/ inline const char *ftype(std::FILE *const file, const char *const filename) { if (!file && !filename) throw CImgArgumentException("cimg::ftype(): Specified filename is (null)."); static const char *const _pnm = "pnm", *const _pfm = "pfm", *const _bmp = "bmp", *const _gif = "gif", *const _jpg = "jpg", *const _off = "off", *const _pan = "pan", *const _png = "png", *const _tif = "tif", *const _inr = "inr", *const _dcm = "dcm"; const char *f_type = 0; CImg header; const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { header._load_raw(file,filename,512,1,1,1,false,false,0); const unsigned char *const uheader = (unsigned char*)header._data; if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // OFF. else if (!std::strncmp(header,"#INRIMAGE",9)) f_type = _inr; // INRIMAGE. else if (!std::strncmp(header,"PANDORE",7)) f_type = _pan; // PANDORE. else if (!std::strncmp(header.data() + 128,"DICM",4)) f_type = _dcm; // DICOM. else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg; // JPEG. else if (header[0]=='B' && header[1]=='M') f_type = _bmp; // BMP. else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // GIF. (header[4]=='7' || header[4]=='9')) f_type = _gif; else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 && // PNG. uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png; else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // TIFF. else { // PNM or PFM. CImgList _header = header.get_split(CImg::vector('\n'),0,false); cimglist_for(_header,l) { if (_header(l,0)=='#') continue; if (_header[l]._height==2 && _header(l,0)=='P') { const char c = _header(l,1); if (c=='f' || c=='F') { f_type = _pfm; break; } if (c>='1' && c<='9') { f_type = _pnm; break; } } f_type = 0; break; } } } catch (CImgIOException&) { } cimg::exception_mode(omode); return f_type; } //! Load file from network as a local temporary file. /** \param filename Filename, as a C-string. \param[out] filename_local C-string containing the path to a local copy of \c filename. \param timeout Maximum time (in seconds) authorized for downloading the file from the URL. \param try_fallback When using libcurl, tells using system calls as fallbacks in case of libcurl failure. \return Value of \c filename_local. \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download. **/ inline char *load_network(const char *const url, char *const filename_local, const unsigned int timeout, const bool try_fallback, const char *const referer) { if (!url) throw CImgArgumentException("cimg::load_network(): Specified URL is (null)."); if (!filename_local) throw CImgArgumentException("cimg::load_network(): Specified destination string is (null)."); const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext; CImg ext = CImg::string(_ext); std::FILE *file = 0; *filename_local = 0; if (ext._width>16 || !cimg::strncasecmp(ext,"cgi",3)) *ext = 0; else cimg::strwindows_reserved(ext); do { cimg_snprintf(filename_local,256,"%s%c%s%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data); if ((file=std::fopen(filename_local,"rb"))!=0) cimg::fclose(file); } while (file); #ifdef cimg_use_curl const unsigned int omode = cimg::exception_mode(); cimg::exception_mode(0); try { CURL *curl = 0; CURLcode res; curl = curl_easy_init(); if (curl) { file = cimg::fopen(filename_local,"wb"); curl_easy_setopt(curl,CURLOPT_URL,url); curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0); curl_easy_setopt(curl,CURLOPT_WRITEDATA,file); curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L); curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout); if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L); if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer); res = curl_easy_perform(curl); curl_easy_cleanup(curl); cimg::fseek(file,0,SEEK_END); // Check if file size is 0. const cimg_ulong siz = cimg::ftell(file); cimg::fclose(file); if (siz>0 && res==CURLE_OK) { cimg::exception_mode(omode); return filename_local; } else std::remove(filename_local); } } catch (...) { } cimg::exception_mode(omode); if (!try_fallback) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with libcurl.",url); #endif CImg command((unsigned int)std::strlen(url) + 64); cimg::unused(try_fallback); // Try with 'curl' first. if (timeout) { if (referer) cimg_snprintf(command,command._width,"%s -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"", cimg::curl_path(),referer,timeout,filename_local,url); else cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"", cimg::curl_path(),timeout,filename_local,url); } else { if (referer) cimg_snprintf(command,command._width,"%s -e %s -f --silent --compressed -o \"%s\" \"%s\"", cimg::curl_path(),referer,filename_local,url); else cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"", cimg::curl_path(),filename_local,url); } cimg::system(command); if (!(file = std::fopen(filename_local,"rb"))) { // Try with 'wget' otherwise. if (timeout) { if (referer) cimg_snprintf(command,command._width,"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", cimg::wget_path(),referer,timeout,filename_local,url); else cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", cimg::wget_path(),timeout,filename_local,url); } else { if (referer) cimg_snprintf(command,command._width,"%s --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", cimg::wget_path(),referer,filename_local,url); else cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", cimg::wget_path(),filename_local,url); } cimg::system(command); if (!(file = std::fopen(filename_local,"rb"))) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with external commands " "'wget' or 'curl'.",url); cimg::fclose(file); // Try gunzip it. cimg_snprintf(command,command._width,"%s.gz",filename_local); std::rename(filename_local,command); cimg_snprintf(command,command._width,"%s --quiet \"%s.gz\"", gunzip_path(),filename_local); cimg::system(command); file = std::fopen(filename_local,"rb"); if (!file) { cimg_snprintf(command,command._width,"%s.gz",filename_local); std::rename(command,filename_local); file = std::fopen(filename_local,"rb"); } } cimg::fseek(file,0,SEEK_END); // Check if file size is 0. if (std::ftell(file)<=0) throw CImgIOException("cimg::load_network(): Failed to load URL '%s' with external commands " "'wget' or 'curl'.",url); cimg::fclose(file); return filename_local; } // Implement a tic/toc mechanism to display elapsed time of algorithms. inline cimg_ulong tictoc(const bool is_tic) { cimg::mutex(2); static CImg times(64); static unsigned int pos = 0; const cimg_ulong t1 = cimg::time(); if (is_tic) { // Tic. times[pos++] = t1; if (pos>=times._width) throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'."); cimg::mutex(2,0); return t1; } // Toc. if (!pos) throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made."); const cimg_ulong t0 = times[--pos], dt = t1>=t0?(t1 - t0):cimg::type::max(); const unsigned int edays = (unsigned int)(dt/86400000.0), ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0), emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0), esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0), ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0); if (!edays && !ehours && !emin && !esec) std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n", cimg::t_red,1 + 2*pos,"",ems,cimg::t_normal); else { if (!edays && !ehours && !emin) std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n", cimg::t_red,1 + 2*pos,"",esec,ems,cimg::t_normal); else { if (!edays && !ehours) std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n", cimg::t_red,1 + 2*pos,"",emin,esec,ems,cimg::t_normal); else{ if (!edays) std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n", cimg::t_red,1 + 2*pos,"",ehours,emin,esec,ems,cimg::t_normal); else{ std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n", cimg::t_red,1 + 2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal); } } } } cimg::mutex(2,0); return dt; } // Return a temporary string describing the size of a memory buffer. inline const char *strbuffersize(const cimg_ulong size) { static CImg res(256); cimg::mutex(5); if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",size,size>1?"s":""); else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,res._width,"%.1f Kio",nsize); } else if (size<1024*1024*1024LU) { const float nsize = size/(1024*1024.0f); cimg_snprintf(res,res._width,"%.1f Mio",nsize); } else { const float nsize = size/(1024*1024*1024.0f); cimg_snprintf(res,res._width,"%.1f Gio",nsize); } cimg::mutex(5,0); return res; } //! Display a simple dialog box, and wait for the user's response. /** \param title Title of the dialog window. \param msg Main message displayed inside the dialog window. \param button1_label Label of the 1st button. \param button2_label Label of the 2nd button (\c 0 to hide button). \param button3_label Label of the 3rd button (\c 0 to hide button). \param button4_label Label of the 4th button (\c 0 to hide button). \param button5_label Label of the 5th button (\c 0 to hide button). \param button6_label Label of the 6th button (\c 0 to hide button). \param logo Image logo displayed at the left of the main message. \param is_centered Tells if the dialog window must be centered on the screen. \return Indice of clicked button (from \c 0 to \c 5), or \c -1 if the dialog window has been closed by the user. \note - Up to 6 buttons can be defined in the dialog window. - The function returns when a user clicked one of the button or closed the dialog window. - If a button text is set to 0, the corresponding button (and the followings) will not appear in the dialog box. At least one button must be specified. **/ template inline int dialog(const char *const title, const char *const msg, const char *const button1_label, const char *const button2_label, const char *const button3_label, const char *const button4_label, const char *const button5_label, const char *const button6_label, const CImg& logo, const bool is_centered=false) { #if cimg_display==0 cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, logo._data,is_centered); throw CImgIOException("cimg::dialog(): No display available."); #else static const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 }; // Create buttons and canvas graphics CImgList buttons, cbuttons, sbuttons; if (button1_label) { CImg().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons); if (button2_label) { CImg().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons); if (button3_label) { CImg().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons); if (button4_label) { CImg().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons); if (button5_label) { CImg().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons); if (button6_label) { CImg().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons); }}}}}} if (!buttons._width) throw CImgArgumentException("cimg::dialog(): No buttons have been defined."); cimglist_for(buttons,l) buttons[l].resize(-100,-100,1,3); unsigned int bw = 0, bh = 0; cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l]._width); bh = cimg::max(bh,buttons[l]._height); } bw+=8; bh+=8; if (bw<64) bw = 64; if (bw>128) bw = 128; if (bh<24) bh = 24; if (bh>48) bh = 48; CImg button(bw,bh,1,3); button.draw_rectangle(0,0,bw - 1,bh - 1,gray); button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white); button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black); button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2); CImg sbutton(bw,bh,1,3); sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray); sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black); sbutton.draw_line(bw - 1,bh - 1,0,bh - 1,black).draw_line(0,bh - 1,0,0,black); sbutton.draw_line(1,1,bw - 2,1,white).draw_line(1,bh - 2,1,1,white); sbutton.draw_line(bw - 2,1,bw - 2,bh - 2,black).draw_line(bw - 2,bh - 2,1,bh - 2,black); sbutton.draw_line(2,bh - 3,bw - 3,bh - 3,gray2).draw_line(bw - 3,bh - 3,bw - 3,2,gray2); sbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); sbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); CImg cbutton(bw,bh,1,3); cbutton.draw_rectangle(0,0,bw - 1,bh - 1,black).draw_rectangle(1,1,bw - 2,bh - 2,gray2). draw_rectangle(2,2,bw - 3,bh - 3,gray); cbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); cbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); cimglist_for(buttons,ll) { CImg(cbutton). draw_image(1 + (bw -buttons[ll].width())/2,1 + (bh - buttons[ll].height())/2,buttons[ll]). move_to(cbuttons); CImg(sbutton). draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). move_to(sbuttons); CImg(button). draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). move_to(buttons[ll]); } CImg canvas; if (msg) ((CImg().draw_text(0,0,"%s",gray,0,1,13,msg)*=-1)+=200).resize(-100,-100,1,3).move_to(canvas); const unsigned int bwall = (buttons._width - 1)*(12 + bw) + bw, w = cimg::max(196U,36 + logo._width + canvas._width,24 + bwall), h = cimg::max(96U,36 + canvas._height + bh,36 + logo._height + bh), lx = 12 + (canvas._data?0:((w - 24 - logo._width)/2)), ly = (h - 12 - bh - logo._height)/2, tx = lx + logo._width + 12, ty = (h - 12 - bh - canvas._height)/2, bx = (w - bwall)/2, by = h - 12 - bh; if (canvas._data) canvas = CImg(w,h,1,3). draw_rectangle(0,0,w - 1,h - 1,gray). draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black). draw_image(tx,ty,canvas); else canvas = CImg(w,h,1,3). draw_rectangle(0,0,w - 1,h - 1,gray). draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black); if (logo._data) canvas.draw_image(lx,ly,logo); unsigned int xbuttons[6] = { 0 }; cimglist_for(buttons,lll) { xbuttons[lll] = bx + (bw + 12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); } // Open window and enter events loop CImgDisplay disp(canvas,title?title:" ",0,false,is_centered?true:false); if (is_centered) disp.move((CImgDisplay::screen_width() - disp.width())/2, (CImgDisplay::screen_height() - disp.height())/2); bool stop_flag = false, refresh = false; int oselected = -1, oclicked = -1, selected = -1, clicked = -1; while (!disp.is_closed() && !stop_flag) { if (refresh) { if (clicked>=0) CImg(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp); else { if (selected>=0) CImg(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp); else canvas.display(disp); } refresh = false; } disp.wait(15); if (disp.is_resized()) disp.resize(disp,false); if (disp.button()&1) { oclicked = clicked; clicked = -1; cimglist_for(buttons,l) if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by + bh) && disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l] + bw)) { clicked = selected = l; refresh = true; } if (clicked!=oclicked) refresh = true; } else if (clicked>=0) stop_flag = true; if (disp.key()) { oselected = selected; switch (disp.key()) { case cimg::keyESC : selected = -1; stop_flag = true; break; case cimg::keyENTER : if (selected<0) selected = 0; stop_flag = true; break; case cimg::keyTAB : case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : selected = (selected + 1)%buttons.width(); break; case cimg::keyARROWLEFT : case cimg::keyARROWUP : selected = (selected + buttons.width() - 1)%buttons.width(); break; } disp.set_key(); if (selected!=oselected) refresh = true; } } if (!disp) selected = -1; return selected; #endif } //! Display a simple dialog box, and wait for the user's response \specialization. inline int dialog(const char *const title, const char *const msg, const char *const button1_label, const char *const button2_label, const char *const button3_label, const char *const button4_label, const char *const button5_label, const char *const button6_label, const bool is_centered) { return dialog(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, CImg::_logo40x38(),is_centered); } //! Evaluate math expression. /** \param expression C-string describing the formula to evaluate. \param x Value of the pre-defined variable \c x. \param y Value of the pre-defined variable \c y. \param z Value of the pre-defined variable \c z. \param c Value of the pre-defined variable \c c. \return Result of the formula evaluation. \note Set \c expression to \c 0 to keep evaluating the last specified \c expression. \par Example \code const double res1 = cimg::eval("cos(x)^2 + sin(y)^2",2,2), // will return '1'. res2 = cimg::eval(0,1,1); // will return '1' too. \endcode **/ inline double eval(const char *const expression, const double x, const double y, const double z, const double c) { static const CImg empty; return empty.eval(expression,x,y,z,c); } template inline CImg::type> eval(const char *const expression, const CImg& xyzc) { static const CImg empty; return empty.eval(expression,xyzc); } // End of cimg:: namespace } // End of cimg_library:: namespace } //! Short alias name. namespace cil = cimg_library_suffixed; #ifdef _cimg_redefine_False #define False 0 #endif #ifdef _cimg_redefine_True #define True 1 #endif #ifdef _cimg_redefine_None #define None 0 #endif #ifdef _cimg_redefine_min #define min(a,b) (((a)<(b))?(a):(b)) #endif #ifdef _cimg_redefine_max #define max(a,b) (((a)>(b))?(a):(b)) #endif #ifdef _cimg_redefine_PI #define PI 3.141592653589793238462643383 #endif #ifdef _MSC_VER #pragma warning(pop) #endif #endif // Local Variables: // mode: c++ // End: ================================================ FILE: BOSS/source/CombatSearch.cpp ================================================ #include "CombatSearch.h" using namespace BOSS; // function which is called to do the actual search void CombatSearch::search() { _searchTimer.start(); // apply the opening build order to the initial state GameState initialState(_params.getInitialState()); _buildOrder = _params.getOpeningBuildOrder(); _buildOrder.doActions(initialState); try { recurse(initialState, 0); _results.solved = true; } catch (int e) { if (e == BOSS_COMBATSEARCH_TIMEOUT) { _results.timedOut = true; } } _results.timeElapsed = _searchTimer.getElapsedTimeInMilliSec(); } // This functio generates the legal actions from a GameState based on the input search parameters void CombatSearch::generateLegalActions(const GameState & state, ActionSet & legalActions, const CombatSearchParameters & params) { // prune actions we have too many of already const ActionSet & allActions = params.getRelevantActions(); for (ActionID a(0); a<(int)allActions.size(); ++a) { const ActionType & action = allActions[a]; bool isLegal = state.isLegal(action); if (!isLegal) { continue; } // prune the action if we have too many of them already if ((params.getMaxActions(action) != -1) && (state.getUnitData().getNumTotal(action) >= params.getMaxActions(action))) { continue; } legalActions.add(action); } // if we enabled the always make workers flag, and workers are legal const ActionType & worker = ActionTypes::GetWorker(state.getRace()); if (_params.getAlwaysMakeWorkers() && legalActions.contains(worker)) { bool actionLegalBeforeWorker = false; // when can we make a worker FrameCountType workerReady = state.whenCanPerform(worker); // if we can make a worker in the next couple of frames, do it if (workerReady <= state.getCurrentFrame() + 2) { legalActions.clear(); legalActions.add(worker); return; } // figure out of anything can be made before a worker for (size_t a(0); a < legalActions.size(); ++a) { const ActionType & actionType = legalActions[a]; const FrameCountType whenCanPerformAction = state.whenCanPerform(actionType); if (whenCanPerformAction < workerReady) { actionLegalBeforeWorker = true; break; } } // if something can be made before a worker, then don't consider workers if (actionLegalBeforeWorker) { legalActions.remove(worker); } // otherwise we can make a worker next so don't consider anything else else { legalActions.clear(); legalActions.add(worker); } } } const CombatSearchResults & CombatSearch::getResults() const { return _results; } bool CombatSearch::timeLimitReached() { return (_params.getSearchTimeLimit() && (_results.nodesExpanded % 100 == 0) && (_searchTimer.getElapsedTimeInMilliSec() > _params.getSearchTimeLimit())); } bool CombatSearch::isTerminalNode(const GameState & s, int depth) { if (s.getCurrentFrame() >= _params.getFrameTimeLimit()) { return true; } return false; } void CombatSearch::recurse(const GameState & state, size_t depth) { // This base class function should never be called, leaving the code // here as a basis to form child classes BOSS_ASSERT(false, "Base CombatSearch doSearch() should never be called"); //if (timeLimitReached()) //{ // throw BOSS_COMBATSEARCH_TIMEOUT; //} //updateResults(state); //if (isTerminalNode(state, depth)) //{ // return; //} //ActionSet legalActions; //generateLegalActions(state, legalActions, _params); // //for (UnitCountType a(0); a < legalActions.size(); ++a) //{ // GameState child(state); // child.doAction(legalActions[a]); // _buildOrder.add(legalActions[a]); // // doSearch(child,depth+1); // _buildOrder.pop_back(); //} } void CombatSearch::updateResults(const GameState & state) { _results.nodesExpanded++; } void CombatSearch::printResults() { std::cout << "Printing base class CombatSearch results!\n\n"; } void CombatSearch::writeResultsFile(const std::string & prefix) { std::cout << "Writing base class CombatSearch results!\n\n"; } ================================================ FILE: BOSS/source/CombatSearch.h ================================================ #pragma once #include "Common.h" #include "Timer.hpp" #include "Eval.h" #include "BuildOrder.h" #include "CombatSearchParameters.h" #include "CombatSearchResults.h" namespace BOSS { #define BOSS_COMBATSEARCH_TIMEOUT -1 #define MAX_COMBAT_SEARCH_DEPTH 100 class CombatSearch { protected: CombatSearchParameters _params; // parameters that will be used in this search CombatSearchResults _results; // the results of the search so far FrameCountType _upperBound; // the current upper bound for search Timer _searchTimer; BuildOrder _buildOrder; virtual void recurse(const GameState & s,size_t depth); virtual void generateLegalActions(const GameState & state,ActionSet & legalActions,const CombatSearchParameters & params); //virtual double eval(const GameState & state) const; virtual bool isTerminalNode(const GameState & s,int depth); virtual void updateResults(const GameState & state); virtual bool timeLimitReached(); public: virtual void search(); virtual void printResults(); virtual void writeResultsFile(const std::string & prefix); virtual const CombatSearchResults & getResults() const; }; } ================================================ FILE: BOSS/source/CombatSearchExperiment.cpp ================================================ #include "CombatSearchExperiment.h" #include "BOSSParameters.h" using namespace BOSS; CombatSearchExperiment::CombatSearchExperiment() : _race(Races::None) { } CombatSearchExperiment::CombatSearchExperiment(const std::string & name, const rapidjson::Value & val) : _race(Races::None) , _name(name) { BOSS_ASSERT(val.HasMember("SearchTypes") && val["SearchTypes"].IsArray(), "CombatSearchExperiment must have a 'SearchTypes' array"); for (size_t i(0); i < val["SearchTypes"].Size(); ++i) { BOSS_ASSERT(val["SearchTypes"][i].IsString(), "searchTypes element is not a string"); _searchTypes.push_back(val["SearchTypes"][i].GetString()); } BOSS_ASSERT(val.HasMember("Race") && val["Race"].IsString(), "CombatSearchExperiment must have a 'Race' string"); _race = Races::GetRaceID(val["Race"].GetString()); BOSS_ASSERT(val.HasMember("State") && val["State"].IsString(), "CombatSearchExperiment must have a 'State' string"); _params.setInitialState(BOSSParameters::Instance().GetState(val["State"].GetString())); BOSS_ASSERT(val.HasMember("FrameTimeLimit") && val["FrameTimeLimit"].IsInt(), "CombatSearchExperiment must have a 'FrameTimeLimit' int"); _params.setFrameTimeLimit(val["FrameTimeLimit"].GetInt()); BOSS_ASSERT(val.HasMember("SearchTimeLimitMS") && val["SearchTimeLimitMS"].IsInt(), "CombatSearchExperiment must have a 'SearchTimeLimitMS' int"); _params.setSearchTimeLimit(val["SearchTimeLimitMS"].GetInt()); if (val.HasMember("MaxActions")) { const rapidjson::Value & maxActions = val["MaxActions"]; BOSS_ASSERT(maxActions.IsArray(), "MaxActions is not an array"); for (size_t i(0); i < maxActions.Size(); ++i) { BOSS_ASSERT(maxActions[i].IsArray(), "MaxActions element must be array of size 2"); BOSS_ASSERT(maxActions[i].Size() == 2 && maxActions[i][0u].IsString() && maxActions[i][1u].IsInt(), "MaxActions element must be [\"Action\", Count]"); BOSS_ASSERT(ActionTypes::TypeExists(maxActions[i][0u].GetString()), "Action Type doesn't exist: %s", maxActions[i][0u].GetString()); _params.setMaxActions(ActionTypes::GetActionType(maxActions[i][0u].GetString()), maxActions[i][1].GetInt()); } } if (val.HasMember("RelevantActions")) { const rapidjson::Value & relevantActions = val["RelevantActions"]; BOSS_ASSERT(relevantActions.IsArray(), "RelevantActions is not an array"); ActionSet relevantActionSet; for (size_t i(0); i < relevantActions.Size(); ++i) { BOSS_ASSERT(relevantActions[i].IsString(), "RelvantActions element must be action type string"); BOSS_ASSERT(ActionTypes::TypeExists(relevantActions[i].GetString()), "Action Type doesn't exist: %s", relevantActions[i].GetString()); relevantActionSet.add(ActionTypes::GetActionType(relevantActions[i].GetString())); } _params.setRelevantActions(relevantActionSet); } if (val.HasMember("AlwaysMakeWorkers")) { BOSS_ASSERT(val["AlwaysMakeWorkers"].IsBool(), "AlwaysMakeWorkers should be a bool"); _params.setAlwaysMakeWorkers(val["AlwaysMakeWorkers"].GetBool()); } if (val.HasMember("OpeningBuildOrder")) { BOSS_ASSERT(val["OpeningBuildOrder"].IsString(), "OpeningBuildOrder should be a string"); _params.setOpeningBuildOrder(BOSSParameters::Instance().GetBuildOrder(val["OpeningBuildOrder"].GetString())); } if (val.HasMember("BestResponseParams")) { const rapidjson::Value & brVal = val["BestResponseParams"]; BOSS_ASSERT(brVal.IsObject(), "BestResponseParams not an object"); BOSS_ASSERT(brVal.HasMember("EnemyState"), "bestResponseParams must have 'enemyState' string"); BOSS_ASSERT(brVal.HasMember("EnemyBuildOrder"), "bestResponseParams must have 'enemyBuildOrder' string"); BOSS_ASSERT(brVal.HasMember("EnemyState") && brVal["EnemyState"].IsString(), "bestResponseParams must have a 'EnemyState' string"); _params.setEnemyInitialState(BOSSParameters::Instance().GetState(brVal["EnemyState"].GetString())); BOSS_ASSERT(brVal.HasMember("EnemyBuildOrder") && brVal["EnemyBuildOrder"].IsString(), "BestResponseParams must have a 'EnemyBuildOrder' string"); _params.setEnemyBuildOrder(BOSSParameters::Instance().GetBuildOrder(brVal["EnemyBuildOrder"].GetString())); } } void CombatSearchExperiment::run() { static std::string stars = "************************************************"; for (size_t i(0); i < _searchTypes.size(); ++i) { std::shared_ptr combatSearch; std::string resultsFile = "gnuplot/" + _name; std::cout << "\n" << stars << "\n* Running Experiment: " << _name << " [" << _searchTypes[i] << "]\n" << stars << "\n"; if (_searchTypes[i].compare("Integral") == 0) { combatSearch = std::shared_ptr(new CombatSearch_Integral(_params)); resultsFile += "_Integral"; } else if (_searchTypes[i].compare("Bucket") == 0) { combatSearch = std::shared_ptr(new CombatSearch_Bucket(_params)); resultsFile += "_Bucket"; } else if (_searchTypes[i].compare("BestResponse") == 0) { combatSearch = std::shared_ptr(new CombatSearch_BestResponse(_params)); resultsFile += "_BestResponse"; } else { BOSS_ASSERT(false, "CombatSearch type not found: %s", _searchTypes[i].c_str()); } combatSearch->search(); combatSearch->printResults(); combatSearch->writeResultsFile(resultsFile); const CombatSearchResults & results = combatSearch->getResults(); std::cout << "\nSearched " << results.nodesExpanded << " nodes in " << results.timeElapsed << "ms @ " << (1000.0*results.nodesExpanded/results.timeElapsed) << " nodes/sec\n\n"; } } ================================================ FILE: BOSS/source/CombatSearchExperiment.h ================================================ #pragma once #include "BOSS.h" #include "JSONTools.h" #include #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace BOSS { class CombatSearchExperiment { std::string _name; CombatSearchParameters _params; RaceID _race; std::vector _searchTypes; RaceID _enemyRace; BuildOrder _enemyBuildOrder; public: CombatSearchExperiment(); CombatSearchExperiment(const std::string & name, const rapidjson::Value & experimentVal); void run(); }; } ================================================ FILE: BOSS/source/CombatSearchParameters.cpp ================================================ #include "CombatSearchParameters.h" using namespace BOSS; // alternate constructor CombatSearchParameters::CombatSearchParameters() : _useRepetitions (true) , _useIncreasingRepetitions (false) , _useWorkerCutoff (false) , _workerCutoff (1) , _useAlwaysMakeWorkers (false) , _useSupplyBounding (false) , _supplyBoundingThreshold (1) , _useLandmarkLowerBoundHeuristic(false) , _useResourceLowerBoundHeuristic(false) , _searchTimeLimit (0) , _initialUpperBound (0) , _initialState (Races::None) , _maxActions (Constants::MAX_ACTIONS, -1) , _repetitionValues (Constants::MAX_ACTIONS, 1) , _repetitionThresholds (Constants::MAX_ACTIONS, 0) , _printNewBest (false) { } void CombatSearchParameters::setSearchTimeLimit(const double timeLimitMS) { _searchTimeLimit = timeLimitMS; } double CombatSearchParameters::getSearchTimeLimit() const { return _searchTimeLimit; } void CombatSearchParameters::setRelevantActions(const ActionSet & set) { _relevantActions = set; } const ActionSet & CombatSearchParameters::getRelevantActions() const { return _relevantActions; } void CombatSearchParameters::setInitialState(const GameState & s) { _initialState = s; } const GameState & CombatSearchParameters::getInitialState() const { return _initialState; } void CombatSearchParameters::setEnemyInitialState(const GameState & s) { _enemyInitialState = s; } const GameState & CombatSearchParameters::getEnemyInitialState() const { return _enemyInitialState; } void CombatSearchParameters::setMaxActions(const ActionType & a, int max) { _maxActions[a.ID()] = max; } void CombatSearchParameters::setOpeningBuildOrder(const BuildOrder & buildOrder) { _openingBuildOrder = buildOrder; } const BuildOrder & CombatSearchParameters::getOpeningBuildOrder() const { return _openingBuildOrder; } void CombatSearchParameters::setEnemyBuildOrder(const BuildOrder & buildOrder) { _enemyBuildOrder = buildOrder; } const BuildOrder & CombatSearchParameters::getEnemyBuildOrder() const { return _enemyBuildOrder; } void CombatSearchParameters::setRepetitions(const ActionType & a,int repetitions) { _repetitionValues[a.ID()] = repetitions; } int CombatSearchParameters::getMaxActions(const ActionType & a) const { return _maxActions[a.ID()]; } int CombatSearchParameters::getRepetitions(const ActionType & a) const { return _repetitionValues[a.ID()]; } void CombatSearchParameters::setFrameTimeLimit(const FrameCountType limit) { _frameTimeLimit = limit; } void CombatSearchParameters::setAlwaysMakeWorkers(const bool flag) { _useAlwaysMakeWorkers = flag; } const bool CombatSearchParameters::getAlwaysMakeWorkers() const { return _useAlwaysMakeWorkers; } FrameCountType CombatSearchParameters::getFrameTimeLimit() const { return _frameTimeLimit; } void CombatSearchParameters::print() { printf("\n\nSearch Parameter Information\n\n"); printf("%s", _useRepetitions ? "\tUSE Repetitions\n" : ""); printf("%s", _useIncreasingRepetitions ? "\tUSE Increasing Repetitions\n" : ""); printf("%s", _useWorkerCutoff ? "\tUSE Worker Cutoff\n" : ""); printf("%s", _useLandmarkLowerBoundHeuristic ? "\tUSE Landmark Lower Bound\n" : ""); printf("%s", _useResourceLowerBoundHeuristic ? "\tUSE Resource Lower Bound\n" : ""); printf("%s", _useAlwaysMakeWorkers ? "\tUSE Always Make Workers\n" : ""); printf("%s", _useSupplyBounding ? "\tUSE Supply Bounding\n" : ""); printf("\n"); //for (int a = 0; a < ACTIONS.size(); ++a) //{ // if (repetitionValues[a] != 1) // { // printf("\tREP %7d %s\n", repetitionValues[a], ACTIONS[a].getName().c_str()); // } //} //for (int a = 0; a < ACTIONS.size(); ++a) //{ // if (repetitionThresholds[a] != 0) // { // printf("\tTHR %7d %s\n", repetitionThresholds[a], ACTIONS[a].getName().c_str()); // } //} printf("\n\n"); } ================================================ FILE: BOSS/source/CombatSearchParameters.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "BuildOrder.h" namespace BOSS { class CombatSearchParameters { void init(); Vec _maxActions; // Flag which determines whether or not doubling macro actions will be used in search. // Macro actions (see paper) trade suboptimality for decreasing search depth. For large // plans repetitions are necessary. For example, to make probes only build in twos // set useRepetitions = true and repetitionValues[probeAction] = 2 // // true: macro actions are used, stored in repetitionValues array // false: macro actions not used, all actions will be carried out once bool _useRepetitions; Vec _repetitionValues; // Flag which determines whether increasing repetitions will be used in search // Increasing repetitions means the reptition value will be 1 until we have at least // repetitionThresholds[a] count of action a. For example, setting: // repetitionThresholds[pylonAction] = 1, repetitionValues[pylonAction] = 2 // means that the first pylon will build on its own but all further pylons will // be built 2 at a time. // // true: increasing repetitions are used // false: increasing repetitions not used bool _useIncreasingRepetitions; Vec _repetitionThresholds; // Flag which determines whether or not we use worker cutoff pruning in search. // Worker cutoff pruning stops workers from being constructed after a certain number // of frames have passed in the search. Intuitively we build the majority of workers // at the beginning of a build, so this can enforce it to make search faster. If // true, workers are no longer legal if currentFrame > workerCutoff * uperBound // in our search algorithm. If workerCutoff is 1, workers will not be pruned. // // true: worker cutoff is used // false: worker cutoff not used bool _useWorkerCutoff; double _workerCutoff; // Flag which determines whether or not we always make workers during search // This abstraction changes the search so that it always makes a worker if it is able to. It // accomplished this by modifying the current legal actions to exclude anything that // can't be started before the next worker. This ends up producing longer makespans but // the economy it produces is much better. Optimal makespan plans often produce very // few workers and the long term economy suffers. // // true: always make workers is used // false: always make workers is not used bool _useAlwaysMakeWorkers; // Flag which determines whether or not we use supply bounding in our search // Supply bounding makes supply producing buildings illegal if we are currently ahead // on supply by a certain amount. If we currently have more than // supplyBoundingThreshold extra supply buildings worth of supply, we no longer // build them. This is an abstraction used to make search faster which may // produce suboptimal plans. // // true: supply bounding is used // false: supply bounding is not used bool _useSupplyBounding; int _supplyBoundingThreshold; // Flag which determines whether or not we use various heuristics in our search. // // true: the heuristic is used // false: the heuristic is not used bool _useLandmarkLowerBoundHeuristic; bool _useResourceLowerBoundHeuristic; // Search time limit measured in milliseconds // If searchTimeLimit is set to a value greater than zero, the search will effectively // time out and the best solution so far will be used in the results. This is // accomplished by throwing an exception if the time limit is hit. Time is checked // once every 1000 nodes expanded, as checking the time is slow. double _searchTimeLimit; // Initial upper bound for the DFBB search // If this value is set to zero, DFBB search will automatically determine an // appropriate upper bound using an upper bound heuristic. If it is non-zero, // it will use the value as an initial bound. int _initialUpperBound; // Initial GameState used for the search. See GameState.h for details GameState _initialState; BuildOrder _openingBuildOrder; GameState _enemyInitialState; BuildOrder _enemyBuildOrder; ActionSet _relevantActions; FrameCountType _frameTimeLimit; bool _printNewBest; public: // alternate constructor CombatSearchParameters(); void setRepetitions(const ActionType & a, int repetitions); int getRepetitions(const ActionType & a) const; void setMaxActions(const ActionType & a, int max); int getMaxActions(const ActionType & a) const; void setRelevantActions(const ActionSet & set); const ActionSet & getRelevantActions() const; void setInitialState(const GameState & s); const GameState & getInitialState() const; void setEnemyInitialState(const GameState & s); const GameState & getEnemyInitialState() const; void setOpeningBuildOrder(const BuildOrder & buildOrder); const BuildOrder & getOpeningBuildOrder() const; void setEnemyBuildOrder(const BuildOrder & buildOrder); const BuildOrder & getEnemyBuildOrder() const; void setSearchTimeLimit(const double timeLimitMS); double getSearchTimeLimit() const; void setFrameTimeLimit(const FrameCountType limit); FrameCountType getFrameTimeLimit() const; void setAlwaysMakeWorkers(const bool flag); const bool getAlwaysMakeWorkers() const; void print(); }; } ================================================ FILE: BOSS/source/CombatSearchResults.cpp ================================================ #include "CombatSearchResults.h" using namespace BOSS; CombatSearchResults::CombatSearchResults() : solved(false) , timedOut(false) , solutionLength(-1) , upperBound(-1) , lowerBound(-1) , nodesExpanded(0) , timeElapsed(0) , avgBranch(0) , minerals(0) , gas(0) , frameCompleted(0) , winner(Races::None) , highestEval(0) { } void CombatSearchResults::printResults(bool pbo) { printf("%12d%12d%12d%14llu%12.4lf%12.2lf%12.2lf ",upperBound,lowerBound,solutionLength,nodesExpanded,avgBranch,timeElapsed,(nodesExpanded/(timeElapsed/1000.0))); if (pbo) { printBuildOrder(); } printf("\n"); } void CombatSearchResults::printBuildOrder() { for (size_t i(0); i buildOrder; // the build order double highestEval; ResourceCountType minerals; ResourceCountType gas; FrameCountType frameCompleted; CombatSearchResults(); CombatSearchResults(bool s,int len,unsigned long long n,double t,std::vector solution); void printResults(bool pbo = true); void printBuildOrder(); }; } ================================================ FILE: BOSS/source/CombatSearch_BestResponse.cpp ================================================ #include "CombatSearch_BestResponse.h" using namespace BOSS; CombatSearch_BestResponse::CombatSearch_BestResponse(const CombatSearchParameters p) : _bestResponseData(p.getEnemyInitialState(), p.getEnemyBuildOrder()) { _params = p; BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, "Combat search initial state is invalid"); } void CombatSearch_BestResponse::recurse(const GameState & state, size_t depth) { if (timeLimitReached()) { throw BOSS_COMBATSEARCH_TIMEOUT; } _bestResponseData.update(_params.getInitialState(), state, _buildOrder); updateResults(state); if (isTerminalNode(state, depth)) { return; } ActionSet legalActions; generateLegalActions(state, legalActions, _params); for (UnitCountType a(0); a < (int)legalActions.size(); ++a) { size_t ri = legalActions.size() - 1 - a; GameState child(state); child.doAction(legalActions[ri]); _buildOrder.add(legalActions[ri]); recurse(child,depth+1); _buildOrder.pop_back(); } } void CombatSearch_BestResponse::printResults() { } #include "BuildOrderPlot.h" void CombatSearch_BestResponse::writeResultsFile(const std::string & filename) { BuildOrderPlot plot(_params.getInitialState(), _bestResponseData.getBestBuildOrder()); plot.writeRectanglePlot(filename + "_BestBuildOrder"); plot.writeArmyValuePlot(filename + "_BestArmyValue"); BuildOrderPlot plot2(_params.getEnemyInitialState(), _params.getEnemyBuildOrder()); plot2.writeRectanglePlot(filename + "_EnemyBuildOrder"); plot2.writeArmyValuePlot(filename + "_EnemyArmyValue"); } ================================================ FILE: BOSS/source/CombatSearch_BestResponse.h ================================================ #pragma once #include "Common.h" #include "Timer.hpp" #include "Eval.h" #include "BuildOrder.h" #include "CombatSearch.h" #include "CombatSearchParameters.h" #include "CombatSearchResults.h" #include "CombatSearch_BestResponseData.h" namespace BOSS { class CombatSearch_BestResponse : public CombatSearch { virtual void recurse(const GameState & s, size_t depth); CombatSearch_BestResponseData _bestResponseData; BuildOrder _bestBuildOrder; double compareBuildOrders(const GameState & selfState, const BuildOrder & selfBuildOrder, const GameState & enemyState, const BuildOrder & enemyBuildOrder); public: CombatSearch_BestResponse(const CombatSearchParameters p = CombatSearchParameters()); virtual void printResults(); virtual void writeResultsFile(const std::string & filename); }; } ================================================ FILE: BOSS/source/CombatSearch_BestResponseData.cpp ================================================ #include "CombatSearch_BestResponseData.h" using namespace BOSS; CombatSearch_BestResponseData::CombatSearch_BestResponseData(const GameState & enemyState, const BuildOrder & enemyBuildOrder) : _enemyInitialState(enemyState) , _enemyBuildOrder(enemyBuildOrder) , _bestEval(std::numeric_limits::max()) { // compute enemy army values calculateArmyValues(_enemyInitialState, _enemyBuildOrder, _enemyArmyValues); } void CombatSearch_BestResponseData::calculateArmyValues(const GameState & initialState, const BuildOrder & buildOrder, std::vector< std::pair > & values) { values.clear(); GameState state(initialState); for (size_t i(0); i < buildOrder.size(); ++i) { state.doAction(buildOrder[i]); values.push_back(std::pair(state.getCurrentFrame(), Eval::ArmyTotalResourceSum(state))); } } #include "BuildOrderPlot.h" void CombatSearch_BestResponseData::update(const GameState & initialState, const GameState & currentState, const BuildOrder & buildOrder) { double eval = compareBuildOrder(initialState, buildOrder); if (eval < _bestEval) { _bestEval = eval; _bestBuildOrder = buildOrder; _bestState = currentState; std::cout << eval/Constants::RESOURCE_SCALE << " " << _bestBuildOrder.getNameString(2) << std::endl; } } double CombatSearch_BestResponseData::compareBuildOrder(const GameState & initialState, const BuildOrder & buildOrder) { calculateArmyValues(initialState, buildOrder, _selfArmyValues); size_t selfIndex = 0; size_t enemyIndex = 0; double maxDiff = std::numeric_limits::lowest(); double sumDiff = 0; int n = 0; for (size_t ei(0); ei < _enemyArmyValues.size(); ++ei) { double enemyTime = _enemyArmyValues[ei].first; double enemyVal = _enemyArmyValues[ei].second; size_t selfIndex = 0; // find the corresponding self army value for this time for (size_t si(0); si < _selfArmyValues.size(); ++si) { if (enemyTime < _selfArmyValues[si].first) { break; } selfIndex = si; } double selfVal = _selfArmyValues[selfIndex].second; double diff = enemyVal - selfVal; maxDiff = std::max(maxDiff, diff); } return maxDiff; } size_t CombatSearch_BestResponseData::getStateIndex(const GameState & state) { FrameCountType frame = state.getCurrentFrame(); if (frame > _enemyStates.back().getCurrentFrame()) { return _enemyStates.size() - 1; } for (size_t i(0); i < _enemyStates.size(); ++i) { if (frame < _enemyStates[i].getCurrentFrame()) { return i; } } BOSS_ASSERT(false, "Should have found an index"); return 0; } const BuildOrder & CombatSearch_BestResponseData::getBestBuildOrder() const { return _bestBuildOrder; } ================================================ FILE: BOSS/source/CombatSearch_BestResponseData.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "Eval.h" #include "BuildOrder.h" namespace BOSS { class CombatSearch_BestResponseData { GameState _enemyInitialState; BuildOrder _enemyBuildOrder; std::vector _enemyStates; std::vector< std::pair > _enemyArmyValues; std::vector< std::pair > _selfArmyValues; double _bestEval; BuildOrder _bestBuildOrder; GameState _bestState; double compareBuildOrder(const GameState & state, const BuildOrder & buildOrder); size_t getStateIndex(const GameState & state); void calculateArmyValues(const GameState & state, const BuildOrder & buildOrder, std::vector< std::pair > & values); public: CombatSearch_BestResponseData(const GameState & enemyState, const BuildOrder & enemyBuildOrder); void update(const GameState & initialState, const GameState & currentState, const BuildOrder & buildOrder); const BuildOrder & getBestBuildOrder() const; }; } ================================================ FILE: BOSS/source/CombatSearch_Bucket.cpp ================================================ #include "CombatSearch_Bucket.h" using namespace BOSS; CombatSearch_Bucket::CombatSearch_Bucket(const CombatSearchParameters p) : _bucket(p.getFrameTimeLimit(), 200) { _params = p; BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, "Combat search initial state is invalid"); } void CombatSearch_Bucket::doSearch(const GameState & state, size_t depth) { if (timeLimitReached()) { throw BOSS_COMBATSEARCH_TIMEOUT; } updateResults(state); _bucket.update(state, _buildOrder); if (isTerminalNode(state, depth)) { return; } if (_bucket.isDominated(state)) { //return; } ActionSet legalActions; generateLegalActions(state, legalActions, _params); for (UnitCountType a(0); a < (int)legalActions.size(); ++a) { GameState child(state); child.doAction(legalActions[a]); _buildOrder.add(legalActions[a]); doSearch(child,depth+1); _buildOrder.pop_back(); } } void CombatSearch_Bucket::printResults() { _bucket.print(); } #include "BuildOrderPlot.h" void CombatSearch_Bucket::writeResultsFile(const std::string & filename) { BuildOrderPlot::WriteGnuPlot(filename + "_BucketResults", _bucket.getBucketResultsString(), " with steps"); // write the final build order data BuildOrderPlot plot(_params.getInitialState(), _bucket.getBucket(_bucket.numBuckets()-1).buildOrder); plot.writeArmyValuePlot(filename + "_FinalBucketArmyPlot"); plot.writeRectanglePlot(filename + "_FinalBucketBuildOrder"); } ================================================ FILE: BOSS/source/CombatSearch_Bucket.h ================================================ #pragma once #include "Common.h" #include "Timer.hpp" #include "Eval.h" #include "BuildOrder.h" #include "CombatSearch.h" #include "CombatSearchParameters.h" #include "CombatSearchResults.h" #include "CombatSearch_BucketData.h" namespace BOSS { class CombatSearch_Bucket : public CombatSearch { CombatSearch_BucketData _bucket; virtual void doSearch(const GameState & s, size_t depth); public: CombatSearch_Bucket(const CombatSearchParameters p = CombatSearchParameters()); virtual void printResults(); virtual void writeResultsFile(const std::string & filename); }; } ================================================ FILE: BOSS/source/CombatSearch_BucketData.cpp ================================================ #include "CombatSearch_BucketData.h" using namespace BOSS; // Combat Search Bucketing // // Computes and stores the build order which maximizes an evaluation function up to a given time interval [t0-t1] // The number of buckets and the frame limit determine the size of the buckets CombatSearch_BucketData::CombatSearch_BucketData(const FrameCountType frameLimit, const size_t numBuckets) : _buckets(numBuckets, BucketData()) , _frameLimit(frameLimit) { } const size_t CombatSearch_BucketData::numBuckets() const { return _buckets.size(); } const size_t CombatSearch_BucketData::getBucketIndex(const GameState & state) const { return (size_t)(((double)state.getCurrentFrame() / (double)_frameLimit) * _buckets.size()); } void CombatSearch_BucketData::update(const GameState & state, const BuildOrder & buildOrder) { if (state.getCurrentFrame() >= _frameLimit) { return; } BOSS_ASSERT(state.getCurrentFrame() <= _frameLimit, "State's frame exceeds bucket frame limit: (%d %d)", (int)state.getCurrentFrame(), (int)_frameLimit); // get the bucket index corresponding to the time of the current state finishing size_t bucketIndex = getBucketIndex(state); // evaluate the state with whatever value we want double eval = Eval::ArmyTotalResourceSum(state); // update the data if we have a new best value for this bucket BucketData & bucket = _buckets[bucketIndex]; if ((eval > bucket.eval) || ((eval == bucket.eval) && Eval::BuildOrderBetter(buildOrder, bucket.buildOrder))) { // update every bucket for which this is a new record for (size_t b=bucketIndex; b < _buckets.size(); ++b) { if (_buckets[b].eval >= eval) { break; } _buckets[b].eval = eval; _buckets[b].buildOrder = buildOrder; _buckets[b].state = state; } } } bool CombatSearch_BucketData::isDominated(const GameState & state) { return Eval::StateDominates(getBucketData(state).state, state); } BucketData & CombatSearch_BucketData::getBucketData(const GameState & state) { BOSS_ASSERT(getBucketIndex(state) < _buckets.size(), "State goes over bucket limit"); return _buckets[getBucketIndex(state)]; } void CombatSearch_BucketData::print() const { std::cout << "\n\nFinal CombatBucket results\n"; std::cout << "\n Frame Sec ArmyEval BuildOrder\n"; double maxEval = 0; for (size_t b(0); b<_buckets.size(); ++b) { if (_buckets[b].eval > maxEval) { maxEval = _buckets[b].eval; double frame = ((double)b / _buckets.size()) * _frameLimit; double sec = frame / 24; printf("%7d %7d %12.2lf ", (int)frame, (int)sec, _buckets[b].eval/Constants::RESOURCE_SCALE); std::cout << _buckets[b].buildOrder.getNameString(2) << std::endl; } } } const BucketData & CombatSearch_BucketData::getBucket(const size_t index) const { return _buckets[index]; } std::string CombatSearch_BucketData::getBucketResultsString() { std::stringstream ss; ss << "0 0" << std::endl; double maxEval = 0; for (size_t b(0); b<_buckets.size(); ++b) { if (_buckets[b].eval > maxEval) { maxEval = _buckets[b].eval; double frame = ((double)b / _buckets.size()) * _frameLimit; double sec = frame / 24; ss << frame << " " << _buckets[b].eval/Constants::RESOURCE_SCALE << std::endl; } } return ss.str(); } ================================================ FILE: BOSS/source/CombatSearch_BucketData.h ================================================ #pragma once #include "BuildOrder.h" #include "Common.h" #include "GameState.h" #include "Eval.h" namespace BOSS { class BucketData { public: double eval; BuildOrder buildOrder; GameState state; BucketData() : eval(0) { } }; class CombatSearch_BucketData { std::vector _buckets; FrameCountType _frameLimit; BucketData & getBucketData(const GameState & state); public: CombatSearch_BucketData(const FrameCountType frameLimit, const size_t numBuckets); const BucketData & getBucket(const size_t index) const; const size_t numBuckets() const; const size_t getBucketIndex(const GameState & state) const; void update(const GameState & state, const BuildOrder & buildOrder); bool isDominated(const GameState & state); void print() const; std::string getBucketResultsString(); }; } ================================================ FILE: BOSS/source/CombatSearch_Integral.cpp ================================================ #include "CombatSearch_Integral.h" using namespace BOSS; CombatSearch_Integral::CombatSearch_Integral(const CombatSearchParameters p) { _params = p; BOSS_ASSERT(_params.getInitialState().getRace() != Races::None, "Combat search initial state is invalid"); } void CombatSearch_Integral::doSearch(const GameState & state, size_t depth) { if (timeLimitReached()) { throw BOSS_COMBATSEARCH_TIMEOUT; } updateResults(state); if (isTerminalNode(state, depth)) { return; } ActionSet legalActions; generateLegalActions(state, legalActions, _params); for (UnitCountType a(0); a < (int)legalActions.size(); ++a) { const UnitCountType index = legalActions.size()-1-a; GameState child(state); child.doAction(legalActions[index]); _buildOrder.add(legalActions[index]); _integral.update(state, _buildOrder); doSearch(child,depth+1); _buildOrder.pop_back(); _integral.pop(); } } void CombatSearch_Integral::printResults() { _integral.print(); } #include "BuildOrderPlot.h" void CombatSearch_Integral::writeResultsFile(const std::string & filename) { BuildOrderPlot plot(_params.getInitialState(), _integral.getBestBuildOrder()); plot.writeResourcePlot(filename + "_Resources"); plot.writeRectanglePlot(filename + "_BuildOrder"); plot.writeArmyValuePlot(filename + "_ArmyValue"); } ================================================ FILE: BOSS/source/CombatSearch_Integral.h ================================================ #pragma once #include "Common.h" #include "Timer.hpp" #include "Eval.h" #include "BuildOrder.h" #include "CombatSearch.h" #include "CombatSearchParameters.h" #include "CombatSearchResults.h" #include "CombatSearch_IntegralData.h" namespace BOSS { class CombatSearch_Integral : public CombatSearch { CombatSearch_IntegralData _integral; virtual void doSearch(const GameState & s, size_t depth); public: CombatSearch_Integral(const CombatSearchParameters p = CombatSearchParameters()); virtual void printResults(); virtual void writeResultsFile(const std::string & filename); }; } ================================================ FILE: BOSS/source/CombatSearch_IntegralData.cpp ================================================ #include "CombatSearch_IntegralData.h" using namespace BOSS; CombatSearch_IntegralData::CombatSearch_IntegralData() : _bestIntegralValue(0) { _integralStack.push_back(IntegralData(0,0,0)); } void CombatSearch_IntegralData::update(const GameState & state, const BuildOrder & buildOrder) { double value = Eval::ArmyTotalResourceSum(state); double timeElapsed = state.getCurrentFrame() - _integralStack.back().timeAdded; double valueToAdd = _integralStack.back().eval * timeElapsed; IntegralData entry(value, _integralStack.back().integral + valueToAdd, state.getCurrentFrame()); _integralStack.push_back(entry); // we have found a new best if: // 1. the new army integral is higher than the previous best // 2. the new army integral is the same as the old best but the build order is 'better' if ( (_integralStack.back().integral > _bestIntegralValue) || ((_integralStack.back().integral == _bestIntegralValue) && Eval::BuildOrderBetter(buildOrder, _bestIntegralBuildOrder))) { _bestIntegralValue = _integralStack.back().integral; _bestIntegralStack = _integralStack; _bestIntegralBuildOrder = buildOrder; // print the newly found best to console printIntegralData(_integralStack.size()-1); } } void CombatSearch_IntegralData::pop() { _integralStack.pop_back(); } void CombatSearch_IntegralData::printIntegralData(const size_t index) const { printf("%7d %10.2lf %13.2lf ", _bestIntegralStack[index].timeAdded, _bestIntegralStack[index].eval/Constants::RESOURCE_SCALE, _bestIntegralStack[index].integral/Constants::RESOURCE_SCALE); std::cout << _bestIntegralBuildOrder.getNameString(2) << std::endl; } void CombatSearch_IntegralData::print() const { std::cout << "\nFinal CombatSearchIntegral Results\n\n"; std::cout << " Frame ArmyEval ArmyIntegral BuildOrder\n"; for (size_t i(0); i<_bestIntegralStack.size(); ++i) { printIntegralData(i); } } const BuildOrder & CombatSearch_IntegralData::getBestBuildOrder() const { return _bestIntegralBuildOrder; } ================================================ FILE: BOSS/source/CombatSearch_IntegralData.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "Eval.h" #include "BuildOrder.h" namespace BOSS { class IntegralData { public: double eval; double integral; FrameCountType timeAdded; IntegralData(double e, double i, FrameCountType t) : eval(e) , integral(i) , timeAdded(t) { } IntegralData() : eval(0) , integral(0) , timeAdded(0) { } }; class CombatSearch_IntegralData { std::vector _integralStack; std::vector _bestIntegralStack; double _bestIntegralValue; BuildOrder _bestIntegralBuildOrder; public: CombatSearch_IntegralData(); void update(const GameState & state, const BuildOrder & buildOrder); void pop(); void printIntegralData(const size_t index) const; void print() const; const BuildOrder & getBestBuildOrder() const; }; } ================================================ FILE: BOSS/source/Common.h ================================================ #pragma once #include "BWAPI.h" #include #include #include #include #include #include #include #include #include "BOSSAssert.h" #include "BaseTypes.h" #include "Constants.h" ================================================ FILE: BOSS/source/Constants.cpp ================================================ #include "Constants.h" #include "Common.h" namespace BOSS { namespace Races { RaceID GetRaceID(BWAPI::Race r) { if (r == BWAPI::Races::Protoss) { return Races::Protoss; } else if (r == BWAPI::Races::Terran) { return Races::Terran; } else if (r == BWAPI::Races::Zerg) { return Races::Zerg; } else { return Races::None; } } BWAPI::Race GetRace(RaceID id) { if (id == Races::Protoss) { return BWAPI::Races::Protoss; } else if (id == Races::Terran) { return BWAPI::Races::Terran; } else if (id == Races::Zerg) { return BWAPI::Races::Zerg; } else { return BWAPI::Races::None; } } RaceID GetRaceID(const std::string & race) { if (race.compare("Protoss") == 0) { return Races::Protoss; } else if (race.compare("Terran") == 0) { return Races::Terran; } else if (race.compare("Zerg") == 0) { return Races::Zerg; } else { return Races::None; } } std::string GetRaceName(RaceID race) { if (race == Races::Protoss) { return "Protoss"; } else if (race == Races::Terran) { return "Terran"; } else if (race == Races::Zerg) { return "Zerg"; } else { return "None"; } } } } ================================================ FILE: BOSS/source/Constants.h ================================================ #pragma once #include "BWAPI.h" #include "BaseTypes.h" namespace BOSS { namespace Constants { const size_t MAX_ACTIONS = 64; // maximum number of actions allowed in StarcraftData const size_t MAX_PROGRESS = 50; // maximum number of actions in progress allowed const size_t MAX_BUILDINGS = 70; // maximum number of buildings allowed const size_t BUILDING_ERROR = -2; // building error return code const size_t MAX_HATCHERIES = 10; // maximum number of hatcheries allowed const size_t ZERG_LARVA_TIMER = 336; // number of frames between zerg larva spawn const size_t BUILDING_PLACEMENT = 24 * 5; // number of frames to use for building placement const size_t MAX_OF_ACTION = 200; const size_t NUM_HASHES = 2; const size_t MPWPF = 45; const size_t GPWPF = 70; const size_t RESOURCE_SCALE = 1000; const size_t MAX_ACTION_TYPES = 100; const size_t ZERG_LARVA_ID = 255; } namespace Races { enum {Protoss, Terran, Zerg, NUM_RACES, None}; RaceID GetRaceID(BWAPI::Race r); BWAPI::Race GetRace(RaceID id); RaceID GetRaceID(const std::string & race); std::string GetRaceName(RaceID race); } } ================================================ FILE: BOSS/source/DFBB_BuildOrderSearchParameters.cpp ================================================ #include "DFBB_BuildOrderSearchParameters.h" using namespace BOSS; // alternate constructor DFBB_BuildOrderSearchParameters::DFBB_BuildOrderSearchParameters(const RaceID & r) : race(r) , useRepetitions(true) , useIncreasingRepetitions(false) , useAlwaysMakeWorkers(false) , useSupplyBounding(false) , supplyBoundingThreshold(1) , useLandmarkLowerBoundHeuristic(true) , useResourceLowerBoundHeuristic(true) , searchTimeLimit(0) , initialUpperBound(0) , repetitionValues(Constants::MAX_ACTIONS, 1) , repetitionThresholds(Constants::MAX_ACTIONS, 0) , goal(r) { } void DFBB_BuildOrderSearchParameters::setRepetitions(const ActionType & a, const UnitCountType & repetitions) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionValues.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == race, "Action type race doesn't match this parameter object"); repetitionValues[a.ID()] = repetitions; } void DFBB_BuildOrderSearchParameters::setRepetitionThreshold(const ActionType & a, const UnitCountType & thresh) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionThresholds.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == race, "Action type race doesn't match this parameter object"); repetitionThresholds[a.ID()] = thresh; } const UnitCountType & DFBB_BuildOrderSearchParameters::getRepetitions(const ActionType & a) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionValues.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == race, "Action type race doesn't match this parameter object"); return repetitionValues[a.ID()]; } const UnitCountType & DFBB_BuildOrderSearchParameters::getRepetitionThreshold(const ActionType & a) { BOSS_ASSERT(a.ID() >= 0 && a.ID() < (int)repetitionThresholds.size(), "Action type not valid"); BOSS_ASSERT(a.getRace() == race, "Action type race doesn't match this parameter object"); return repetitionThresholds[a.ID()]; } std::string DFBB_BuildOrderSearchParameters::toString() const { std::stringstream ss; ss << "\n\nSearch Parameter Information\n\n"; ss << (useRepetitions ? "\tUSE Repetitions\n" : ""); ss << (useIncreasingRepetitions ? "\tUSE Increasing Repetitions\n" : ""); ss << (useLandmarkLowerBoundHeuristic ? "\tUSE Landmark Lower Bound\n" : ""); ss << (useResourceLowerBoundHeuristic ? "\tUSE Resource Lower Bound\n" : ""); ss << (useAlwaysMakeWorkers ? "\tUSE Always Make Workers\n" : ""); ss << (useSupplyBounding ? "\tUSE Supply Bounding\n" : ""); ss << ("\n"); for (ActionID a(0); a < (int)repetitionValues.size(); ++a) { if (repetitionValues[a] != 1) { ss << "\tREP " << repetitionValues[a] << " " << ActionTypes::GetActionType(race, a).getName() << "\n"; } } for (ActionID a(0); a < (int)repetitionThresholds.size(); ++a) { if (repetitionThresholds[a] != 0) { ss << "\tTHR " << repetitionThresholds[a] << " " << ActionTypes::GetActionType(race, a).getName() << "\n"; } } ss << "\n\n" << goal.toString(); ss << "\n\n" << initialState.toString(); for (size_t i(0); i < relevantActions.size(); ++i) { ss << "Relevant: " << relevantActions[i].getName() << "\n"; } ss << "\n\n" << initialState.getUnitData().getBuildingData().toString(); return ss.str(); } ================================================ FILE: BOSS/source/DFBB_BuildOrderSearchParameters.h ================================================ #pragma once #include "Common.h" #include "BuildOrderSearchGoal.h" #include "GameState.h" #include "DFBB_BuildOrderSearchSaveState.h" namespace BOSS { class DFBB_BuildOrderSearchParameters { void init(); public: RaceID race; // Flag which determines whether or not doubling macro actions will be used in search. // Macro actions (see paper) trade suboptimality for decreasing search depth. For large // plans repetitions are necessary. For example, to make probes only build in twos // set useRepetitions = true and repetitionValues[probeAction] = 2 // // true: macro actions are used, stored in repetitionValues array // false: macro actions not used, all actions will be carried out once bool useRepetitions; Vec repetitionValues; // Flag which determines whether increasing repetitions will be used in search // Increasing repetitions means the reptition value will be 1 until we have at least // repetitionThresholds[a] count of action a. For example, setting: // repetitionThresholds[pylonAction] = 1, repetitionValues[pylonAction] = 2 // means that the first pylon will build on its own but all further pylons will // be built 2 at a time. // // true: increasing repetitions are used // false: increasing repetitions not used bool useIncreasingRepetitions; Vec repetitionThresholds; // Flag which determines whether or not we always make workers during search // This abstraction changes the search so that it always makes a worker if it is able to. It // accomplished this by modifying the current legal actions to exclude anything that // can't be started before the next worker. This ends up producing longer makespans but // the economy it produces is much better. Optimal makespan plans often produce very // few workers and the long term economy suffers. // // true: always make workers is used // false: always make workers is not used bool useAlwaysMakeWorkers; // Flag which determines whether or not we use supply bounding in our search // Supply bounding makes supply producing buildings illegal if we are currently ahead // on supply by a certain amount. If we currently have more than // supplyBoundingThreshold extra supply buildings worth of supply, we no longer // build them. This is an abstraction used to make search faster which may // produce suboptimal plans. // // true: supply bounding is used // false: supply bounding is not used bool useSupplyBounding; double supplyBoundingThreshold; // Flag which determines whether or not we use various heuristics in our search. // // true: the heuristic is used // false: the heuristic is not used bool useLandmarkLowerBoundHeuristic; bool useResourceLowerBoundHeuristic; // Search time limit measured in milliseconds // If searchTimeLimit is set to a value greater than zero, the search will effectively // time out and the best solution so far will be used in the results. This is // accomplished by throwing an exception if the time limit is hit. Time is checked // once every 1000 nodes expanded, as checking the time is slow. double searchTimeLimit; // Initial upper bound for the DFBB search // If this value is set to zero, DFBB search will automatically determine an // appropriate upper bound using an upper bound heuristic. If it is non-zero, // it will use the value as an initial bound. int initialUpperBound; // StarcraftSearchGoal used for the search. See StarcraftSearchGoal.hpp for details BuildOrderSearchGoal goal; // Initial StarcraftState used for the search. See StarcraftState.hpp for details GameState initialState; ActionSet relevantActions; // alternate constructor DFBB_BuildOrderSearchParameters(const RaceID & r = Races::None); void setMaxActions(const ActionType & a,const UnitCountType & max); void setRepetitions(const ActionType & a,const UnitCountType & repetitions); void setRepetitionThreshold(const ActionType & a,const UnitCountType & thresh); const UnitCountType & getRepetitions(const ActionType & a); const UnitCountType & getMaxActions(const ActionType & a); const UnitCountType & getRepetitionThreshold(const ActionType & a); std::string toString() const; }; } ================================================ FILE: BOSS/source/DFBB_BuildOrderSearchResults.cpp ================================================ #include "DFBB_BuildOrderSearchResults.h" using namespace BOSS; DFBB_BuildOrderSearchResults::DFBB_BuildOrderSearchResults() : solved(false) , timedOut(false) , solutionFound(false) , upperBound(0) , nodesExpanded(0) , timeElapsed(0) { } void DFBB_BuildOrderSearchResults::printResults(bool pbo) const { printf("%12d%14llu%12.2lf ",upperBound,nodesExpanded,timeElapsed); if (pbo) { printBuildOrder(); } printf("\n"); } void DFBB_BuildOrderSearchResults::printBuildOrder() const { for (size_t i(0); i solution); void printResults(bool pbo = true) const; void printBuildOrder() const; }; } ================================================ FILE: BOSS/source/DFBB_BuildOrderSearchSaveState.cpp ================================================ //#include "DFBB_BuildOrderSearchSaveState.h" // //using namespace BOSS; // //DFBBSearchSaveState::DFBBSearchSaveState() // : depth(0) //{ //} // //DFBBSearchSaveState::DFBBSearchSaveState(const std::vector & buildOrder, int ub) // : upperBound(ub) //{ // // set the depth equal to the size of the build order vector // depth = buildOrder.size(); // // // copy the values of the vector into the array (backwards due to buildorder vector being backwards) // for (size_t i(0); i & buildOrder, int ub); int getUpperBound() const; int operator [] (const int index) const; int getDepth() const; int getAction(const int d) const; void print() const; }; } ================================================ FILE: BOSS/source/DFBB_BuildOrderSmartSearch.cpp ================================================ #include "DFBB_BuildOrderSmartSearch.h" using namespace BOSS; DFBB_BuildOrderSmartSearch::DFBB_BuildOrderSmartSearch(const RaceID race) : _race(race) , _params(race) , _goal(race) , _stackSearch(race) , _searchTimeLimit(30) { } void DFBB_BuildOrderSmartSearch::doSearch() { BOSS_ASSERT(_initialState.getRace() != Races::None, "Must set initial state before performing search"); // if we are resuming a search if (_stackSearch.getResults().timedOut) { _stackSearch.setTimeLimit(_searchTimeLimit); _stackSearch.search(); } else { calculateSearchSettings(); _params.goal = _goal; _params.initialState = _initialState; _params.useRepetitions = true; _params.useIncreasingRepetitions = true; _params.useAlwaysMakeWorkers = true; _params.useSupplyBounding = true; _params.supplyBoundingThreshold = 1.5; _params.relevantActions = _relevantActions; _params.searchTimeLimit = _searchTimeLimit; //BWAPI::Broodwar->printf("Constructing new search object time limit is %lf", _params.searchTimeLimit); _stackSearch = DFBB_BuildOrderStackSearch(_params); _stackSearch.search(); } _results = _stackSearch.getResults(); if (_results.solved && !_results.solutionFound) { //std::cout << "No solution found better than naive, using naive build order" << std::endl; //_results.buildOrder = Tools::GetOptimizedNaiveBuildOrder(_params.initialState, _params.goal); } } void DFBB_BuildOrderSmartSearch::calculateSearchSettings() { // set the max number of resource depots to what we have since no expanding is allowed const ActionType & resourceDepot = ActionTypes::GetResourceDepot(getRace()); const ActionType & refinery = ActionTypes::GetRefinery(getRace()); const ActionType & worker = ActionTypes::GetWorker(getRace()); const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(getRace()); _goal.setGoalMax(resourceDepot, _initialState.getUnitData().getNumTotal(resourceDepot)); // set the number of refineries _goal.setGoalMax(refinery, std::min((UnitCountType)3, calculateRefineriesRequired())); // set the maximum number of workers to an initial ridiculously high upper bound _goal.setGoalMax(worker, std::min((int)_initialState.getUnitData().getNumTotal(worker) + 20, 100)); // set the number of supply providers required _goal.setGoalMax(supplyProvider, calculateSupplyProvidersRequired()); // set the maximums for all goal prerequisites setPrerequisiteGoalMax(); // set relevant actions setRelevantActions(); // set the repetitions setRepetitions(); int maxWorkers = 45; if (_goal.getGoal(worker) > maxWorkers) { _goal.setGoal(worker, maxWorkers); } if (_goal.getGoalMax(worker) > maxWorkers) { _goal.setGoalMax(worker, maxWorkers); } } // calculates maximum number of refineries we'll need UnitCountType DFBB_BuildOrderSmartSearch::calculateRefineriesRequired() { const ActionType & refinery = ActionTypes::GetRefinery(getRace()); const ActionType & resourceDepot = ActionTypes::GetResourceDepot(getRace()); if (_goal.getGoal(refinery)) { return _goal.getGoal(refinery); } // loop to check if we need gas bool gasRequired = false; for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); if (_goal.getGoal(actionType) > 0 && actionType.gasPrice() > 0) { gasRequired = true; break; } } return gasRequired ? _initialState.getUnitData().getNumTotal(resourceDepot) : 0; } // handles all goalMax calculations for prerequisites of goal actions void DFBB_BuildOrderSmartSearch::setPrerequisiteGoalMax() { if (getRace() == Races::Protoss || getRace() == Races::Terran) { // for each unit in the goal vector for (const auto & actionType : ActionTypes::GetAllActionTypes(getRace())) { // if we want one of these if (_goal.getGoal(actionType) > 0) { // set goalMax for each strict dependency equal to 1 recurseOverStrictDependencies(actionType); } } // vector which stores the number of goal units which are built by [index] std::vector numGoalUnitsBuiltBy(ActionTypes::GetAllActionTypes(getRace()).size(), 0); for (size_t a(0); a < numGoalUnitsBuiltBy.size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); if (_goal.getGoal(actionType) > 0) { // add this to the sum numGoalUnitsBuiltBy[actionType.whatBuildsAction()] += _goal.getGoal(actionType); // if it's in the goal, make sure it's in the max _goal.setGoalMax(actionType, std::max(_goal.getGoal(actionType), _goal.getGoalMax(actionType))); } } UnitCountType additionalProductionBuildingLimit = 2; for (size_t a(0); a < numGoalUnitsBuiltBy.size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); // if it's not a resource depot if (!actionType.isResourceDepot() && actionType.isBuilding()) { // if this building produces units if (numGoalUnitsBuiltBy[actionType.ID()] > 0) { // set the goal max to how many units _goal.setGoalMax(actionType, std::min(_initialState.getUnitData().getNumTotal(actionType) + additionalProductionBuildingLimit, (int)numGoalUnitsBuiltBy[actionType.ID()])); } } } // set the upper bound on addons to the upper bound on the building that makes them for (const auto & actionType : ActionTypes::GetAllActionTypes(getRace())) { if (actionType.isAddon() && _goal.getGoalMax(actionType) > 0) { const ActionType & whatBuilds = actionType.whatBuildsActionType(); if (_goal.getGoalMax(whatBuilds) > 0) { _goal.setGoalMax(actionType, _goal.getGoalMax(whatBuilds)); } } } } else if (getRace() == Races::Zerg) { _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Spawning_Pool"), 1); _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Extractor"), 1); _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Lair"), 1); _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Spire"), 1); _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Hydralisk_Den"), 1); } } // recursively checks the tech tree of Action and sets each to have goalMax of 1 void DFBB_BuildOrderSmartSearch::recurseOverStrictDependencies(const ActionType & actionType) { if (actionType.isResourceDepot() || actionType.isWorker() || actionType.isSupplyProvider() || actionType.isRefinery()) { return; } PrerequisiteSet recursivePrerequisites = actionType.getRecursivePrerequisites(); for (size_t a(0); a < recursivePrerequisites.size(); ++a) { const ActionType & actionType = recursivePrerequisites.getActionType(a); if (actionType.isResourceDepot() ||actionType.isWorker() || actionType.isSupplyProvider() || actionType.isRefinery()) { continue; } _goal.setGoalMax(actionType, std::max((UnitCountType)1, _goal.getGoalMax(actionType))); } } void DFBB_BuildOrderSmartSearch::setRelevantActions() { _relevantActions.clear(); for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); if (_goal.getGoalMax(actionType) > 0 || _goal.getGoal(actionType) > 0) { _relevantActions.add(actionType); } } } UnitCountType DFBB_BuildOrderSmartSearch::calculateSupplyProvidersRequired() { const ActionType & resourceDepot = ActionTypes::GetResourceDepot(getRace()); const ActionType & worker = ActionTypes::GetWorker(getRace()); const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(getRace()); // calculate the upper bound on supply for this goal int supplyNeeded = _goal.getGoalMax(worker) * worker.supplyRequired(); // for each prerequisite of things in the goal which aren't production facilities set one of for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); // add the supply required for this number of goal units and all units currently made supplyNeeded += std::max(_goal.getGoal(actionType), _initialState.getUnitData().getNumTotal(actionType)) * actionType.supplyRequired(); } // set the upper bound on supply based on these values UnitCountType supplyFromResourceDepots = _initialState.getUnitData().getNumTotal(resourceDepot) * resourceDepot.supplyProvided(); // take this away from the supply needed supplyNeeded -= supplyFromResourceDepots; // return the number of supply providers required return supplyNeeded > 0 ? (UnitCountType)ceil((double)supplyNeeded / (double)supplyProvider.supplyProvided()) : 0; } void DFBB_BuildOrderSmartSearch::setRepetitions() { //const ActionType & resourceDepot = ActionTypes::GetResourceDepot(getRace()); //const ActionType & refinery = ActionTypes::GetRefinery(getRace()); //const ActionType & worker = ActionTypes::GetWorker(getRace()); //const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(getRace()); //_params.setRepetitions(supplyProvider, 1); //_params.setRepetitionThreshold(supplyProvider, 3); // for each action for (size_t a(0); a < ActionTypes::GetAllActionTypes(getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(getRace(), a); // if if want 4 or more of something that isn't supply providing if (!actionType.isSupplyProvider() && _goal.getGoal(actionType) >= 5) { // set the repetitions to half of the value _params.setRepetitions(actionType, std::min((UnitCountType)4, (UnitCountType)(_goal.getGoal(actionType) / 2))); _params.setRepetitions(actionType.whatBuildsActionType(), 2); _params.setRepetitionThreshold(actionType.whatBuildsActionType(), 1); } } } const RaceID DFBB_BuildOrderSmartSearch::getRace() const { return _race; } void DFBB_BuildOrderSmartSearch::addGoal(const ActionType & a, const UnitCountType count) { _goal.setGoal(a,count); } void DFBB_BuildOrderSmartSearch::setGoal(const BuildOrderSearchGoal & g) { _goal = g; } void DFBB_BuildOrderSmartSearch::setState(const GameState & state) { _initialState = state; } void DFBB_BuildOrderSmartSearch::setTimeLimit(int n) { _searchTimeLimit = n; } void DFBB_BuildOrderSmartSearch::search() { doSearch(); } const DFBB_BuildOrderSearchResults & DFBB_BuildOrderSmartSearch::getResults() const { return _results; } const DFBB_BuildOrderSearchParameters & DFBB_BuildOrderSmartSearch::getParameters() { calculateSearchSettings(); _params.goal = _goal; _params.initialState = _initialState; _params.useRepetitions = true; _params.useIncreasingRepetitions = true; _params.useAlwaysMakeWorkers = true; _params.useSupplyBounding = true; return _params; } void DFBB_BuildOrderSmartSearch::print() { //initialState.printData(); printf("\n\n"); } ================================================ FILE: BOSS/source/DFBB_BuildOrderSmartSearch.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "DFBB_BuildOrderStackSearch.h" #include "Timer.hpp" namespace BOSS { class DFBB_BuildOrderSmartSearch { RaceID _race; DFBB_BuildOrderSearchParameters _params; BuildOrderSearchGoal _goal; ActionSet _relevantActions; GameState _initialState; int _searchTimeLimit; Timer _searchTimer; DFBB_BuildOrderStackSearch _stackSearch; DFBB_BuildOrderSearchResults _results; void doSearch(); void calculateSearchSettings(); void setPrerequisiteGoalMax(); void recurseOverStrictDependencies(const ActionType & action); void setRelevantActions(); void setRepetitions(); UnitCountType calculateSupplyProvidersRequired(); UnitCountType calculateRefineriesRequired(); const RaceID getRace() const; public: DFBB_BuildOrderSmartSearch(const RaceID race); void addGoal(const ActionType & a, const UnitCountType count); void setGoal(const BuildOrderSearchGoal & goal); void setState(const GameState & state); void print(); void setTimeLimit(int n); void search(); const DFBB_BuildOrderSearchResults & getResults() const; const DFBB_BuildOrderSearchParameters & getParameters(); }; } ================================================ FILE: BOSS/source/DFBB_BuildOrderStackSearch.cpp ================================================ #include "DFBB_BuildOrderStackSearch.h" using namespace BOSS; DFBB_BuildOrderStackSearch::DFBB_BuildOrderStackSearch(const DFBB_BuildOrderSearchParameters & p) : _params(p) , _depth(0) , _firstSearch(true) , _wasInterrupted(false) , _stack(100, StackData()) { } void DFBB_BuildOrderStackSearch::setTimeLimit(double ms) { _params.searchTimeLimit = ms; } // function which is called to do the actual search void DFBB_BuildOrderStackSearch::search() { _searchTimer.start(); if (!_results.solved) { if (_firstSearch) { _results.upperBound = _params.initialUpperBound ? _params.initialUpperBound : Tools::GetUpperBound(_params.initialState, _params.goal); // add one frame to the upper bound so our strictly lesser than check still works if we have an exact upper bound _results.upperBound += 1; _stack[0].state = _params.initialState; _firstSearch = false; //BWAPI::Broodwar->printf("Upper bound is %d", _results.upperBound); //std::cout << "Upper bound is: " << _results.upperBound << std::endl; } try { // search on the initial state DFBB(); _results.timedOut = false; } catch (int e) { if (e == DFBB_TIMEOUT_EXCEPTION) { //BWAPI::Broodwar->printf("I timed out!"); _results.timedOut = true; } } double ms = _searchTimer.getElapsedTimeInMilliSec(); _results.solved = !_results.timedOut; _results.timeElapsed = ms; } } const DFBB_BuildOrderSearchResults & DFBB_BuildOrderStackSearch::getResults() const { return _results; } void DFBB_BuildOrderStackSearch::generateLegalActions(const GameState & state, ActionSet & legalActions) { legalActions.clear(); BuildOrderSearchGoal & goal = _params.goal; const ActionType & worker = ActionTypes::GetWorker(state.getRace()); // add all legal relevant actions that are in the goal for (size_t a(0); a < _params.relevantActions.size(); ++a) { const ActionType & actionType = _params.relevantActions[a]; const std::string & actionName = actionType.getName(); const size_t numTotal = state.getUnitData().getNumTotal(actionType); if (state.isLegal(actionType)) { // if there's none of this action in the goal it's not legal if (!goal.getGoal(actionType) && !goal.getGoalMax(actionType)) { continue; } // if we already have more than the goal it's not legal if (goal.getGoal(actionType) && ((int)numTotal >= goal.getGoal(actionType))) { continue; } // if we already have more than the goal max it's not legal if (goal.getGoalMax(actionType) && ((int)numTotal >= goal.getGoalMax(actionType))) { continue; } legalActions.add(_params.relevantActions[a]); } } // if we enabled the supply bounding flag if (_params.useSupplyBounding) { UnitCountType supplySurplus = state.getUnitData().getMaxSupply() + state.getUnitData().getSupplyInProgress() - state.getUnitData().getCurrentSupply(); UnitCountType threshold = (UnitCountType)(ActionTypes::GetSupplyProvider(state.getRace()).supplyProvided() * _params.supplyBoundingThreshold); if (supplySurplus >= threshold) { legalActions.remove(ActionTypes::GetSupplyProvider(state.getRace())); } } // if we enabled the always make workers flag, and workers are legal if (_params.useAlwaysMakeWorkers && legalActions.contains(worker)) { bool actionLegalBeforeWorker = false; ActionSet legalEqualWorker; FrameCountType workerReady = state.whenCanPerform(worker); for (size_t a(0); a < legalActions.size(); ++a) { const ActionType & actionType = legalActions[a]; const FrameCountType whenCanPerformAction = state.whenCanPerform(actionType); if (whenCanPerformAction < workerReady) { actionLegalBeforeWorker = true; break; } if ((whenCanPerformAction == workerReady) && (actionType.mineralPrice() == worker.mineralPrice())) { legalEqualWorker.add(actionType); } } if (actionLegalBeforeWorker) { legalActions.remove(worker); } else { legalActions = legalEqualWorker; } } } UnitCountType DFBB_BuildOrderStackSearch::getRepetitions(const GameState & state, const ActionType & a) { // set the repetitions if we are using repetitions, otherwise set to 1 int repeat = _params.useRepetitions ? _params.getRepetitions(a) : 1; // if we are using increasing repetitions if (_params.useIncreasingRepetitions) { // if we don't have the threshold amount of units, use a repetition value of 1 repeat = state.getUnitData().getNumTotal(a) >= _params.getRepetitionThreshold(a) ? repeat : 1; } // make sure we don't repeat to more than we need for this unit type if (_params.goal.getGoal(a)) { repeat = std::min(repeat, (int)(_params.goal.getGoal(a) - state.getUnitData().getNumTotal(a))); } else if (_params.goal.getGoalMax(a)) { repeat = std::min(repeat, (int)(_params.goal.getGoalMax(a) - state.getUnitData().getNumTotal(a))); } return repeat; } bool DFBB_BuildOrderStackSearch::isTimeOut() { return (_params.searchTimeLimit && (_results.nodesExpanded % 200 == 0) && (_searchTimer.getElapsedTimeInMilliSec() > _params.searchTimeLimit)); } void DFBB_BuildOrderStackSearch::updateResults(const GameState & state) { FrameCountType finishTime = state.getLastActionFinishTime(); // new best solution if (finishTime < _results.upperBound) { _results.timeElapsed = _searchTimer.getElapsedTimeInMilliSec(); _results.upperBound = finishTime; _results.solutionFound = true; _results.finalState = state; _results.buildOrder = _buildOrder; //_results.printResults(true); } } #define ACTION_TYPE _stack[_depth].currentActionType #define STATE _stack[_depth].state #define CHILD_STATE _stack[_depth+1].state #define CHILD_NUM _stack[_depth].currentChildIndex #define LEGAL_ACTINS _stack[_depth].legalActions #define REPETITIONS _stack[_depth].repetitionValue #define COMPLETED_REPS _stack[_depth].completedRepetitions #define DFBB_CALL_RETURN if (_depth == 0) { return; } else { --_depth; goto SEARCH_RETURN; } #define DFBB_CALL_RECURSE { ++_depth; goto SEARCH_BEGIN; } // recursive function which does all search logic void DFBB_BuildOrderStackSearch::DFBB() { FrameCountType actionFinishTime = 0; FrameCountType heuristicTime = 0; FrameCountType maxHeuristic = 0; SEARCH_BEGIN: _results.nodesExpanded++; if (isTimeOut()) { throw DFBB_TIMEOUT_EXCEPTION; } generateLegalActions(STATE, LEGAL_ACTINS); for (CHILD_NUM = 0; CHILD_NUM < LEGAL_ACTINS.size(); ++CHILD_NUM) { ACTION_TYPE = LEGAL_ACTINS[CHILD_NUM]; actionFinishTime = STATE.whenCanPerform(ACTION_TYPE) + ACTION_TYPE.buildTime(); heuristicTime = STATE.getCurrentFrame() + Tools::GetLowerBound(STATE, _params.goal); maxHeuristic = (actionFinishTime > heuristicTime) ? actionFinishTime : heuristicTime; if (maxHeuristic > _results.upperBound) { continue; } REPETITIONS = getRepetitions(STATE, ACTION_TYPE); BOSS_ASSERT(REPETITIONS > 0, "Can't have zero repetitions!"); // do the action as many times as legal to to 'repeat' CHILD_STATE = STATE; COMPLETED_REPS = 0; for (; COMPLETED_REPS < REPETITIONS; ++COMPLETED_REPS) { if (CHILD_STATE.isLegal(ACTION_TYPE)) { _buildOrder.add(ACTION_TYPE); CHILD_STATE.doAction(ACTION_TYPE); } else { break; } } if (_params.goal.isAchievedBy(CHILD_STATE)) { updateResults(CHILD_STATE); } else { DFBB_CALL_RECURSE; } SEARCH_RETURN: for (int r(0); r < COMPLETED_REPS; ++r) { _buildOrder.pop_back(); } } DFBB_CALL_RETURN; } ================================================ FILE: BOSS/source/DFBB_BuildOrderStackSearch.h ================================================ #pragma once #include "Common.h" #include "ActionType.h" #include "DFBB_BuildOrderSearchResults.h" #include "DFBB_BuildOrderSearchParameters.h" #include "Timer.hpp" #include "Tools.h" #include "BuildOrder.h" #define DFBB_TIMEOUT_EXCEPTION 1 namespace BOSS { class StackData { public: size_t currentChildIndex; GameState state; ActionSet legalActions; ActionType currentActionType; UnitCountType repetitionValue; UnitCountType completedRepetitions; StackData() : currentChildIndex(0) , repetitionValue(1) , completedRepetitions(0) { } }; class DFBB_BuildOrderStackSearch { DFBB_BuildOrderSearchParameters _params; //parameters that will be used in this search DFBB_BuildOrderSearchResults _results; //the results of the search so far Timer _searchTimer; BuildOrder _buildOrder; std::vector _stack; size_t _depth; bool _firstSearch; bool _wasInterrupted; void updateResults(const GameState & state); bool isTimeOut(); void calculateRecursivePrerequisites(const ActionType & action, ActionSet & all); void generateLegalActions(const GameState & state, ActionSet & legalActions); std::vector getBuildOrder(GameState & state); UnitCountType getRepetitions(const GameState & state, const ActionType & a); ActionSet calculateRelevantActions(); public: DFBB_BuildOrderStackSearch(const DFBB_BuildOrderSearchParameters & p); void setTimeLimit(double ms); void search(); const DFBB_BuildOrderSearchResults & getResults() const; void DFBB(); }; } ================================================ FILE: BOSS/source/Eval.cpp ================================================ #include "Eval.h" namespace BOSS { namespace Eval { double ArmyCompletedResourceSum(const GameState & state) { ResourceCountType sum(0); const std::vector & allActions = ActionTypes::GetAllActionTypes(state.getRace()); for (ActionID i(0); i< (int)allActions.size(); ++i) { const ActionType & a = allActions[i]; if (!a.isBuilding() && !a.isWorker() && !a.isSupplyProvider()) { sum += state.getUnitData().getNumCompleted(a)*a.mineralPrice(); sum += 2*state.getUnitData().getNumCompleted(a)*a.gasPrice(); } } return sum; } double ArmyTotalResourceSum(const GameState & state) { ResourceCountType sum(0); const std::vector & allActions = ActionTypes::GetAllActionTypes(state.getRace()); for (ActionID i(0); i< (int)allActions.size(); ++i) { const ActionType & a = allActions[i]; if (!a.isBuilding() && !a.isWorker() && !a.isSupplyProvider()) { sum += state.getUnitData().getNumTotal(a)*a.mineralPrice(); sum += 2*state.getUnitData().getNumTotal(a)*a.gasPrice(); } } return sum; } bool BuildOrderBetter(const BuildOrder & buildOrder, const BuildOrder & compareTo) { size_t numWorkers = 0; size_t numWorkersOther = 0; for (size_t a(0); a numWorkersOther; } } bool StateDominates(const GameState & state, const GameState & other) { // we can't define domination for different races if (state.getRace() != other.getRace()) { return false; } // if we have less resources than the other state we are not dominating it if ((state.getMinerals() < other.getMinerals()) || (state.getGas() < other.getGas())) { return false; } // if we have less of any unit than the other state we are not dominating it for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a) { const ActionType & action = ActionTypes::GetActionType(state.getRace(), a); if (state.getUnitData().getNumTotal(action) < other.getUnitData().getNumTotal(action)) { return false; } if (state.getUnitData().getNumCompleted(action) < other.getUnitData().getNumCompleted(action)) { return false; } } return true; } } } ================================================ FILE: BOSS/source/Eval.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "BuildOrder.h" namespace BOSS { namespace Eval { double ArmyCompletedResourceSum(const GameState & state); double ArmyTotalResourceSum(const GameState & state); bool BuildOrderBetter(const BuildOrder & buildOrder, const BuildOrder & compareTo); bool StateDominates(const GameState & state, const GameState & other); } } ================================================ FILE: BOSS/source/GameState.cpp ================================================ #include "GameState.h" using namespace BOSS; GameState::GameState(const RaceID r) : _race (r) , _units (r) , _currentFrame (0) , _lastActionFrame (0) , _minerals (0) , _gas (0) { } #ifdef _MSC_VER GameState::GameState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * self, const std::vector & buildingsQueued) : _race (Races::GetRaceID(self->getRace())) , _currentFrame (game->getFrameCount()) , _lastActionFrame (0) , _units (Races::GetRaceID(self->getRace())) , _minerals (self->minerals() * Constants::RESOURCE_SCALE) , _gas (self->gas() * Constants::RESOURCE_SCALE) { // we will count the worker jobs as we add units UnitCountType mineralWorkerCount = 0; UnitCountType gasWorkerCount = 0; UnitCountType buildingWorkerCount = 0; UnitCountType larvaCount = 0; _units.setMineralWorkers(mineralWorkerCount); _units.setGasWorkers(gasWorkerCount); _units.setBuildingWorkers(buildingWorkerCount); // add buildings queued like they had just been started for (const BWAPI::UnitType & type : buildingsQueued) { _units.addActionInProgress(ActionType(type), game->getFrameCount() + type.buildTime(), false); } // add each unit we have to the current state for (BWAPI::UnitInterface * unit : self->getUnits()) { // if the unit is an egg then we're building a zerg unit, add it with the finish time if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg) { _units.addActionInProgress(ActionType(unit->getBuildType()), game->getFrameCount() + unit->getRemainingBuildTime(), false); continue; } if (unit->getType() == BWAPI::UnitTypes::Zerg_Larva) { ++larvaCount; continue; } // don't add any units that we don't have any the action space, this should never happen though if (!ActionTypes::TypeExists(unit->getType())) { continue; } ActionType actionType(unit->getType()); // if the unit is completed if (unit->isCompleted()) { // if it is a building that is not an addon if (unit->getType().isBuilding()) { // add the building data accordingly FrameCountType trainTime = unit->getRemainingTrainTime() + unit->getRemainingResearchTime() + unit->getRemainingUpgradeTime(); ActionType constructing; ActionType addon; bool isHatchery = unit->getType().isResourceDepot() && unit->getType().getRace() == BWAPI::Races::Zerg; // if this is a hatchery subtract the training time which is just larva production time if (isHatchery) { trainTime -= unit->getRemainingTrainTime(); } // if this unit is currently building an addon, set it if (unit->getAddon() && unit->getAddon()->isBeingConstructed()) { constructing = ActionType(unit->getAddon()->getType()); } // if it's a non-hatchery currently training something, add it else if (!isHatchery && unit->getRemainingTrainTime() > 0) { // find the unit we have that has the same construction time remaining // this is an awful hack but there seems to be no alternative bool set = false; for (auto & u : self->getUnits()) { if (u->getRemainingBuildTime() > 0 && u->getPosition().getDistance(unit->getPosition()) < 16) { constructing = ActionType(u->getType()); set = true; break; } } // check to see if the last order issued was a trianing order and grab the unit type from that if (!set && unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Train) { BWAPI::UnitType trainType = unit->getLastCommand().getUnitType(); if (BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() < 2*BWAPI::Broodwar->getLatencyFrames()) { constructing = ActionType(trainType); set = true; // we now need to add this to units in progress, since it won't be detected below as an actual unit in progress _units.addActionInProgress(trainType, game->getFrameCount() + trainType.buildTime(), false); } } if (!set) { // if we couldn't find the unit type that this unit is training // then we have to treat it as if it doesn't exist otherwise BOSS will act strangely trainTime = 0; BWAPI::Broodwar->printf("Couldn't find training unit for %s %s %d %d", unit->getType().getName().c_str(), unit->getBuildType().getName().c_str(), unit->getTrainingQueue().size(), unit->getRemainingTrainTime()); } } // if it's researching something, add it else if (unit->getRemainingResearchTime() > 0) { constructing = ActionType(unit->getTech()); _units.addActionInProgress(constructing, game->getFrameCount() + unit->getRemainingResearchTime(), false); } // if it's upgrading something, add it else if (unit->getRemainingUpgradeTime() > 0) { constructing = ActionType(unit->getUpgrade()); _units.addActionInProgress(constructing, game->getFrameCount() + unit->getRemainingUpgradeTime(), false); } // add addons if (unit->getAddon() != nullptr) { if (unit->getAddon()->isConstructing()) { constructing = ActionType(unit->getAddon()->getType()); } else { addon = ActionType(unit->getAddon()->getType()); } } _units.addCompletedBuilding(actionType, trainTime, constructing, addon, unit->getLarva().size()); } // otherwise it is a non-building unit else { if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode) { actionType = ActionType(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode); } // add the unit to the state _units.addCompletedAction(actionType, false); // set the supply accordingly _units.setCurrentSupply(_units.getCurrentSupply() + actionType.supplyRequired()); } } // the unit is currently under construction else if ((unit->getRemainingBuildTime() > 0) && !unit->getType().isAddon()) { // special case of a zerg building morphing into its upgrade if (actionType.isBuilding() && actionType.isMorphed()) { // add the completed building which is morphing into this building _units.addCompletedBuilding(actionType.whatBuildsActionType(), unit->getRemainingBuildTime(), actionType, ActionType(), unit->getLarva().size()); } // add the unit itself in progress _units.addActionInProgress(actionType, game->getFrameCount() + unit->getRemainingBuildTime(), false); } } for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes()) { if (!ActionTypes::TypeExists(type)) { continue; } if (self->getUpgradeLevel(type) > 0) { _units.addCompletedAction(ActionType(type)); } } for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes()) { if (!ActionTypes::TypeExists(type)) { continue; } if (self->hasResearched(type)) { _units.addCompletedAction(ActionType(type)); } } } #endif void GameState::setStartingState() { _minerals = 50 * Constants::RESOURCE_SCALE; _gas = 0; _units.addCompletedAction(ActionTypes::GetResourceDepot(getRace()), false); _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false); _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false); _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false); _units.addCompletedAction(ActionTypes::GetWorker(getRace()), false); if (getRace() == Races::Zerg) { _units.addCompletedAction(ActionTypes::GetSupplyProvider(Races::Zerg), false); } _units.setCurrentSupply(8); } const RaceID GameState::getRace() const { return _race; } void GameState::getAllLegalActions(ActionSet & actions) const { const std::vector & allActions = ActionTypes::GetAllActionTypes(getRace()); for (ActionID i(0); i< (int)allActions.size(); ++i) { const ActionType & action = allActions[i]; if (isLegal(action)) { actions.add(action); } } } bool GameState::isLegal(const ActionType & action) const { const size_t mineralWorkers = getNumMineralWorkers(); const size_t numRefineries = _units.getNumTotal(ActionTypes::GetRefinery(getRace())); const size_t numDepots = _units.getNumTotal(ActionTypes::GetResourceDepot(getRace())); const size_t refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace())); // we can never build a larva static const ActionType & Zerg_Larva = ActionTypes::GetActionType("Zerg_Larva"); if (action == Zerg_Larva) { return false; } // check if the tech requirements are met if (!_units.hasPrerequisites(action.getPrerequisites())) { return false; } // if it's a unit and we are out of supply and aren't making an overlord, it's not legal if (!action.isMorphed() && !action.isSupplyProvider() && ((_units.getCurrentSupply() + action.supplyRequired()) > (_units.getMaxSupply() + _units.getSupplyInProgress()))) { return false; } // TODO: require an extra for refineries byt not buildings // rules for buildings which are built by workers if (action.isBuilding() && !action.isMorphed() && !action.isAddon()) { // be very strict about when we can make refineries to ensure we have enough workers to go in gas if (action.isRefinery() && (getNumMineralWorkers() <= (int)(4 + 3*refineriesInProgress))) { return false; } int workersPerRefinery = 3; int workersRequiredToBuild = getRace() == Races::Protoss ? 0 : 1; int buildingIsRefinery = action.isRefinery() ? 1 : 0; int candidateWorkers = getNumMineralWorkers() + _units.getNumInProgress(ActionTypes::GetWorker(getRace())) + getNumBuildingWorkers(); int workersToBeUsed = workersRequiredToBuild + workersPerRefinery*(refineriesInProgress); if (candidateWorkers < workersToBeUsed) { return false; } } // if we have no gas income we can't make a gas unit if (!canAffordGas(action) && !_units.hasGasIncome()) { return false; } // if we have no mineral income we'll never have a minerla unit if (!canAffordMinerals(action) && !_units.hasMineralIncome()) { return false; } // don't build more refineries than resource depots if (action.isRefinery() && (numRefineries >= numDepots)) { return false; } // we don't need to go over the maximum supply limit with supply providers if (action.isSupplyProvider() && (_units.getMaxSupply() + _units.getSupplyInProgress() > 400)) { return false; } // can only build one of a tech type if (action.isTech() && getUnitData().getNumTotal(action) > 0) { return false; } // check to see if an addon can ever be built if (action.isAddon() && !_units.getBuildingData().canBuildEventually(action) && (_units.getNumInProgress(action.whatBuildsActionType()) == 0)) { return false; } return true; } // do an action, action must be legal for this not to break std::vector GameState::doAction(const ActionType & action) { BOSS_ASSERT(action.getRace() == _race, "Race of action does not match race of the state"); _actionsPerformed.push_back(ActionPerformed()); _actionsPerformed[_actionsPerformed.size()-1].actionType = action; BOSS_ASSERT(isLegal(action), "Trying to perform an illegal action: %s %s", action.getName().c_str(), getActionsPerformedString().c_str()); // set the actionPerformed _actionPerformed = action; _actionPerformedK = 1; FrameCountType workerReadyTime = whenWorkerReady(action); FrameCountType ffTime = whenCanPerform(action); const std::string & name = action.getName(); BOSS_ASSERT(ffTime >= 0 && ffTime < 1000000, "FFTime is very strange: %d", ffTime); auto actionsFinished = fastForward(ffTime); _actionsPerformed[_actionsPerformed.size()-1].actionQueuedFrame = _currentFrame; _actionsPerformed[_actionsPerformed.size()-1].gasWhenQueued = _gas; _actionsPerformed[_actionsPerformed.size()-1].mineralsWhenQueued = _minerals; // how much time has elapsed since the last action was queued? FrameCountType elapsed(_currentFrame - _lastActionFrame); _lastActionFrame = _currentFrame; BOSS_ASSERT(canAffordMinerals(action), "Minerals less than price: %ld < %d, ffTime=%d %s", _minerals, action.mineralPrice(), (int)elapsed, action.getName().c_str()); BOSS_ASSERT(canAffordGas(action), "Gas less than price: %ld < %d, ffTime=%d %s", _gas, action.gasPrice(), (int)elapsed, action.getName().c_str()); // modify our resources _minerals -= action.mineralPrice(); _gas -= action.gasPrice(); // do race specific things here if (getRace() == Races::Protoss) { _units.addActionInProgress(action, _currentFrame + action.buildTime()); } else if (getRace() == Races::Terran) { if (action.isBuilding() && !action.isAddon()) { BOSS_ASSERT(getNumMineralWorkers() > 0, "Don't have any mineral workers to assign"); _units.setBuildingWorker(); } _units.addActionInProgress(action, _currentFrame + action.buildTime()); } else if (getRace() == Races::Zerg) { // zerg must subtract a larva if the action was unit creation if (action.isUnit() && !action.isBuilding()) { if (action.isMorphed()) { _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime()); } else { BOSS_ASSERT(getHatcheryData().numLarva() > 0, "We should have a larva to use"); _units.getHatcheryData().useLarva(); _units.addActionInProgress(action, _currentFrame + action.buildTime()); } } else if (action.isBuilding()) { _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime()); } else { // if it's not a unit or a building it's a tech so we queue it normally _units.addActionInProgress(action, _currentFrame + action.buildTime()); } } return actionsFinished; } // fast forwards the current state to time toFrame std::vector GameState::fastForward(const FrameCountType toFrame) { // fast forward the building timers to the current frame FrameCountType previousFrame = _currentFrame; _units.setBuildingFrame(toFrame - _currentFrame); // update resources & finish each action FrameCountType lastActionFinished = _currentFrame; FrameCountType totalTime = 0; ResourceCountType moreGas = 0; ResourceCountType moreMinerals = 0; std::vector actionsFinished; // while we still have units in progress while ((_units.getNumActionsInProgress() > 0) && (_units.getNextActionFinishTime() <= toFrame)) { // figure out how long since the last action was finished FrameCountType timeElapsed = _units.getNextActionFinishTime() - lastActionFinished; totalTime += timeElapsed; // update our mineral and gas count for that period moreMinerals += timeElapsed * getMineralsPerFrame(); moreGas += timeElapsed * getGasPerFrame(); // update when the last action was finished lastActionFinished = _units.getNextActionFinishTime(); // finish the action, which updates mineral and gas rates if required actionsFinished.push_back(_units.finishNextActionInProgress()); } // update resources from the last action finished to toFrame FrameCountType elapsed = toFrame - lastActionFinished; moreMinerals += elapsed * getMineralsPerFrame(); moreGas += elapsed * getGasPerFrame(); totalTime += elapsed; _minerals += moreMinerals; _gas += moreGas; // we are now in the FUTURE... "the future, conan?" _currentFrame = toFrame; if (getRace() == Races::Zerg) { _units.getHatcheryData().fastForward(previousFrame, toFrame); } return actionsFinished; } // returns the time at which all resources to perform an action will be available const FrameCountType GameState::whenCanPerform(const ActionType & action) const { const std::string & name = action.getName(); // the resource times we care about FrameCountType mineralTime (_currentFrame); // minerals FrameCountType gasTime (_currentFrame); // gas FrameCountType classTime (_currentFrame); // class-specific FrameCountType supplyTime (_currentFrame); // supply FrameCountType prereqTime (_currentFrame); // prerequisites FrameCountType workerTime (_currentFrame); FrameCountType maxVal (_currentFrame); // figure out when prerequisites will be ready prereqTime = whenPrerequisitesReady(action); // check minerals mineralTime = whenMineralsReady(action); // check gas gasTime = whenGasReady(action); // race specific timings (Zerg Larva) classTime = raceSpecificWhenReady(action); // set when we will have enough supply for this unit supplyTime = whenSupplyReady(action); // when will we have a worker ready to build it? workerTime = whenWorkerReady(action); // figure out the max of all these times maxVal = (mineralTime > maxVal) ? mineralTime : maxVal; maxVal = (gasTime > maxVal) ? gasTime : maxVal; maxVal = (classTime > maxVal) ? classTime : maxVal; maxVal = (supplyTime > maxVal) ? supplyTime : maxVal; maxVal = (prereqTime > maxVal) ? prereqTime : maxVal; maxVal = (workerTime > maxVal) ? workerTime : maxVal; // return the time return maxVal; } const FrameCountType GameState::raceSpecificWhenReady(const ActionType & a) const { const static ActionType larva = ActionTypes::GetActionType("Zerg_Larva"); if (getRace() == Races::Zerg) { if (a.whatBuildsActionType() != larva) { return 0; } if (getHatcheryData().numLarva() == 0) { return getHatcheryData().nextLarvaFrameAfter(_currentFrame); } } return 0; } const FrameCountType GameState::whenWorkerReady(const ActionType & action) const { if (!action.whatBuildsActionType().isWorker()) { return _currentFrame; } int refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace())); // protoss doesn't tie up a worker to build, so they can build whenever a mineral worker is free if (getRace() == Races::Protoss && getNumMineralWorkers() > 0) { return _currentFrame; } // if we have a mineral worker, then it is ready right now if (getNumMineralWorkers() > 3*refineriesInProgress) { return _currentFrame; } // at this point we need to wait for the next worker to become free since existing workers // are either all used, or they are reserved to be put into refineries // so we must have either a worker in progress, or a building in progress const ActionType & Worker = ActionTypes::GetWorker(getRace()); BOSS_ASSERT(_units.getNumInProgress(Worker) > 0 || getNumBuildingWorkers() > 0, "No worker will ever be free"); FrameCountType workerReadyTime = _currentFrame; // if we have a worker in progress, when will it be ready? FrameCountType whenWorkerInProgressFinished = std::numeric_limits::max(); if (_units.getNumInProgress(Worker)) { whenWorkerInProgressFinished = _units.getFinishTime(Worker); } // if we have a worker currently building, when will it be free? FrameCountType whenBuildingWorkerFree = std::numeric_limits::max(); if (getNumBuildingWorkers() > 0) { whenBuildingWorkerFree = _units.getNextBuildingFinishTime(); } return std::min(whenWorkerInProgressFinished, whenBuildingWorkerFree); } const FrameCountType GameState::whenSupplyReady(const ActionType & action) const { int supplyNeeded = action.supplyRequired() + _units.getCurrentSupply() - _units.getMaxSupply(); if (supplyNeeded <= 0) { return getCurrentFrame(); } FrameCountType whenSupplyReady = _currentFrame; if (supplyNeeded > 0) { FrameCountType min = 99999; // if we don't have the resources, this action would only be legal if there is an // overlord in progress, so check to see when the first overlord will finish for (int i(0); i<_units.getNumActionsInProgress(); ++i) { // so, if the unit provides the supply we need if (_units.getActionInProgressByIndex(i).supplyProvided() > supplyNeeded) { // set 'min' to the min of these times min = (_units.getFinishTimeByIndex(i) < min) ? _units.getFinishTimeByIndex(i) : min; } // then set supply time to min whenSupplyReady = min; } } return whenSupplyReady; } const FrameCountType GameState::whenPrerequisitesReady(const ActionType & action) const { if (action == ActionTypes::GetActionType("Protoss_Dark_Templar")) { int a = 6; } FrameCountType preReqReadyTime = _currentFrame; // if a building builds this action if (action.whatBuildsIsBuilding()) { // get when the building / prereqs will be ready preReqReadyTime = whenBuildingPrereqReady(action); } // otherwise something else builds this action so we don't worry about buildings else { // if requirement in progress (and not already made), set when it will be finished PrerequisiteSet reqInProgress = _units.getPrerequistesInProgress(action); // if it's not empty, check when they will be done if (!reqInProgress.isEmpty()) { preReqReadyTime = _units.getFinishTime(reqInProgress); } } return preReqReadyTime; } const FrameCountType GameState::whenBuildingPrereqReady(const ActionType & action) const { FrameCountType buildingAvailableTime(0); const ActionType & builder = action.whatBuildsActionType(); BOSS_ASSERT(builder.isBuilding(), "The thing that builds this is not a building"); bool buildingIsConstructed = _units.getBuildingData().canBuildEventually(action);//getNumCompleted(builder) > 0; bool buildingInProgress = _units.getNumInProgress(builder) > 0; FrameCountType constructedBuildingFreeTime = std::numeric_limits::max()-10; FrameCountType buildingInProgressFinishTime = std::numeric_limits::max()-10; BOSS_ASSERT(buildingIsConstructed || (!action.requiresAddon() && buildingInProgress), "We will never be able to build action: %s", action.getName().c_str()); if (buildingIsConstructed) { constructedBuildingFreeTime = _currentFrame + _units.getBuildingData().getTimeUntilCanBuild(action); } if (!action.requiresAddon() && buildingInProgress) { buildingInProgressFinishTime = _units.getFinishTime(builder); } // this will give us when the building will be free to build this action buildingAvailableTime = std::min(constructedBuildingFreeTime, buildingInProgressFinishTime); // get all prerequisites currently in progress but do not have any completed PrerequisiteSet prereqInProgress = _units.getPrerequistesInProgress(action); // remove the specific builder from this list since we calculated that earlier prereqInProgress.remove(builder); //// if we actually have some prerequisites in progress other than the building if (!prereqInProgress.isEmpty()) { // get the max time the earliest of each type will be finished in FrameCountType C = _units.getFinishTime(prereqInProgress); // take the maximum of this value and when the building was available buildingAvailableTime = (C > buildingAvailableTime) ? C : buildingAvailableTime; } return buildingAvailableTime; } //const FrameCountType GameState::whenConstructedBuildingReady(const ActionType & builder) const //{ // // if what builds a is a building and we have at least one of them completed so far // if (builder.isBuilding() && _units.getNumTotal(builder) > 0) // { // FrameCountType returnTime = _currentFrame + _units.getTimeUntilBuildingFree(builder); // // // get when the next building is available // return returnTime; // } // // return getCurrentFrame(); //} // when will minerals be ready const FrameCountType GameState::whenMineralsReady(const ActionType & action) const { if (_minerals >= action.mineralPrice()) { return getCurrentFrame(); } UnitCountType currentMineralWorkers = _units.getNumMineralWorkers(); UnitCountType currentGasWorkers = _units.getNumGasWorkers(); FrameCountType lastActionFinishFrame = _currentFrame; FrameCountType addedTime = 0; ResourceCountType addedMinerals = 0; ResourceCountType difference = action.mineralPrice() - _minerals; // loop through each action in progress, adding the minerals we would gather from each interval for (int i(0); i< (int)_units.getNumActionsInProgress(); ++i) { // the vector is sorted in descending order int progressIndex = _units.getNumActionsInProgress() - i - 1; // the time elapsed and the current minerals per frame FrameCountType elapsed = _units.getFinishTimeByIndex(progressIndex) - lastActionFinishFrame; ResourceCountType mineralsPerFrame = (currentMineralWorkers * Constants::MPWPF); // the amount of minerals that would be added this time step ResourceCountType tempAdd = elapsed * mineralsPerFrame; // if this amount isn't enough, update the amount added for this interval if (addedMinerals + tempAdd < difference) { addedMinerals += tempAdd; addedTime += elapsed; } else { // otherwise we can just break out and update at the end break; } // if it was a drone or extractor update the temp variables const ActionType & actionPerformed = _units.getActionInProgressByIndex(progressIndex); // finishing a building as terran gives you a mineral worker back if (actionPerformed.isBuilding() && !actionPerformed.isAddon() && (getRace() == Races::Terran)) { currentMineralWorkers++; } if (actionPerformed.isWorker()) { currentMineralWorkers++; } else if (actionPerformed.isRefinery()) { BOSS_ASSERT(currentMineralWorkers > 3, "Not enough mineral workers \n"); currentMineralWorkers -= 3; currentGasWorkers += 3; } // update the last action lastActionFinishFrame = _units.getFinishTimeByIndex(progressIndex); } // if we still haven't added enough minerals, add more time if (addedMinerals < difference) { BOSS_ASSERT(currentMineralWorkers > 0, "Shouldn't have 0 mineral workers"); FrameCountType finalTimeToAdd; if (currentMineralWorkers != 0) { finalTimeToAdd = (difference - addedMinerals) / (currentMineralWorkers * Constants::MPWPF); } else { finalTimeToAdd = 1000000; } addedMinerals += finalTimeToAdd * currentMineralWorkers * Constants::MPWPF; addedTime += finalTimeToAdd; // the last operation could have added one frame too little due to integer division so we need to check if (addedMinerals < difference) { addedTime += 1; addedMinerals += currentMineralWorkers * Constants::MPWPF; } } BOSS_ASSERT(addedMinerals >= difference, "Mineral prediction error"); // for some reason if i don't return +1, i mine 1 less mineral in the interval return _currentFrame + addedTime; } const FrameCountType GameState::whenGasReady(const ActionType & action) const { if (_gas >= action.gasPrice()) { return getCurrentFrame(); } UnitCountType currentMineralWorkers = _units.getNumMineralWorkers(); UnitCountType currentGasWorkers = _units.getNumGasWorkers(); FrameCountType lastActionFinishFrame = _currentFrame; FrameCountType addedTime = 0; ResourceCountType addedGas = 0; ResourceCountType difference = action.gasPrice() - _gas; // loop through each action in progress, adding the minerals we would gather from each interval for (int i(0); i<_units.getNumActionsInProgress(); ++i) { // the vector is sorted in descending order int progressIndex = _units.getNumActionsInProgress() - i - 1; // the time elapsed and the current minerals per frame FrameCountType elapsed = _units.getFinishTimeByIndex(progressIndex) - lastActionFinishFrame; ResourceCountType gasPerFrame = (currentGasWorkers * Constants::GPWPF); // the amount of minerals that would be added this time step ResourceCountType tempAdd = elapsed * gasPerFrame; // if this amount isn't enough, update the amount added for this interval if (addedGas + tempAdd < difference) { addedGas += tempAdd; addedTime += elapsed; } else { // otherwise we can just break out and update at the end break; } // if it was a drone or extractor update the temp variables const ActionType & actionPerformed = _units.getActionInProgressByIndex(progressIndex); // finishing a building as terran gives you a mineral worker back if (actionPerformed.isBuilding() && !actionPerformed.isAddon() && (getRace() == Races::Terran)) { currentMineralWorkers++; } if (actionPerformed.isWorker()) { currentMineralWorkers++; } else if (actionPerformed.isRefinery()) { BOSS_ASSERT(currentMineralWorkers > 3, "Not enough mineral workers"); currentMineralWorkers -= 3; currentGasWorkers += 3; } // update the last action lastActionFinishFrame = _units.getFinishTimeByIndex(progressIndex); } // if we still haven't added enough minerals, add more time if (addedGas < difference) { BOSS_ASSERT(currentGasWorkers > 0, "Shouldn't have 0 gas workers"); FrameCountType finalTimeToAdd; if (currentGasWorkers != 0) { finalTimeToAdd = (difference - addedGas) / (currentGasWorkers * Constants::GPWPF); } else { finalTimeToAdd = 1000000; } addedGas += finalTimeToAdd * currentGasWorkers * Constants::GPWPF; addedTime += finalTimeToAdd; // the last operation could have added one frame too little due to integer division so we need to check if (addedGas < difference) { addedTime += 1; addedGas += currentGasWorkers * Constants::GPWPF; } } BOSS_ASSERT(addedGas >= difference, "Gas prediction error"); // for some reason if i don't return +1, i mine 1 less mineral in the interval return _currentFrame + addedTime; } const FrameCountType GameState::getCurrentFrame() const { return _currentFrame; } const FrameCountType GameState::getLastActionFinishTime() const { return _units.getLastActionFinishTime(); } bool GameState::canAfford(const ActionType & action) const { return canAffordMinerals(action) && canAffordGas(action); } bool GameState::canAffordGas(const ActionType & action) const { return _gas >= action.gasPrice(); } bool GameState::canAffordMinerals(const ActionType & action) const { return _minerals >= action.mineralPrice(); } // getter methods for the internal variables size_t GameState::getMineralsPerFrame() const { return Constants::MPWPF * _units.getNumMineralWorkers(); } size_t GameState::getGasPerFrame() const { return Constants::GPWPF * _units.getNumGasWorkers(); } const UnitCountType GameState::getNumMineralWorkers() const { return _units.getNumMineralWorkers(); } const UnitCountType GameState::getNumBuildingWorkers() const { return _units.getNumBuildingWorkers(); } const UnitCountType GameState::getNumGasWorkers() const { return _units.getNumGasWorkers(); } const ResourceCountType GameState::getMinerals() const { return _minerals; } const ResourceCountType GameState::getGas() const { return _gas; } const ResourceCountType GameState::getMinerals(const int frame) const { BOSS_ASSERT(frame >= _currentFrame, "Frame is not in the future"); return _minerals + (int)(getMineralsPerFrame() * (frame-_currentFrame)); } const ResourceCountType GameState::getGas(const int frame) const { BOSS_ASSERT(frame >= _currentFrame, "Frame is not in the future"); return _gas + (int)(getGasPerFrame() * (frame-_currentFrame)); } const ResourceCountType GameState::getFinishTimeMinerals() const { return getMinerals(_units.getLastActionFinishTime()); } const ResourceCountType GameState::getFinishTimeGas() const { return getGas(_units.getLastActionFinishTime()); } const UnitData & GameState::getUnitData() const { return _units; } const BuildingData & GameState::getBuildingData() const { return _units.getBuildingData(); } const HatcheryData & GameState::getHatcheryData() const { return _units.getHatcheryData(); } void GameState::setMinerals(const ResourceCountType & minerals) { _minerals = minerals * Constants::RESOURCE_SCALE; } void GameState::setGas(const ResourceCountType & gas) { _gas = gas * Constants::RESOURCE_SCALE; } void GameState::addCompletedAction(const ActionType & action, const size_t num) { for (size_t i(0); i < num; ++i) { _units.addCompletedAction(action, false); _units.setCurrentSupply(_units.getCurrentSupply() + action.supplyRequired()); } } void GameState::removeCompletedAction(const ActionType & action, const size_t num) { for (size_t i(0); i < num; ++i) { _units.setCurrentSupply(_units.getCurrentSupply() - action.supplyRequired()); _units.removeCompletedAction(action); } } const std::string GameState::toString() const { std::stringstream ss; ss << "\n-----------------------------------------------------------\n"; ss << "Current Frame: " << _currentFrame << " (" << (_currentFrame / (60 * 24)) << "m " << ((_currentFrame / 24) % 60) << "s)\n\n"; ss << "Units Completed:\n"; const std::vector & allActions = ActionTypes::GetAllActionTypes(getRace()); for (ActionID i(0); i< (int)allActions.size(); ++i) { const ActionType & action = allActions[i]; if (_units.getNumCompleted(action) > 0) { ss << "\t" << (int)_units.getNumCompleted(action) << "\t" << action.getName() << "\n"; } } ss << "\nUnits In Progress:\n"; for (int i(0); i<_units.getNumActionsInProgress(); i++) { ss << "\t" << (int)_units.getFinishTimeByIndex(i) << "\t" << _units.getActionInProgressByIndex(i).getName() << "\n"; } if (_race == Races::Zerg) { const HatcheryData & hd = _units.getHatcheryData(); ss << "\nHatcheries:\n"; ss << "\t" << hd.size() << " Hatcheries\n"; ss << "\t" << hd.numLarva() << " Larva\n"; } ss << "\nLegal Actions:\n"; ActionSet legalActions; getAllLegalActions(legalActions); for (UnitCountType a(0); a< (int)legalActions.size(); ++a) { ss << "\t" << legalActions[a].getName() << "\n"; } ss << "\nResources:\n"; ss << "\t" << _minerals / Constants::RESOURCE_SCALE << "\tMinerals\n"; ss << "\t" << _gas / Constants::RESOURCE_SCALE << "\tGas\n"; ss << "\t" << _units.getNumMineralWorkers() << "\tMineral Workers\n"; ss << "\t" << _units.getNumGasWorkers() << "\tGas Workers\n"; ss << "\t" << _units.getNumBuildingWorkers() << "\tBuilding Workers\n"; ss << "\n\t" << _units.getCurrentSupply()/2 << " / " << _units.getMaxSupply()/2 << "\tSupply\n"; ss << "-----------------------------------------------------------\n"; //printPath(); return ss.str(); } const std::string GameState::getActionsPerformedString() const { std::stringstream ss; ss << std::endl; for (size_t a(0); a<_actionsPerformed.size(); ++a) { ss << (int)_actionsPerformed[a].actionQueuedFrame << " " << (int)_actionsPerformed[a].mineralsWhenQueued << " " << (int)_actionsPerformed[a].gasWhenQueued << " " << _actionsPerformed[a].actionType.getName() << std::endl; } return ss.str(); } std::string GameState::whyIsNotLegal(const ActionType & action) const { std::stringstream ss; const size_t mineralWorkers = getNumMineralWorkers(); const size_t numRefineries = _units.getNumTotal(ActionTypes::GetRefinery(getRace())); const size_t numDepots = _units.getNumTotal(ActionTypes::GetResourceDepot(getRace())); const size_t refineriesInProgress = _units.getNumInProgress(ActionTypes::GetRefinery(getRace())); // we can never build a larva static const ActionType & Zerg_Larva = ActionTypes::GetActionType("Zerg_Larva"); if (action == Zerg_Larva) { ss << action.getName() << " - Reason: Cannot build a Larva" << std::endl; return ss.str(); } if (action.getRace() == Races::Protoss && action.isBuilding() && !action.isResourceDepot() && _units.getNumTotal(ActionTypes::GetSupplyProvider(Races::Protoss)) == 0) { ss << action.getName() << " - Reason: Protoss buildings require a Pylon" << std::endl; return ss.str(); } // check if the tech requirements are met if (!_units.hasPrerequisites(action.getPrerequisites())) { ss << action.getName() << " - Reason: Tech prerequisites not met" << std::endl; return ss.str(); } // if it's a unit and we are out of supply and aren't making an overlord, it's not legal if (!action.isMorphed() && !action.isSupplyProvider() && ((_units.getCurrentSupply() + action.supplyRequired()) > (_units.getMaxSupply() + _units.getSupplyInProgress()))) { ss << action.getName() << " - Reason: Not enough supply" << std::endl; return ss.str(); } // TODO: require an extra for refineries byt not buildings // rules for buildings which are built by workers if (action.isBuilding() && !action.isMorphed() && !action.isAddon()) { // be very strict about when we can make refineries to ensure we have enough workers to go in gas if (action.isRefinery() && (getNumMineralWorkers() <= (int)(4 + 3*refineriesInProgress))) { ss << action.getName() << " - Reason: Not enough workers for refinery" << std::endl; return ss.str(); } int workersPerRefinery = 3; int workersRequiredToBuild = getRace() == Races::Protoss ? 0 : 1; int buildingIsRefinery = action.isRefinery() ? 1 : 0; int candidateWorkers = getNumMineralWorkers() + _units.getNumInProgress(ActionTypes::GetWorker(getRace())) + getNumBuildingWorkers(); int workersToBeUsed = workersRequiredToBuild + workersPerRefinery*(refineriesInProgress); if (candidateWorkers < workersToBeUsed) { ss << action.getName() << " - Reason: Not enough workers to build building" << std::endl; return ss.str(); } } // if we have no gas income we can't make a gas unit if (!canAffordGas(action) && !_units.hasGasIncome()) { ss << action.getName() << " - Reason: No gas income" << std::endl; return ss.str(); } // if we have no mineral income we'll never have a minerla unit if (!canAffordMinerals(action) && !_units.hasMineralIncome()) { ss << action.getName() << " - Reason: No mineral income" << std::endl; return ss.str(); } // don't build more refineries than resource depots if (action.isRefinery() && (numRefineries >= numDepots)) { ss << action.getName() << " - Reason: Can't have more refineries than depots" << std::endl; return ss.str(); } // we don't need to go over the maximum supply limit with supply providers if (action.isSupplyProvider() && (_units.getMaxSupply() + _units.getSupplyInProgress() > 420)) { ss << action.getName() << " - Reason: Unnecessary supply providers" << std::endl; return ss.str(); } // can only build one of a tech type if (action.isTech() && getUnitData().getNumTotal(action) > 0) { ss << action.getName() << " - Reason: Can't build more than one of a tech" << std::endl; return ss.str(); } // check to see if an addon can ever be built if (action.isAddon() && !_units.getBuildingData().canBuildEventually(action) && (_units.getNumInProgress(action.whatBuildsActionType()) == 0)) { ss << action.getName() << " - Reason: No building for addon" << std::endl; return ss.str(); } return "Legal"; } ================================================ FILE: BOSS/source/GameState.h ================================================ #pragma once #include "Common.h" #include "ActionInProgress.h" #include "BuildingData.h" #include "UnitData.h" #include "ActionType.h" #include "PrerequisiteSet.h" #include "ActionSet.h" //#define ENABLE_BWAPI_GAMESTATE_CONSTRUCTOR namespace BOSS { typedef std::pair ResourcePair; typedef std::pair FramePair; class ActionPerformed { public: ActionType actionType; FrameCountType actionQueuedFrame; ResourceCountType mineralsWhenQueued; ResourceCountType gasWhenQueued; ActionPerformed() : actionQueuedFrame(0) , mineralsWhenQueued(0) , gasWhenQueued(0) { } }; class GameState { UnitData _units; RaceID _race; ActionType _actionPerformed; // the action which generated this state size_t _actionPerformedK; FrameCountType _currentFrame; FrameCountType _lastActionFrame; // the current frame of the game ResourceCountType _minerals; // current mineral count ResourceCountType _gas; // current gas count std::vector _actionsPerformed; const FrameCountType raceSpecificWhenReady(const ActionType & a) const; void fixZergUnitMasks(); const FrameCountType whenSupplyReady(const ActionType & action) const; const FrameCountType whenPrerequisitesReady(const ActionType & action) const; const FrameCountType whenBuildingPrereqReady(const ActionType & action) const; //const FrameCountType whenConstructedBuildingReady(const ActionType & builder) const; const FrameCountType whenMineralsReady(const ActionType & action) const; const FrameCountType whenGasReady(const ActionType & action) const; const FrameCountType whenWorkerReady(const ActionType & action) const; public: GameState(const RaceID r = Races::None); // constructor based on BWAPI::Game only makes sense if using VS // we won't be using this if we're compiling to emscripten or linux #ifdef _MSC_VER GameState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, const std::vector & buildingsQueued); #endif std::vector doAction(const ActionType & action); std::vector fastForward(const FrameCountType toFrame) ; void finishNextActionInProgress(); const FrameCountType getCurrentFrame() const; const FrameCountType whenCanPerform(const ActionType & action) const; const FrameCountType getLastActionFinishTime() const; void getAllLegalActions(ActionSet & actions) const; std::string whyIsNotLegal(const ActionType & action) const; bool isLegal(const ActionType & action) const; bool canAfford(const ActionType & action) const; bool canAffordGas(const ActionType & action) const; bool canAffordMinerals(const ActionType & action) const; size_t getMineralsPerFrame() const; size_t getGasPerFrame() const; const UnitCountType getNumMineralWorkers() const; const UnitCountType getNumGasWorkers() const; const UnitCountType getNumBuildingWorkers() const; const ResourceCountType getMinerals() const; const ResourceCountType getGas() const; const RaceID getRace() const; const UnitData & getUnitData() const; const ResourceCountType getMinerals(const int frame) const; const ResourceCountType getGas(const int frame) const; const ResourceCountType getFinishTimeMinerals() const; const ResourceCountType getFinishTimeGas() const; const std::string toString() const; const std::string getActionsPerformedString() const; const BuildingData & getBuildingData() const; const HatcheryData & getHatcheryData() const; void setStartingState(); void setMinerals(const ResourceCountType & minerals); void setGas(const ResourceCountType & gas); void addCompletedAction(const ActionType & action, const size_t num = 1); void removeCompletedAction(const ActionType & action, const size_t num = 1); }; } ================================================ FILE: BOSS/source/GraphViz.hpp ================================================ #pragma once #include #include #include #include namespace BOSS { namespace GraphViz { class Property { public: std::string prop; std::string value; Property(std::string p, std::string val) : prop(p), value(val) { } void print(std::ofstream & out) { out << prop << "=\"" << value << "\", "; } }; class Node { public: std::vector props; std::string name; Node(std::string n) : name(n) {} Node() {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void print(std::ofstream & out) { out << name << " ["; for (size_t p(0); p nodes; std::vector props; Edge(std::string n1, std::string n2) : nodes(n1, n2) {} Edge(Node & n1, Node & n2) : nodes(n1.name, n2.name) {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void print(std::ofstream & out) { out << nodes.first << " -> " << nodes.second << " ["; for (size_t p(0); p nodes; std::vector edges; std::vector props; std::string name; public: Graph(std::string n) : name(n) {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void addNode(Node & n) { nodes.push_back(n); } void addEdge(Edge & e) { edges.push_back(e); } void print(std::ofstream & out) { out << "digraph " << name << " {\n"; for (size_t p(0); p test.png }*/ } } ================================================ FILE: BOSS/source/HatcheryData.cpp ================================================ #include "HatcheryData.h" using namespace BOSS; Hatchery::Hatchery(const UnitCountType & numLarva) : _numLarva(numLarva) { } Hatchery::Hatchery() : _numLarva(3) { } void Hatchery::fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame) { if (_numLarva == 3) { return; } UnitCountType larvaToAdd = (toFrame / Constants::ZERG_LARVA_TIMER) - (currentFrame / Constants::ZERG_LARVA_TIMER); larvaToAdd = std::min(larvaToAdd, (UnitCountType)(3 - _numLarva)); _numLarva += larvaToAdd; } void Hatchery::useLarva() { BOSS_ASSERT(_numLarva > 0, "We should have larva to use"); _numLarva--; } const UnitCountType & Hatchery::numLarva() const { return _numLarva; } HatcheryData::HatcheryData() { } void HatcheryData::addHatchery(const UnitCountType & numLarva) { _hatcheries.push_back(Hatchery(numLarva)); } void HatcheryData::removeHatchery() { _hatcheries.pop_back(); } void HatcheryData::fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame) { for (size_t i(0); i < _hatcheries.size(); ++i) { _hatcheries[i].fastForward(currentFrame, toFrame); } } void HatcheryData::useLarva() { int maxLarvaIndex = -1; for (size_t i(0); i < _hatcheries.size(); ++i) { if (_hatcheries[i].numLarva() > 0) { if (maxLarvaIndex == -1 || (_hatcheries[i].numLarva() > _hatcheries[maxLarvaIndex].numLarva())) { maxLarvaIndex = i; } } } if (maxLarvaIndex != -1) { _hatcheries[maxLarvaIndex].useLarva(); } else { BOSS_ASSERT(false, "Should have found a larva to use"); } } const FrameCountType HatcheryData::nextLarvaFrameAfter(const FrameCountType & currentFrame) const { if (currentFrame % Constants::ZERG_LARVA_TIMER == 0) { return currentFrame + Constants::ZERG_LARVA_TIMER; } else { return Constants::ZERG_LARVA_TIMER * ((currentFrame / Constants::ZERG_LARVA_TIMER) + 1); } } const UnitCountType HatcheryData::numLarva() const { UnitCountType sumLarva = 0; for (size_t i(0); i < _hatcheries.size(); ++i) { sumLarva += _hatcheries[i].numLarva(); } return sumLarva; } const UnitCountType HatcheryData::size() const { return _hatcheries.size(); } const Hatchery & HatcheryData::getHatchery(const UnitCountType & index) const { return _hatcheries[index]; } ================================================ FILE: BOSS/source/HatcheryData.h ================================================ #pragma once #include "Common.h" #include #include #include #include "PrerequisiteSet.h" #include "Array.hpp" #include "ActionType.h" namespace BOSS { class Hatchery { UnitCountType _numLarva; public: Hatchery(const UnitCountType & numLarva); Hatchery(); void useLarva(); void fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame); const UnitCountType & numLarva() const; }; class HatcheryData { Vec _hatcheries; public: HatcheryData(); void addHatchery(const UnitCountType & numLarva); void removeHatchery(); void useLarva(); void fastForward(const FrameCountType & currentFrame, const FrameCountType & toFrame); const FrameCountType nextLarvaFrameAfter(const FrameCountType & currentFrame) const; const UnitCountType numLarva() const; const UnitCountType size() const; const Hatchery & getHatchery(const UnitCountType & index) const; }; } ================================================ FILE: BOSS/source/JSONTools.cpp ================================================ #include "JSONTools.h" using namespace BOSS; std::string JSONTools::ReadJsonFile(const std::string & filename) { // set up the file std::ifstream fin(filename.c_str()); if (!fin.is_open()) { BOSS_ASSERT(false, "Could not open file: %s", filename.c_str()); } std::string line; std::stringstream ss; // each line of the file will be a new player to add while (fin.good()) { // get the line and set up the string stream getline(fin, line); ss << line; } fin.close(); return ss.str(); } void JSONTools::ParseJSONString(rapidjson::Document & document, const std::string & json) { bool parsingFailed = document.Parse<0>(json.c_str()).HasParseError(); if (parsingFailed) { int errorPos = document.GetErrorOffset(); std::stringstream ss; ss << std::endl << "JSON Parse Error: " << document.GetParseError() << std::endl; ss << "Error Position: " << errorPos << std::endl; ss << "Error Substring: " << json.substr(errorPos-5, 10) << std::endl; BOSS_ASSERT(!parsingFailed, "Error parsing JSON config file: %s", ss.str().c_str()); } BOSS_ASSERT(!parsingFailed, "Parsing of the JSON string failed"); } void JSONTools::ParseJSONFile(rapidjson::Document & document, const std::string & filename) { JSONTools::ParseJSONString(document, JSONTools::ReadJsonFile(filename)); } GameState JSONTools::GetGameState(const std::string & jsonString) { rapidjson::Document document; JSONTools::ParseJSONString(document, jsonString); return GetGameState(document); } GameState JSONTools::GetGameState(const rapidjson::Value & stateVal) { BOSS_ASSERT(stateVal.HasMember("race") && stateVal["race"].IsString(), "State doesn't have a race"); const RaceID race = Races::GetRaceID(stateVal["race"].GetString()); BOSS_ASSERT(race != Races::None, "Unknown race (make sure to use a single upper case): %s", stateVal["race"].GetString()); GameState state(race); if (stateVal.HasMember("minerals") && stateVal["minerals"].IsInt()) { state.setMinerals(stateVal["minerals"].GetInt()); } if (stateVal.HasMember("gas") && stateVal["gas"].IsInt()) { state.setGas(stateVal["gas"].GetInt()); } if (stateVal.HasMember("units") && stateVal["units"].IsArray()) { const rapidjson::Value & units = stateVal["units"]; for (size_t i(0); i < units.Size(); ++i) { const rapidjson::Value & unit = units[i]; BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), "Unit has to be array of size 2"); state.addCompletedAction(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt()); } } return state; } BuildOrder JSONTools::GetBuildOrder(const std::string & jsonString) { rapidjson::Document document; JSONTools::ParseJSONString(document, jsonString); return GetBuildOrder(document); } BuildOrder JSONTools::GetBuildOrder(const rapidjson::Value & stateVal) { BOSS_ASSERT(stateVal.IsArray(), "Build order isn't an array"); BuildOrder buildOrder; for (size_t i(0); i < stateVal.Size(); ++i) { BOSS_ASSERT(stateVal[i].IsString(), "Build order item is not a string"); buildOrder.add(ActionTypes::GetActionType(stateVal[i].GetString())); } return buildOrder; } BuildOrderSearchGoal JSONTools::GetBuildOrderSearchGoal(const std::string & jsonString) { rapidjson::Document document; JSONTools::ParseJSONString(document, jsonString); return GetBuildOrderSearchGoal(document); } BuildOrderSearchGoal JSONTools::GetBuildOrderSearchGoal(const rapidjson::Value & val) { BOSS_ASSERT(val.HasMember("race") && val["race"].IsString(), "State doesn't have a race"); const RaceID race = Races::GetRaceID(val["race"].GetString()); BOSS_ASSERT(race != Races::None, "Unknown race (make sure to use a single upper case): %s", val["race"].GetString()); BuildOrderSearchGoal goal(race); if (val.HasMember("goal") && val["goal"].IsArray()) { const rapidjson::Value & goalUnits = val["goal"]; for (size_t i(0); i < goalUnits.Size(); ++i) { const rapidjson::Value & unit = goalUnits[i]; BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), "Goal entry has to be array of size 2"); goal.setGoal(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt()); } } if (val.HasMember("goalMax") && val["goalMax"].IsArray()) { const rapidjson::Value & goalMax = val["goalMax"]; for (size_t i(0); i < goalMax.Size(); ++i) { const rapidjson::Value & unit = goalMax[i]; BOSS_ASSERT(unit.IsArray() && unit.Size() == 2 && unit[0u].IsString() && unit[1u].IsInt(), "Goal max entry has to be array of size 2"); goal.setGoalMax(ActionTypes::GetActionType(unit[0u].GetString()), unit[1u].GetInt()); } } return goal; } std::string JSONTools::GetBuildOrderString(const std::vector & buildOrder) { std::stringstream ss; ss << "\"Test Build\" : ["; for (size_t i(0); i < buildOrder.size(); ++i) { ss << "\"" << buildOrder[i].getName() << "\"" << (i < buildOrder.size() - 1 ? ", " : ""); } ss << "]"; return ss.str(); } ================================================ FILE: BOSS/source/JSONTools.h ================================================ #pragma once #include "BOSS.h" #include "Common.h" #include "BuildOrder.h" #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace BOSS { namespace JSONTools { std::string ReadJsonFile(const std::string & filename); void ParseJSONString(rapidjson::Document & document, const std::string & json); void ParseJSONFile(rapidjson::Document & document, const std::string & filename); GameState GetGameState(const std::string & jsonString); GameState GetGameState(const rapidjson::Value & stateVal); BuildOrder GetBuildOrder(const std::string & jsonString); BuildOrder GetBuildOrder(const rapidjson::Value & stateVal); BuildOrderSearchGoal GetBuildOrderSearchGoal(const std::string & jsonString); BuildOrderSearchGoal GetBuildOrderSearchGoal(const rapidjson::Value & stateVal); std::string GetBuildOrderString(const std::vector & buildOrder); } } ================================================ FILE: BOSS/source/NaiveBuildOrderSearch.cpp ================================================ #include "NaiveBuildOrderSearch.h" using namespace BOSS; NaiveBuildOrderSearch::NaiveBuildOrderSearch(const GameState & state, const BuildOrderSearchGoal & goal) : _state(state) , _goal(goal) , _naiveSolved(false) { } bool NaiveBuildOrderSearch::checkUnsolvable() { const ActionType & worker = ActionTypes::GetWorker(_state.getRace()); const ActionType & supply = ActionTypes::GetSupplyProvider(_state.getRace()); const ActionType & depot = ActionTypes::GetResourceDepot(_state.getRace()); UnitCountType mineralWorkers = _state.getUnitData().getNumMineralWorkers(); UnitCountType numDepot = _state.getUnitData().getNumTotal(depot); if (mineralWorkers == 0 || numDepot == 0) { return true; } if (!_state.isLegal(worker) && !_state.isLegal(supply)) { return true; } return false; } const BuildOrder & NaiveBuildOrderSearch::solve() { if (_naiveSolved) { return _buildOrder; } if (checkUnsolvable()) { bool temp = checkUnsolvable(); _buildOrder = BuildOrder(); return _buildOrder; } PrerequisiteSet wanted; int minWorkers = 0; const ActionType & worker = ActionTypes::GetWorker(_state.getRace()); // add everything from the goal to the needed set for (size_t a(0); a < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(_state.getRace(), a); UnitCountType numCompleted = _state.getUnitData().getNumTotal(actionType); if (_goal.getGoal(actionType) > numCompleted) { wanted.addUnique(actionType); } } if (wanted.size() == 0) { return _buildOrder; } // Calculate which prerequisite units we need to build to achieve the units we want from the goal PrerequisiteSet requiredToBuild; Tools::CalculatePrerequisitesRequiredToBuild(_state, wanted, requiredToBuild); // Add the required units to a preliminary build order BuildOrder buildOrder; for (size_t a(0); a < requiredToBuild.size(); ++a) { const ActionType & type = requiredToBuild.getActionType(a); buildOrder.add(type); } // Add some workers to the build order if we don't have many, this usually gives a lower upper bound int requiredWorkers = minWorkers - _state.getUnitData().getNumCompleted(ActionTypes::GetWorker(_state.getRace())); buildOrder.add(worker, requiredWorkers); // Add the goal units to the end of the build order for (size_t a(0); a < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(_state.getRace(), a); int need = (int)_goal.getGoal(actionType); int have = (int)_state.getUnitData().getNumTotal(actionType); int numNeeded = need - have - buildOrder.getTypeCount(actionType); buildOrder.add(actionType, numNeeded); } // if we are zerg, make sure we have enough morphers for morphed units if (_state.getRace() == Races::Zerg) { // do this whole thing twice so that Hive->Lair->Hatchery is satisfied for (size_t t=0; t<2; ++t) { std::vector neededMorphers(ActionTypes::GetAllActionTypes(_state.getRace()).size(), 0); for (size_t i(0); i < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++i) { const ActionType & type = ActionTypes::GetActionType(Races::Zerg, i); if (type.isMorphed()) { const ActionType & morpher = type.whatBuildsActionType(); int willMorph = buildOrder.getTypeCount(type); int haveMorpher = _state.getUnitData().getNumTotal(morpher); int boMoprher = buildOrder.getTypeCount(morpher); int need = willMorph - haveMorpher - boMoprher; if (need > 0) { neededMorphers[morpher.ID()] += need; } } } // add the morphers to the build order for (size_t i(0); i 0) { int currentHydras = _state.getUnitData().getNumTotal(Hydralisk) + buildOrder.getTypeCount(Hydralisk) - buildOrder.getTypeCount(Lurker); int additionalHydras = _goal.getGoal(Hydralisk) - currentHydras; buildOrder.add(Hydralisk, additionalHydras); } if (_goal.getGoal(Guardian) > 0 && _goal.getGoal(Devourer) > 0) { int currentMutas = _state.getUnitData().getNumTotal(Mutalisk) + buildOrder.getTypeCount(Mutalisk); int additionalMutas = buildOrder.getTypeCount(Guardian) + buildOrder.getTypeCount(Devourer) - currentMutas; buildOrder.add(Mutalisk, additionalMutas); } if (_goal.getGoal(Mutalisk) > 0) { int currentMutas = _state.getUnitData().getNumTotal(Mutalisk) + buildOrder.getTypeCount(Mutalisk) - buildOrder.getTypeCount(Guardian) - buildOrder.getTypeCount(Devourer); int additionalMutas = _goal.getGoal(Mutalisk) - currentMutas; buildOrder.add(Mutalisk, additionalMutas); } if (_goal.getGoal(Sunken) > 0 && _goal.getGoal(Spore) > 0) { int currentCreep = _state.getUnitData().getNumTotal(Creep) + buildOrder.getTypeCount(Creep); int additionalCreep = buildOrder.getTypeCount(Spore) + buildOrder.getTypeCount(Sunken) - currentCreep; buildOrder.add(Creep, additionalCreep); } if (_goal.getGoal(Creep) > 0) { int currentCreep = _state.getUnitData().getNumTotal(Creep) + buildOrder.getTypeCount(Creep) - buildOrder.getTypeCount(Spore) - buildOrder.getTypeCount(Sunken); int additionalCreep = _goal.getGoal(Creep) - currentCreep; buildOrder.add(Creep, additionalCreep); } } // figure out how many workers are needed for the build order to be legal size_t workersNeeded = _goal.getGoal(worker); // we need enough workers to fill all the refineries that will be built size_t gasWorkersNeeded = 3*_state.getUnitData().getNumTotal(ActionTypes::GetRefinery(_state.getRace())) + 3*buildOrder.getTypeCount(ActionTypes::GetRefinery(_state.getRace())); workersNeeded = std::max(workersNeeded, gasWorkersNeeded); // special case for zerg: buildings consume drones if (_state.getRace() == Races::Zerg) { for (size_t i(0); i < ActionTypes::GetAllActionTypes(_state.getRace()).size(); ++i) { const ActionType & type = ActionTypes::GetActionType(Races::Zerg, i); if (type.whatBuildsActionType().isWorker() && !type.isMorphed()) { workersNeeded += buildOrder.getTypeCount(type); } } } int workersToAdd = workersNeeded - _state.getUnitData().getNumTotal(worker) - buildOrder.getTypeCount(worker); workersToAdd = std::max(0, workersToAdd); buildOrder.add(worker, workersToAdd); // Check to see if we have enough buildings for the required addons if (_state.getRace() == Races::Terran) { // Terran buildings that can make addons static const ActionType CommandCenter = ActionTypes::GetActionType("Terran_Command_Center"); static const ActionType Factory = ActionTypes::GetActionType("Terran_Factory"); static const ActionType Starport = ActionTypes::GetActionType("Terran_Starport"); static const ActionType ScienceFacility = ActionTypes::GetActionType("Terran_Science_Facility"); // Terran building addons static const ActionType ComsatStation = ActionTypes::GetActionType("Terran_Comsat_Station"); static const ActionType NuclearSilo = ActionTypes::GetActionType("Terran_Nuclear_Silo"); static const ActionType MachineShop = ActionTypes::GetActionType("Terran_Machine_Shop"); static const ActionType ControlTower = ActionTypes::GetActionType("Terran_Control_Tower"); static const ActionType PhysicsLab = ActionTypes::GetActionType("Terran_Physics_Lab"); static const ActionType CovertOps = ActionTypes::GetActionType("Terran_Covert_Ops"); int numCommandCenters = _state.getUnitData().getNumTotal(CommandCenter) + buildOrder.getTypeCount(CommandCenter); int numFactories = _state.getUnitData().getNumTotal(Factory) + buildOrder.getTypeCount(Factory); int numStarports = _state.getUnitData().getNumTotal(Starport) + buildOrder.getTypeCount(Starport); int numSci = _state.getUnitData().getNumTotal(ScienceFacility) + buildOrder.getTypeCount(ScienceFacility); int commandCenterAddons = buildOrder.getTypeCount(ComsatStation) + buildOrder.getTypeCount(NuclearSilo); int factoryAddons = buildOrder.getTypeCount(MachineShop); int starportAddons = buildOrder.getTypeCount(ControlTower); int sciAddons = buildOrder.getTypeCount(PhysicsLab) + buildOrder.getTypeCount(CovertOps); // add the necessary buildings to make the addons buildOrder.add(CommandCenter, commandCenterAddons - numCommandCenters); buildOrder.add(Factory, factoryAddons - numFactories); buildOrder.add(Starport, starportAddons - numStarports); buildOrder.add(ScienceFacility, sciAddons - numSci); } // Bubble sort the build order so that prerequites always come before what requires them buildOrder.sortByPrerequisites(); // Insert supply buildings so that build order is legal w.r.t. supply counts int maxSupply = _state.getUnitData().getMaxSupply() + _state.getUnitData().getSupplyInProgress(); int currentSupply = _state.getUnitData().getCurrentSupply(); const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(_state.getRace()); BuildOrder finalBuildOrder; for (size_t a(0); a < buildOrder.size(); ++a) { const ActionType & nextAction = buildOrder[a]; UnitCountType maxSupply = _state.getUnitData().getMaxSupply(); UnitCountType currentSupply = _state.getUnitData().getCurrentSupply(); UnitCountType supplyInProgress = _state.getUnitData().getSupplyInProgress(); // insert 1 or more supply providers if needed // TODO: don't go over 200 supply while (!nextAction.isMorphed() && !nextAction.isSupplyProvider() && (nextAction.supplyRequired() > (maxSupply + supplyInProgress - currentSupply))) { BOSS_ASSERT(_state.isLegal(supplyProvider), "Should be able to build more supply here. Max: %d", maxSupply); finalBuildOrder.add(supplyProvider); _state.doAction(supplyProvider); maxSupply = _state.getUnitData().getMaxSupply(); currentSupply = _state.getUnitData().getCurrentSupply(); supplyInProgress = _state.getUnitData().getSupplyInProgress(); } BOSS_ASSERT(_state.isLegal(nextAction), "Should be able to build the next action now"); finalBuildOrder.add(nextAction); _state.doAction(nextAction); } _buildOrder = finalBuildOrder; _naiveSolved = true; return _buildOrder; } ================================================ FILE: BOSS/source/NaiveBuildOrderSearch.h ================================================ #pragma once #include "Common.h" #include "BuildOrderSearchGoal.h" #include "GameState.h" #include "BuildOrder.h" #include "Tools.h" namespace BOSS { class NaiveBuildOrderSearch { GameState _state; BuildOrderSearchGoal _goal; BuildOrder _buildOrder; bool _naiveSolved; bool checkUnsolvable(); public: NaiveBuildOrderSearch(const GameState & state, const BuildOrderSearchGoal & goal); const BuildOrder & solve(); }; } ================================================ FILE: BOSS/source/Position.hpp ================================================ #pragma once #include "Common.h" #include typedef int PositionType; namespace BOSS { class Position { PositionType _x; PositionType _y; public: Position() : _x(0) , _y(0) { } Position(const PositionType & x, const PositionType & y) : _x(x) , _y(y) { } const bool operator < (const Position & rhs) const { return (x() < rhs.x()) || ((x() == rhs.x()) && y() < rhs.y()); } const bool operator == (const Position & rhs) const { return x() == rhs.x() && y() == rhs.y(); } const Position operator + (const Position & rhs) const { return Position(x() + rhs.x(), y() + rhs.y()); } const Position operator - (const Position & rhs) const { return Position(x() - rhs.x(), y() - rhs.y()); } const Position operator / (const PositionType & d) const { return Position(_x / d, _y / d); } const Position operator * (const PositionType & d) const { return Position(_x * d, _y * d); } const Position scale(const float & f) const { return Position((PositionType)(f * x()), (PositionType)(f * y())); } void scalePosition(const float & f) { _x = (PositionType)(f * _x); _y = (PositionType)(f * _y); } void add(const Position & rhs) { _x += rhs.x(); _y += rhs.y(); } void subtract(const Position & rhs) { _x -= rhs.x(); _y -= rhs.y(); } void moveTo(const Position & pos) { _x = pos.x(); _y = pos.y(); } void add(const PositionType & x, const PositionType & y) { _x += x; _y += y; } void moveTo(const PositionType & x, const PositionType & y) { _x = x; _y = y; } const PositionType x() const { return _x; } const PositionType y() const { return _y; } const Position flipX() const { return Position(-_x,_y); } const Position flipY() const { return Position(_y,_x); } const float Q_rsqrt( float number ) const { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = * ( long * ) &y; // evil floating point bit level hacking i = 0x5f3759df - ( i >> 1 ); y = * ( float * ) &i; y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed return y; } const Position flip() const { return Position(-_x, -_y); } inline const PositionType getDistance(const Position & p) const { PositionType dX = x() - p.x(); PositionType dY = y() - p.y(); if (dX == 0) { return abs(dY); } else if (dY == 0) { return abs(dX); } else { return (PositionType)sqrt((float)(dX*dX - dY*dY)); } } inline const PositionType getDistanceSq(const Position & p) const { return (x()-p.x())*(x()-p.x()) + (y()-p.y())*(y()-p.y()); } void print() const { printf("Position = (%d, %d)\n", _x, _y); } const std::string getString() const { std::stringstream ss; ss << "(" << x() << ", " << y() << ")"; return ss.str(); } }; } ================================================ FILE: BOSS/source/PrerequisiteSet.cpp ================================================ #include "PrerequisiteSet.h" using namespace BOSS; ActionCountPair::ActionCountPair() : _count(0) { } ActionCountPair::ActionCountPair(const ActionType & action, const UnitCountType count) : _action(action) , _count(count) { } const ActionType & ActionCountPair::getAction() const { return _action; } const UnitCountType & ActionCountPair::getCount() const { return _count; } PrerequisiteSet::PrerequisiteSet() { } const size_t PrerequisiteSet::size() const { return _actionCounts.size(); } const bool PrerequisiteSet::isEmpty() const { return size() == 0; } const bool PrerequisiteSet::contains(const ActionType & action) const { for (size_t i(0); i<_actionCounts.size(); ++i) { if (getActionType(i) == action) { return true; } } return false; } const ActionType & PrerequisiteSet::getActionType(const UnitCountType index) const { return _actionCounts[index].getAction(); } const UnitCountType & PrerequisiteSet::getActionTypeCount(const UnitCountType index) const { return _actionCounts[index].getCount(); } void PrerequisiteSet::add(const ActionType & action, const UnitCountType count) { _actionCounts.push_back(ActionCountPair(action, count)); } void PrerequisiteSet::addUnique(const ActionType & action, const UnitCountType count) { if (!contains(action)) { add(action, count); } } void PrerequisiteSet::addUnique(const PrerequisiteSet & set) { for (size_t i(0); i _actionCounts; public: PrerequisiteSet(); const size_t size() const; const bool isEmpty() const; const bool contains(const ActionType & action) const; const ActionType & getActionType(const UnitCountType index) const; const UnitCountType & getActionTypeCount(const UnitCountType index) const; void add(const ActionType & action, const UnitCountType count = 1); void addUnique(const ActionType & action, const UnitCountType count = 1); void addUnique(const PrerequisiteSet & set); void remove(const ActionType & action); void remove(const PrerequisiteSet & set); const std::string toString() const; }; } ================================================ FILE: BOSS/source/StarCraftGUI.cpp ================================================ #include "StarCraftGUI.h" #include "BWAPI.h" #include #include using namespace BOSS; const size_t MaxStarCraftTextures = 512; const int StarCraftGUI::TextureFont = 256; GLfloat ColorWhite[4] = {1.0f, 1.0f, 1.0f, 1.0f}; StarCraftGUI::StarCraftGUI(int width, int height) : _initialWidth(width) , _initialHeight(height) , _cameraX(0) , _cameraY(0) , _previousMouseX(0) , _previousMouseY(0) , _isStarted(false) , _mousePressed(false) , _shiftPressed(false) , _currentFrame(0) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cout << "Could not initialize SDL\n"; exit(-1); } onStart(); } StarCraftGUI::~StarCraftGUI() { SDL_Quit(); } bool StarCraftGUI::isStarted() const { return _isStarted; } // This function must be called before OnFrame void StarCraftGUI::onStart() { // if we've already called OnStart, don't re-initialize everything if (_isStarted) { return; } // the top-left corner of the scene will be 0, 0 _cameraX = 0; _cameraY = 0; // double buffer and swap attributes, makes switching scenes fast SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetSwapInterval(1); // set up the window that the OpenGL context will be bound to _window = SDL_CreateWindow("StarCraft OpenGL Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initialWidth, _initialHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); // set the glcontext to the window we just created _glcontext = SDL_GL_CreateContext(_window); // load all the Starcraft textures that we'll need loadTextures(); // enable alpha blending for transparency glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); // set up the viewport glViewport(0, 0, width(), height()); _isStarted = true; } void StarCraftGUI::onFrame() { BOSS_ASSERT(isStarted(), "Must initialize GUI before calling OnFrame()"); // Handle input events handleEvents(); // Render the frame glClear(GL_COLOR_BUFFER_BIT); render(); SDL_GL_SwapWindow(_window); } void StarCraftGUI::handleEvents() { // Handle SDL events SDL_Event event; while (SDL_PollEvent(&event)) { const bool pressed(event.key.state == SDL_PRESSED); switch (event.type) { case SDL_MOUSEMOTION: { if ((_previousMouseX != 0 || _previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT)) { _cameraX -= event.motion.xrel; _cameraY -= event.motion.yrel; } _previousMouseX = event.motion.x; _previousMouseY = event.motion.y; break; } case SDL_KEYDOWN: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: _shiftPressed = pressed; break; case SDLK_p: { } } break; } case SDL_KEYUP: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: _shiftPressed = pressed; break; } break; } case SDL_MOUSEWHEEL: { break; } case SDL_MOUSEBUTTONDOWN: { break; } case SDL_MOUSEBUTTONUP: { if (event.button.button == SDL_BUTTON_LEFT) { } break; } case SDL_WINDOWEVENT_RESIZED: { break; } case SDL_QUIT: { std::cerr << "SDL_QUIT caught\n\n"; exit(0); } } } } void StarCraftGUI::render() { glViewport(0, 0, width(), height()); glMatrixMode(GL_PROJECTION); glPushMatrix(); { glOrtho(0, width(), height(), 0, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); { glTranslatef(static_cast(-_cameraX),static_cast(-_cameraY),0); drawAllBWAPIUnits(); //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, ColorWhite); //GUITools::DrawString(Position(300, 300), "Test String", ColorWhite); } glPopMatrix(); } glMatrixMode(GL_PROJECTION); glPopMatrix(); _currentFrame++; } int StarCraftGUI::width() { int x, y; SDL_GetWindowSize(_window, &x, &y); return x; } int StarCraftGUI::height() { int x, y; SDL_GetWindowSize(_window, &x, &y); return y; } void StarCraftGUI::setCenter(int x, int y) { _cameraX = -(width() - x) / 2; _cameraY = -(height() - y) / 2; } void StarCraftGUI::drawAllBWAPIUnits() { Position p(0, 0); size_t maxHeight = 0; std::vector allIDs; for (const auto & kv : _techTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & kv : _upgradeTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & kv : _unitTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & id : allIDs) { if (p.x() + _textureSizes[id].x() > width()) { p = Position(0, p.y() + maxHeight); maxHeight = 0; } GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite); maxHeight = std::max((size_t)_textureSizes[id].y(), maxHeight); p.add(Position(_textureSizes[id].x(), 0)); } } void StarCraftGUI::drawUnitType(const BWAPI::UnitType & type, Position & p) { const int id = _unitTypeTextureID[type]; GUITools::DrawString(p, type.getName(), ColorWhite); GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite); } void StarCraftGUI::loadTextures() { std::string imageDir = "../asset/images/"; // set up the vectors that will hold the textures _textures = std::vector(MaxStarCraftTextures, 0); _textureSizes = std::vector(MaxStarCraftTextures); glGenTextures(MaxStarCraftTextures, &_textures[0]); // load all the starcraft unit textures size_t textureNumber = 1; for (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _unitTypeTextureID[type] = textureNumber; textureNumber++; } } for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _techTypeTextureID[type] = textureNumber; textureNumber++; } } for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _upgradeTypeTextureID[type] = textureNumber; textureNumber++; } } loadTexture(TextureFont, imageDir + "fonts/alpha_trans.png"); std::cout << "Successfully loaded " << textureNumber << " textures" << std::endl; } bool StarCraftGUI::loadTexture(int textureNumber, const std::string & fileName) { struct stat buf; if (stat(fileName.c_str(), &buf) == -1) { //std::cout << "Couldn't find texture: " << fileName << std::endl; return false; } SDL_Surface *surface2 = IMG_Load(fileName.c_str()); GLenum texture_format = GL_RGBA; GLint nOfColors = 4; if (surface2 != NULL) { glBindTexture( GL_TEXTURE_2D, textureNumber ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels); } else { printf("SDL could not load image: %s\n", SDL_GetError()); } if (surface2) { _textureSizes[textureNumber] = Position(surface2->w, surface2->h); SDL_FreeSurface( surface2 ); } std::cout << textureNumber << "Loaded: " << fileName << std::endl; return true; } bool StarCraftGUI::saveScreenshotBMP(const std::string & filename) { SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, width(), height(), 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); glReadBuffer(GL_FRONT); glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_SaveBMP(image, filename.c_str()); SDL_FreeSurface(image); return true; } std::string StarCraftGUI::GetTextureFileName(const BWAPI::TechType & type) { std::string filename = "command_icons/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } std::string StarCraftGUI::GetTextureFileName(const BWAPI::UnitType & type) { std::string filename = "units/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } std::string StarCraftGUI::GetTextureFileName(const BWAPI::UpgradeType & type) { std::string filename = "command_icons/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } ================================================ FILE: BOSS/source/StarCraftGUI.h ================================================ #pragma once #include "BWAPI.h" #include "GUITools.h" #include "Timer.hpp" #include "Position.hpp" #include #include #undef main #include #include #include "GUITools.h" #include using BOSS::Position; struct TextureInfo { int _id; Position _size; TextureInfo(int i, Position & s) : _id(i), _size(s) { } }; class StarCraftGUI { int _initialWidth; int _initialHeight; int _windowSizeY; int _cameraX; int _cameraY; bool _isStarted; int _previousMouseX; int _previousMouseY; bool _mousePressed; bool _shiftPressed; size_t _currentFrame; SDL_Window * _window; SDL_Surface * _surface; SDL_GLContext _glcontext; std::vector _textures; std::vector _textureSizes; std::map _textureInfo; std::map _unitTypeTextureID; std::map _techTypeTextureID; std::map _upgradeTypeTextureID; void handleEvents(); void render(); void renderTextGlut(int x, int y, std::string & s); void loadTextures(); bool loadTexture(int textureNumber, const std::string & fileName); void onResize(SDL_Event & event); void drawAllBWAPIUnits(); void onStart(); void testRender(); void drawUnitType(const BWAPI::UnitType & type, Position & p); bool isStarted() const; static std::string GetTextureFileName(const BWAPI::UnitType & type); static std::string GetTextureFileName(const BWAPI::UpgradeType & type); static std::string GetTextureFileName(const BWAPI::TechType & type); public: static const int TextureASCIIOffset; static const int TextureFont; StarCraftGUI(int width, int height); ~StarCraftGUI(); int width(); int height(); void onFrame(); void setCenter(int x, int y); bool saveScreenshotBMP(const std::string & filename); }; ================================================ FILE: BOSS/source/Timer.hpp ================================================ ////////////////////////////////////////////////////////////////////////////// // Timer.hpp // ======= // High Resolution Timer. // This timer is able to measure the elapsed time with 1 micro-second accuracy // in both Windows, Linux and Unix system // // AUTHOR: Song Ho Ahn (song.ahn@gmail.com) // CREATED: 2003-01-13 // UPDATED: 2006-01-13 // // Copyright (c) 2003 Song Ho Ahn ////////////////////////////////////////////////////////////////////////////// #ifndef TIMER_H_DEF #define TIMER_H_DEF #ifdef WIN32 // Windows system specific #include #else // Unix based system specific #include #endif namespace BOSS { class Timer { double startTimeInMicroSec; // starting time in micro-second double endTimeInMicroSec; // ending time in micro-second int stopped; // stop flag #ifdef WIN32 LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER startCount; // LARGE_INTEGER endCount; // #else timeval startCount; // timeval endCount; // #endif public: Timer() { #ifdef WIN32 QueryPerformanceFrequency(&frequency); startCount.QuadPart = 0; endCount.QuadPart = 0; #else startCount.tv_sec = startCount.tv_usec = 0; endCount.tv_sec = endCount.tv_usec = 0; #endif stopped = 0; startTimeInMicroSec = 0; endTimeInMicroSec = 0; start(); } ~Timer() {} // default destructor void start() { stopped = 0; // reset stop flag #ifdef WIN32 QueryPerformanceCounter(&startCount); #else gettimeofday(&startCount, NULL); #endif } void stop() { stopped = 1; // set timer stopped flag #ifdef WIN32 QueryPerformanceCounter(&endCount); #else gettimeofday(&endCount, NULL); #endif } double getElapsedTimeInMicroSec() { #ifdef WIN32 if(!stopped) QueryPerformanceCounter(&endCount); startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart); endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart); #else if(!stopped) gettimeofday(&endCount, NULL); startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec; endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec; #endif return endTimeInMicroSec - startTimeInMicroSec; } double getElapsedTimeInMilliSec() { return this->getElapsedTimeInMicroSec() * 0.001; } double getElapsedTimeInSec() { return this->getElapsedTimeInMicroSec() * 0.000001; } double getElapsedTime() { return this->getElapsedTimeInSec(); } }; } #endif // TIMER_H_DEF ================================================ FILE: BOSS/source/Tools.cpp ================================================ #include "Tools.h" #include "BuildOrderSearchGoal.h" #include "NaiveBuildOrderSearch.h" using namespace BOSS; #include "JSONTools.h" BuildOrder Tools::GetOptimizedNaiveBuildOrderOld(const GameState & state, const BuildOrderSearchGoal & goal) { BuildOrder bestBuildOrder = GetNaiveBuildOrderAddWorkersOld(state, goal, 4); FrameCountType minCompletionTime = bestBuildOrder.getCompletionTime(state); UnitCountType bestNumWorkers = bestBuildOrder.getTypeCount(ActionTypes::GetWorker(state.getRace())); for (UnitCountType numWorkers(8); numWorkers < 27; ++numWorkers) { BuildOrder buildOrder = Tools::GetNaiveBuildOrderAddWorkersOld(state, goal, numWorkers); FrameCountType completionTime = buildOrder.getCompletionTime(state); UnitCountType workers = buildOrder.getTypeCount(ActionTypes::GetWorker(state.getRace())); if (completionTime <= minCompletionTime + ((workers-bestNumWorkers)*24)) { minCompletionTime = completionTime; bestBuildOrder = buildOrder; } } FrameCountType bestCompletionTime = bestBuildOrder.getCompletionTime(state); BuildOrder testBuildOrder; //std::cout << "Found a better build order that takes " << bestCompletionTime << " frames\n"; while (true) { const static ActionType gateway = ActionTypes::GetActionType("Protoss_Gateway"); InsertActionIntoBuildOrder(testBuildOrder, bestBuildOrder, state, gateway); FrameCountType completionTime = testBuildOrder.getCompletionTime(state); if (completionTime < bestCompletionTime) { //std::cout << "Found a better build order that takes " << completionTime << " frames\n"; bestCompletionTime = completionTime; bestBuildOrder = testBuildOrder; } else { break; } } return bestBuildOrder; } BuildOrder Tools::GetNaiveBuildOrderAddWorkersOld(const GameState & state, const BuildOrderSearchGoal & goal, UnitCountType maxWorkers) { PrerequisiteSet wanted; int minWorkers = 8; const ActionType & worker = ActionTypes::GetWorker(state.getRace()); std::vector buildOrderActionTypeCount(ActionTypes::GetAllActionTypes(state.getRace()).size(), 0); // add everything from the goal to the needed set for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a); UnitCountType numCompleted = state.getUnitData().getNumTotal(actionType); if (goal.getGoal(actionType) > numCompleted) { wanted.addUnique(actionType); } } if (wanted.size() == 0) { return BuildOrder(); } // Calculate which prerequisite units we need to build to achieve the units we want from the goal PrerequisiteSet requiredToBuild; CalculatePrerequisitesRequiredToBuild(state, wanted, requiredToBuild); // Add the required units to a preliminary build order BuildOrder buildOrder; for (size_t a(0); a < requiredToBuild.size(); ++a) { const ActionType & type = requiredToBuild.getActionType(a); buildOrder.add(type); buildOrderActionTypeCount[type.ID()]++; } // Add some workers to the build order if we don't have many, this usually gives a lower upper bound int requiredWorkers = minWorkers - state.getUnitData().getNumCompleted(ActionTypes::GetWorker(state.getRace())); while (requiredWorkers-- > 0) { buildOrder.add(worker); buildOrderActionTypeCount[worker.ID()]++; } // Add the goal units to the end of the build order for (size_t a(0); a < ActionTypes::GetAllActionTypes(state.getRace()).size(); ++a) { const ActionType & actionType = ActionTypes::GetActionType(state.getRace(), a); int need = (int)goal.getGoal(actionType); int have = (int)state.getUnitData().getNumTotal(actionType); int numNeeded = need - have - buildOrderActionTypeCount[actionType.ID()]; for (int i(0); i < numNeeded; ++i) { buildOrder.add(actionType); } } static const ActionType commandCenter = ActionTypes::GetActionType("Terran_Command_Center"); static const ActionType factory = ActionTypes::GetActionType("Terran_Factory"); static const ActionType starport = ActionTypes::GetActionType("Terran_Starport"); static const ActionType scienceFacility = ActionTypes::GetActionType("Terran_Science_Facility"); // Check to see if we have enough buildings for the required addons if (state.getRace() == Races::Terran) { int commandCenterAddons = 0; int factoryAddons = 0; int starportAddons = 0; int sciAddons = 0; int numCommandCenters = state.getUnitData().getNumTotal(commandCenter); int numFactories = state.getUnitData().getNumTotal(factory); int numStarports = state.getUnitData().getNumTotal(starport); int numSci = state.getUnitData().getNumTotal(scienceFacility); for (size_t a(0); a < buildOrder.size(); ++a) { const ActionType & actionType = buildOrder[a]; if (actionType.isAddon()) { if (actionType.whatBuildsActionType() == commandCenter) { ++commandCenterAddons; } else if (actionType.whatBuildsActionType() == factory) { ++factoryAddons; } else if (actionType.whatBuildsActionType() == starport) { ++starportAddons; } else if (actionType.whatBuildsActionType() == scienceFacility) { ++sciAddons; } else { BOSS_ASSERT(false, "Addon has no builder: %s %s", actionType.getName().c_str(), actionType.whatBuildsActionType().getName().c_str()); } } if (actionType == commandCenter) { ++numCommandCenters; } else if (actionType == factory) { ++numFactories; } else if (actionType == starport) { ++numStarports; } else if (actionType == scienceFacility) { ++numSci; } } // add the necessary buildings to make the addons for (int n(0); n < commandCenterAddons - numCommandCenters; ++n) { buildOrder.add(commandCenter); } for (int n(0); n < factoryAddons - numFactories; ++n) { buildOrder.add(factory); } for (int n(0); n < starportAddons - numStarports; ++n) { buildOrder.add(starport); } for (int n(0); n < sciAddons - numSci; ++n) { buildOrder.add(scienceFacility); } } // Bubble sort the build order so that prerequites always come before what requires them for (size_t i(0); i < buildOrder.size()-1; ++i) { for (size_t j(i+1); j < buildOrder.size(); ++j) { const PrerequisiteSet & recursivePre = buildOrder[i].getRecursivePrerequisites(); if (recursivePre.contains(buildOrder[j])) { std::swap(buildOrder[i], buildOrder[j]); } } } // finish the build order with workers and supply BuildOrder finalBuildOrder; GameState currentState(state); size_t i = 0; while (i < buildOrder.size()) { const ActionType & worker = ActionTypes::GetWorker(currentState.getRace()); const ActionType & supplyProvider = ActionTypes::GetSupplyProvider(currentState.getRace()); const ActionType & nextAction = buildOrder[i]; UnitCountType maxSupply = currentState.getUnitData().getMaxSupply() + currentState.getUnitData().getSupplyInProgress(); UnitCountType numWorkers = currentState.getUnitData().getNumTotal(worker); UnitCountType currentSupply = currentState.getUnitData().getCurrentSupply(); if (numWorkers < 8) { finalBuildOrder.add(worker); currentState.doAction(worker); continue; } // insert a supply provider if we are behind int surplusSupply = maxSupply - currentSupply; if (surplusSupply < nextAction.supplyRequired() + 2) { try { BOSS_ASSERT(currentState.isLegal(supplyProvider), "supplyProvider should be legal"); finalBuildOrder.add(supplyProvider); currentState.doAction(supplyProvider); continue; } catch (BOSSException e) { break; } } FrameCountType whenWorkerReady = currentState.whenCanPerform(worker); FrameCountType whennextActionReady = currentState.whenCanPerform(nextAction); if ((numWorkers < maxWorkers) && (whenWorkerReady < whennextActionReady)) { // check to see if we should insert a worker try { BOSS_ASSERT(currentState.isLegal(worker), "Worker should be legal"); finalBuildOrder.add(worker); currentState.doAction(worker); } catch (BOSSException) { } continue; } else { ActionType testNextAction = buildOrder[i]; BOSS_ASSERT(currentState.isLegal(nextAction), "nextAction should be legal"); finalBuildOrder.add(nextAction); currentState.doAction(nextAction); ++i; } } return finalBuildOrder; } void Tools::InsertActionIntoBuildOrder(BuildOrder & result, const BuildOrder & buildOrder, const GameState & initialState, const ActionType & action) { int bestInsertIndex = -1; BuildOrder runningBuildOrder; GameState runningState(initialState); FrameCountType minCompletionTime = buildOrder.getCompletionTime(initialState); BuildOrder testBuildOrder = buildOrder; for (size_t insertIndex(0); insertIndex < buildOrder.size(); ++insertIndex) { // if we can test the action here, do it if (runningState.isLegal(action)) { // figure out the build time of build order with action inserted here GameState tempState(runningState); tempState.doAction(action); for (size_t a(insertIndex); a < buildOrder.size(); ++a) { tempState.doAction(buildOrder[a]); } FrameCountType completionTime = tempState.getLastActionFinishTime(); if (completionTime < minCompletionTime) { minCompletionTime = completionTime; bestInsertIndex = insertIndex; } } BOSS_ASSERT(runningState.isLegal(buildOrder[insertIndex]), "We have made the next action illegal somehow"); runningBuildOrder.add(buildOrder[insertIndex]); runningState.doAction(buildOrder[insertIndex]); } result.clear(); for (size_t a(0); a numCompleted) { wanted.addUnique(actionType); } } FrameCountType lowerBound = Tools::CalculatePrerequisitesLowerBound(state, wanted, 0); return lowerBound; } void Tools::CalculatePrerequisitesRequiredToBuild(const GameState & state, const PrerequisiteSet & needed, PrerequisiteSet & added) { // if anything needed gas and we don't have a refinery, we need to add one PrerequisiteSet allNeeded(needed); const ActionType & refinery = ActionTypes::GetRefinery(state.getRace()); if (!needed.contains(refinery) && (state.getUnitData().getNumCompleted(refinery) == 0) && !added.contains(refinery)) { for (size_t n(0); n 0) { allNeeded.add(refinery); break; } } } for (size_t n(0); n 0) { } // if we have the needed type in progress we can add that time else if (state.getUnitData().getNumInProgress(neededType) > 0) { //added.add(neededType); } // otherwise we need to recurse on the needed type to build its prerequisites else { added.add(neededType); CalculatePrerequisitesRequiredToBuild(state, neededType.getPrerequisites(), added); } } } // returns the amount of time necessary to complete the longest chain of sequential prerequisites FrameCountType Tools::CalculatePrerequisitesLowerBound(const GameState & state, const PrerequisiteSet & needed, FrameCountType timeSoFar, int depth) { FrameCountType max = 0; for (size_t n(0); n 0) { thisActionTime = timeSoFar; } // if we have the needed type in progress we can add that time else if (state.getUnitData().getNumInProgress(neededType) > 0) { thisActionTime = timeSoFar + state.getUnitData().getFinishTime(neededType) - state.getCurrentFrame(); } // otherwise we need to recurse on the needed type to build its prerequisites else { /*for (int i=0; i max) { max = thisActionTime; } } return max; } ================================================ FILE: BOSS/source/Tools.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "BuildOrderSearchGoal.h" #include "BuildOrder.h" namespace BOSS { namespace Tools { FrameCountType GetUpperBound(const GameState & state, const BuildOrderSearchGoal & goal); FrameCountType GetLowerBound(const GameState & state, const BuildOrderSearchGoal & goal); FrameCountType CalculatePrerequisitesLowerBound(const GameState & state, const PrerequisiteSet & needed, FrameCountType timeSoFar, int depth = 0); void InsertActionIntoBuildOrder(BuildOrder & result, const BuildOrder & buildOrder, const GameState & initialState, const ActionType & action); void CalculatePrerequisitesRequiredToBuild(const GameState & state, const PrerequisiteSet & wanted, PrerequisiteSet & requiredToBuild); BuildOrder GetOptimizedNaiveBuildOrderOld(const GameState & state, const BuildOrderSearchGoal & goal); BuildOrder GetNaiveBuildOrderAddWorkersOld(const GameState & state, const BuildOrderSearchGoal & goal, UnitCountType maxWorkers); } } ================================================ FILE: BOSS/source/UnitData.cpp ================================================ #include "UnitData.h" using namespace BOSS; UnitData::UnitData(const RaceID race) : _race(race) , _numUnits(Constants::MAX_ACTIONS, 0) , _currentSupply(0) , _maxSupply(0) , _mineralWorkers(0) , _gasWorkers(0) , _buildingWorkers(0) { } const RaceID UnitData::getRace() const { return _race; } const UnitCountType UnitData::getNumCompleted(const ActionType & action) const { return _numUnits[action.ID()]; } void UnitData::setCurrentSupply(const UnitCountType & supply) { _currentSupply = supply; } const FrameCountType UnitData::getWhenBuildingCanBuild(const ActionType & action) const { return _buildings.getTimeUntilCanBuild(action); } // only used for adding existing buildings from a BWAPI Game * object void UnitData::addCompletedBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon, int numLarva) { _numUnits[action.ID()] += action.numProduced(); _maxSupply += action.supplyProvided(); // if it's an extractor if (action.isRefinery()) { // take those workers from minerals and put them into it _mineralWorkers -= 3; _gasWorkers += 3; } // if it's a building that can produce units, add it to the building data if (action.isBuilding() && !action.isSupplyProvider()) { _buildings.addBuilding(action, timeUntilFree, constructing, addon); } // special case for hatcheries if (action.getRace() == Races::Zerg && action.isResourceDepot()) { _hatcheryData.addHatchery(numLarva); } } void UnitData::addCompletedAction(const ActionType & action, bool wasBuilt) { const static ActionType Lair = ActionTypes::GetActionType("Zerg_Lair"); const static ActionType Hive = ActionTypes::GetActionType("Zerg_Hive"); _numUnits[action.ID()] += wasBuilt ? action.numProduced() : 1; if (wasBuilt) { // a lair or hive from a hatchery don't produce additional supply if (action != Lair && action != Hive) { _maxSupply += action.supplyProvided(); } } else { _maxSupply += action.supplyProvided(); } if (action.isWorker()) { _mineralWorkers++; } // if it's an extractor if (action.isRefinery()) { // take those workers from minerals and put them into it _mineralWorkers -= 3; _gasWorkers += 3; } // if it's a building that can produce units, add it to the building data if (action.isBuilding() && !action.isSupplyProvider()) { if (!action.isMorphed()) { _buildings.addBuilding(action, ActionTypes::None); } } // special case for hatcheries if (action.isBuilding() && (action.getUnitType() == BWAPI::UnitTypes::Zerg_Hatchery)) { _hatcheryData.addHatchery(wasBuilt ? 1 : 3); } } void UnitData::removeCompletedAction(const ActionType & action) { //Logger::LogAppendToFile(BOSS_LOGFILE, "Unit removed " + action.getName()); const static ActionType Lair = ActionTypes::GetActionType("Zerg_Lair"); const static ActionType Hive = ActionTypes::GetActionType("Zerg_Hive"); _numUnits[action.ID()] -= action.numProduced(); // a lair or hive from a hatchery don't produce additional supply if (action != Lair && action != Hive) { _maxSupply -= action.supplyProvided(); } if (action.isWorker()) { if (_mineralWorkers > 0) { _mineralWorkers--; } else if (_gasWorkers > 0) { _gasWorkers--; } } // if it's an extractor if (action.isRefinery()) { // take those workers from minerals and put them into it _mineralWorkers += 3; _gasWorkers -= 3; } BOSS_ASSERT(_mineralWorkers >= 0, "Can't have negative mineral workers"); BOSS_ASSERT(_gasWorkers >= 0, "Can't have negative gas workers"); // if it's a building that can produce units, add it to the building data if (action.isBuilding() && !action.isSupplyProvider()) { if (!action.isMorphed()) { _buildings.removeBuilding(action, ActionTypes::None); } } // special case for hatcheries if (action.isBuilding() && (action.getUnitType() == BWAPI::UnitTypes::Zerg_Hatchery)) { _hatcheryData.removeHatchery(); } } void UnitData::addActionInProgress(const ActionType & action, const FrameCountType & completionFrame, bool queueAction) { FrameCountType finishTime = (action.isBuilding() && !action.isMorphed()) ? completionFrame + Constants::BUILDING_PLACEMENT : completionFrame; // add it to the actions in progress _progress.addAction(action, finishTime); if (!action.isMorphed()) { _currentSupply += action.supplyRequired() * action.numProduced(); } if (queueAction && action.whatBuildsIsBuilding()) { // add it to a free building, which MUST be free since it's called from doAction // which must be already fastForwarded to the correct time _buildings.queueAction(action); } } const bool UnitData::hasActionsInProgress() const { return _progress.isEmpty(); } const SupplyCountType UnitData::getCurrentSupply() const { return _currentSupply; } const SupplyCountType UnitData::getMaxSupply() const { return _maxSupply; } void UnitData::setBuildingWorker() { BOSS_ASSERT(_mineralWorkers > 0, "Tried to build without a worker"); _mineralWorkers--; _buildingWorkers++; } const bool UnitData::hasGasIncome() const { return _gasWorkers > 0 || getNumTotal(ActionTypes::GetRefinery(getRace())) > 0; } const bool UnitData::hasMineralIncome() const { return getNumMineralWorkers() > 0 || getNumBuildingWorkers() > 0 || getNumInProgress(ActionTypes::GetWorker(getRace())) > 0; } void UnitData::releaseBuildingWorker() { _mineralWorkers++; _buildingWorkers--; } void UnitData::setMineralWorkers(const UnitCountType & mineralWorkers) { _mineralWorkers = mineralWorkers; } void UnitData::setGasWorkers(const UnitCountType & gasWorkers) { _gasWorkers = gasWorkers; } void UnitData::setBuildingWorkers(const UnitCountType & buildingWorkers) { _buildingWorkers = buildingWorkers; } void UnitData::morphUnit(const ActionType & from, const ActionType & to, const FrameCountType & completionFrame) { BOSS_ASSERT(getNumCompleted(from) > 0, "Must have the unit type to morph it"); _numUnits[from.ID()]--; _currentSupply -= from.supplyRequired(); if (from.isWorker()) { BOSS_ASSERT(_mineralWorkers > 0, "Need mineral worker"); _mineralWorkers--; } addActionInProgress(to, completionFrame); } const UnitCountType UnitData::getNumMineralWorkers() const { return _mineralWorkers; } const UnitCountType UnitData::getNumGasWorkers() const { return _gasWorkers; } const UnitCountType UnitData::getNumBuildingWorkers() const { return _buildingWorkers; } ActionType UnitData::finishNextActionInProgress() { // get the actionUnit from the progress data ActionType action = _progress.nextAction(); // add the unit to the unit counter addCompletedAction(action); // pop it from the progress vector _progress.popNextAction(); if (getRace() == Races::Terran) { // if it's a building, release the worker back if (action.isBuilding() && !action.isAddon()) { releaseBuildingWorker(); } } else if (getRace() == Races::Zerg) { const static ActionType hatchery = ActionTypes::GetActionType("Zerg_Hatchery"); } return action; } const FrameCountType UnitData::getNextActionFinishTime() const { return _progress.nextActionFinishTime(); } const FrameCountType UnitData::getNextBuildingFinishTime() const { return _progress.nextBuildingFinishTime(); } void UnitData::setBuildingFrame(const FrameCountType & frame) { _buildings.fastForwardBuildings(frame); } const UnitCountType UnitData::getNumTotal(const ActionType & action) const { return _numUnits[action.ID()] + (_progress.numInProgress(action) * action.numProduced()); } const bool UnitData::hasPrerequisites(const PrerequisiteSet & required) const { static const ActionType & Hatchery = ActionTypes::GetActionType("Zerg_Hatchery"); static const ActionType & Lair = ActionTypes::GetActionType("Zerg_Lair"); static const ActionType & Hive = ActionTypes::GetActionType("Zerg_Hive"); static const ActionType & Spire = ActionTypes::GetActionType("Zerg_Spire"); static const ActionType & GreaterSpire = ActionTypes::GetActionType("Zerg_Greater_Spire"); for (size_t a(0); a 0 && getNumCompleted(actionType) == 0) { inProgress.add(actionType); } } return inProgress; } const BuildingData & UnitData::getBuildingData() const { return _buildings; } HatcheryData & UnitData::getHatcheryData() { return _hatcheryData; } const HatcheryData & UnitData::getHatcheryData() const { return _hatcheryData; } ================================================ FILE: BOSS/source/UnitData.h ================================================ #pragma once #include "Common.h" #include "Array.hpp" #include "BuildingData.h" #include "ActionType.h" #include "ActionInProgress.h" #include "HatcheryData.h" namespace BOSS { class UnitData { RaceID _race; UnitCountType _mineralWorkers; // number of workers currently mining UnitCountType _gasWorkers; // number of workers currently getting gas UnitCountType _buildingWorkers; SupplyCountType _maxSupply; // our maximum allowed supply SupplyCountType _currentSupply; // our current allocated supply Vec _numUnits; // how many of each unit are completed HatcheryData _hatcheryData; ActionsInProgress _progress; BuildingData _buildings; public: UnitData(const RaceID race); const RaceID getRace() const; const bool hasActionsInProgress() const; const bool hasPrerequisites(const PrerequisiteSet & required) const; const bool hasGasIncome() const; const bool hasMineralIncome() const; const PrerequisiteSet getPrerequistesInProgress(const ActionType & action) const; const UnitCountType getNumTotal(const ActionType & action) const; const UnitCountType getNumInProgress(const ActionType & action) const; const UnitCountType getNumCompleted(const ActionType & action) const; const UnitCountType getNumActionsInProgress() const; const UnitCountType getNumLarva() const; const UnitCountType getNumMineralWorkers() const; const UnitCountType getNumGasWorkers() const; const UnitCountType getNumBuildingWorkers() const; const UnitCountType getSupplyInProgress() const; const ActionType & getActionInProgressByIndex(const UnitCountType & index) const; const FrameCountType getActionInProgressFinishTimeByIndex(const UnitCountType & index) const; const FrameCountType getNextBuildingFinishTime() const; const FrameCountType getFinishTime(const ActionType & action) const; const FrameCountType getFinishTime(const PrerequisiteSet & set) const; const FrameCountType getFinishTimeByIndex(const UnitCountType & index) const; const FrameCountType getNextActionFinishTime() const; const FrameCountType getLastActionFinishTime() const; //const FrameCountType getTimeUntilBuildingFree(const ActionType & action) const; const FrameCountType getWhenBuildingCanBuild(const ActionType & action) const; const SupplyCountType getCurrentSupply() const; const SupplyCountType getMaxSupply() const; void setCurrentSupply(const UnitCountType & supply); void setBuildingWorker(); void releaseBuildingWorker(); void addCompletedBuilding(const ActionType & action, const FrameCountType timeUntilFree, const ActionType & constructing, const ActionType & addon, int numLarva); void addCompletedAction(const ActionType & action, bool wasBuilt = true); void removeCompletedAction(const ActionType & action); void addActionInProgress(const ActionType & action, const FrameCountType & completionFrame, bool queueAction = true); void setBuildingFrame(const FrameCountType & frame); void setMineralWorkers(const UnitCountType & mineralWorkers); void setGasWorkers(const UnitCountType & gasWorkers); void setBuildingWorkers(const UnitCountType & buildingWorkers); void morphUnit(const ActionType & from, const ActionType & to, const FrameCountType & completionFrame); ActionType finishNextActionInProgress(); const BuildingData & getBuildingData() const; const HatcheryData & getHatcheryData() const; HatcheryData & getHatcheryData(); }; } ================================================ FILE: BOSS/source/deprecated/BOSSAssert.cpp ================================================ #include "BOSSAssert.h" using namespace BOSS; char BOSS_LOGFILE[100] { "BOSS_error_log.txt" }; namespace BOSS { namespace Assert { std::string lastErrorMessage; const std::string currentDateTime() { time_t now = time(0); struct tm tstruct; char buf[80]; //tstruct = *localtime(&now); localtime_s(&tstruct, &now); strftime(buf, sizeof(buf), "%Y-%m-%d_%X", &tstruct); return buf; } void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...) { char messageBuffer[1024] = ""; if (msg != NULL) { va_list args; va_start(args, msg); //vsprintf(messageBuffer, msg, args); vsnprintf_s(messageBuffer, 1024, msg, args); va_end(args); } std::stringstream ss; ss << std::endl; ss << "!Assert: " << condition << std::endl; ss << "File: " << file << std::endl; ss << "Message: " << messageBuffer << std::endl; ss << "Line: " << line << std::endl; ss << "Time: " << currentDateTime() << std::endl; lastErrorMessage = messageBuffer; std::cerr << ss.str(); throw BOSSException(ss.str()); } } } ================================================ FILE: BOSS/source/deprecated/BOSSAssert.h ================================================ #pragma once #include "Common.h" #include #include #include "BOSSLogger.h" #include #include #include #include extern char BOSS_LOGFILE[100]; #ifdef _MSC_VER #define BOSS_BREAK #else #define BOSS_BREAK exit(-1); #endif #define BOSS_ASSERT_ALL #ifdef BOSS_ASSERT_ALL #define BOSS_ASSERT(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ BOSS::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ BOSS_BREAK \ } \ } while(0) #else #define BOSS_ASSERT(cond, msg, ...) #endif namespace BOSS { namespace Assert { class BOSSException : public std::exception { std::string s; public : BOSSException(std::string ss) : s(ss) {} ~BOSSException() throw () {} const char* what() const throw() { return s.c_str(); } }; void ShutDown(); extern std::string lastErrorMessage; const std::string currentDateTime(); void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...); } } ================================================ FILE: BOSS/source/deprecated/BOSSVisExperiment.cpp ================================================ #include "BOSSVisExperiment.h" #include "GUI.h" using namespace BOSS; BOSSVisExperiment::BOSSVisExperiment() : _fps(0) , _scenarios(0) , _finished(true) { } BOSSVisExperiment::BOSSVisExperiment(const rapidjson::Value & val, std::map< std::string, GameState > & stateMap, std::map< std::string, BuildOrder > & buildOrderMap) : _startTimes(val["scenarios"].Size(), std::vector()) , _finishTimes(val["scenarios"].Size(), std::vector()) , _nextActionIndexes(val["scenarios"].Size(), 0) , _fps(0) , _scenarios(0) , _finished(false) { if (val.HasMember("fps") && val["fps"].IsInt()) { _fps = val["fps"].GetInt(); } const rapidjson::Value & scenarios = val["scenarios"]; _scenarios = scenarios.Size(); for (size_t i(0); i < scenarios.Size(); ++i) { const rapidjson::Value & scenario = scenarios[i]; BOSS_ASSERT(scenario.HasMember("state") && scenario["state"].IsString(), "Scenario has no 'state' string"); BOSS_ASSERT(scenario.HasMember("buildOrder") && scenario["buildOrder"].IsString(), "Scenario has no 'buildOrder' string"); const std::string & stateName = scenario["state"].GetString(); const std::string & boName = scenario["buildOrder"].GetString(); BOSS_ASSERT(stateMap.find(stateName) != stateMap.end(), "State not found: %s", stateName.c_str()); BOSS_ASSERT(buildOrderMap.find(boName) != buildOrderMap.end(), "Build Order not found: %s", boName.c_str()); _states.push_back(stateMap[scenario["state"].GetString()]); _buildOrders.push_back(buildOrderMap[scenario["buildOrder"].GetString()]); } } const Position & BOSSVisExperiment::getLastDrawPosition() const { return _lastDrawPosition; } void BOSSVisExperiment::draw() { Position drawAt(0,0); for (size_t i(0); i < _scenarios; ++i) { PositionType endY = DrawScenario(drawAt, i); drawAt = Position(0, endY); } _lastDrawPosition = drawAt; } void BOSSVisExperiment::onFrame() { if (_finished) { return; } for (size_t s(0); s < _states.size(); ++s) { bool didAction = false; if (_nextActionIndexes[s] < _buildOrders[s].size()) { FrameCountType nextActionFrame = _states[s].whenCanPerform(_buildOrders[s][_nextActionIndexes[s]]); if (nextActionFrame == _states[s].getCurrentFrame()) { ActionType type = _buildOrders[s][_nextActionIndexes[s]]; FrameCountType finish = _states[s].getCurrentFrame() + _buildOrders[s][_nextActionIndexes[s]].buildTime(); if (type.isBuilding() && !type.isAddon() && !type.isMorphed()) { finish += Constants::BUILDING_PLACEMENT; } _startTimes[s].push_back(_states[s].getCurrentFrame()); _finishTimes[s].push_back(finish); _states[s].doAction(_buildOrders[s][_nextActionIndexes[s]]); didAction = true; //std::cout << states[s].getCurrentFrame() << " Action Performed: " << buildOrder[nextActionIndex].getName() << std::endl; _nextActionIndexes[s]++; } } if (!didAction) { _states[s].fastForward(_states[s].getCurrentFrame() + 3); } } draw(); bool notFinished = false; for (size_t i(0); i < _states.size(); ++i) { if (_nextActionIndexes[i] < _buildOrders[i].size() || _states[i].getCurrentFrame() < _states[i].getLastActionFinishTime()) { notFinished = true; return; } } _finished = !notFinished; } std::string BOSSVisExperiment::getTimeString(const FrameCountType & frameCount) { std::stringstream min; min << (frameCount/24)/60; std::string minString = min.str(); std::stringstream sec; sec << (frameCount/24)%60; std::string secString = sec.str(); while (secString.length() < 2) secString = "0" + secString; std::string timeString = minString + ":" + secString; return timeString; } //const GameState & currentState, const std::vector & buildOrder, const size_t & boIndex, const std::vector & startTimes, const std::vector & finishTimes); PositionType BOSSVisExperiment::DrawScenario(const Position & pos, const size_t scenario) { const GameState & currentState = _states[scenario]; const BuildOrder & buildOrder = _buildOrders[scenario]; const std::vector & startTimes = _startTimes[scenario]; const std::vector & finishTimes = _finishTimes[scenario]; //const size_t & boIndex = _buildO const std::vector & allActions = ActionTypes::GetAllActionTypes(currentState.getRace()); static const ActionType & Larva = ActionTypes::GetActionType("Zerg_Larva"); static const ActionType & Hatchery = ActionTypes::GetActionType("Zerg_Hatchery"); GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat white2[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat white[4] = {1.0f, 1.0f, 1.0f, 0.8f}; GLfloat grey[4] = {0.1f, 0.1f, 0.1f, 1.0f}; GLfloat grey2[4] = {0.4f, 0.4f, 0.4f, 1.0f}; GLfloat red[4] = {0.6f, 0.0f, 0.0f, 1.0f}; GLfloat blue[4] = {0.0f, 0.0f, 0.5f, 1.0f}; GLfloat bblue[4] = {0.5f, 0.5f, 1.0f, 1.0f}; GLfloat bred[4] = {1.0f, 0.0f, 0.0f, 1.0f}; GLfloat green[4] = {0.0f, 0.4f, 0.0f, 1.0f}; GLfloat bgreen[4] = {0.0f, 1.0f, 0.0f, 1.0f}; std::string stateTime = getTimeString(currentState.getCurrentFrame()); std::stringstream ssres; ssres << "Frame: " << currentState.getCurrentFrame() <<"\n"; ssres << "Minerals: " << currentState.getMinerals()/Constants::RESOURCE_SCALE << "\n"; ssres << "Gas: " << currentState.getGas()/Constants::RESOURCE_SCALE << "\n"; ssres << "MWorkers: " << currentState.getNumMineralWorkers() << "\n"; ssres << "GWorkers: " << currentState.getNumGasWorkers() << "\n"; ssres << "C Supply: " << currentState.getUnitData().getCurrentSupply() << "\n"; ssres << "M Supply: " << currentState.getUnitData().getMaxSupply() << "\n"; GUITools::DrawString(pos + Position(20, 20), ssres.str(), white); Position completed = pos + Position(225,0); size_t cwidth = 64; if (currentState.getRace() == Races::Zerg) { const UnitCountType & numLarva = currentState.getHatcheryData().numLarva(); GUI::Instance().DrawActionType(Larva, completed, cwidth); std::stringstream num; num << numLarva << "\n" << (Constants::ZERG_LARVA_TIMER-(currentState.getCurrentFrame() % Constants::ZERG_LARVA_TIMER)); GUITools::DrawString(completed + Position(10, 20), num.str(), white); completed.add(cwidth, 0); } for (size_t a(0); a < allActions.size(); ++a) { const size_t numCompleted = currentState.getUnitData().getNumCompleted(allActions[a]); if (numCompleted > 0) { GUI::Instance().DrawActionType(allActions[a], completed, cwidth); std::stringstream num; num << numCompleted; GUITools::DrawString(completed + Position(10, 20), num.str(), white); completed.add(cwidth, 0); } } Position legal = pos + Position(225,80); ActionSet legalActions; currentState.getAllLegalActions(legalActions); GUITools::DrawString(legal + Position(0,-5), "Legal Actions", white); for (size_t a(0); a < legalActions.size(); ++a) { const ActionType & action = legalActions[a]; GUI::Instance().DrawActionType(legalActions[a], legal, 32); legal.add(32, 0); } std::vector layers(startTimes.size(), -1); int maxLayer = 0; for (size_t i(0); i < startTimes.size(); ++i) { FrameCountType start = startTimes[i]; FrameCountType finish = finishTimes[i]; std::vector layerOverlap; // loop through everything up to this action and see which layers it can't be in for (size_t j(0); j < i; ++j) { if (start < finishTimes[j]) { layerOverlap.push_back(layers[j]); } } // find a layer we can assign to this value int layerTest = 0; while (true) { if (std::find(layerOverlap.begin(), layerOverlap.end(), layerTest) == layerOverlap.end()) { layers[i] = layerTest; if (layerTest > maxLayer) { maxLayer = layerTest; } break; } layerTest++; } } float maxWidth = (float)GUI::Instance().Width() - 430; float maxFinishTime = 1; for (size_t i(0); i < _finishTimes.size(); ++i) { for (size_t j(0); j < _finishTimes[i].size(); ++j) { if (_finishTimes[i][j] > maxFinishTime) { maxFinishTime = (float)_finishTimes[i][j]; } } } if (currentState.getCurrentFrame() < maxWidth && currentState.getCurrentFrame() > maxFinishTime) { maxFinishTime = (float)currentState.getCurrentFrame(); } maxFinishTime = std::max(maxFinishTime, maxWidth); //maxFinishTime = std::max(currentState.getCurrentFrame()*1.10f, maxWidth); float scale = maxWidth / maxFinishTime; // draw it PositionType height = 20; PositionType heightBuffer = 3; Position concurrent = pos + Position(25, 200); float framePos = (concurrent.x() + scale*currentState.getCurrentFrame()); Position boxTopLeft = Position(concurrent.x() - 10, concurrent.y() - 10); Position boxBottomRight = Position(PositionType(concurrent.x() + maxWidth + 10), (PositionType)(concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height)); GUITools::DrawRect(boxTopLeft, boxBottomRight, grey2); GUITools::DrawRect(boxTopLeft + Position(1,1), boxBottomRight - Position(1,1), grey); for (size_t i(0); i < layers.size(); ++i) { float boxWidth = (finishTimes[i] - startTimes[i])*scale; Position topLeft(PositionType(concurrent.x() + startTimes[i]*scale), PositionType(concurrent.y() + (height + heightBuffer) * layers[i])); Position bottomRight(PositionType(topLeft.x() + boxWidth), topLeft.y() + height); std::string name = buildOrder[i].getName(); #ifndef EMSCRIPTEN size_t loc = name.find("_") + 1; #else size_t loc = name.find(" ") + 1; #endif if (loc != std::string::npos) { name = name.substr(loc); } GUITools::DrawRect(topLeft, bottomRight, white); GUITools::DrawRect(topLeft+Position(1,1), bottomRight-Position(1,1), finishTimes[i] < currentState.getCurrentFrame() ? red : blue); GUITools::DrawString(topLeft + Position(3, 13), name, white); } PositionType boWidth = std::min(32, (PositionType)(maxWidth / buildOrder.size())); for (size_t i(0); i < buildOrder.size(); ++i) { Position topLeft(concurrent.x() + i*boWidth, concurrent.y() - boWidth - 20); if (i < _nextActionIndexes[scenario]) { GUITools::DrawRect(topLeft, topLeft + Position(boWidth, boWidth), grey2); GUITools::DrawRect(topLeft + Position(1,1), topLeft + Position(boWidth-1, boWidth-1), finishTimes[i] < currentState.getCurrentFrame() ? grey : blue); } if (i < startTimes.size()) { //GUITools::DrawString(topLeft - Position(-2,20), getTimeString(startTimes[i]).c_str(), bblue); //GUITools::DrawString(topLeft - Position(-2,9), getTimeString(finishTimes[i]).c_str(), bred); } GUI::Instance().DrawActionType(buildOrder[i], topLeft, boWidth); std::string name = buildOrder[i].getName(); #ifndef EMSCRIPTEN size_t loc = name.find("_") + 1; #else size_t loc = name.find(" ") + 1; #endif if (loc != std::string::npos) { name = name.substr(loc, 2); } GUITools::DrawString(topLeft - Position(-1, 3), name, white); } if (currentState.getCurrentFrame() < maxFinishTime) { GUITools::DrawLine(Position((PositionType)framePos, concurrent.y() - 10), Position((PositionType)framePos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height), 1, white); GUITools::DrawString(Position((PositionType)framePos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20), stateTime.c_str(), white); } for (FrameCountType timeFrame = 0; timeFrame < maxFinishTime; timeFrame += 24*30) { float xPos = concurrent.x() + timeFrame*scale; GUITools::DrawString(Position((PositionType)xPos, concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20), getTimeString(timeFrame).c_str(), white); } Position progress = concurrent + Position(PositionType(maxWidth + 20), 0); Position progressBar(175,20); Position progressBuffer(0, 3); GUITools::DrawString(progress - Position(0,5), "Actions in Progress:", white); for (size_t a(0); a < currentState.getUnitData().getNumActionsInProgress(); ++a) { size_t index = currentState.getUnitData().getNumActionsInProgress() - a - 1; const ActionType actionInProgress = currentState.getUnitData().getActionInProgressByIndex(index); const FrameCountType finishTime = currentState.getUnitData().getActionInProgressFinishTimeByIndex(index); //DrawActionType(actionInProgress, progress, width); double remainingTime = (finishTime - currentState.getCurrentFrame()); double timeRatio = remainingTime / actionInProgress.buildTime(); Position ratioBar((PositionType)(timeRatio * progressBar.x()), progressBar.y()); GUITools::DrawRect(progress + progressBuffer, progress + progressBuffer + progressBar, white); GUITools::DrawRect(progress + progressBuffer + Position(1,1), progress + progressBuffer - Position(1,1) + progressBar, grey); GUITools::DrawRect(progress + progressBuffer + Position(1,1), progress + progressBuffer - Position(1,1) + ratioBar, blue); std::stringstream time; time << actionInProgress.getName() << " " << (int)remainingTime; GUITools::DrawString(progress + progressBuffer + Position(10, 13), time.str(), white); progress.add(0, progressBar.y() + progressBuffer.y()); } Position buildings(progress.x() + 195, concurrent.y()); const BuildingData & buildingData = currentState.getBuildingData(); GUITools::DrawString(buildings - Position(0,5), "Completed Buildings", white); for (size_t i(0); i < buildingData.size(); ++i) { const BuildingStatus & buildingStatus = buildingData.getBuilding(i); const ActionType & type = buildingStatus._type; const FrameCountType & finishTime = buildingStatus._timeRemaining; const ActionType & makingType = buildingStatus._isConstructing; GUITools::DrawRect(buildings + progressBuffer, buildings + progressBuffer + progressBar, white); GUITools::DrawRect(buildings + progressBuffer + Position(1,1), buildings + progressBuffer - Position(1,1) + progressBar, grey); if (finishTime > 0) { double remainingTime = finishTime; double timeRatio = remainingTime / makingType.buildTime(); Position ratioBar((PositionType)(timeRatio * progressBar.x()), progressBar.y()); GUITools::DrawRect(buildings + progressBuffer + Position(1,1), buildings + progressBuffer - Position(1,1) + ratioBar, blue); std::stringstream time; time << type.getName() << " " << (int)remainingTime; GUITools::DrawString(buildings + progressBuffer + Position(10, 13), time.str(), white); } else { GUITools::DrawString(buildings + progressBuffer + Position(10, 13), type.getName(), white); } buildings.add(0, progressBar.y() + progressBuffer.y()); } return concurrent.y() + (maxLayer)*(height + heightBuffer) + 10 + height + 20 + 30; } ================================================ FILE: BOSS/source/deprecated/BOSSVisExperiment.h ================================================ #pragma once #include "BOSS.h" #include "GUITools.h" #include "JSONTools.h" #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace BOSS { class BOSSVisExperiment { std::vector< GameState > _states; std::vector< BuildOrder > _buildOrders; std::vector< std::vector > _startTimes; std::vector< std::vector > _finishTimes; std::vector< size_t > _nextActionIndexes; double _fps; size_t _scenarios; bool _finished; Position _lastDrawPosition; PositionType DrawScenario(const Position & pos, const size_t scenario); std::string getTimeString(const FrameCountType & frameCount); void draw(); public: BOSSVisExperiment(); BOSSVisExperiment(const rapidjson::Value & experimentVal, std::map< std::string, GameState > & stateMap, std::map< std::string, BuildOrder > & buildOrderMap); void onFrame(); const Position & getLastDrawPosition() const; }; } ================================================ FILE: BOSS/source/deprecated/GUI.cpp ================================================ #include "GUI.h" using namespace BOSS; #define GUI_INITIAL_WIDTH 1920 #define GUI_INITIAL_HEIGHT 1080 #define BOSS_MAX_TEXTURES 512 #define BOSS_TEXTURE_INTERVAL 64 const int GUI::TextureASCIIOffset = 200; const int GUI::TextureFont = 198; GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GUI::GUI() : windowSizeX(GUI_INITIAL_WIDTH) , windowSizeY(GUI_INITIAL_HEIGHT) , bl(false) , br(false) , bu(false) , bd(false) , cameraX(0) , cameraY(0) , previousMouseX(0) , previousMouseY(0) , started(false) , mousePressed(false) , shiftPressed(false) , currentFrame(0) , lastFrameTime(0) , zoomX(1.0) , zoomY(1.0) { timer.start(); if(SDL_Init(SDL_INIT_VIDEO) != 0) { BOSS_ASSERT(false, "Unable to initialise SDL"); } } GUI & GUI::Instance() { static GUI g; return g; } GUI::~GUI() { SDL_Quit(); } bool GUI::isStarted() const { return started; } void GUI::OnStart() { if (started) { return; } cameraX = 0; cameraY = 0; SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetSwapInterval(1); #ifndef EMSCRIPTEN window = SDL_CreateWindow("Prismata OpenGL Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSizeX, windowSizeY, SDL_WINDOW_OPENGL); glcontext = SDL_GL_CreateContext(window); #else screen = SDL_SetVideoMode(windowSizeX,windowSizeY,32,SDL_OPENGL | SDL_RESIZABLE); #endif LoadTextures(); // enable alpha blending for transparency glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glViewport(0,0,(GLsizei)(windowSizeX*zoomX),(GLsizei)(windowSizeY*zoomY)); started = true; } void GUI::OnFrame() { BOSS_ASSERT(isStarted(), "Must initialize GUI before calling OnFrame()"); // Handle input events HandleEvents(); // Render the frame glClear(GL_COLOR_BUFFER_BIT); Render(); SDL_GL_SwapWindow(window); } void GUI::OnResize(SDL_Event & event) { //windowSizeX = event.resize.w; //windowSizeY = event.resize.h; glViewport(0,0,(GLsizei)(windowSizeX*zoomX),(GLsizei)(windowSizeY*zoomY)); OnFrame(); } void GUI::HandleEvents() { // Handle SDL events SDL_Event event; while (SDL_PollEvent(&event)) { const bool pressed(event.key.state == SDL_PRESSED); switch (event.type) { /*case SDL_VIDEORESIZE: { OnResize(event); break; }*/ case SDL_MOUSEMOTION: { if ((previousMouseX != 0 || previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT)) { cameraX -= (int)(event.motion.xrel * zoomX); cameraY -= (int)(event.motion.yrel * zoomY); } previousMouseX = event.motion.x; previousMouseY = event.motion.y; break; } case SDL_KEYDOWN: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: shiftPressed = pressed; break; case SDLK_p: { } } break; } case SDL_KEYUP: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: shiftPressed = pressed; break; } break; } case SDL_MOUSEWHEEL: { //cameraY -= event.wheel.y; zoomX *= event.wheel.y < 0 ? 1.05 : 0.95; zoomY *= event.wheel.y < 0 ? 1.05 : 0.95; //glViewport(0,0,windowSizeX*zoomX,windowSizeY*zoomY); break; } case SDL_MOUSEBUTTONDOWN: { break; } case SDL_MOUSEBUTTONUP: { if (event.button.button == SDL_BUTTON_LEFT) { } break; } case SDL_QUIT: { std::cerr << "SDL_QUIT caught\n\n"; exit(0); } } } } void GUI::Render() { glMatrixMode(GL_PROJECTION); glPushMatrix(); { glOrtho(0,windowSizeX*zoomX,windowSizeY*zoomY,0,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); { glTranslatef(static_cast(-cameraX),static_cast(-cameraY),0); _currentExperiment.onFrame(); //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, white); } glPopMatrix(); } glMatrixMode(GL_PROJECTION); glPopMatrix(); currentFrame++; } void GUI::DrawActionType(const ActionType & type, const Position & topLeft, const size_t & width) { int textureNumber = getTextureNumber(type); float ratio = (float)width / textureSizes[textureNumber].x(); Position size = Position((PositionType)(textureSizes[textureNumber].x() * ratio), (PositionType)(textureSizes[textureNumber].y() * ratio)); Position bottomRight(topLeft + size); GUITools::DrawTexturedRect(topLeft, bottomRight, textureNumber, white); } int GUI::Width() { return windowSizeX; } int GUI::Height() { return windowSizeY; } void GUI::DrawAllUnits() { GLfloat color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; float width = 64; Position p; Position techp(p.x(), p.y() + 100); for (size_t r(0); r < 3; ++r) { for (size_t i(0); i < ActionTypes::GetAllActionTypes(r).size(); ++i) { const ActionType & type = ActionTypes::GetAllActionTypes(r)[i]; DrawActionType(type, (type.isUnit() ? p : techp), (PositionType)width); if (type.isUnit()) { p = p + Position((PositionType)width, 0); } else { techp = techp + Position((PositionType)width, 0); } } p = Position(0, (r+1) * 200); techp = Position(p.x(), p.y() + 100); } } void GUI::LoadTextures() { std::string imageDir = "../asset/images/"; #ifdef EMSCRIPTEN imageDir = "asset/images/"; #endif textures = std::vector(BOSS_MAX_TEXTURES); textureSizes = std::vector(BOSS_MAX_TEXTURES); glGenTextures(BOSS_MAX_TEXTURES,&textures[0]); for (size_t r(0); r < Races::NUM_RACES; ++r) { for (size_t i(0); i < ActionTypes::GetAllActionTypes(r).size(); ++i) { const ActionType & type = ActionTypes::GetAllActionTypes(r)[i]; LoadTexture(getTextureNumber(type), imageDir + getTextureFileName(type).c_str()); } } LoadTexture(TextureFont, imageDir + "fonts/alpha_trans.png"); } const int GUI::getTextureNumber(const ActionType & type) const { return BOSS_TEXTURE_INTERVAL * type.getRace() + type.ID(); } void GUI::LoadTexture(int textureNumber, const std::string & fileName) { struct stat buf; if (stat(fileName.c_str(), &buf) == -1) { std::cout << "Couldn't find texture: " << fileName << std::endl; return; } SDL_Surface *surface2 = IMG_Load(fileName.c_str()); GLenum texture_format = GL_RGBA; GLint nOfColors = 4; if (surface2 != NULL) { glBindTexture( GL_TEXTURE_2D, textureNumber ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels); } else { printf("SDL could not load image: %s\n", SDL_GetError()); } if ( surface2 ) { textureSizes[textureNumber] = Position(surface2->w, surface2->h); SDL_FreeSurface( surface2 ); } } void GUI::SetVisExperiment(BOSSVisExperiment & exp) { _currentExperiment = exp; } bool GUI::saveScreenshotBMP(const std::string & filename) { SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, windowSizeX, windowSizeY, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); glReadBuffer(GL_FRONT); glReadPixels(0, 0, windowSizeX, windowSizeY, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_SaveBMP(image, filename.c_str()); SDL_FreeSurface(image); return true; } const std::string GUI::getTextureFileName(const ActionType & type) const { std::string filename = "units/" + type.getName() + ".png"; if (type.isTech()) { filename = "command_icons/" + type.getName() + ".png"; } else if (type.isUpgrade()) { filename = "command_icons/" + type.getName() + ".png"; } for (size_t i(0); i #undef main #include #include #include "GameState.h" #include "GUITools.h" #include #include "BOSSVisExperiment.h" namespace BOSS { class BOSSVisExperiment; class GUI { unsigned int texFont; int windowSizeX; int windowSizeY; int cameraX; int cameraY; int mapPixelWidth; int mapPixelHeight; bool bl,br,bd,bu; bool started; int previousMouseX; int previousMouseY; bool mousePressed; bool shiftPressed; double zoomX, zoomY; size_t currentFrame; Timer timer; double lastFrameTime; SDL_Window * window; SDL_Surface * screen; SDL_GLContext glcontext; std::vector textures; std::vector textureSizes; BOSSVisExperiment _currentExperiment; void HandleEvents(); void Render(); void RenderTextGlut(int x, int y, std::string & s); void LoadTextures(); void LoadTexture(int textureNumber, const std::string & fileName); void OnResize(SDL_Event & event); void DrawAllUnits(); void DrawGameState(); PositionType DrawVisExperiment(const Position & pos, const GameState & currentState, const std::vector & buildOrder, const size_t & boIndex, const std::vector & startTimes, const std::vector & finishTimes); std::string getTimeString(const FrameCountType & frameCount); const std::string getTextureFileName(const ActionType & type) const; const int getTextureNumber(const ActionType & type) const; PositionType DrawScenario(const Position & pos, const size_t scenario); GUI(); public: static const int TextureASCIIOffset; static const int TextureFont; static GUI & Instance(); ~GUI(); int Width(); int Height(); void OnStart(); void OnFrame(); bool isStarted() const; bool saveScreenshotBMP(const std::string & filename); void SetVisExperiment(BOSSVisExperiment & exp); void DrawActionType(const ActionType & type, const Position & tl, const size_t & width); }; } ================================================ FILE: BOSS/source/deprecated/GUITools.cpp ================================================ #include "GUITools.h" #include "StarCraftGUI.h" namespace BOSS { namespace GUITools { void DrawString(const Position & p, const std::string & text, const GLfloat * rgba) { Position origin(p); Position fontSize(8,8); int linePos = 0; for (size_t i(0); i < text.length(); ++i) { if (text[i] == '\n') { origin = Position(p.x(), origin.y() + fontSize.y()); linePos = 0; } else { Position charStart = Position(origin.x() + linePos*fontSize.x(), origin.y() - fontSize.y()); Position charEnd = charStart + fontSize; DrawChar(charStart, charEnd, text[i], rgba); linePos++; } } } const size_t FontTextureSize = 128; const size_t CharSize = 8; const float CharDelta = 1.0f / 16.0f; void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba) { float xPos = ((ch % 16) / 16.0f); float yPos = (ch >> 4) / 16.0f; glPushMatrix(); glEnable( GL_TEXTURE_2D ); glColor4fv(rgba); glBindTexture( GL_TEXTURE_2D, StarCraftGUI::TextureFont ); glBegin( GL_QUADS ); glTexCoord2f(xPos,yPos); glVertex2i(tl.x(), tl.y()); glTexCoord2f(xPos+CharDelta,yPos); glVertex2i(br.x(), tl.y()); glTexCoord2f(xPos+CharDelta,yPos+CharDelta); glVertex2i(br.x(), br.y()); glTexCoord2f(xPos,yPos+CharDelta); glVertex2i(tl.x(), br.y()); glEnd(); glDisable( GL_TEXTURE_2D ); glPopMatrix(); } void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba) { glPushMatrix(); glLineWidth(thickness); glColor4fv(rgba); glBegin(GL_LINES); glVertex2i(p1.x(),p1.y()); glVertex2i(p2.x(),p2.y()); glEnd(); glPopMatrix(); } void DrawCircle(const Position & pos, float r, int num_segments) { float theta = 2 * (float)3.1415926 / float(num_segments); float c = cosf(theta);//precalculate the sine and cosine float s = sinf(theta); float t; float x = r;//we start at angle = 0 float y = 0; glBegin(GL_LINE_LOOP); for(int ii = 0; ii < num_segments; ii++) { glVertex2f(x + pos.x(), y + pos.y());//output vertex //apply the rotation matrix t = x; x = c * x - s * y; y = s * t + c * y; } glEnd(); } void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba) { glPushMatrix(); glColor4fv(rgba); glBegin(GL_QUADS); glVertex2i(tl.x(),tl.y()); glVertex2i(br.x(),tl.y()); glVertex2i(br.x(),br.y()); glVertex2i(tl.x(),br.y()); glEnd(); glPopMatrix(); } void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight) { glPushMatrix(); glBegin(GL_QUADS); glColor4fv(rgbaLeft); glVertex2i(tl.x(),tl.y()); glColor4fv(rgbaRight); glVertex2i(br.x(),tl.y()); glColor4fv(rgbaRight); glVertex2i(br.x(),br.y()); glColor4fv(rgbaLeft); glVertex2i(tl.x(),br.y()); glEnd(); glPopMatrix(); } void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba) { glPushMatrix(); glEnable( GL_TEXTURE_2D ); glColor4fv(rgba); glBindTexture( GL_TEXTURE_2D, textureID ); glBegin( GL_QUADS ); glTexCoord2f(0.0,0.0); glVertex2i(tl.x(),tl.y()); glTexCoord2f(1.0,0.0); glVertex2i(br.x(),tl.y()); glTexCoord2f(1.0,1.0); glVertex2i(br.x(),br.y()); glTexCoord2f(0.0,1.0); glVertex2i(tl.x(),br.y()); glEnd(); glDisable( GL_TEXTURE_2D ); glPopMatrix(); } void DrawIconAndText(const Position & tl, const Position & br, const int & textureID, const int & textureID2, const GLfloat * rgba) { GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; Position iconSize = br - tl; Position statusNumPos = tl + Position(-iconSize.scale(0.15f).x(), iconSize.scale(0.4f).y()); GUITools::DrawTexturedRect(tl, br, textureID, rgba); GUITools::DrawTexturedRect(statusNumPos, statusNumPos + iconSize.scale(0.65f), textureID2, rgba); } } } ================================================ FILE: BOSS/source/deprecated/GUITools.h ================================================ #pragma once #include "Common.h" #include "Position.hpp" #include #include namespace BOSS { namespace GUITools { const int FLIP_VERTICAL = 1; const int FLIP_HORIZONTAL = 2; void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba); void DrawString(const Position & p, const std::string & text, const GLfloat * rgba); void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba); void DrawCircle(const Position & p, float r, int num_segments); void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba); void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba); void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight); void SetColor(const GLfloat * src, GLfloat * dest); void SetColor(const GLfloat * src, GLfloat * dest); } } ================================================ FILE: BOSS/source/deprecated/bwapidata/README.txt ================================================ bwapidata ---------------- This is used to compile SparCraft in a linux environment without having to worry about reconfiguring BWAPI This is a stripped-down version of BWAPI which contains only headers and .cpp files, without BWTA Used with permission from Adam Heinermann of the BWAPI project: https://code.google.com/p/bwapi/ ================================================ FILE: BOSS/source/deprecated/bwapidata/include/AIModule.cpp ================================================ #include namespace BWAPI { AIModule::AIModule() { } AIModule::~AIModule() { } void AIModule::onStart() { } void AIModule::onEnd(bool isWinner) { } void AIModule::onFrame() { } void AIModule::onSendText(std::string text) { } void AIModule::onReceiveText(Player* player, std::string text) { } void AIModule::onPlayerLeft(Player *player) { } void AIModule::onNukeDetect(Position target) { } void AIModule::onUnitDiscover(BWAPI::Unit* unit) { } void AIModule::onUnitEvade(BWAPI::Unit* unit) { } void AIModule::onUnitShow(BWAPI::Unit* unit) { } void AIModule::onUnitHide(BWAPI::Unit* unit) { } void AIModule::onUnitCreate(BWAPI::Unit* unit) { } void AIModule::onUnitDestroy(BWAPI::Unit* unit) { } void AIModule::onUnitMorph(BWAPI::Unit* unit) { } void AIModule::onUnitRenegade(BWAPI::Unit* unit) { } void AIModule::onSaveGame(std::string gameName) { } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/AIModule.h ================================================ #pragma once #include #include #include namespace BWAPI { class Unit; class Player; /** AIModule is a virtual class that is intended to be implemented or inherited by a custom AI class. * * \note * Using BWAPI in a different thread than the default one will produce unexpected results and possibly crash * the program. Multi-threaded AIs are possible so long as all BWAPI interaction is limited to the default * thread (during one of the call-backs). */ class AIModule { public: AIModule(); virtual ~AIModule(); /** BWAPI calls this at the start of a match. Typically an AI will execute set up code in this method * (initialize data structures, load build orders, etc). */ virtual void onStart(); /** BWAPI calls this at the end of the match. isWinner will be true if the AIModule won the game. If the * game is a replay, isWinner will always be false. */ virtual void onEnd(bool isWinner); /** BWAPI calls this on every logical frame in the game. */ virtual void onFrame(); /** If Flag::UserInput is enabled, BWAPI will call this each time a user enters a message into the chat. * */ virtual void onSendText(std::string text); /** BWAPI calls this when another player sends a message. */ virtual void onReceiveText(Player* player, std::string text); /** BWAPI calls this when a player leaves the game. */ virtual void onPlayerLeft(Player* player); /** BWAPI calls this when a nuclear launch has been detected. If the target position is visible, or if * Complete Map Information is enabled, the target position will also be provided. If Complete Map * Information is disabled and the target position is not visible, target will be set to * Positions::Unknown. */ virtual void onNukeDetect(Position target); /** BWAPI calls this when a unit becomes accessible. */ virtual void onUnitDiscover(Unit* unit); /** BWAPI calls this when a unit becomes inaccessible. */ virtual void onUnitEvade(Unit* unit); /** BWAPI calls this the instant a previously invisible unit becomes visible. The complete map * information flag has no effect on this callback. */ virtual void onUnitShow(Unit* unit); /** BWAPI calls this right before a unit becomes invisible, so if you want your non-cheating AI to * remember where it last saw a unit, this callback would be a good place to implement it. The complete * map information flag has no effect on this callback. */ virtual void onUnitHide(Unit* unit); /** BWAPI calls this when a unit is created. Note that this is NOT called when a unit changes type * (such as larva into egg or egg into drone). Building a refinery/assimilator/extractor will not * produce an onUnitCreate call since the vespene geyser changes to the unit type of the * refinery/assimilator/extractor. If Complete Map Information is enabled, this will also be called for * new units that are hidden by the fog of war. If the unit is visible upon creation, onUnitShow will be * called shortly after onUnitCreate is called. */ virtual void onUnitCreate(Unit* unit); /** BWAPI calls this when a unit dies or otherwise removed from the game (i.e. a mined out mineral * patch). When a zerg drone becomes an extractor, the Vespene geyser changes to the Zerg Extractor type * and the drone is removed. If Complete Map Information is enabled, this will also be called for units * that are hidden by the fog of war. If a unit that was visible gets destroyed, onUnitHide will be * called right before onUnitDestroy is called. */ virtual void onUnitDestroy(Unit* unit); /** BWAPI calls this when a unit changes type, such as from a Zerg Drone to a Zerg Hatchery, or from a * Terran Siege Tank Tank Mode to Terran Siege Tank Siege Mode. This is not called when the type changes * to or from UnitTypes::Unknown (which happens when a unit becomes visible or invisible). */ virtual void onUnitMorph(Unit* unit); /** BWAPI calls this when an accessible unit changes ownership. */ virtual void onUnitRenegade(Unit* unit); // TODO: Add Doxygen documentation virtual void onSaveGame(std::string gameName); }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Bitmap.h ================================================ #include #pragma once namespace BWAPI { class BitmapProxy { public: BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x); Color operator[](int y); private: unsigned char *data; unsigned short width; unsigned short height; int x; }; class Bitmap { public: BitmapProxy operator[](int x); unsigned short getWidth(); unsigned short getHeight(); private: unsigned short wid; unsigned short ht; unsigned char *data; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Bullet.h ================================================ #pragma once #include #include namespace BWAPI { class Player; class Unit; class Bullet { public: virtual int getID() const = 0; virtual Player* getPlayer() const = 0; virtual BulletType getType() const = 0; virtual Unit* getSource() const = 0; virtual Position getPosition() const = 0; virtual double getAngle() const = 0; virtual double getVelocityX() const = 0; virtual double getVelocityY() const = 0; virtual Unit* getTarget() const = 0; virtual Position getTargetPosition() const = 0; virtual int getRemoveTimer() const = 0; virtual bool exists() const = 0; virtual bool isVisible() const = 0; virtual bool isVisible(Player* player) const = 0; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/BulletType.h ================================================ #pragma once #include #include namespace BWAPI { class BulletType { public: BulletType(); BulletType(int id); BulletType(const BulletType& other); BulletType& operator=(const BulletType& other); bool operator==(const BulletType& other) const; bool operator!=(const BulletType& other) const; bool operator<(const BulletType& other) const; /** Returns the unique ID for this bullet type. */ int getID() const; /** Returns the name of this bullet type. */ std::string getName() const; private: int id; }; namespace BulletTypes { /** Given the name of an bullet type, getBulletType() will return the corresponding BulletType object. */ BulletType getBulletType(std::string name); /** Returns the set of all the BulletTypes. */ std::set& allBulletTypes(); void init(); extern const BulletType Melee; extern const BulletType Fusion_Cutter_Hit; extern const BulletType Gauss_Rifle_Hit; extern const BulletType C_10_Canister_Rifle_Hit; extern const BulletType Gemini_Missiles; extern const BulletType Fragmentation_Grenade; extern const BulletType Longbolt_Missile; extern const BulletType ATS_ATA_Laser_Battery; extern const BulletType Burst_Lasers; extern const BulletType Arclite_Shock_Cannon_Hit; extern const BulletType EMP_Missile; extern const BulletType Dual_Photon_Blasters_Hit; extern const BulletType Particle_Beam_Hit; extern const BulletType Anti_Matter_Missile; extern const BulletType Pulse_Cannon; extern const BulletType Psionic_Shockwave_Hit; extern const BulletType Psionic_Storm; extern const BulletType Yamato_Gun; extern const BulletType Phase_Disruptor; extern const BulletType STA_STS_Cannon_Overlay; extern const BulletType Sunken_Colony_Tentacle; extern const BulletType Acid_Spore; extern const BulletType Glave_Wurm; extern const BulletType Seeker_Spores; extern const BulletType Queen_Spell_Carrier; extern const BulletType Plague_Cloud; extern const BulletType Consume; extern const BulletType Needle_Spine_Hit; extern const BulletType Invisible; extern const BulletType Optical_Flare_Grenade; extern const BulletType Halo_Rockets; extern const BulletType Subterranean_Spines; extern const BulletType Corrosive_Acid_Shot; extern const BulletType Neutron_Flare; extern const BulletType None; extern const BulletType Unknown; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/BulletData.h ================================================ #pragma once namespace BWAPI { struct BulletData { int id; int player; int type; int source; int positionX; int positionY; double angle; double velocityX; double velocityY; int target; int targetPositionX; int targetPositionY; int removeTimer; bool exists; bool isVisible[9]; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/BulletImpl.h ================================================ #pragma once #include #include "BulletData.h" #include #include namespace BWAPI { class Player; class Unit; class BulletImpl : public Bullet { private: const BulletData* self; int index; public: BulletImpl(int index); virtual int getID() const; virtual Player* getPlayer() const; virtual BulletType getType() const; virtual Unit* getSource() const; virtual Position getPosition() const; virtual double getAngle() const; virtual double getVelocityX() const; virtual double getVelocityY() const; virtual Unit* getTarget() const; virtual Position getTargetPosition() const; virtual int getRemoveTimer() const; virtual bool exists() const; virtual bool isVisible() const; virtual bool isVisible(Player* player) const; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Client.h ================================================ #pragma once #include #include "GameData.h" #include "GameImpl.h" #include "ForceImpl.h" #include "PlayerImpl.h" #include "UnitImpl.h" namespace BWAPI { class Client { public: Client(); ~Client(); GameData* data; bool isConnected(); bool connect(); void disconnect(); void update(); private: HANDLE pipeObjectHandle; HANDLE mapFileHandle; bool connected; }; extern Client BWAPIClient; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Command.h ================================================ #pragma once #include "CommandType.h" namespace BWAPIC { struct Command { Command(CommandType::Enum _commandType, int _value1=0, int _value2=0) { type=_commandType; value1=_value1; value2=_value2; } CommandType::Enum type; int value1; int value2; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/CommandType.h ================================================ #pragma once /** * Used in UnitCommand */ namespace BWAPIC { namespace CommandType { enum Enum { None, SetScreenPosition, PingMinimap, EnableFlag, Printf, SendText, ChangeRace, StartGame, PauseGame, ResumeGame, LeaveGame, RestartGame, SetLocalSpeed, SetTextSize, SetLatCom, SetGui }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Event.h ================================================ #pragma once #include #include namespace BWAPIC { struct Event { BWAPI::EventType::Enum type; int v1; int v2; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ForceData.h ================================================ #pragma once namespace BWAPI { struct ForceData { char name[32]; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ForceImpl.h ================================================ #pragma once #include #include "ForceData.h" #include #include namespace BWAPI { class Game; class Player; class Unit; class ForceImpl : public Force { private: const ForceData* self; int id; public: ForceImpl(int id); virtual int getID() const; virtual std::string getName() const; virtual std::set getPlayers() const; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/GameData.h ================================================ #pragma once #include "UnitCommand.h" #include "ForceData.h" #include "PlayerData.h" #include "UnitData.h" #include "BulletData.h" #include "Event.h" #include "Command.h" #include "Shape.h" namespace BWAPI { struct GameData { GameData(); int instanceID; //forces int forceCount; ForceData forces[5]; //players int playerCount; PlayerData players[12]; //units int initialUnitCount; UnitData units[10000]; //unit table int unitArray[1700]; //bullets BulletData bullets[100]; int gameType; int latency; int latencyFrames; int latencyTime; int remainingLatencyFrames; int remainingLatencyTime; int revision; bool isDebug; bool hasLatCom; int replayFrameCount; int frameCount; int fps; double averageFPS; // user input int mouseX; int mouseY; bool mouseState[3]; bool keyState[256]; int screenX; int screenY; bool flags[2]; // map int mapWidth; int mapHeight; char mapFileName[261]; //size based on broodwar memory char mapPathName[261]; //size based on broodwar memory char mapName[33]; //size based on broodwar memory char mapHash[41]; //tile data int getGroundHeight[256][256]; bool isWalkable[1024][1024]; bool isBuildable[256][256]; bool isVisible[256][256]; bool isExplored[256][256]; bool hasCreep[256][256]; unsigned short mapTileRegionId[256][256]; unsigned short mapSplitTilesMiniTileMask[5000]; unsigned short mapSplitTilesRegion1[5000]; unsigned short mapSplitTilesRegion2[5000]; unsigned short regionGroupIndex[5000]; // start locations int startLocationCount; int startLocationsX[8]; int startLocationsY[8]; // match mode bool isInGame; bool isMultiplayer; bool isBattleNet; bool isPaused; bool isReplay; //selected units int selectedUnitCount; int selectedUnits[12]; // players int self; //events from server to client int eventCount; BWAPIC::Event events[10000]; //strings (used in events, shapes, and commands) int stringCount; char strings[20000][256]; //shapes, commands, unitCommands, from client to server int shapeCount; BWAPIC::Shape shapes[20000]; int commandCount; BWAPIC::Command commands[20000]; int unitCommandCount; BWAPIC::UnitCommand unitCommands[20000]; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/GameImpl.h ================================================ #pragma once #include #include "GameData.h" #include "Client.h" #include "Shape.h" #include "Command.h" #include "UnitCommand.h" #include "ForceImpl.h" #include "PlayerImpl.h" #include "UnitImpl.h" #include "BulletImpl.h" #include #include #include #include namespace BWAPI { class Force; class Player; class Unit; class GameImpl : public Game { private : int addShape(BWAPIC::Shape &s); int addString(const char* text); int addText(BWAPIC::Shape &s, const char* text); int addCommand(BWAPIC::Command &c); void clearAll(); GameData* data; std::vector forceVector; std::vector playerVector; std::vector unitVector; std::vector bulletVector; std::set forces; std::set players; std::set accessibleUnits;//all units that are accessible (and definitely alive) //notDestroyedUnits - accessibleUnits = all units that may or may not be alive (status unknown) std::set minerals; std::set geysers; std::set neutralUnits; std::set staticMinerals; std::set staticGeysers; std::set staticNeutralUnits; std::set bullets; std::set selectedUnits; std::set pylons; std::set unitsOnTileData[256][256]; std::set< TilePosition > startLocations; std::list< Event > events; bool flagEnabled[2]; Player* thePlayer; Player* theEnemy; Error lastError; public : Event makeEvent(BWAPIC::Event e); int addUnitCommand(BWAPIC::UnitCommand& c); bool inGame; GameImpl(GameData* data); void onMatchStart(); void onMatchEnd(); void onMatchFrame(); const GameData* getGameData() const; std::set& getPlayerUnits(const Player* player); virtual std::set< Force* >& getForces(); virtual std::set< Player* >& getPlayers(); virtual std::set< Unit* >& getAllUnits(); virtual std::set< Unit* >& getMinerals(); virtual std::set< Unit* >& getGeysers(); virtual std::set< Unit* >& getNeutralUnits(); virtual std::set< Unit* >& getStaticMinerals(); virtual std::set< Unit* >& getStaticGeysers(); virtual std::set< Unit* >& getStaticNeutralUnits(); virtual std::set< Bullet* >& getBullets(); virtual std::list< Event>& getEvents(); virtual Force* getForce(int forceID); virtual Player* getPlayer(int playerID); virtual Unit* getUnit(int unitID); virtual Unit* indexToUnit(int unitIndex); virtual GameType getGameType(); virtual int getLatency(); virtual int getFrameCount(); virtual int getFPS(); virtual double getAverageFPS(); virtual BWAPI::Position getMousePosition(); virtual bool getMouseState(MouseButton button); virtual bool getMouseState(int button); virtual bool getKeyState(Key key); virtual bool getKeyState(int key); virtual BWAPI::Position getScreenPosition(); virtual void setScreenPosition(int x, int y); virtual void setScreenPosition(BWAPI::Position p); virtual void pingMinimap(int x, int y); virtual void pingMinimap(BWAPI::Position p); virtual bool isFlagEnabled(int flag); virtual void enableFlag(int flag); virtual std::set& unitsOnTile(int x, int y); virtual Error getLastError() const; virtual bool setLastError(BWAPI::Error e); virtual int mapWidth(); virtual int mapHeight(); virtual std::string mapFileName(); virtual std::string mapPathName(); virtual std::string mapName(); virtual std::string mapHash(); virtual bool isWalkable(int x, int y); virtual int getGroundHeight(int x, int y); virtual int getGroundHeight(TilePosition position); virtual bool isBuildable(int x, int y); virtual bool isBuildable(TilePosition position); virtual bool isVisible(int x, int y); virtual bool isVisible(TilePosition position); virtual bool isExplored(int x, int y); virtual bool isExplored(TilePosition position); virtual bool hasCreep(int x, int y); virtual bool hasCreep(TilePosition position); virtual bool hasPower(int x, int y, int tileWidth, int tileHeight); virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight); virtual bool canBuildHere(Unit* builder, TilePosition position, UnitType type, bool checkExplored = false); virtual bool canMake(Unit* builder, UnitType type); virtual bool canResearch(Unit* unit, TechType type); virtual bool canUpgrade(Unit* unit, UpgradeType type); virtual std::set< TilePosition >& getStartLocations(); virtual void printf(const char* text, ...); virtual void sendText(const char* text, ...); virtual void sendTextEx(bool toAllies, const char *format, ...); virtual void changeRace(BWAPI::Race race); virtual bool isInGame(); virtual bool isMultiplayer(); virtual bool isBattleNet(); virtual bool isPaused(); virtual bool isReplay(); virtual void startGame(); virtual void pauseGame(); virtual void resumeGame(); virtual void leaveGame(); virtual void restartGame(); virtual void setLocalSpeed(int speed = -1); virtual std::set& getSelectedUnits(); virtual Player* self(); virtual Player* enemy(); virtual void setTextSize(int size = 1); virtual void drawText(int ctype, int x, int y, const char* text, ...); virtual void drawTextMap(int x, int y, const char* text, ...); virtual void drawTextMouse(int x, int y, const char* text, ...); virtual void drawTextScreen(int x, int y, const char* text, ...); virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawDot(int ctype, int x, int y, Color color); virtual void drawDotMap(int x, int y, Color color); virtual void drawDotMouse(int x, int y, Color color); virtual void drawDotScreen(int x, int y, Color color); virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color); virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color); virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color); virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color); virtual void *getScreenBuffer(); virtual int getLatencyFrames(); virtual int getLatencyTime(); virtual int getRemainingLatencyFrames(); virtual int getRemainingLatencyTime(); virtual int getRevision(); virtual bool isDebug(); virtual bool isLatComEnabled(); virtual void setLatCom(bool isEnabled); virtual int getReplayFrameCount(); virtual void setGUI(bool enabled = true); virtual int getInstanceNumber(); }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/PlayerData.h ================================================ #pragma once namespace BWAPI { struct PlayerData { char name[25]; int race; int type; int force; bool isAlly[12]; bool isEnemy[12]; bool isNeutral; int startLocationX; int startLocationY; bool isVictorious; bool isDefeated; bool leftGame; int minerals; int gas; int cumulativeMinerals; int cumulativeGas; int supplyTotal[3]; int supplyUsed[3]; int allUnitCount[230]; int completedUnitCount[230]; int deadUnitCount[230]; int killedUnitCount[230]; int upgradeLevel[63]; bool hasResearched[47]; bool isResearching[47]; bool isUpgrading[63]; int colorByte; int color; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/PlayerImpl.h ================================================ #pragma once #include #include "PlayerData.h" #include #include namespace BWAPI { class Unit; class Force; class PlayerImpl : public Player { private: int id; public: PlayerData* self; std::set units; void clear(); PlayerImpl(int id); virtual int getID() const; virtual std::string getName() const; virtual const std::set& getUnits() const; virtual Race getRace() const; virtual PlayerType getType() const; virtual Force* getForce() const; virtual bool isAlly(Player* player) const; virtual bool isEnemy(Player* player) const; virtual bool isNeutral() const; virtual TilePosition getStartLocation() const; virtual bool isVictorious() const; virtual bool isDefeated() const; virtual bool leftGame() const; virtual int minerals() const; virtual int gas() const; virtual int cumulativeMinerals() const; virtual int cumulativeGas() const; virtual int supplyTotal() const; virtual int supplyUsed() const; virtual int supplyTotal(Race race) const; virtual int supplyUsed(Race race) const; virtual int allUnitCount(UnitType unit) const; virtual int completedUnitCount(UnitType unit) const; virtual int incompleteUnitCount(UnitType unit) const; virtual int deadUnitCount(UnitType unit) const; virtual int killedUnitCount(UnitType unit) const; virtual int getUpgradeLevel(UpgradeType upgrade) const; virtual bool hasResearched(TechType tech) const; virtual bool isResearching(TechType tech) const; virtual bool isUpgrading(UpgradeType upgrade) const; virtual int maxEnergy(UnitType unit) const; virtual BWAPI::Color getColor() const; virtual int getTextColor() const; }; }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/Shape.h ================================================ #pragma once #include "ShapeType.h" namespace BWAPIC { struct Shape { Shape(ShapeType::Enum _shapeType, int _ctype, int _x1, int _y1, int _x2, int _y2, int _extra1, int _extra2, int _color, bool _isSolid) { type=_shapeType; ctype=_ctype; x1=_x1; y1=_y1; x2=_x2; y2=_y2; extra1=_extra1; extra2=_extra2; color=_color; isSolid=_isSolid; } ShapeType::Enum type; int ctype; int x1; int y1; int x2; int y2; int extra1; int extra2; int color; bool isSolid; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/ShapeType.h ================================================ #pragma once /** * Used in UnitCommand */ namespace BWAPIC { namespace ShapeType { enum Enum { None, Text, Box, Triangle, Circle, Ellipse, Dot, Line }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitCommand.h ================================================ #pragma once #include /** * UnitOrder contains a single whole order */ namespace BWAPIC { struct UnitCommand { BWAPI::UnitCommandType type; int unitIndex; int targetIndex; int x; int y; int extra; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitData.h ================================================ #pragma once namespace BWAPI { struct UnitData { int clearanceLevel; int id; int player; int type; int positionX; int positionY; double angle; double velocityX; double velocityY; int hitPoints; int lastHitPoints; int shields; int energy; int resources; int resourceGroup; int killCount; int scarabCount; int spiderMineCount; int groundWeaponCooldown; int airWeaponCooldown; int spellCooldown; int defenseMatrixPoints; int defenseMatrixTimer; int ensnareTimer; int irradiateTimer; int lockdownTimer; int maelstromTimer; int orderTimer; int plagueTimer; int removeTimer; int stasisTimer; int stimTimer; int buildType; int trainingQueueCount; int trainingQueue[5]; int tech; int upgrade; int remainingBuildTime; int remainingTrainTime; int remainingResearchTime; int remainingUpgradeTime; int buildUnit; int target; int targetPositionX; int targetPositionY; int order; int orderTarget; int secondaryOrder; int rallyPositionX; int rallyPositionY; int rallyUnit; int addon; int nydusExit; int powerUp; int transport; int carrier; int hatchery; bool exists; bool hasNuke; bool isAccelerating; bool isAttacking; bool isBeingGathered; bool isBlind; bool isBraking; bool isBurrowed; int carryResourceType; bool isCloaked; bool isCompleted; bool isConstructing; bool isDetected; bool isGathering; bool isHallucination; bool isIdle; bool isInterruptible; bool isLifted; bool isMorphing; bool isMoving; bool isParasited; bool isSelected; bool isStartingAttack; bool isStuck; bool isTraining; bool isUnderStorm; bool isUnpowered; bool isVisible[9]; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client/UnitImpl.h ================================================ #pragma once #include #include "UnitData.h" #include #include namespace BWAPI { class Player; class UnitImpl : public Unit { private: int id; UnitType initialType; int initialResources; int initialHitPoints; Position initialPosition; int lastOrderFrame; void* clientInfo; public: UnitData* self; std::set connectedUnits; std::set loadedUnits; void clear(); void saveInitialState(); UnitImpl(int id); virtual int getID() const; virtual Player* getPlayer() const; virtual UnitType getType() const; virtual Position getPosition() const; virtual TilePosition getTilePosition() const; virtual double getAngle() const; virtual double getVelocityX() const; virtual double getVelocityY() const; virtual int getHitPoints() const; virtual int getShields() const; virtual int getEnergy() const; virtual int getResources() const; virtual int getResourceGroup() const; virtual double getDistance(Unit* target) const; virtual double getDistance(Position target) const; virtual bool hasPath(Unit* target) const; virtual bool hasPath(Position target) const; virtual int getLastOrderFrame() const; virtual int getUpgradeLevel(UpgradeType upgrade) const; virtual UnitType getInitialType() const; virtual Position getInitialPosition() const; virtual TilePosition getInitialTilePosition() const; virtual int getInitialHitPoints() const; virtual int getInitialResources() const; virtual int getKillCount() const; virtual int getInterceptorCount() const; virtual int getScarabCount() const; virtual int getSpiderMineCount() const; virtual int getGroundWeaponCooldown() const; virtual int getAirWeaponCooldown() const; virtual int getSpellCooldown() const; virtual int getDefenseMatrixPoints() const; virtual int getDefenseMatrixTimer() const; virtual int getEnsnareTimer() const; virtual int getIrradiateTimer() const; virtual int getLockdownTimer() const; virtual int getMaelstromTimer() const; virtual int getOrderTimer() const; virtual int getPlagueTimer() const; virtual int getRemoveTimer() const; virtual int getStasisTimer() const; virtual int getStimTimer() const; virtual UnitType getBuildType() const; virtual std::list getTrainingQueue() const; virtual TechType getTech() const; virtual UpgradeType getUpgrade() const; virtual int getRemainingBuildTime() const; virtual int getRemainingTrainTime() const; virtual int getRemainingResearchTime() const; virtual int getRemainingUpgradeTime() const; virtual Unit* getBuildUnit() const; virtual Unit* getTarget() const; virtual Position getTargetPosition() const; virtual Order getOrder() const; virtual Unit* getOrderTarget() const; virtual Order getSecondaryOrder() const; virtual Position getRallyPosition() const; virtual Unit* getRallyUnit() const; virtual Unit* getAddon() const; virtual Unit* getNydusExit() const; virtual Unit* getPowerUp() const; virtual Unit* getTransport() const; virtual std::set getLoadedUnits() const; virtual Unit* getCarrier() const; virtual std::set getInterceptors() const; virtual Unit* getHatchery() const; virtual std::set getLarva() const; virtual bool exists() const; virtual bool hasNuke() const; virtual bool isAccelerating() const; virtual bool isAttacking() const; virtual bool isBeingConstructed() const; virtual bool isBeingGathered() const; virtual bool isBeingHealed() const; virtual bool isBlind() const; virtual bool isBraking() const; virtual bool isBurrowed() const; virtual bool isCarryingGas() const; virtual bool isCarryingMinerals() const; virtual bool isCloaked() const; virtual bool isCompleted() const; virtual bool isConstructing() const; virtual bool isDefenseMatrixed() const; virtual bool isDetected() const; virtual bool isEnsnared() const; virtual bool isFollowing() const; virtual bool isGatheringGas() const; virtual bool isGatheringMinerals() const; virtual bool isHallucination() const; virtual bool isHoldingPosition() const; virtual bool isIdle() const; virtual bool isInterruptible() const; virtual bool isIrradiated() const; virtual bool isLifted() const; virtual bool isLoaded() const; virtual bool isLockedDown() const; virtual bool isMaelstrommed() const; virtual bool isMorphing() const; virtual bool isMoving() const; virtual bool isParasited() const; virtual bool isPatrolling() const; virtual bool isPlagued() const; virtual bool isRepairing() const; virtual bool isResearching() const; virtual bool isSelected() const; virtual bool isSieged() const; virtual bool isStartingAttack() const; virtual bool isStasised() const; virtual bool isStimmed() const; virtual bool isStuck() const; virtual bool isTraining() const; virtual bool isUnderStorm() const; virtual bool isUnpowered() const; virtual bool isUpgrading() const; virtual bool isVisible() const; virtual bool isVisible(Player* player) const; virtual bool issueCommand(UnitCommand command); virtual bool attackMove(Position target); virtual bool attackUnit(Unit* target); virtual bool build(TilePosition target, UnitType type); virtual bool buildAddon(UnitType type); virtual bool train(UnitType type); virtual bool morph(UnitType type); virtual bool research(TechType tech); virtual bool upgrade(UpgradeType upgrade); virtual bool setRallyPoint(Position target); virtual bool setRallyPoint(Unit* target); virtual bool move(Position target); virtual bool patrol(Position target); virtual bool holdPosition(); virtual bool stop(); virtual bool follow(Unit* target); virtual bool gather(Unit* target); virtual bool returnCargo(); virtual bool repair(Unit* target); virtual bool burrow(); virtual bool unburrow(); virtual bool cloak(); virtual bool decloak(); virtual bool siege(); virtual bool unsiege(); virtual bool lift(); virtual bool land(TilePosition target); virtual bool load(Unit* target); virtual bool unload(Unit* target); virtual bool unloadAll(); virtual bool unloadAll(Position target); virtual bool rightClick(Position target); virtual bool rightClick(Unit* target); virtual bool haltConstruction(); virtual bool cancelConstruction(); virtual bool cancelAddon(); virtual bool cancelTrain(int slot = -2); virtual bool cancelMorph(); virtual bool cancelResearch(); virtual bool cancelUpgrade(); virtual bool useTech(TechType tech); virtual bool useTech(TechType tech, Position target); virtual bool useTech(TechType tech, Unit* target); virtual void setClientInfo(void* clientinfo); virtual void* getClientInfo() const; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Client.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Color.h ================================================ #pragma once #include #include namespace BWAPI { // TODO: Add color palette image and info about text color /** StarCraft uses a 256 color palette to render everything, so the colors we can use to draw shapes using * BWAPI is limited to the colors available in the Palette. */ class Color { public: Color(); /** Create a color using the specified index from the Broodwar color palette. */ Color(int id); Color(const Color& other); /** Create a color using the color in the palette that is closest to the RGB color specified. */ Color(int red, int green, int blue); /** Return the index of the color in the color palette. */ int getID() const; /** Return the red component of the color. */ int red() const; /** Return the green component of the color. */ int green() const; /** Return the blue component of the color. */ int blue() const; Color& operator=(const Color& other); bool operator==(const Color& other) const; bool operator!=(const Color& other) const; bool operator<(const Color& other) const; private: int id; }; /** While any color from the palette can be used, the following colors are available as short cuts. */ namespace Colors { void init(); extern const Color Red; extern const Color Blue; extern const Color Teal; extern const Color Purple; extern const Color Orange; extern const Color Brown; extern const Color White; extern const Color Yellow; extern const Color Green; extern const Color Cyan; extern const Color Black; extern const Color Grey; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Constants.h ================================================ #pragma once namespace BWAPI { /** Used for converting between TilePosition coordinates and Position coordinates. */ #define TILE_SIZE 32 #define PYLON_X_RADIUS 8 #define PYLON_Y_RADIUS 5 } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/CoordinateType.h ================================================ #pragma once namespace BWAPI { namespace CoordinateType { enum Enum { Screen = 1, /**< (0,0) corresponds to the top left corner of the screen. */ Map = 2, /**< (0,0) corresponds to the top left corner of the map. */ Mouse = 3, /**< (0,0) corresponds to the tip of the mouse . */ }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/DamageType.h ================================================ #pragma once #include #include namespace BWAPI { class DamageType { public: DamageType(); DamageType(int id); DamageType(const DamageType& other); DamageType& operator=(const DamageType& other); bool operator==(const DamageType& other) const; bool operator!=(const DamageType& other) const; bool operator<(const DamageType& other) const; /** Returns a unique ID for this damage type. */ int getID() const; /** Returns the name of this damage type. For example DamageTypes::Explosive.getName() will return * std::string("Explosive"). */ std::string getName() const; private: int id; }; namespace DamageTypes { /** Given the name of a damage type, this will return a corresponding DamageType object. For example, * DamageTypes::getDamageType("Concussive") will return DamageTypes::Concussive. */ DamageType getDamageType(std::string name); /** Returns the set of all the DamageTypes. */ std::set& allDamageTypes(); void init(); extern const DamageType Independent; extern const DamageType Explosive; extern const DamageType Concussive; extern const DamageType Normal; extern const DamageType Ignore_Armor; extern const DamageType None; extern const DamageType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Error.h ================================================ #pragma once #include #include namespace BWAPI { class UnitType; /** Functions in BWAPI may set an error code. To retrieve the error code, call Game::getLastError. */ class Error { public: Error(); Error(int id); Error(const Error& other); Error& operator=(const Error& other); bool operator==(const Error& other) const; bool operator!=(const Error& other) const; bool operator<(const Error& other) const; /** Returns a unique ID for this error. */ int getID() const; /** Returns the name of the error. For example Errors::Insufficient_Minerals?.toString() will return a * std::string object containing "Insufficient Minerals". */ std::string toString() const; private: int id; }; namespace Errors { /** Given the name of an error, this function will return the error code. For example: * Errors::getError("Unbuildable Location") will return Errors::Unbuildable_Location?. */ Error getError(std::string name); /** The set of all the error codes. */ std::set& allErrors(); void init(); /** Returned if you try to order a unit or get information from a unit that no longer exists. */ extern const Error Unit_Does_Not_Exist; /** Returned if you try to retrieve information about a unit that is not currently visible or is dead. */ extern const Error Unit_Not_Visible; /** Returned when attempting to order a unit that BWAPI does not own (i.e. can't order enemy army to go * away) */ extern const Error Unit_Not_Owned; /** Returned when trying to order a unit to do something when it is performing another order or is in a * state which prevents it from performing the desired order. For example, ordering a Terran Engineering * Bay to upgrade something while it is already upgrading something else will return this error. * Similarly, trying to train units from a factory that is lifted will return this error. */ extern const Error Unit_Busy; /** Returned if you do something weird like try to build a Pylon with an SCV, or train Vultures in a * Barracks, or order a Hydralisk to lay a spider mine. */ extern const Error Incompatible_UnitType; /** Returned when trying to use a tech type with the wrong Unit::useTech method. */ extern const Error Incompatible_TechType; /** Returned if you to do something like try to cancel an upgrade when the unit isn't upgrading. */ extern const Error Incompatible_State; /** Returned if you try to research something that is already researched. */ extern const Error Already_Researched; /** Returned if you try to upgrade something that is already fully upgraded. */ extern const Error Fully_Upgraded; /** Returned if you try to research something that is already being researched. */ extern const Error Currently_Researching; /** Returned if you try to upgrade something that is already being upgraded. */ extern const Error Currently_Upgrading; /** Returned if you try to train or build something without enough minerals. */ extern const Error Insufficient_Minerals; /** Returned if you try to train or build something without enough vespene gas. */ extern const Error Insufficient_Gas; /** Returned if you try to train something without enough supply. */ extern const Error Insufficient_Supply; /** Returned if you to do something like try to order a Defiler to cast a Dark Swarm without enough * energy. */ extern const Error Insufficient_Energy; /** Returned if you do something like try to train Medics when you don't have an Academy, or try to lay * Spider Mines before spider mines have been researched. */ extern const Error Insufficient_Tech; /** Returned if you do something like try to lay Spider Mines when your Vulture is out of Spider Mines. * Same thing with Reavers and Scarabs. */ extern const Error Insufficient_Ammo; /** Returned if you try to build something on unbuildable terrain (either from the buildability map data * or if a unit is in the way). For build tiles that are not visible, we could just use the buildability * map data and assume that no units are blocking it (to prevent cheating). */ extern const Error Insufficient_Space; /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out * of range. */ extern const Error Unbuildable_Location; /** Returned if you try to construct a building where the worker cannot reach based on static map data. */ extern const Error Unreachable_Location; /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out of * range.*/ extern const Error Out_Of_Range; /** Returned if you do something like order a Vulture to attack a flying unit. */ extern const Error Unable_To_Hit; /** Returned if you try to get information that is not allowed with the given flag settings. For example, * trying to read the enemy's resource counts while the CompleteMapInformation? flag is not enabled will * return this error. Similarly, trying to read the coordinates of the screen or mouse while the UserInput * flag is not enabled will also return this error. */ extern const Error Access_Denied; /** Used when no error has been encountered. */ extern const Error None; /** Used when the error code is not recognized or can not be determined. */ extern const Error Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Event.h ================================================ #pragma once #include #include #include #include #include namespace BWAPI { class Event { public: Event(); bool operator==(const Event& other); static Event MatchStart(); static Event MatchEnd(bool isWinner); static Event MatchFrame(); static Event MenuFrame(); static Event SendText(std::string text); static Event ReceiveText(Player* player, std::string text); static Event PlayerLeft(Player* player); static Event NukeDetect(Position target); static Event UnitDiscover(Unit* unit); static Event UnitEvade(Unit* unit); static Event UnitShow(Unit* unit); static Event UnitHide(Unit* unit); static Event UnitCreate(Unit* unit); static Event UnitDestroy(Unit* unit); static Event UnitMorph(Unit* unit); static Event UnitRenegade(Unit* unit); static Event SaveGame(std::string gameName); EventType::Enum type; Position position; std::string text; Unit* unit; Player* player; bool isWinner; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/EventType.h ================================================ #pragma once namespace BWAPI { namespace EventType { enum Enum { MatchStart, MatchEnd, MatchFrame, MenuFrame, SendText, ReceiveText, PlayerLeft, NukeDetect, UnitDiscover, UnitEvade, UnitShow, UnitHide, UnitCreate, UnitDestroy, UnitMorph, UnitRenegade, SaveGame, None }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/ExplosionType.h ================================================ #pragma once #include #include namespace BWAPI { class ExplosionType { public: ExplosionType(); ExplosionType(int id); ExplosionType(const ExplosionType& other); ExplosionType& operator=(const ExplosionType& other); bool operator==(const ExplosionType& other) const; bool operator!=(const ExplosionType& other) const; bool operator<(const ExplosionType& other) const; /** Returns a unique ID for this explosion type. */ int getID() const; /** Returns the name of this explosion type. */ std::string getName() const; private: int id; }; namespace ExplosionTypes { /** Given a name of an explosion type, this will return the corresponding ExplosionType object. */ ExplosionType getExplosionType(std::string name); /** Returns the set of all ExplosionTypes. */ std::set& allExplosionTypes(); void init(); extern const ExplosionType None; extern const ExplosionType Normal; extern const ExplosionType Radial_Splash; extern const ExplosionType Enemy_Splash; extern const ExplosionType Lockdown; extern const ExplosionType Nuclear_Missile; extern const ExplosionType Parasite; extern const ExplosionType Broodlings; extern const ExplosionType EMP_Shockwave; extern const ExplosionType Irradiate; extern const ExplosionType Ensnare; extern const ExplosionType Plague; extern const ExplosionType Stasis_Field; extern const ExplosionType Dark_Swarm; extern const ExplosionType Consume; extern const ExplosionType Yamato_Gun; extern const ExplosionType Restoration; extern const ExplosionType Disruption_Web; extern const ExplosionType Corrosive_Acid; extern const ExplosionType Mind_Control; extern const ExplosionType Feedback; extern const ExplosionType Optical_Flare; extern const ExplosionType Maelstrom; extern const ExplosionType Air_Splash; extern const ExplosionType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Flag.h ================================================ #pragma once namespace BWAPI { namespace Flag { enum Enum { /** Enable to get information about all units on the map, not just the visible units. */ CompleteMapInformation = 0, /** Enable to get information from the user (what units are selected, chat messages the user enters, * etc) */ UserInput = 1, Max }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Force.h ================================================ #pragma once #include #include namespace BWAPI { class Player; /** The Force class is used to get information about each force in the match, such as the name of the force * and the set of players in the force. */ class Force { public : /** Returns a unique ID for the force. */ virtual int getID() const = 0; /** Returns the name of the force. */ virtual std::string getName() const = 0; /** Returns the set of players in the force. */ virtual std::set getPlayers() const = 0; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Game.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace BWAPI { class Force; class Player; class Unit; class Bullet; /** The abstract Game class is implemented by BWAPI and offers many methods for retrieving information * about the current Broodwar game, including the set of players, units, map information, as well as * information about the user, such as mouse position, screen position, and the current selection of * units. */ class Game { public : /** Returns the set of all forces in the match. */ virtual std::set< Force* >& getForces() = 0; /** Returns the set of all players in the match. Note that this includes the Neutral player, which owns * all the neutral units such as minerals, critters, etc. */ virtual std::set< Player* >& getPlayers() = 0; /** Returns all the visible units. If Flag::CompleteMapInformation is enabled, the set of all units * is returned, not just visible ones. Note that units inside refineries are not included in this set * yet. */ virtual std::set< Unit* >& getAllUnits() = 0; /** Returns the set of all accessible mineral patches. */ virtual std::set< Unit* >& getMinerals() = 0; /** Returns the set of all accessible vespene geysers. */ virtual std::set< Unit* >& getGeysers() = 0; /** Returns the set of all accessible neutral units. */ virtual std::set< Unit* >& getNeutralUnits() = 0; /** Returns the set of all mineral patches (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticMinerals() = 0; /** Returns the set of all vespene geysers (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticGeysers() = 0; /** Returns the set of all neutral units (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticNeutralUnits() = 0; /** Returns all visible bullets. If Flag::CompleteMapInformation is enabled, the set of all bullets is * returned, not just visible ones. */ virtual std::set< Bullet* >& getBullets() = 0; /** Returns the list of events */ virtual std::list< Event >& getEvents() = 0; /** Returns the force with the given ID, or NULL if no force has the given ID */ virtual Force* getForce(int forceID) = 0; /** Returns the player with the given ID, or NULL if no player has the given ID */ virtual Player* getPlayer(int playerID) = 0; /** Returns the unit with the given ID, or NULL if no unit has the given ID */ virtual Unit* getUnit(int unitID) = 0; /** Returns a pointer to a Unit given an index. */ virtual Unit* indexToUnit(int unitIndex) = 0; /** Returns the game type */ virtual GameType getGameType() = 0; /** Returns the amount of latency the current game has. Currently only returns Latency::SinglePlayer, * Latency::LanLow, Latency::LanMedium, or Latency::LanHigh. */ virtual int getLatency() = 0; /** Returns the number of logical frames since the match started. If the game is paused, * Game::getFrameCount will not increase however AIModule::onFrame will still be called while paused. * On Fastest, there are about 23.8 - 24 frames per second. */ virtual int getFrameCount() = 0; /** Returns the Frames Per Second (FPS) that the game is currently running at */ virtual int getFPS() = 0; virtual double getAverageFPS() = 0; /** Returns the position of the mouse on the screen. Returns Positions::Unknown if Flag::UserInput is * disabled. */ virtual BWAPI::Position getMousePosition() = 0; /** Returns true if the specified mouse button is pressed. Returns false if Flag::UserInput is * disabled. */ virtual bool getMouseState(MouseButton button) = 0; /** \copydoc getMouseState(MouseButton) */ virtual bool getMouseState(int button) = 0; /** Returns true if the specified key is pressed. Returns false if Flag::UserInput is disabled. * Unfortunately this does not read the raw keyboard input yet - when you hold down a key, the * getKeyState function is true for a frame, then false for a few frames, and then alternates between * true and false (as if you were holding down the key in a text box). Hopefully this will be fixed in * a later version. */ virtual bool getKeyState(Key key) = 0; /** \copydoc getKeyState(Key) */ virtual bool getKeyState(int key) = 0; /** Returns the position of the top left corner of the screen on the map. Returns Positions::Unknown if * Flag::UserInput is disabled. */ virtual BWAPI::Position getScreenPosition() = 0; /** Moves the screen to the given position on the map. The position specified where the top left corner * of the screen will be. */ virtual void setScreenPosition(int x, int y) = 0; /** \copydoc setScreenPosition(int, int) */ virtual void setScreenPosition(BWAPI::Position p) = 0; /** Pings the given position on the minimap. */ virtual void pingMinimap(int x, int y) = 0; /** \copydoc pingMinimap(int, int) */ virtual void pingMinimap(BWAPI::Position p) = 0; /** Returns true if the given flag has been enabled. Note that flags can only be enabled at the * beginning of a match, during the AIModule::onStart callback. */ virtual bool isFlagEnabled(int flag) = 0; /** Enables the specified flag. Note that flags can only be enabled at the beginning of a match, during * the AIModule::onStart callback. */ virtual void enableFlag(int flag) = 0; /** Returns the set of units that are on the given build tile. Only returns accessible units on * accessible tiles. */ virtual std::set& unitsOnTile(int tileX, int tileY) = 0; /** Returns the last error that was set. If you try to order enemy units around, or morph bunkers into * lurkers, BWAPI will set error codes, which can be retrieved using this function. */ virtual Error getLastError() const = 0; /** Sets the last error code. */ virtual bool setLastError(BWAPI::Error e) = 0; /** Returns the width of the current map, in build tile units. To get the width of the current map in * walk tile units, multiply by 4. To get the width of the current map in Position units, multiply by * TILE_SIZE (which is 32). */ virtual int mapWidth() = 0; /** Returns the height of the current map, in build tile units. To get the height of the current map in * walk tile units, multiply by 4. To get the height of the current map in Position units, multiply by * TILE_SIZE (which is 32). */ virtual int mapHeight() = 0; /** Returns the file name of the current map. */ virtual std::string mapFileName() = 0; /** Returns the full path name of the current map. */ virtual std::string mapPathName() = 0; /** Returns the name/title of the current map. */ virtual std::string mapName() = 0; /** Returns the SHA-1 hash of the map file. */ virtual std::string mapHash() = 0; /** Returns true if the specified walk tile is walkable. The values of x and y are in walk tile * coordinates (different from build tile coordinates). Note that this just uses the static map data. * You will also need to make sure no ground units are on the coresponding build tile to see if its * currently walkable. To do this, see unitsOnTile. */ virtual bool isWalkable(int walkX, int walkY) = 0; /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */ virtual int getGroundHeight(int tileX, int tileY) = 0; /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */ virtual int getGroundHeight(TilePosition position) = 0; /** Returns true if the specified build tile is buildable. Note that this just uses the static map data. * You will also need to make sure no ground units on the tile to see if its currently buildable. To do * this, see unitsOnTile. */ virtual bool isBuildable(int tileX, int tileY) = 0; /** \copydoc isBuildable(int, int) */ virtual bool isBuildable(TilePosition position) = 0; /** Returns true if the specified build tile is visible. If the tile is concealed by fog of war, the * function will return false. */ virtual bool isVisible(int tileX, int tileY) = 0; /** \copydoc isVisible(int, int) */ virtual bool isVisible(TilePosition position) = 0; /** Returns true if the specified build tile has been explored (i.e. was visible at some point in the * match). */ virtual bool isExplored(int tileX, int tileY) = 0; /** \copydoc isExplored(int, int) */ virtual bool isExplored(TilePosition position) = 0; /** Returns true if the specified build tile has zerg creep on it. If the tile is concealed by fog of * war, the function will return false. */ virtual bool hasCreep(int tileX, int tileY) = 0; /** \copydoc hasCreep(int, int) */ virtual bool hasCreep(TilePosition position) = 0; /** Returns true if the given build location is powered by a nearby friendly pylon. */ virtual bool hasPower(int tileX, int tileY, int tileWidth, int tileHeight) = 0; /** \copydoc hasPower(int, int, int, int) */ virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight) = 0; /** Returns true if the given unit type can be built at the given build tile position. Note the tile * position specifies the top left tile of the building. If builder is not null, the unit will be * discarded when determining whether or not any ground units are blocking the build location. */ virtual bool canBuildHere(Unit *builder, TilePosition position, UnitType type, bool checkExplored = false) = 0; /** Returns true if the AI player has enough resources, supply, tech, and required units in order to * make the given unit type. If builder is not null, canMake will return true only if the builder unit * can build the given unit type. */ virtual bool canMake(Unit *builder, UnitType type) = 0; /** Returns true if the AI player has enough resources required to research the given tech type. If unit * is not null, canResearch will return true only if the given unit can research the given tech type. */ virtual bool canResearch(Unit *unit, TechType type) = 0; /** Returns true if the AI player has enough resources required to upgrade the given upgrade type. If * unit is not null, canUpgrade will return true only if the given unit can upgrade the given upgrade * type. */ virtual bool canUpgrade(Unit *unit, UpgradeType type) = 0; /** Returns the set of starting locations for the given map. To determine the starting location for the * players in the current match, see Player::getStartLocation. */ virtual std::set< TilePosition >& getStartLocations() = 0; /** Prints text on the screen. Text is not sent to other players in multiplayer games. */ virtual void printf(const char *format, ...) = 0; /** Sends text to other players - as if it were entered in chat. In single player games and replays, * this will just print the text on the screen. If the game is a single player match and not a replay, * then this function can be used to execute cheat codes, i.e. Broodwar->sendText("show me the money"). */ virtual void sendText(const char *format, ...) = 0; virtual void sendTextEx(bool toAllies, const char *format, ...) = 0; /** Used to change the race while in a lobby. Note that there is no onLobbyEnter callback yet, so this * function cannot be used at this time. */ virtual void changeRace(Race race) = 0; /** Returns true if Broodwar is in a game. Returns false for lobby and menu screens */ virtual bool isInGame() = 0; /** Returns true if Broodwar is in a multiplayer game. Returns false for single player games and * replays. */ virtual bool isMultiplayer() = 0; /** Returns true if Broodwar is in a BNet multiplayer game. */ virtual bool isBattleNet() = 0; /** Returns true if Broodwar is paused. If the game is paused, Game::getFrameCount will continue to * increase and AIModule::onFrame will still be called while paused. */ virtual bool isPaused() = 0; /** Returns true if Broodwar is in a replay. */ virtual bool isReplay() = 0; /** Used to start the game while in a lobby. Note that there is no onLobbyEnter callback yet, so this * function cannot be used at this time. */ virtual void startGame() = 0; /** Pauses the game. If the game is paused, Game::getFrameCount will not increase however * AIModule::onFrame will still be called while paused. */ virtual void pauseGame() = 0; /** Resumes the game. */ virtual void resumeGame() = 0; /** Leaves the current match and goes to the after-game stats screen. */ virtual void leaveGame() = 0; /** Restarts the match. Works the same way as if you restarted the match from the menu screen. Only * available in single player mode. */ virtual void restartGame() = 0; /** Sets the speed of the game to the given number. Lower numbers are faster. 0 is the fastest speed * StarCraft can handle (which is about as fast as the fastest speed you can view a replay at). Any * negative value will reset the speed to the StarCraft default. */ virtual void setLocalSpeed(int speed = -1) = 0; /** Returns the set of units currently selected by the user in the GUI. If Flag?::UserInput? was not * enabled during the AIModule::onStart callback, this function will always return an empty set. */ virtual std::set& getSelectedUnits() = 0; /** Returns a pointer to the player that BWAPI controls. In replays this will return null. */ virtual Player* self() = 0; /** Returns a pointer to the enemy player. If there is more than one enemy, this returns a pointer to * just one enemy (see getPlayers and Player::isEnemy to get the other enemies). In replays this will * return NULL. */ virtual Player* enemy() = 0; virtual void setTextSize(int size = 1) = 0; /** Draws text on the screen at the given position. Text can be drawn in different colors by using the * following control characters: TODO: add image from wiki.*/ virtual void drawText(int ctype, int x, int y, const char* text, ...) = 0; virtual void drawTextMap(int x, int y, const char* text, ...) = 0; virtual void drawTextMouse(int x, int y, const char* text, ...) = 0; virtual void drawTextScreen(int x, int y, const char* text, ...) = 0; /** Draws a box on the screen, with the given color. If isSolid is true, the entire box will be * rendered, otherwise just the outline will be drawn. */ virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; /** Draws a triangle on the screen. If isSolid is true, a solid triangle is drawn, otherwise just the * outline of the triangle will be drawn. */ virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; /** Draws a circle on the screen, with the given color. If isSolid is true, a solid circle is drawn, * otherwise just the outline of a circle will be drawn. */ virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false) = 0; /** Draws an ellipse on the screen, with the given color. If isSolid is true, a solid ellipse is drawn, * otherwise just the outline of an ellipse will be drawn. */ virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; /** Draws a dot on the screen at the given position with the given color. */ virtual void drawDot(int ctype, int x, int y, Color color) = 0; virtual void drawDotMap(int x, int y, Color color) = 0; virtual void drawDotMouse(int x, int y, Color color) = 0; virtual void drawDotScreen(int x, int y, Color color) = 0; /** Draws a line on the screen from (x1,y1) to (x2,y2) with the given color. */ virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color) = 0; /** Retrieves the screen buffer for the game (excluding the HUD) */ virtual void *getScreenBuffer() = 0; /** Retrieves latency values for the game. Includes latency, speed, and mode */ virtual int getLatencyFrames() = 0; virtual int getLatencyTime() = 0; virtual int getRemainingLatencyFrames() = 0; virtual int getRemainingLatencyTime() = 0; /** Retrieves the current revision of BWAPI. */ virtual int getRevision() = 0; /** Retrieves the debug state of the BWAPI build. */ virtual bool isDebug() = 0; /** Returns true if latency compensation is enabled */ virtual bool isLatComEnabled() = 0; /** Use to enable or disable latency compensation. Default: Enabled */ virtual void setLatCom(bool isEnabled) = 0; /** Retrieves the number of frames in the replay */ virtual int getReplayFrameCount() = 0; /** Sets the rendering state of the Starcraft GUI */ virtual void setGUI(bool enabled = true) = 0; /** Retrieves the instance number recorded by BWAPI to identify which instance an AI module belongs to */ virtual int getInstanceNumber() = 0; }; extern Game* Broodwar; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/GameType.h ================================================ #pragma once #include #include namespace BWAPI { class GameType { public: GameType(); GameType(int id); GameType(const GameType& other); GameType& operator=(const GameType& other); bool operator==(const GameType& other) const; bool operator!=(const GameType& other) const; bool operator<(const GameType& other) const; /** Returns the unique ID for this game type. */ int getID() const; /** Returns the name of the game type. For example GameTypes::Melee.getName() will return an * std::string object containing "Melee". */ std::string getName() const; private: int id; }; namespace GameTypes { /** Given the name of a game type, this function will return the GameType. For example: * GameTypes::getGameType("Free For All") will return GameTypes::Free_For_All. */ GameType getGameType(std::string name); /** Returns the set of all the GameTypes. */ std::set& allGameTypes(); void init(); extern const GameType Melee; extern const GameType Free_For_All; extern const GameType One_on_One; extern const GameType Capture_The_Flag; extern const GameType Greed; extern const GameType Slaughter; extern const GameType Sudden_Death; extern const GameType Ladder; extern const GameType Use_Map_Settings; extern const GameType Team_Melee; extern const GameType Team_Free_For_All; extern const GameType Team_Capture_The_Flag; extern const GameType Top_vs_Bottom; extern const GameType Pro_Gamer_League; extern const GameType None; extern const GameType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Input.h ================================================ #pragma once namespace BWAPI { enum MouseButton { M_LEFT = 0, M_RIGHT = 1, M_MIDDLE = 2, }; enum Key { K_LBUTTON = 0x01, K_RBUTTON = 0x02, K_CANCEL = 0x03, K_MBUTTON = 0x04, K_XBUTTON1 = 0x05, K_XBUTTON2 = 0x06, K_BACK = 0x08, K_TAB = 0x09, K_CLEAR = 0x0C, K_RETURN = 0x0D, K_SHIFT = 0x10, K_CONTROL = 0x11, K_MENU = 0x12, K_PAUSE = 0x13, K_CAPITAL = 0x14, K_KANA = 0x15, K_HANGEUL = 0x15, K_HANGUL = 0x15, K_JUNJA = 0x17, K_FINAL = 0x18, K_HANJA = 0x19, K_KANJI = 0x19, K_ESCAPE = 0x1B, K_CONVERT = 0x1C, K_NONCONVERT = 0x1D, K_ACCEPT = 0x1E, K_MODECHANGE = 0x1F, K_SPACE = 0x20, K_PRIOR = 0x21, K_NEXT = 0x22, K_END = 0x23, K_HOME = 0x24, K_LEFT = 0x25, K_UP = 0x26, K_RIGHT = 0x27, K_DOWN = 0x28, K_SELECT = 0x29, K_PRINT = 0x2A, K_EXECUTE = 0x2B, K_SNAPSHOT = 0x2C, K_INSERT = 0x2D, K_DELETE = 0x2E, K_HELP = 0x2F, K_0 = 0x30, K_1 = 0x31, K_2 = 0x32, K_3 = 0x33, K_4 = 0x34, K_5 = 0x35, K_6 = 0x36, K_7 = 0x37, K_8 = 0x38, K_9 = 0x39, K_A = 0x41, K_B = 0x42, K_C = 0x43, K_D = 0x44, K_E = 0x45, K_F = 0x46, K_G = 0x47, K_H = 0x48, K_I = 0x49, K_J = 0x4A, K_K = 0x4B, K_L = 0x4C, K_M = 0x4D, K_N = 0x4E, K_O = 0x4F, K_P = 0x50, K_Q = 0x51, K_R = 0x52, K_S = 0x53, K_T = 0x54, K_U = 0x55, K_V = 0x56, K_W = 0x57, K_X = 0x58, K_Y = 0x59, K_Z = 0x5A, K_LWIN = 0x5B, K_RWIN = 0x5C, K_APPS = 0x5D, K_SLEEP = 0x5F, K_NUMPAD0 = 0x60, K_NUMPAD1 = 0x61, K_NUMPAD2 = 0x62, K_NUMPAD3 = 0x63, K_NUMPAD4 = 0x64, K_NUMPAD5 = 0x65, K_NUMPAD6 = 0x66, K_NUMPAD7 = 0x67, K_NUMPAD8 = 0x68, K_NUMPAD9 = 0x69, K_MULTIPLY = 0x6A, K_ADD = 0x6B, K_SEPARATOR = 0x6C, K_SUBTRACT = 0x6D, K_DECIMAL = 0x6E, K_DIVIDE = 0x6F, K_F1 = 0x70, K_F2 = 0x71, K_F3 = 0x72, K_F4 = 0x73, K_F5 = 0x74, K_F6 = 0x75, K_F7 = 0x76, K_F8 = 0x77, K_F9 = 0x78, K_F10 = 0x79, K_F11 = 0x7A, K_F12 = 0x7B, K_F13 = 0x7C, K_F14 = 0x7D, K_F15 = 0x7E, K_F16 = 0x7F, K_F17 = 0x80, K_F18 = 0x81, K_F19 = 0x82, K_F20 = 0x83, K_F21 = 0x84, K_F22 = 0x85, K_F23 = 0x86, K_F24 = 0x87, K_NUMLOCK = 0x90, K_SCROLL = 0x91, K_OEM_NEC_EQUAL = 0x92, K_OEM_FJ_JISHO = 0x92, K_OEM_FJ_MASSHOU = 0x93, K_OEM_FJ_TOUROKU = 0x94, K_OEM_FJ_LOYA = 0x95, K_OEM_FJ_ROYA = 0x96, K_LSHIFT = 0xA0, K_RSHIFT = 0xA1, K_LCONTROL = 0xA2, K_RCONTROL = 0xA3, K_LMENU = 0xA4, K_RMENU = 0xA5, K_BROWSER_BACK = 0xA6, K_BROWSER_FORWARD = 0xA7, K_BROWSER_REFRESH = 0xA8, K_BROWSER_STOP = 0xA9, K_BROWSER_SEARCH = 0xAA, K_BROWSER_FAVORITES = 0xAB, K_BROWSER_HOME = 0xAC, K_VOLUME_MUTE = 0xAD, K_VOLUME_DOWN = 0xAE, K_VOLUME_UP = 0xAF, K_MEDIA_NEXT_TRACK = 0xB0, K_MEDIA_PREV_TRACK = 0xB1, K_MEDIA_STOP = 0xB2, K_MEDIA_PLAY_PAUSE = 0xB3, K_LAUNCH_MAIL = 0xB4, K_LAUNCH_MEDIA_SELECT = 0xB5, K_LAUNCH_APP1 = 0xB6, K_LAUNCH_APP2 = 0xB7, K_OEM_1 = 0xBA, K_OEM_PLUS = 0xBB, K_OEM_COMMA = 0xBC, K_OEM_MINUS = 0xBD, K_OEM_PERIOD = 0xBE, K_OEM_2 = 0xBF, K_OEM_3 = 0xC0, K_OEM_4 = 0xDB, K_OEM_5 = 0xDC, K_OEM_6 = 0xDD, K_OEM_7 = 0xDE, K_OEM_8 = 0xDF, K_OEM_AX = 0xE1, K_OEM_102 = 0xE2, K_ICO_HELP = 0xE3, K_ICO_00 = 0xE4, K_PROCESSKEY = 0xE5, K_ICO_CLEAR = 0xE6, K_PACKET = 0xE7, K_OEM_RESET = 0xE9, K_OEM_JUMP = 0xEA, K_OEM_PA1 = 0xEB, K_OEM_PA2 = 0xEC, K_OEM_PA3 = 0xED, K_OEM_WSCTRL = 0xEE, K_OEM_CUSEL = 0xEF, K_OEM_ATTN = 0xF0, K_OEM_FINISH = 0xF1, K_OEM_COPY = 0xF2, K_OEM_AUTO = 0xF3, K_OEM_ENLW = 0xF4, K_OEM_BACKTAB = 0xF5, K_ATTN = 0xF6, K_CRSEL = 0xF7, K_EXSEL = 0xF8, K_EREOF = 0xF9, K_PLAY = 0xFA, K_ZOOM = 0xFB, K_NONAME = 0xFC, K_PA1 = 0xFD, K_OEM_CLEAR = 0xFE }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Latency.h ================================================ #pragma once namespace BWAPI { namespace Latency { enum Enum { SinglePlayer = 2, LanLow = 5, LanMedium = 7, LanHigh = 9, BattlenetLow = 14, BattlenetMedium = 19, BattlenetHigh = 24 }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Order.h ================================================ #pragma once #include #include namespace BWAPI { /** To get detailed information about what a unit is doing, you can use the Unit::getOrder method, which * will return an Order object. Note that a single command, like gather minerals, can consist of several * orders ( MoveToMinerals, HarvestMinerals2, MiningMinerals, ReturnMinerals, etc) which will indicate what * state the unit is in while executing the command. For information about how to issue commands to units, * go to Unit. */ class Order { public: Order(); Order(int id); Order(const Order& other); Order& operator=(const Order& other); bool operator==(const Order& other) const; bool operator!=(const Order& other) const; bool operator<(const Order& other) const; /** Returns the unique ID for this order. */ int getID() const; /** Returns the name of this order. */ std::string getName() const; private: int id; }; namespace Orders { /** Given the name of an order, getOrder() will return the corresponding order object. */ Order getOrder(std::string name); /** Returns the set of all the Orders. */ std::set& allOrders(); void init(); extern const Order Die; extern const Order Stop; extern const Order Guard; extern const Order PlayerGuard; extern const Order TurretGuard; extern const Order BunkerGuard; extern const Order Move; extern const Order AttackUnit; extern const Order AttackTile; extern const Order Hover; extern const Order AttackMove; extern const Order InfestedCommandCenter; extern const Order UnusedNothing; extern const Order UnusedPowerup; extern const Order TowerGuard; extern const Order VultureMine; extern const Order Nothing; extern const Order Nothing3; extern const Order CastInfestation; extern const Order InfestingCommandCenter; extern const Order PlaceBuilding; extern const Order BuildProtoss2; extern const Order ConstructingBuilding; extern const Order Repair; extern const Order PlaceAddon; extern const Order BuildAddon; extern const Order Train; extern const Order RallyPointUnit; extern const Order RallyPointTile; extern const Order ZergBirth; extern const Order ZergUnitMorph; extern const Order ZergBuildingMorph; extern const Order IncompleteBuilding; extern const Order BuildNydusExit; extern const Order EnterNydusCanal; extern const Order Follow; extern const Order Carrier; extern const Order ReaverCarrierMove; extern const Order CarrierIgnore2; extern const Order Reaver; extern const Order TrainFighter; extern const Order InterceptorAttack; extern const Order ScarabAttack; extern const Order RechargeShieldsUnit; extern const Order RechargeShieldsBattery; extern const Order ShieldBattery; extern const Order InterceptorReturn; extern const Order BuildingLand; extern const Order BuildingLiftOff; extern const Order DroneLiftOff; extern const Order LiftingOff; extern const Order ResearchTech; extern const Order Upgrade; extern const Order Larva; extern const Order SpawningLarva; extern const Order Harvest1; extern const Order Harvest2; extern const Order MoveToGas; extern const Order WaitForGas; extern const Order HarvestGas; extern const Order ReturnGas; extern const Order MoveToMinerals; extern const Order WaitForMinerals; extern const Order MiningMinerals; extern const Order Harvest3; extern const Order Harvest4; extern const Order ReturnMinerals; extern const Order Interrupted; extern const Order EnterTransport; extern const Order PickupIdle; extern const Order PickupTransport; extern const Order PickupBunker; extern const Order Pickup4; extern const Order PowerupIdle; extern const Order Sieging; extern const Order Unsieging; extern const Order InitCreepGrowth; extern const Order SpreadCreep; extern const Order StoppingCreepGrowth; extern const Order GuardianAspect; extern const Order ArchonWarp; extern const Order CompletingArchonsummon; extern const Order HoldPosition; extern const Order Cloak; extern const Order Decloak; extern const Order Unload; extern const Order MoveUnload; extern const Order FireYamatoGun; extern const Order CastLockdown; extern const Order Burrowing; extern const Order Burrowed; extern const Order Unburrowing; extern const Order CastDarkSwarm; extern const Order CastParasite; extern const Order CastSpawnBroodlings; extern const Order CastEMPShockwave; extern const Order NukeWait; extern const Order NukeTrain; extern const Order NukeLaunch; extern const Order NukeUnit; extern const Order CastNuclearStrike; extern const Order NukeTrack; extern const Order CloakNearbyUnits; extern const Order PlaceMine; extern const Order RightClickAction; extern const Order CastRecall; extern const Order TeleporttoLocation; extern const Order CastScannerSweep; extern const Order Scanner; extern const Order CastDefensiveMatrix; extern const Order CastPsionicStorm; extern const Order CastIrradiate; extern const Order CastPlague; extern const Order CastConsume; extern const Order CastEnsnare; extern const Order CastStasisField; extern const Order CastHallucination; extern const Order Hallucination2; extern const Order ResetCollision; extern const Order Patrol; extern const Order CTFCOPInit; extern const Order CTFCOP1; extern const Order CTFCOP2; extern const Order ComputerAI; extern const Order AtkMoveEP; extern const Order HarassMove; extern const Order AIPatrol; extern const Order GuardPost; extern const Order RescuePassive; extern const Order Neutral; extern const Order ComputerReturn; extern const Order SelfDestrucing; extern const Order Critter; extern const Order HiddenGun; extern const Order OpenDoor; extern const Order CloseDoor; extern const Order HideTrap; extern const Order RevealTrap; extern const Order Enabledoodad; extern const Order Disabledoodad; extern const Order Warpin; extern const Order Medic; extern const Order MedicHeal1; extern const Order HealMove; extern const Order MedicHeal2; extern const Order CastRestoration; extern const Order CastDisruptionWeb; extern const Order CastMindControl; extern const Order DarkArchonMeld; extern const Order CastFeedback; extern const Order CastOpticalFlare; extern const Order CastMaelstrom; extern const Order JunkYardDog; extern const Order Fatal; extern const Order None; extern const Order Unknown; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Player.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include namespace BWAPI { class Unit; class Force; /** Each player in a match will have his or her own player instance. There is also a neutral player which * owns all the neutral units. */ class Player { public : /** Returns a unique ID for the player. */ virtual int getID() const = 0; /** Returns the name of the player. */ virtual std::string getName() const = 0; /** Returns the set of units the player own. Note that units loaded into Terran dropships, Terran * bunkers, Terran refineries, Protoss assimilators, and Zerg extractors are not yet included in the * set. */ virtual const std::set& getUnits() const = 0; /** Returns the race of the player. */ virtual Race getRace() const = 0; /** Returns the type of the player. */ virtual PlayerType getType() const = 0; /** Returns the force the player is on. */ virtual Force* getForce() const = 0; /** Returns true if other player is an ally of this player. */ virtual bool isAlly(Player* player) const = 0; /** Returns true if other player is an enemy of this player. */ virtual bool isEnemy(Player* player) const = 0; /** Returns true if the player is the neutral player. */ virtual bool isNeutral() const = 0; /** Returns the starting location of the player. If complete map information is disabled, this function * will return TilePositions::Unknown for enemy players. For the complete set of starting locations for * the current map, see Game::getStartLocations. */ virtual TilePosition getStartLocation() const = 0; /** Returns true if the player has achieved victory. */ virtual bool isVictorious() const = 0; /** Returns true if the player has been defeated. */ virtual bool isDefeated() const = 0; /** Returns true if the player left the game. */ virtual bool leftGame() const = 0; /** Returns the amount of minerals the player has. */ virtual int minerals() const = 0; /** Returns the amount of vespene gas the player has. */ virtual int gas() const = 0; /** Returns the cumulative amount of minerals the player has mined up to this point (including the 50 * minerals at the start of the game). */ virtual int cumulativeMinerals() const = 0; /** Returns the cumulative amount of gas the player has harvested up to this point. */ virtual int cumulativeGas() const = 0; // TODO: ground methods /** Returns the total amount of supply the player has. If a race is provided, the total supply for the * given race will be returned, otherwise the player's initial race will be used. Supply counts returned * by BWAPI are double what you would expect to see from playing the game. This is because zerglings * take up 0.5 in-game supply. */ virtual int supplyTotal() const = 0; virtual int supplyTotal(Race race) const = 0; /** Returns how much of the supply is actually being used by units. If a race is provided, the used * supply for the given race will be returned, otherwise the player's initial race will be used. Supply * counts returned by BWAPI are double what you would expect to see from playing the game. This is * because zerglings take up 0.5 in-game supply. */ virtual int supplyUsed() const = 0; virtual int supplyUsed(Race race) const = 0; /** Returns the number of all units of the given type. */ virtual int allUnitCount(UnitType unit) const = 0; /** Returns the number of completed units of the given type. */ virtual int completedUnitCount(UnitType unit) const = 0; /** Returns the number of incomplete units of the given type. */ virtual int incompleteUnitCount(UnitType unit) const = 0; /** Returns the number of dead units of the given type. */ virtual int deadUnitCount(UnitType unit) const = 0; /** Returns the number of killed units of the given type. */ virtual int killedUnitCount(UnitType unit) const = 0; /** Returns the player's current upgrade level of the given upgrade. To order a unit to upgrade a given * upgrade type, see Unit::upgrade. */ virtual int getUpgradeLevel(UpgradeType upgrade) const = 0; /** Returns true if the player has finished researching the given tech. To order a unit to research a * given tech type, see Unit::research. */ virtual bool hasResearched(TechType tech) const = 0; /** Returns true if the player is researching the given tech. To order a unit to research a given tech * type, see Unit::reseach. */ virtual bool isResearching(TechType tech) const = 0; /** Returns true if the player is upgrading the given upgrade. To order a unit to upgrade a given * upgrade type, see Unit::upgrade. */ virtual bool isUpgrading(UpgradeType upgrade) const = 0; /** Returns the max energy of the given unit type, taking into account upgrades */ virtual int maxEnergy(UnitType unit) const = 0; /** Returns the color of the player for drawing */ virtual BWAPI::Color getColor() const = 0; /** Returns the color of the player for text messages */ virtual int getTextColor() const = 0; }; }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/PlayerType.h ================================================ #pragma once #include #include namespace BWAPI { class PlayerType { public: PlayerType(); PlayerType(int id); PlayerType(const PlayerType& other); PlayerType& operator=(const PlayerType& other); bool operator==(const PlayerType& other) const; bool operator!=(const PlayerType& other) const; bool operator<(const PlayerType& other) const; /** Returns the unique ID for this player type. */ int getID() const; /** Returns the name of the player type. For example PlayerTypes::Computer.getName() will return an * std::string object containing "Computer". */ std::string getName() const; private: int id; }; namespace PlayerTypes { /** Given the name of a player type, this function will return the playertype. For example: * PlayerTypes::getPlayerType("Human") will return PlayerTypes::Human. */ PlayerType getPlayerType(std::string name); /** Returns the set of all the PlayerTypes. */ std::set& allPlayerTypes(); void init(); extern const PlayerType None; extern const PlayerType Computer; extern const PlayerType Player; extern const PlayerType RescuePassive; extern const PlayerType EitherPreferComputer; extern const PlayerType EitherPreferHuman; extern const PlayerType Neutral; extern const PlayerType Closed; extern const PlayerType PlayerLeft; extern const PlayerType ComputerLeft; extern const PlayerType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Position.h ================================================ #pragma once namespace BWAPI { class TilePosition; // TODO: Add doxygen documentation class Position { public : Position(); explicit Position(const TilePosition& position); Position(int x, int y); bool operator == (const Position& position) const; bool operator != (const Position& position) const; bool operator < (const Position& position) const; bool isValid() const; Position operator+(const Position& position) const; Position operator-(const Position& position) const; Position& makeValid(); Position& operator+=(const Position& position); Position& operator-=(const Position& position); double getDistance(const Position& position) const; double getApproxDistance(const Position& position) const; double getLength() const; int& x(); int& y(); int x() const; int y() const; private : int _x; int _y; }; namespace Positions { extern const Position Invalid; extern const Position None; extern const Position Unknown; } }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Race.h ================================================ #pragma once #include #include namespace BWAPI { class UnitType; class Race { public: Race(); Race(int id); Race(const Race& other); Race& operator=(const Race& other); bool operator==(const Race& other) const; bool operator!=(const Race& other) const; bool operator<(const Race& other) const; /** Returns a unique ID for this race. */ int getID() const; /** Returns the name of the race. For example Races::Terran.getName() will return a std::string object * containing "Terran". */ std::string getName() const; /** Returns the worker unit type for the given race. For example Races::Protoss.getWorker() will return * a pointer to UnitTypes::Protoss_Probe. */ UnitType getWorker() const; /** Returns the center unit type for the given race. For example Races::Terran.getCenter() will return a * pointer to UnitTypes::Terran_Command_Center. While there are three center types for Zerg * (Hatchery, Lair, and Hive), Races::Zerg.getCenter() will only return a pointer to * UnitTypes::Zerg_Hatchery, since it is the unit type needed to make a new center. */ UnitType getCenter() const; /** Returns the refinery unit type for the given race. For example: Races::Zerg.getRefinery() will * return a pointer to UnitTypes::Zerg_Extractor?. */ UnitType getRefinery() const; /** Returns the transport unit type for the given race. For example: Races::Protoss.getTransport() will * return a pointer to UnitTypes::Protoss_Shuttle. */ UnitType getTransport() const; /** Returns the main supply provider unit type for the given race. For example: * Races::Terran.getSupplyProvider() will return a pointer to UnitTypes::Terran_Supply_Depot?. */ UnitType getSupplyProvider() const; private: int id; }; namespace Races { /** Given the name of a race, this function will return the race type. For example: * Races::getRace("Zerg") will return Races::Zerg. */ Race getRace(std::string name); /** Returns the set of all the races, which are listed below. */ std::set& allRaces(); void init(); extern const Race Zerg; extern const Race Terran; extern const Race Protoss; extern const Race Random; extern const Race Other; extern const Race None; extern const Race Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/TechType.h ================================================ #pragma once #include #include #include namespace BWAPI { class UnitType; class WeaponType; class TechType { public: TechType(); TechType(int id); TechType(const TechType& other); TechType& operator=(const TechType& other); bool operator==(const TechType& other) const; bool operator!=(const TechType& other) const; bool operator<(const TechType& other) const; /** Returns the unique ID for this tech type. */ int getID() const; /** Returns the name of the tech type. */ std::string getName() const; /** Returns the race that uses the TechType. For example, TechTypes::Scanner_Sweep?.getRace() will * return Races::Terran. */ Race getRace() const; /** Returns the mineral cost of the tech type. */ int mineralPrice() const; /** Returns the vespene gas price of the tech type. */ int gasPrice() const; /** Returns the number of frames needed to research the tech type. */ int researchTime() const; /** Returns the amount of energy used each time this tech type is used. */ int energyUsed() const; /** Returns the type of unit that researches this tech type. If this tech type is available for free * (does not need to be researched), then this method will return UnitTypes::None. */ UnitType whatResearches() const; /** Returns the corresponding weapon for this tech type, or TechTypes::None if no corresponding weapon * exists. For example, TechTypes::Dark_Swarm.getWeapon() will return a pointer to * WeaponTypes::Dark_Swarm. */ WeaponType getWeapon() const; /** Returns the set of units that can use this tech type. Usually this will just be a set of one unit * type, however in some cases, such as TechTypes::Burrowing, several unit types will be returned. */ const std::set& whatUses() const; private: int id; }; namespace TechTypes { /** Given a string, this will return the tech type. */ TechType getTechType(std::string name); /** Returns the set of all the TechTypes. */ std::set& allTechTypes(); void init(); extern const TechType Stim_Packs; extern const TechType Lockdown; extern const TechType EMP_Shockwave; extern const TechType Spider_Mines; extern const TechType Scanner_Sweep; extern const TechType Tank_Siege_Mode; extern const TechType Defensive_Matrix; extern const TechType Irradiate; extern const TechType Yamato_Gun; extern const TechType Cloaking_Field; extern const TechType Personnel_Cloaking; extern const TechType Burrowing; extern const TechType Infestation; extern const TechType Spawn_Broodlings; extern const TechType Dark_Swarm; extern const TechType Plague; extern const TechType Consume; extern const TechType Ensnare; extern const TechType Parasite; extern const TechType Psionic_Storm; extern const TechType Hallucination; extern const TechType Recall; extern const TechType Stasis_Field; extern const TechType Archon_Warp; extern const TechType Restoration; extern const TechType Disruption_Web; extern const TechType Mind_Control; extern const TechType Dark_Archon_Meld; extern const TechType Feedback; extern const TechType Optical_Flare; extern const TechType Maelstrom; extern const TechType Lurker_Aspect; extern const TechType Healing; extern const TechType None; extern const TechType Unknown; extern const TechType Nuclear_Strike; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/TilePosition.h ================================================ #pragma once namespace BWAPI { class Position; // TODO: Add doxygen documentation class TilePosition { public : TilePosition(); explicit TilePosition(const Position& position); TilePosition(int x, int y); bool operator == (const TilePosition& TilePosition) const; bool operator != (const TilePosition& TilePosition) const; bool operator < (const TilePosition& TilePosition) const; bool isValid() const; TilePosition operator+(const TilePosition& position) const; TilePosition operator-(const TilePosition& position) const; TilePosition& makeValid(); TilePosition& operator+=(const TilePosition& position); TilePosition& operator-=(const TilePosition& position); double getDistance(const TilePosition& position) const; double getLength() const; int& x(); int& y(); int x() const; int y() const; private : int _x; int _y; }; namespace TilePositions { extern const TilePosition Invalid; extern const TilePosition None; extern const TilePosition Unknown; } }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/Unit.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include namespace BWAPI { class Player; /** The Unit class is used to get information about individual units as well as issue orders to units. Each * unit in the game has a unique Unit object, and Unit objects are not deleted until the end of the match * (so you don't need to worry about unit pointers becoming invalid). * * Every Unit in the game is either accessible or inaccessible. To determine if an AI can access a * particular unit, BWAPI checks to see if Flag::CompleteMapInformation? is enabled. So there are two cases * to consider - either the flag is enabled, or it is disabled: * * If Flag::CompleteMapInformation? is disabled, then a unit is accessible if and only if it is visible. * Note also that some properties of visible enemy units will not be made available to the AI (such as the * contents of visible enemy dropships). If a unit is not visible, Unit::exists will return false, * regardless of whether or not the unit exists. This is because absolutely no state information on * invisible enemy units is made available to the AI. To determine if an enemy unit has been destroyed, the * AI must watch for AIModule::onUnitDestroy messages from BWAPI, which is only called for visible units * which get destroyed. * * If Flag::CompleteMapInformation? is enabled, then all units that exist in the game are accessible, and * Unit::exists is accurate for all units. Similarly AIModule::onUnitDestroy messages are generated for all * units that get destroyed, not just visible ones. * * If a Unit is not accessible, in general the only the getInitial__ functions will be available to the AI. * However for units that were owned by the player, getPlayer and getType will continue to work for units * that have been destroyed. */ class Unit { public: /** Returns a unique ID for this unit. It simply casts the unit's address as an integer, since each unit * has a unique address. */ virtual int getID() const = 0; /** Returns a pointer to the player that owns this unit. */ virtual Player* getPlayer() const = 0; /** Returns the current type of the unit. */ virtual UnitType getType() const = 0; /** Returns the position of the unit on the map. */ virtual Position getPosition() const = 0; /** Returns the build tile position of the unit on the map. Useful if the unit is a building. The tile * position is of the top left corner of the building. */ virtual TilePosition getTilePosition() const = 0; /** Returns the direction the unit is facing, measured in radians. An angle of 0 means the unit is * facing east. */ virtual double getAngle() const = 0; /** Returns the x component of the unit's velocity, measured in pixels per frame. */ virtual double getVelocityX() const = 0; /** Returns the y component of the unit's velocity, measured in pixels per frame. */ virtual double getVelocityY() const = 0; /** Returns the unit's current amount of hit points. */ virtual int getHitPoints() const = 0; /** Returns the unit's current amount of shields. */ virtual int getShields() const = 0; /** Returns the unit's current amount of energy. */ virtual int getEnergy() const = 0; /** Returns the unit's current amount of containing resources. Useful for determining how much minerals * are left in a mineral patch, or how much gas is left in a geyser * (can also be called on a refinery/assimilator/extractor). */ virtual int getResources() const = 0; /** Retrieves the group ID of a resource. Can be used to identify which resources belong to an expansion. */ virtual int getResourceGroup() const = 0; /** Returns the edge-to-edge distance between the current unit and the target unit. */ virtual double getDistance(Unit* target) const = 0; /** Returns the distance from the edge of the current unit to the target position. */ virtual double getDistance(Position target) const = 0; /** Returns true if the unit is able to move to the target unit */ virtual bool hasPath(Unit* target) const = 0; /** Returns true if the unit is able to move to the target position */ virtual bool hasPath(Position target) const = 0; /** Retrieves the frame of the last successful order. Frame is comparable to Game::getFrameCount(). */ virtual int getLastOrderFrame() const = 0; /** Returns the player's current upgrade level for the given upgrade, if the unit is affected by this * upgrade.*/ virtual int getUpgradeLevel(UpgradeType upgrade) const = 0; /** Returns the initial type of the unit or Unknown if it wasn't a neutral unit at the beginning of the * game. */ virtual UnitType getInitialType() const = 0; /** Returns the initial position of the unit on the map, or Positions::Unknown if the unit wasn't a * neutral unit at the beginning of the game. */ virtual Position getInitialPosition() const = 0; /** Returns the initial build tile position of the unit on the map, or TilePositions::Unknown if the * unit wasn't a neutral unit at the beginning of the game. The tile position is of the top left corner * of the building. */ virtual TilePosition getInitialTilePosition() const = 0; /** Returns the unit's initial amount of hit points, or 0 if it wasn't a neutral unit at the beginning * of the game. */ virtual int getInitialHitPoints() const = 0; /** Returns the unit's initial amount of containing resources, or 0 if the unit wasn't a neutral unit * at the beginning of the game. */ virtual int getInitialResources() const = 0; /** Returns the unit's current kill count. */ virtual int getKillCount() const = 0; /** Returns the number of interceptors the Protoss Carrier has. */ virtual int getInterceptorCount() const = 0; /** Returns the number of scarabs in the Protoss Reaver. */ virtual int getScarabCount() const = 0; /** Returns the number of spider mines in the Terran Vulture. */ virtual int getSpiderMineCount() const = 0; /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready to attack. */ virtual int getGroundWeaponCooldown() const = 0; /** Returns unit's air weapon cooldown. It is 0 if the unit is ready to attack. */ virtual int getAirWeaponCooldown() const = 0; /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready cast a spell. */ virtual int getSpellCooldown() const = 0; /** Returns the remaining hit points of the defense matrix. Initially a defense Matrix has 250 points. * \see Unit::getDefenseMatrixTimer, Unit::isDefenseMatrixed. */ virtual int getDefenseMatrixPoints() const = 0; /** Returns the time until the defense matrix wears off. 0 -> No defense Matrix present. */ virtual int getDefenseMatrixTimer() const = 0; /** Returns the time until the ensnare effect wears off. 0 -> No ensnare effect present. */ virtual int getEnsnareTimer() const = 0; /** Returns the time until the radiation wears off. 0 -> No radiation present. */ virtual int getIrradiateTimer() const = 0; /** Returns the time until the lockdown wears off. 0 -> No lockdown present. */ virtual int getLockdownTimer() const = 0; /** Returns the time until the maelstrom wears off. 0 -> No maelstrom present. */ virtual int getMaelstromTimer() const = 0; // TODO: add doc virtual int getOrderTimer() const = 0; /** Returns the time until the plague wears off. 0 -> No plague present. */ virtual int getPlagueTimer() const = 0; /** Returns the amount of time until the unit is removed, or 0 if the unit does not have a remove timer. * Used to determine how much time remains before hallucinated units, dark swarm, etc have until they * are removed. */ virtual int getRemoveTimer() const = 0; /** Returns the time until the stasis field wears off. 0 -> No stasis field present. */ virtual int getStasisTimer() const = 0; /** Returns the time until the stimpack wears off. 0 -> No stimpack boost present. */ virtual int getStimTimer() const = 0; /** Returns the building type a worker is about to construct. If the unit is a morphing Zerg unit or an * incomplete building, this returns the UnitType the unit is about to become upon completion.*/ virtual UnitType getBuildType() const = 0; /** Returns the list of units queued up to be trained. * \see Unit::train, Unit::cancelTrain, Unit::isTraining. */ virtual std::list getTrainingQueue() const = 0; /** Returns the tech that the unit is currently researching. If the unit is not researching anything, * TechTypes::None is returned. * \see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getRemainingResearchTime. */ virtual TechType getTech() const = 0; /** Returns the upgrade that the unit is currently upgrading. If the unit is not upgrading anything, * UpgradeTypes::None is returned. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getRemainingUpgradeTime. */ virtual UpgradeType getUpgrade() const = 0; /** Returns the remaining build time of a unit/building that is being constructed. */ virtual int getRemainingBuildTime() const = 0; /** Returns the remaining time of the unit that is currently being trained. If the unit is a Hatchery, * Lair, or Hive, this returns the amount of time until the next larva spawns, or 0 if the unit already * has 3 larva. */ virtual int getRemainingTrainTime() const = 0; /** Returns the amount of time until the unit is done researching its current tech. If the unit is not * researching anything, 0 is returned. * \see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getTech. */ virtual int getRemainingResearchTime() const = 0; /** Returns the amount of time until the unit is done upgrading its current upgrade. If the unit is not * upgrading anything, 0 is returned. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getUpgrade. */ virtual int getRemainingUpgradeTime() const = 0; /** If the unit is an SCV that is constructing a building, this will return the building it is * constructing. If the unit is a Terran building that is being constructed, this will return the SCV * that is constructing it. */ virtual Unit* getBuildUnit() const = 0; /** Generally returns the appropriate target unit after issuing an order that accepts a target unit * (i.e. attack, repair, gather, follow, etc.). To check for a target that has been acquired * automatically (without issuing an order) see getOrderTarget. */ virtual Unit* getTarget() const = 0; /** Returns the target position the unit is moving to (provided a valid path to the target position * exists). */ virtual Position getTargetPosition() const = 0; // TODO: add doc virtual Order getOrder() const = 0; /** This is usually set when the low level unit AI acquires a new target automatically. For example if * an enemy probe comes in range of your marine, the marine will start attacking it, and getOrderTarget * will be set in this case, but not getTarget. */ virtual Unit* getOrderTarget() const = 0; virtual Order getSecondaryOrder() const = 0; /** Returns the position the building is rallied to. If the building does not produce units, * Positions::None is returned. * \see Unit::setRallyPoint, Unit::getRallyUnit. */ virtual Position getRallyPosition() const = 0; /** Returns the unit the building is rallied to. If the building is not rallied to any unit, NULL is * returned. * \see Unit::setRallyPoint, Unit::getRallyPosition. */ virtual Unit* getRallyUnit() const = 0; /** Returns the add-on of this unit, or NULL if the unit doesn't have an add-on. */ virtual Unit* getAddon() const = 0; /** Returns the corresponding connected nydus canal of this unit, or NULL if the unit does not have a * connected nydus canal. */ virtual Unit* getNydusExit() const = 0; /** Returns the power up the unit is holding, or NULL if the unit is not holding a power up */ virtual Unit* getPowerUp() const = 0; /** Returns the dropship, shuttle, overlord, or bunker that is this unit is loaded in to. */ virtual Unit* getTransport() const = 0; /** Returns a list of the units loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg * Overlord. */ virtual std::set getLoadedUnits() const = 0; /** For Protoss Interceptors, this returns the Carrier unit this Interceptor is controlled by. For all * other unit types this function returns NULL. */ virtual Unit* getCarrier() const = 0; /** Returns the set of interceptors controlled by this unit. If the unit has no interceptors, or is not * a Carrier, this function returns an empty set. */ virtual std::set getInterceptors() const = 0; /** For Zerg Larva, this returns the Hatchery, Lair, or Hive unit this Larva was spawned from. For all * other unit types this function returns NULL. */ virtual Unit* getHatchery() const = 0; /** Returns the set of larva spawned by this unit. If the unit has no larva, or is not a Hatchery, Lair, * or Hive, this function returns an empty set. Equivalent to clicking "Select Larva" from the Starcraft * GUI. */ virtual std::set getLarva() const = 0; /** * 3 cases to consider: * * - If exists() returns true, the unit exists. * - If exists() returns false and the unit is owned by self(), then the unit does not exist. * - If exists() returns false and the unit is not owned by self(), then the unit may or may not exist. * * \see Unit::isVisible. * */ virtual bool exists() const = 0; /* Returns true if the Nuclear Missile Silo has a nuke */ virtual bool hasNuke() const = 0; /** Returns true if the unit is currently accelerating. */ virtual bool isAccelerating() const = 0; // TODO: add doc virtual bool isAttacking() const = 0; /** Returns true if the unit is being constructed. Always true for incomplete Protoss and Zerg * buildings, and true for incomplete Terran buildings that have an SCV constructing them. If the SCV * halts construction, isBeingConstructed will return false. * * \see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isConstructing. */ virtual bool isBeingConstructed() const = 0; /** Returns true if the unit is a mineral patch or refinery that is being gathered. */ virtual bool isBeingGathered() const = 0; /** Returns true if the unit is currently being healed by a Terran Medic, or repaired by a Terran SCV. */ virtual bool isBeingHealed() const = 0; /** Returns true if the unit is currently blind from a Medic's Optical Flare. */ virtual bool isBlind() const = 0; /** Returns true if the unit is currently braking/slowing down. */ virtual bool isBraking() const = 0; /** Returns true if the unit is a Zerg unit that is current burrowed. * \see Unit::burrow, Unit::unburrow. */ virtual bool isBurrowed() const = 0; /** Returns true if the unit is a worker that is carrying gas. * \see Unit::returnCargo, Unit::isGatheringGas. */ virtual bool isCarryingGas() const = 0; /** Returns true if the unit is a worker that is carrying minerals. * \see Unit::returnCargo, Unit::isGatheringMinerals. */ virtual bool isCarryingMinerals() const = 0; /** Returns true if the unit is cloaked. * \see Unit::cloak, Unit::decloak. */ virtual bool isCloaked() const = 0; /** Returns true if the unit has been completed. */ virtual bool isCompleted() const = 0; /** Returns true when a unit has been issued an order to build a structure and is moving to the build * location. Also returns true for Terran SCVs while they construct a building. * \see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isBeingConstructed. */ virtual bool isConstructing() const = 0; /** Returns true if the unit has a defense matrix from a Terran Science Vessel. */ virtual bool isDefenseMatrixed() const = 0; /** Returns true if the unit is detected. */ virtual bool isDetected() const = 0; /** Returns true if the unit has been ensnared by a Zerg Queen. */ virtual bool isEnsnared() const = 0; /** Returns true if the unit is following another unit. * \see Unit::follow, Unit::getTarget. */ virtual bool isFollowing() const = 0; /** Returns true if the unit is in one of the four states for gathering gas (MoveToGas, WaitForGas, * HarvestGas, ReturnGas). * \see Unit::isCarryingGas. */ virtual bool isGatheringGas() const = 0; /** Returns true if the unit is in one of the four states for gathering minerals (MoveToMinerals, * WaitForMinerals, MiningMinerals, ReturnMinerals). * \see Unit::isCarryingMinerals. */ virtual bool isGatheringMinerals() const = 0; /** Returns true for hallucinated units, false for normal units. Returns true for hallucinated enemy * units only if Complete Map Information is enabled. * \see Unit::getRemoveTimer. */ virtual bool isHallucination() const = 0; /** Returns true if the unit is holding position * \see Unit::holdPosition. */ virtual bool isHoldingPosition() const = 0; /** Returns true if the unit is not doing anything. * \see Unit::stop. */ virtual bool isIdle() const = 0; /** Returns true if the unit can be interrupted. */ virtual bool isInterruptible() const = 0; /** Returns true if the unit is being irradiated by a Terran Science Vessel. * \see Unit::getIrradiateTimer. */ virtual bool isIrradiated() const = 0; /** Returns true if the unit is a Terran building that is currently lifted off the ground. * \see Unit::lift,Unit::land. */ virtual bool isLifted() const = 0; /** Return true if the unit is loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg * Overlord. * \see Unit::load, Unit::unload, Unit::unloadAll. */ virtual bool isLoaded() const = 0; /** Returns true if the unit is locked down by a Terran Ghost. * \see Unit::getLockdownTimer. */ virtual bool isLockedDown() const = 0; /** Returns true if the unit is being maelstrommed. * \see Unit::getMaelstromTimer. */ virtual bool isMaelstrommed() const = 0; /** Returns true if the unit is a zerg unit that is morphing. * \see Unit::morph, Unit::cancelMorph, Unit::getBuildType, Unit::getRemainingBuildTime. */ virtual bool isMorphing() const = 0; /** Returns true if the unit is moving. * \see Unit::attackMove, Unit::stop. */ virtual bool isMoving() const = 0; /** Returns true if the unit has been parasited by some other player. */ virtual bool isParasited() const = 0; /** Returns true if the unit is patrolling between two positions. * \see Unit::patrol. */ virtual bool isPatrolling() const = 0; /** Returns true if the unit has been plagued by a Zerg Defiler. * \see Unit::getPlagueTimer. */ virtual bool isPlagued() const = 0; /** Returns true if the unit is a Terran SCV that is repairing or moving to repair another unit. */ virtual bool isRepairing() const = 0; /** Returns true if the unit is a building that is researching tech. See TechTypes for the complete list * of available techs in Broodwar. * \see Unit::research, Unit::cancelResearch, Unit::getTech, Unit::getRemainingResearchTime. */ virtual bool isResearching() const = 0; /** Returns true if the unit has been selected by the user via the starcraft GUI. Only available if you * enable Flag::UserInput during AIModule::onStart. * \see Game::getSelectedUnits. */ virtual bool isSelected() const = 0; /** Returns true if the unit is a Terran Siege Tank that is currently in Siege mode. * \see Unit::siege, Unit::unsiege. */ virtual bool isSieged() const = 0; /** Returns true if the unit is starting to attack. * \see Unit::attackUnit, Unit::getGroundWeaponCooldown, Unit::getAirWeaponCooldown. */ virtual bool isStartingAttack() const = 0; /** Returns true if the unit has been stasised by a Protoss Arbiter. * \see Unit::getStasisTimer. */ virtual bool isStasised() const = 0; /** Returns true if the unit is currently stimmed. * \see Unit::getStimTimer. */ virtual bool isStimmed() const = 0; /** Returns true if the unit is being pushed off of another unit */ virtual bool isStuck() const = 0; /** Returns true if the unit is training units (i.e. a Barracks training Marines). * \see Unit::train, Unit::getTrainingQueue, Unit::cancelTrain, Unit::getRemainingTrainTime. */ virtual bool isTraining() const = 0; /** Returns true if the unit is under a Protoss Psionic Storm. */ virtual bool isUnderStorm() const = 0; /** Returns true if the unit is a Protoss building that is unpowered because no pylons are in range. */ virtual bool isUnpowered() const = 0; /** Returns true if the unit is a building that is upgrading. See UpgradeTypes for the complete list * of available upgrades in Broodwar. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::getUpgrade, Unit::getRemainingUpgradeTime. */ virtual bool isUpgrading() const = 0; /** Returns true if the unit is visible. If the CompleteMapInformation? cheat flag is enabled, existing * units hidden by the fog of war will be accessible, but isVisible will still return false. * \see Unit::exists. */ virtual bool isVisible() const = 0; virtual bool isVisible(Player* player) const = 0; /** Takes any unit command and calls the corresponding order that will execute it */ virtual bool issueCommand(UnitCommand command) = 0; /** Orders the unit to attack move to the specified location. */ virtual bool attackMove(Position target) = 0; /** Orders the unit to attack the specified unit. */ virtual bool attackUnit(Unit* target) = 0; /** Orders the unit to build the given unit type at the given position. Note that if the player does not * have enough resources when the unit attempts to place the building down, the order will fail. The * tile position specifies where the top left corner of the building will be placed. */ virtual bool build(TilePosition target, UnitType type) = 0; /** Orders the unit to build the given addon. The unit must be a Terran building that can have an addon * and the specified unit type must be an addon unit type. */ virtual bool buildAddon(UnitType type) = 0; /** Orders this unit to add the specified unit type to the training queue. Note that the player must * have sufficient resources to train. If you wish to make units from a hatchery, use getLarva to get * the larva associated with the hatchery and then call morph on the larva you want to morph. This * command can also be used to make interceptors and scarabs. */ virtual bool train(UnitType type) = 0; /** Orders the unit to morph into the specified unit type. Returns false if given a wrong type. * \see Unit::cancelMorph, Unit::isMorphing. */ virtual bool morph(UnitType type) = 0; /** Orders the unit to research the given tech type. * \see Unit::cancelResearch, Unit::Unit#isResearching, Unit::getRemainingResearchTime, Unit::getTech. */ virtual bool research(TechType tech) = 0; /** Orders the unit to upgrade the given upgrade type. * \see Unit::cancelUpgrade, Unit::Unit#isUpgrading, Unit::getRemainingUpgradeTime, Unit::getUpgrade. */ virtual bool upgrade(UpgradeType upgrade) = 0; /** Orders the unit to set its rally position to the specified position. * \see Unit::getRallyPosition, Unit::getRallyUnit. */ virtual bool setRallyPoint(Position target) = 0; /** Orders the unit to set its rally unit to the specified unit. * \see Unit::setRallyPosition, Unit::getRallyPosition, Unit::getRallyUnit. */ virtual bool setRallyPoint(Unit* target) = 0; /** Orders the unit to move from its current position to the specified position. * \see Unit::isMoving. */ virtual bool move(Position target) = 0; /** Orders the unit to patrol between its current position and the specified position. * \see Unit::isPatrolling. */ virtual bool patrol(Position target) = 0; /** Orders the unit to hold its position.*/ virtual bool holdPosition() = 0; /** Orders the unit to stop. */ virtual bool stop() = 0; /** Orders the unit to follow the specified unit. * \see Unit::isFollowing. */ virtual bool follow(Unit* target) = 0; /** Orders the unit to gather the specified unit (must be mineral or refinery type). * \see Unit::isGatheringGas, Unit::isGatheringMinerals. */ virtual bool gather(Unit* target) = 0; /** Orders the unit to return its cargo to a nearby resource depot such as a Command Center. Only * workers that are carrying minerals or gas can be ordered to return cargo. * \see Unit::isCarryingGas, Unit::isCarryingMinerals. */ virtual bool returnCargo() = 0; /** Orders the unit to repair the specified unit. Only Terran SCVs can be ordered to repair, and the * target must be a mechanical Terran unit or building. * \see Unit::isRepairing. */ virtual bool repair(Unit* target) = 0; /** Orders the unit to burrow. Either the unit must be a Zerg Lurker, or the unit must be a Zerg ground * unit and burrow tech must be researched. * \see: Unit::unburrow, Unit::isBurrowed. */ virtual bool burrow() = 0; /** Orders the burrowed unit to unburrow. * \see: Unit::burrow, Unit::isBurrowed. * */ virtual bool unburrow() = 0; /** Orders the unit to cloak. * \see: Unit::decloak, Unit::isCloaked. */ virtual bool cloak() = 0; /** Orders the unit to decloak. * \see: Unit::cloak, Unit::isCloaked. */ virtual bool decloak() = 0; /** Orders the unit to siege. Note: unit must be a Terran siege tank. * \see Unit::unsiege, Unit::isSieged. */ virtual bool siege() = 0; /** Orders the unit to unsiege. Note: unit must be a Terran siege tank. * \see: Unit::unsiege, Unit::isSieged. */ virtual bool unsiege() = 0; /** Orders the unit to lift. Note: unit must be a Terran building that can be lifted. * \see Unit::land, Unit::isLifted. */ virtual bool lift() = 0; /** Orders the unit to land. Note: unit must be a Terran building that is currently lifted. * \see Unit::lift, Unit::isLifted. */ virtual bool land(TilePosition target) = 0; /** Orders the unit to load the target unit. * \see Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool load(Unit* target) = 0; /** Orders the unit to unload the target unit. * \see Unit::load, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unload(Unit* target) = 0; /** Orders the unit to unload all loaded units at the unit's current position. * \see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unloadAll() = 0; /** Orders the unit to unload all loaded units at the specified location. Unit should be a Terran * Dropship, Protoss Shuttle, or Zerg Overlord. If the unit is a Terran Bunker, the units will be * unloaded right outside the bunker, like in the first version of unloadAll. * \see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unloadAll(Position target) = 0; /** Works like the right click in the GUI. */ virtual bool rightClick(Position target) = 0; /** Works like the right click in the GUI. Right click on a mineral patch to order a worker to mine, * right click on an enemy to attack it. */ virtual bool rightClick(Unit* target) = 0; /** Orders the SCV to stop constructing the building, and the building is left in a partially complete * state until it is canceled, destroyed, or completed. * \see Unit::isConstructing. */ virtual bool haltConstruction() = 0; /** Orders the building to stop being constructed. * \see Unit::beingConstructed. */ virtual bool cancelConstruction() = 0; /** Orders the unit to stop making the addon. */ virtual bool cancelAddon() = 0; /** Orders the unit to remove the specified unit from its training queue. * \see Unit::train, Unit::cancelTrain, Unit::isTraining, Unit::getTrainingQueue. */ virtual bool cancelTrain(int slot = -2) = 0; /** Orders the unit to stop morphing. * \see Unit::morph, Unit::isMorphing. */ virtual bool cancelMorph() = 0; /** Orders the unit to cancel a research in progress. * \see Unit::research, Unit::isResearching, Unit::getTech. */ virtual bool cancelResearch() = 0; /** Orders the unit to cancel an upgrade in progress. * \see Unit::upgrade, Unit::isUpgrading, Unit::getUpgrade. */ virtual bool cancelUpgrade() = 0; /** Orders the unit to use a tech not requiring a target (ie Stim Pack). Returns true if it is a valid * tech. */ virtual bool useTech(TechType tech) = 0; /** Orders the unit to use a tech requiring a position target (ie Dark Swarm). Returns true if it is a * valid tech.*/ virtual bool useTech(TechType tech, Position target) = 0; /** Orders the unit to use a tech requiring a unit target (ie Irradiate). Returns true if it is a valid * tech.*/ virtual bool useTech(TechType tech, Unit* target) = 0; /** Sets the unit's custom client info. The client is responsible for deallocation. */ virtual void setClientInfo(void* clientinfo) = 0; /** Returns the unit's custom client info. The client is responsible for deallocation. */ virtual void* getClientInfo() const = 0; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/UnitCommand.h ================================================ #pragma once #include #include #include #include #include #include namespace BWAPI { class Unit; class UnitCommand { public: UnitCommand() : target(NULL), x(0), y(0), extra(0) { type = UnitCommandTypes::None; } UnitCommand(Unit* source, UnitCommandType _type, Unit* _target, int _x, int _y, int _extra) : unit(source), type(_type), target(_target), x(_x), y(_y), extra(_extra) {} static UnitCommand attackMove(Unit* unit, Position target); static UnitCommand attackUnit(Unit* unit, Unit* target); static UnitCommand build(Unit* unit, TilePosition target, UnitType type); static UnitCommand buildAddon(Unit* unit, UnitType type); static UnitCommand train(Unit* unit, UnitType type); static UnitCommand morph(Unit* unit, UnitType type); static UnitCommand research(Unit* unit, TechType tech); static UnitCommand upgrade(Unit* unit, UpgradeType upgrade); static UnitCommand setRallyPosition(Unit* unit, Position target); static UnitCommand setRallyUnit(Unit* unit, Unit* target); static UnitCommand move(Unit* unit, Position target); static UnitCommand patrol(Unit* unit, Position target); static UnitCommand holdPosition(Unit* unit); static UnitCommand stop(Unit* unit); static UnitCommand follow(Unit* unit, Unit* target); static UnitCommand gather(Unit* unit, Unit* target); static UnitCommand returnCargo(Unit* unit); static UnitCommand repair(Unit* unit, Unit* target); static UnitCommand burrow(Unit* unit); static UnitCommand unburrow(Unit* unit); static UnitCommand cloak(Unit* unit); static UnitCommand decloak(Unit* unit); static UnitCommand siege(Unit* unit); static UnitCommand unsiege(Unit* unit); static UnitCommand lift(Unit* unit); static UnitCommand land(Unit* unit, TilePosition target); static UnitCommand load(Unit* unit, Unit* target); static UnitCommand unload(Unit* unit, Unit* target); static UnitCommand unloadAll(Unit* unit); static UnitCommand unloadAll(Unit* unit, Position target); static UnitCommand rightClick(Unit* unit, Position target); static UnitCommand rightClick(Unit* unit, Unit* target); static UnitCommand haltConstruction(Unit* unit); static UnitCommand cancelConstruction(Unit* unit); static UnitCommand cancelAddon(Unit* unit); static UnitCommand cancelTrain(Unit* unit, int slot = -2); static UnitCommand cancelMorph(Unit* unit); static UnitCommand cancelResearch(Unit* unit); static UnitCommand cancelUpgrade(Unit* unit); static UnitCommand useTech(Unit* unit,TechType tech); static UnitCommand useTech(Unit* unit,TechType tech, Position target); static UnitCommand useTech(Unit* unit,TechType tech, Unit* target); Unit* unit; UnitCommandType type; Unit* target; int x; int y; int extra; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/UnitCommandType.h ================================================ #pragma once #include #include namespace BWAPI { class UnitCommandType { public: UnitCommandType(); UnitCommandType(int id); UnitCommandType(const UnitCommandType& other); UnitCommandType& operator=(const UnitCommandType& other); bool operator==(const UnitCommandType& other) const; bool operator!=(const UnitCommandType& other) const; bool operator<(const UnitCommandType& other) const; /** Returns a unique ID for this UnitCommandType. */ int getID() const; /** Returns the string corresponding to the UnitCommandType object. For example, * UnitCommandTypes::Set_Rally_Position.getName() returns std::string("Set Rally Position")*/ std::string getName() const; private: int id; }; namespace UnitCommandTypes { /** Given a string, this function returns the command type it refers to. For example, * UnitCommandTypes::getUnitCommandType("Attack Position") returns UnitCommandTypes::Attack_Position. */ UnitCommandType getUnitCommandType(std::string name); /** Returns the set of all the sizes, which are listed below: */ std::set& allUnitCommandTypes(); void init(); extern const UnitCommandType Attack_Move; extern const UnitCommandType Attack_Unit; extern const UnitCommandType Build; extern const UnitCommandType Build_Addon; extern const UnitCommandType Train; extern const UnitCommandType Morph; extern const UnitCommandType Research; extern const UnitCommandType Upgrade; extern const UnitCommandType Set_Rally_Position; extern const UnitCommandType Set_Rally_Unit; extern const UnitCommandType Move; extern const UnitCommandType Patrol; extern const UnitCommandType Hold_Position; extern const UnitCommandType Stop; extern const UnitCommandType Follow; extern const UnitCommandType Gather; extern const UnitCommandType Return_Cargo; extern const UnitCommandType Repair; extern const UnitCommandType Burrow; extern const UnitCommandType Unburrow; extern const UnitCommandType Cloak; extern const UnitCommandType Decloak; extern const UnitCommandType Siege; extern const UnitCommandType Unsiege; extern const UnitCommandType Lift; extern const UnitCommandType Land; extern const UnitCommandType Load; extern const UnitCommandType Unload; extern const UnitCommandType Unload_All; extern const UnitCommandType Unload_All_Position; extern const UnitCommandType Right_Click_Position; extern const UnitCommandType Right_Click_Unit; extern const UnitCommandType Halt_Construction; extern const UnitCommandType Cancel_Construction; extern const UnitCommandType Cancel_Addon; extern const UnitCommandType Cancel_Train; extern const UnitCommandType Cancel_Train_Slot; extern const UnitCommandType Cancel_Morph; extern const UnitCommandType Cancel_Research; extern const UnitCommandType Cancel_Upgrade; extern const UnitCommandType Use_Tech; extern const UnitCommandType Use_Tech_Position; extern const UnitCommandType Use_Tech_Unit; extern const UnitCommandType None; extern const UnitCommandType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/UnitSizeType.h ================================================ #pragma once #include #include namespace BWAPI { class UnitSizeType { public: UnitSizeType(); UnitSizeType(int id); UnitSizeType(const UnitSizeType& other); UnitSizeType& operator=(const UnitSizeType& other); bool operator==(const UnitSizeType& other) const; bool operator!=(const UnitSizeType& other) const; bool operator<(const UnitSizeType& other) const; /** Returns a unique ID for this UnitSizeType. */ int getID() const; /** Returns the string corresponding to the UnitSizeType object. For example, * UnitSizeTypes::Medium.getName() returns std::string("Medium")*/ std::string getName() const; private: int id; }; namespace UnitSizeTypes { /** Given a string, this function returns the size type it refers to. For example, * UnitSizeTypes::getUnitSizeType("Small") returns UnitSizeTypes::Small. */ UnitSizeType getUnitSizeType(std::string name); /** Returns the set of all the sizes, which are listed below: */ std::set& allUnitSizeTypes(); void init(); extern const UnitSizeType Independent; extern const UnitSizeType Small; extern const UnitSizeType Medium; extern const UnitSizeType Large; extern const UnitSizeType None; extern const UnitSizeType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/UnitType.h ================================================ #pragma once #include #include #include #include #include namespace BWAPI { class TechType; class UpgradeType; class WeaponType; /** The UnitType class is used to get information about a particular type of unit, such as the build time * of a Lurker, or the mineral price of an Ultralisk. TODO Add the unittype table from the wiki*/ class UnitType { public: UnitType(); UnitType(int id); UnitType(const UnitType& other); UnitType& operator=(const UnitType& other); bool operator==(const UnitType& other) const; bool operator!=(const UnitType& other) const; bool operator<(const UnitType& other) const; /** Returns a unique ID for this unit type. */ int getID() const; /** Returns the name of the unit. */ std::string getName() const; /** Returns the race that the unit belongs to. For example UnitTypes::Terran_SCV.getRace() will return * Races::Terran. */ Race getRace() const; /** Returns what builds this unit type. The second number will usually be 1 unless the unit type is * Protoss_Archon or Protoss_Dark_Archon. Units that cannot be created, such as critters and mineral * fields, will return a pair where the unit type is UnitTypes::None, and the second component is 0. * * Example: UnitTypes::Terran_Marine.whatBuilds() will return an std::pair, where the first component * is UnitTypes::Terran_Barracks. */ const std::pair< UnitType, int > whatBuilds() const; /** Returns the units the player is required to have before it can train or build the given unit type. * * Example: UnitTypes::Terran_Battlecruiser.requiredUnits() will return a map of three keys: * UnitTypes::Terran_Starport, UnitTypes::Terran_Control_Tower, and UnitTypes::Terran_Physics_Lab. */ const std::map< UnitType, int >& requiredUnits() const; /** Included in the API for completeness, since the only units that actually needs tech to be trained * are the Zerg_Lurker and Zerg_Lurker_Egg. The tech type needed is TechTypes::Lurker_Aspect. */ TechType requiredTech() const; /** Returns the tech used to cloak the unit, or TechTypes::None if the unit cannot cloak or is permanently cloaked */ TechType cloakingTech() const; /** Returns the set of tech types this unit can use, provided the tech types have been researched and * the unit has enough energy. */ const std::set< TechType >& abilities() const; /** Returns the set of upgrade types that can affect this unit. */ const std::set< UpgradeType >& upgrades() const; /** Returns the upgrade that increase's the unit's armor, or UpgradeTypes::None if no upgrade * increase's this unit's armor. For example UnitTypes::Terran_Marine.armorUpgrade() will return a * pointer to UpgradeTypes::Terran_Infantry_Armor. */ UpgradeType armorUpgrade() const; /** Returns the maximum amount of hit points the unit type can have. */ int maxHitPoints() const; /** Returns the maximum amount of shields the unit type can have. */ int maxShields() const; /** Returns the maximum amount of energy the unit type can have. */ int maxEnergy() const; /** Returns the amount of armor the non-upgraded unit type has. */ int armor() const; /** Returns the mineral price of the unit. * * Example: UnitTypes::Siege_Tank_Tank_Mode.mineralPrice() returns 150. */ int mineralPrice() const; /** UnitTypes::Siege_Tank_Tank_Mode.gasPrice() returns 100. */ int gasPrice() const; /** Returns the number of frames needed to make this unit type. */ int buildTime() const; /** Returns the amount of supply used by this unit. Supply counts returned by BWAPI are double what you * would expect to see from playing the game. This is because zerglings take up 0.5 in-game supply. */ int supplyRequired() const; /** Returns the amount of supply produced by this unit (i.e. for a Protoss_Pylon). Supply counts * returned by BWAPI are double what you would expect to see from playing the game. This is because * zerglings take up 0.5 in-game supply. */ int supplyProvided() const; /** Returns the amount of space this unit type takes up inside a bunker or transport unit. */ int spaceRequired() const; /** Returns the amount of space this unit type provides. */ int spaceProvided() const; /** Returns the score which is used to determine the total scores in the after-game stats screen. */ int buildScore() const; /** Returns the score which is used to determine the total scores in the after-game stats screen. */ int destroyScore() const; /** Returns the size of the unit - either Small, Medium, Large, or Independent. */ UnitSizeType size() const; /** Returns the tile width of the unit. Useful for determining the size of buildings. For example * UnitTypes::Terran_Supply_Depot.tileWidth() will return 3. */ int tileWidth() const; /** Returns the tile height of the unit. Useful for determining the size of buildings. For example * UnitTypes::Terran_Supply_Depot.tileHeight() will return 2. */ int tileHeight() const; /** Distance from the center of the unit to the left edge of the unit, measured in pixels. */ int dimensionLeft() const; /** Distance from the center of the unit to the top edge of the unit, measured in pixels. */ int dimensionUp() const; /** Distance from the center of the unit to the right edge of the unit, measured in pixels. */ int dimensionRight() const; /** Distance from the center of the unit to the bottom edge of the unit, measured in pixels. */ int dimensionDown() const; /** Returns the range at which the unit will start targeting enemy units, measured in pixels. */ int seekRange() const; /** Returns how far the un-upgraded unit type can see into the fog of war, measured in pixels. */ int sightRange() const; /** Returns the unit's ground weapon. */ WeaponType groundWeapon() const; // TODO: add doc int maxGroundHits() const; /** Returns the unit's air weapon. */ WeaponType airWeapon() const; // TODO: add doc int maxAirHits() const; /** Returns the unit's non-upgraded top speed in pixels per frame. For Terran buildings that can lift * off and the Zerg Infested Command Center, this returns how fast the building moves when it is * lifted. */ double topSpeed() const; /** Returns how fast the unit can accelerate to its top speed. What units this quantity is measured in * is currently unknown. */ int acceleration() const; /** Related to how fast the unit can halt. What units this quantity is measured in is currently * unknown. */ int haltDistance() const; /** Related to how fast the unit can turn. What units this quantity is measured in is currently * unknown. */ int turnRadius() const; /** Returns true if the unit can train other units. For example, UnitTypes::Terran_Barracks.canProduce() * will return true, while UnitTypes::Terran_Marine?.canProduce() will return false. This is also true * for two non-building units: Protoss Carrier (can produce interceptors) and Protoss Reaver * (can produce scarabs). */ bool canProduce() const; /** Returns true if the unit can attack (either ground or air). Returns false for units that can only * inflict damage via special abilities (such as Protoss High Templar). */ bool canAttack() const; /** Returns true if the unit can move. Note that buildings will return false, even Terran buildings * which can move once lifted. */ bool canMove() const; /** Returns true for flying/air units. */ bool isFlyer() const; /** Returns true for units that regenerate health (i.e. zerg units). */ bool regeneratesHP() const; /** Returns true if the unit type is capable of casting spells / using technology. */ bool isSpellcaster() const; /** Returns true for the two units that are permanently cloaked - Protoss Observer and Protoss Dark * Templar. */ bool hasPermanentCloak() const; /** Returns true for units that cannot be destroyed (i.e. Terran Nuclear Missile, Mineral Field, * Vespene Geyser, etc) */ bool isInvincible() const; /** Returns true if the unit is organic, such as a Terran Marine. */ bool isOrganic() const; /** Returns true if the unit is mechanical such as a Terran Vulture. */ bool isMechanical() const; /** Returns true for the four robotic Protoss units - Probe, Shuttle, Reaver, and Observer. */ bool isRobotic() const; /** Returns true for the seven units that can detect cloaked units - Terran Science Vessel, Spell * Scanner Sweep, Zerg Overlord, Protoss Observer, Terran Missile Turret, Zerg Spore Colony, and Protoss * Photon Cannon. */ bool isDetector() const; /** Returns true for the five units that hold resources - Mineral Field, Vespene Geyser, * Terran Refinery, Zerg Extractor, and Protoss Assimilator. */ bool isResourceContainer() const; /** Returns true for the five units that can accept resources - Terran Command Center, Protoss Nexus, * Zerg Hatchery, Zerg Lair, and Zerg Hive. */ bool isResourceDepot() const; /** Returns true for Terran Refinery, Zerg Extractor, and Protoss Assimilator. */ bool isRefinery() const; /** Returns true for Protoss Probe, Terran SCV, and Zerg Drone. */ bool isWorker() const; /** Returns true for buildings that must be near a pylon to be constructed. */ bool requiresPsi() const; /** Returns true for buildings that can only be built on zerg creep. */ bool requiresCreep() const; /** Returns true for Zergling and Scourge. */ bool isTwoUnitsInOneEgg() const; /** Returns true for Zerg Lurker and units that can burrow when burrow tech is researched. */ bool isBurrowable() const; /** Returns true for units that can be cloaked - Terran Ghost and Terran Wraith. Does not include units * which have permanent cloak (Protoss Observer and Protoss Dark Templar). */ bool isCloakable() const; /** Returns true if the unit is a building (also true for mineral field and vespene geyser). */ bool isBuilding() const; /** Returns true if the unit is an add-on, such as a Terran Comsat Station. */ bool isAddon() const; /** Returns true for Terran buildings that can lift off (i.e. Barracks). */ bool isFlyingBuilding() const; /** Returns true if the unit is neutral, such as a critter or mineral field. */ bool isNeutral() const; /** Returns true if the unit is a Hero unit. */ bool isHero() const; /** Returns true if the unit is a Powerup unit. */ bool isPowerup() const; /** Returns true if the unit is a regular Beacon. */ bool isBeacon() const; /** Returns true if the unit is a flag Beacon. */ bool isFlagBeacon() const; /** Returns true if the unit is a special building. */ bool isSpecialBuilding() const; /** Returns true if the unit is a spell unit. */ bool isSpell() const; /** Returns true if the unit produces larva. */ bool producesLarva() const; private: int id; }; namespace UnitTypes { /** Given the name of a unit type, this function will return the unit type. * For example, UnitTypes::getUnitType("Terran Marine") will return UnitTypes::Terran_Marine. */ UnitType getUnitType(std::string name); /** Returns the set of all the UnitTypes. */ std::set& allUnitTypes(); void init(); extern const UnitType Terran_Marine; extern const UnitType Hero_Jim_Raynor_Marine; extern const UnitType Terran_Ghost; extern const UnitType Hero_Sarah_Kerrigan; extern const UnitType Hero_Samir_Duran; extern const UnitType Hero_Infested_Duran; extern const UnitType Hero_Alexei_Stukov; extern const UnitType Terran_Vulture; extern const UnitType Hero_Jim_Raynor_Vulture; extern const UnitType Terran_Goliath; extern const UnitType Hero_Alan_Schezar; extern const UnitType Terran_Siege_Tank_Tank_Mode; extern const UnitType Hero_Edmund_Duke_Tank_Mode; extern const UnitType Terran_SCV; extern const UnitType Terran_Wraith; extern const UnitType Hero_Tom_Kazansky; extern const UnitType Terran_Science_Vessel; extern const UnitType Hero_Magellan; extern const UnitType Terran_Dropship; extern const UnitType Terran_Battlecruiser; extern const UnitType Hero_Arcturus_Mengsk; extern const UnitType Hero_Hyperion; extern const UnitType Hero_Norad_II; extern const UnitType Hero_Gerard_DuGalle; extern const UnitType Terran_Vulture_Spider_Mine; extern const UnitType Terran_Nuclear_Missile; extern const UnitType Terran_Siege_Tank_Siege_Mode; extern const UnitType Hero_Edmund_Duke_Siege_Mode; extern const UnitType Terran_Firebat; extern const UnitType Hero_Gui_Montag; extern const UnitType Spell_Scanner_Sweep; extern const UnitType Terran_Medic; extern const UnitType Terran_Civilian; extern const UnitType Zerg_Larva; extern const UnitType Zerg_Egg; extern const UnitType Zerg_Zergling; extern const UnitType Hero_Devouring_One; extern const UnitType Hero_Infested_Kerrigan; extern const UnitType Zerg_Hydralisk; extern const UnitType Hero_Hunter_Killer; extern const UnitType Zerg_Ultralisk; extern const UnitType Hero_Torrasque; extern const UnitType Zerg_Broodling; extern const UnitType Zerg_Drone; extern const UnitType Zerg_Overlord; extern const UnitType Hero_Yggdrasill; extern const UnitType Zerg_Mutalisk; extern const UnitType Hero_Kukulza_Mutalisk; extern const UnitType Zerg_Guardian; extern const UnitType Hero_Kukulza_Guardian; extern const UnitType Zerg_Queen; extern const UnitType Hero_Matriarch; extern const UnitType Zerg_Defiler; extern const UnitType Hero_Unclean_One; extern const UnitType Zerg_Scourge; extern const UnitType Zerg_Infested_Terran; extern const UnitType Terran_Valkyrie; extern const UnitType Zerg_Cocoon; extern const UnitType Protoss_Corsair; extern const UnitType Hero_Raszagal; extern const UnitType Protoss_Dark_Templar; extern const UnitType Hero_Dark_Templar; extern const UnitType Hero_Zeratul; extern const UnitType Zerg_Devourer; extern const UnitType Protoss_Dark_Archon; extern const UnitType Protoss_Probe; extern const UnitType Protoss_Zealot; extern const UnitType Hero_Fenix_Zealot; extern const UnitType Protoss_Dragoon; extern const UnitType Hero_Fenix_Dragoon; extern const UnitType Protoss_High_Templar; extern const UnitType Hero_Tassadar; extern const UnitType Hero_Aldaris; extern const UnitType Protoss_Archon; extern const UnitType Hero_Tassadar_Zeratul_Archon; extern const UnitType Protoss_Shuttle; extern const UnitType Protoss_Scout; extern const UnitType Hero_Mojo; extern const UnitType Hero_Artanis; extern const UnitType Protoss_Arbiter; extern const UnitType Hero_Danimoth; extern const UnitType Protoss_Carrier; extern const UnitType Hero_Gantrithor; extern const UnitType Protoss_Interceptor; extern const UnitType Protoss_Reaver; extern const UnitType Hero_Warbringer; extern const UnitType Protoss_Observer; extern const UnitType Protoss_Scarab; extern const UnitType Critter_Rhynadon; extern const UnitType Critter_Bengalaas; extern const UnitType Critter_Scantid; extern const UnitType Critter_Kakaru; extern const UnitType Critter_Ragnasaur; extern const UnitType Critter_Ursadon; extern const UnitType Zerg_Lurker_Egg; extern const UnitType Zerg_Lurker; extern const UnitType Spell_Disruption_Web; extern const UnitType Terran_Command_Center; extern const UnitType Terran_Comsat_Station; extern const UnitType Terran_Nuclear_Silo; extern const UnitType Terran_Supply_Depot; extern const UnitType Terran_Refinery; extern const UnitType Terran_Barracks; extern const UnitType Terran_Academy; extern const UnitType Terran_Factory; extern const UnitType Terran_Starport; extern const UnitType Terran_Control_Tower; extern const UnitType Terran_Science_Facility; extern const UnitType Terran_Covert_Ops; extern const UnitType Terran_Physics_Lab; extern const UnitType Terran_Machine_Shop; extern const UnitType Terran_Engineering_Bay; extern const UnitType Terran_Armory; extern const UnitType Terran_Missile_Turret; extern const UnitType Terran_Bunker; extern const UnitType Special_Crashed_Norad_II; extern const UnitType Special_Ion_Cannon; extern const UnitType Zerg_Infested_Command_Center; extern const UnitType Zerg_Hatchery; extern const UnitType Zerg_Lair; extern const UnitType Zerg_Hive; extern const UnitType Zerg_Nydus_Canal; extern const UnitType Zerg_Hydralisk_Den; extern const UnitType Zerg_Defiler_Mound; extern const UnitType Zerg_Greater_Spire; extern const UnitType Zerg_Queens_Nest; extern const UnitType Zerg_Evolution_Chamber; extern const UnitType Zerg_Ultralisk_Cavern; extern const UnitType Zerg_Spire; extern const UnitType Zerg_Spawning_Pool; extern const UnitType Zerg_Creep_Colony; extern const UnitType Zerg_Spore_Colony; extern const UnitType Zerg_Sunken_Colony; extern const UnitType Special_Overmind_With_Shell; extern const UnitType Special_Overmind; extern const UnitType Zerg_Extractor; extern const UnitType Special_Mature_Chrysalis; extern const UnitType Special_Cerebrate; extern const UnitType Special_Cerebrate_Daggoth; extern const UnitType Protoss_Nexus; extern const UnitType Protoss_Robotics_Facility; extern const UnitType Protoss_Pylon; extern const UnitType Protoss_Assimilator; extern const UnitType Protoss_Observatory; extern const UnitType Protoss_Gateway; extern const UnitType Protoss_Photon_Cannon; extern const UnitType Protoss_Citadel_of_Adun; extern const UnitType Protoss_Cybernetics_Core; extern const UnitType Protoss_Templar_Archives; extern const UnitType Protoss_Forge; extern const UnitType Protoss_Stargate; extern const UnitType Special_Stasis_Cell_Prison; extern const UnitType Protoss_Fleet_Beacon; extern const UnitType Protoss_Arbiter_Tribunal; extern const UnitType Protoss_Robotics_Support_Bay; extern const UnitType Protoss_Shield_Battery; extern const UnitType Special_Khaydarin_Crystal_Form; extern const UnitType Special_Protoss_Temple; extern const UnitType Special_XelNaga_Temple; extern const UnitType Resource_Mineral_Field; extern const UnitType Resource_Vespene_Geyser; extern const UnitType Special_Warp_Gate; extern const UnitType Special_Psi_Disrupter; extern const UnitType Special_Power_Generator; extern const UnitType Special_Overmind_Cocoon; extern const UnitType Special_Zerg_Beacon; extern const UnitType Special_Terran_Beacon; extern const UnitType Special_Protoss_Beacon; extern const UnitType Special_Zerg_Flag_Beacon; extern const UnitType Special_Terran_Flag_Beacon; extern const UnitType Special_Protoss_Flag_Beacon; extern const UnitType Spell_Dark_Swarm; extern const UnitType Powerup_Uraj_Crystal; extern const UnitType Powerup_Khalis_Crystal; extern const UnitType Powerup_Flag; extern const UnitType Powerup_Young_Chrysalis; extern const UnitType Powerup_Psi_Emitter; extern const UnitType Powerup_Data_Disk; extern const UnitType Powerup_Khaydarin_Crystal; extern const UnitType None; extern const UnitType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/UpgradeType.h ================================================ #pragma once #include #include #include namespace BWAPI { class UnitType; class UpgradeType { public: UpgradeType(); UpgradeType(int id); UpgradeType(const UpgradeType& other); UpgradeType& operator=(const UpgradeType& other); bool operator==(const UpgradeType& other) const; bool operator!=(const UpgradeType& other) const; bool operator<(const UpgradeType& other) const; /** Returns the unique ID for this upgrade type. */ int getID() const; /** Returns the name for the upgrade type. */ std::string getName() const; /** Returns the race the upgrade is for. For example, UpgradeTypes::Terran_Infantry_Armor.getRace() * will return Races::Terran. */ Race getRace() const; /** Returns the mineral price for the first upgrade. */ int mineralPrice() const; /** Returns the amount that the mineral price increases for each additional upgrade. */ int mineralPriceFactor() const; /** Returns the vespene gas price for the first upgrade. */ int gasPrice() const; /** Returns the amount that the vespene gas price increases for each additional upgrade. */ int gasPriceFactor() const; /** Returns the number of frames needed to research the first upgrade. */ int upgradeTime() const; /** Returns the number of frames that the upgrade time increases for each additional upgrade. */ int upgradeTimeFactor() const; /** Returns the maximum number of times the upgrade can be researched. */ int maxRepeats() const; /** Returns the type of unit that researches the upgrade. */ UnitType whatUpgrades() const; /** Returns the set of units that are affected by this upgrade. */ const std::set& whatUses() const; private: int id; }; namespace UpgradeTypes { /** Given a string, this will return the upgrade type. */ UpgradeType getUpgradeType(std::string name); /** Returns the set of all the UpgradeTypes. */ std::set& allUpgradeTypes(); void init(); extern const UpgradeType Terran_Infantry_Armor; extern const UpgradeType Terran_Vehicle_Plating; extern const UpgradeType Terran_Ship_Plating; extern const UpgradeType Zerg_Carapace; extern const UpgradeType Zerg_Flyer_Carapace; extern const UpgradeType Protoss_Ground_Armor; extern const UpgradeType Protoss_Air_Armor; extern const UpgradeType Terran_Infantry_Weapons; extern const UpgradeType Terran_Vehicle_Weapons; extern const UpgradeType Terran_Ship_Weapons; extern const UpgradeType Zerg_Melee_Attacks; extern const UpgradeType Zerg_Missile_Attacks; extern const UpgradeType Zerg_Flyer_Attacks; extern const UpgradeType Protoss_Ground_Weapons; extern const UpgradeType Protoss_Air_Weapons; extern const UpgradeType Protoss_Plasma_Shields; extern const UpgradeType U_238_Shells; extern const UpgradeType Ion_Thrusters; extern const UpgradeType Titan_Reactor; extern const UpgradeType Ocular_Implants; extern const UpgradeType Moebius_Reactor; extern const UpgradeType Apollo_Reactor; extern const UpgradeType Colossus_Reactor; extern const UpgradeType Ventral_Sacs; extern const UpgradeType Antennae; extern const UpgradeType Pneumatized_Carapace; extern const UpgradeType Metabolic_Boost; extern const UpgradeType Adrenal_Glands; extern const UpgradeType Muscular_Augments; extern const UpgradeType Grooved_Spines; extern const UpgradeType Gamete_Meiosis; extern const UpgradeType Metasynaptic_Node; extern const UpgradeType Singularity_Charge; extern const UpgradeType Leg_Enhancements; extern const UpgradeType Scarab_Damage; extern const UpgradeType Reaver_Capacity; extern const UpgradeType Gravitic_Drive; extern const UpgradeType Sensor_Array; extern const UpgradeType Gravitic_Boosters; extern const UpgradeType Khaydarin_Amulet; extern const UpgradeType Apial_Sensors; extern const UpgradeType Gravitic_Thrusters; extern const UpgradeType Carrier_Capacity; extern const UpgradeType Khaydarin_Core; extern const UpgradeType Argus_Jewel; extern const UpgradeType Argus_Talisman; extern const UpgradeType Caduceus_Reactor; extern const UpgradeType Chitinous_Plating; extern const UpgradeType Anabolic_Synthesis; extern const UpgradeType Charon_Boosters; extern const UpgradeType None; extern const UpgradeType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI/WeaponType.h ================================================ #pragma once #include #include namespace BWAPI { class TechType; class UpgradeType; class DamageType; class ExplosionType; class WeaponType { public: WeaponType(); WeaponType(int id); WeaponType(const WeaponType& other); WeaponType& operator=(const WeaponType& other); bool operator==(const WeaponType& other) const; bool operator!=(const WeaponType& other) const; bool operator<(const WeaponType& other) const; /** Returns a unique ID for this weapon type. */ int getID() const; /** Returns the name of the weapon. */ std::string getName() const; /** Returns the tech type that must be researched before this weapon can be used, or TechTypes::None if * no tech type is required. */ TechType getTech() const; /** Returns the unit that can use this weapon. */ UnitType whatUses() const; /** Returns the amount of damage that this weapon deals per attack. */ int damageAmount() const; // TODO: add doc int damageBonus() const; /** Returns the amount of cooldown time between attacks. */ int damageCooldown() const; /** Returns the amount that the damage increases per upgrade. * \see WeaponType::upgradeType. */ int damageFactor() const; /** Returns the upgrade type that can be upgraded to increase the attack damage. */ UpgradeType upgradeType() const; /** Returns the type of damage that this weapon uses (i.e. concussive, normal, explosive, etc). */ DamageType damageType() const; /** Returns the type of explosion that this weapon uses. */ ExplosionType explosionType() const; /** Returns the minimum attack range of the weapon, measured in pixels, 0 for most things except * WeaponTypes::Arclite_Shock_Cannon (the weapon of the Terran Siege Tank in Siege Mode). */ int minRange() const; /** Returns the maximum attack range of the weapon, measured in pixels. */ int maxRange() const; /** Inner radius used in splash damage calculations. */ int innerSplashRadius() const; /** Median radius used in splash damage calculations. */ int medianSplashRadius() const; /** Outer radius used in splash damage calculations. */ int outerSplashRadius() const; /** Returns true if this weapon can attack air units. */ bool targetsAir() const; // TODO: group these methods /** Returns true if this weapon can attack ground units. */ bool targetsGround() const; bool targetsMechanical() const; bool targetsOrganic() const; bool targetsNonBuilding() const; bool targetsNonRobotic() const; bool targetsTerrain() const; bool targetsOrgOrMech() const; bool targetsOwn() const; private: int id; }; namespace WeaponTypes { /** Given the name of a weapon, this will return the corresponding weapon type object. */ WeaponType getWeaponType(std::string name); /** Returns the set of all the WeaponTypes. */ std::set& allWeaponTypes(); /** Returns the set of all normal weapons in WeaponTypes. */ std::set& normalWeaponTypes(); /** Returns the set of all special weapons in WeaponTypes. */ std::set& specialWeaponTypes(); void init(); extern const WeaponType Gauss_Rifle; extern const WeaponType Gauss_Rifle_Jim_Raynor; extern const WeaponType C_10_Canister_Rifle; extern const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan; extern const WeaponType C_10_Canister_Rifle_Samir_Duran; extern const WeaponType C_10_Canister_Rifle_Infested_Duran; extern const WeaponType C_10_Canister_Rifle_Alexei_Stukov; extern const WeaponType Fragmentation_Grenade; extern const WeaponType Fragmentation_Grenade_Jim_Raynor; extern const WeaponType Spider_Mines; extern const WeaponType Twin_Autocannons; extern const WeaponType Twin_Autocannons_Alan_Schezar; extern const WeaponType Hellfire_Missile_Pack; extern const WeaponType Hellfire_Missile_Pack_Alan_Schezar; extern const WeaponType Arclite_Cannon; extern const WeaponType Arclite_Cannon_Edmund_Duke; extern const WeaponType Fusion_Cutter; extern const WeaponType Gemini_Missiles; extern const WeaponType Gemini_Missiles_Tom_Kazansky; extern const WeaponType Burst_Lasers; extern const WeaponType Burst_Lasers_Tom_Kazansky; extern const WeaponType ATS_Laser_Battery; extern const WeaponType ATS_Laser_Battery_Hero; extern const WeaponType ATS_Laser_Battery_Hyperion; extern const WeaponType ATA_Laser_Battery; extern const WeaponType ATA_Laser_Battery_Hero; extern const WeaponType ATA_Laser_Battery_Hyperion; extern const WeaponType Flame_Thrower; extern const WeaponType Flame_Thrower_Gui_Montag; extern const WeaponType Arclite_Shock_Cannon; extern const WeaponType Arclite_Shock_Cannon_Edmund_Duke; extern const WeaponType Longbolt_Missile; extern const WeaponType Claws; extern const WeaponType Claws_Devouring_One; extern const WeaponType Claws_Infested_Kerrigan; extern const WeaponType Needle_Spines; extern const WeaponType Needle_Spines_Hunter_Killer; extern const WeaponType Kaiser_Blades; extern const WeaponType Kaiser_Blades_Torrasque; extern const WeaponType Toxic_Spores; extern const WeaponType Spines; extern const WeaponType Acid_Spore; extern const WeaponType Acid_Spore_Kukulza; extern const WeaponType Glave_Wurm; extern const WeaponType Glave_Wurm_Kukulza; extern const WeaponType Seeker_Spores; extern const WeaponType Subterranean_Tentacle; extern const WeaponType Suicide_Infested_Terran; extern const WeaponType Suicide_Scourge; extern const WeaponType Particle_Beam; extern const WeaponType Psi_Blades; extern const WeaponType Psi_Blades_Fenix; extern const WeaponType Phase_Disruptor; extern const WeaponType Phase_Disruptor_Fenix; extern const WeaponType Psi_Assault; extern const WeaponType Psionic_Shockwave; extern const WeaponType Psionic_Shockwave_TZ_Archon; extern const WeaponType Dual_Photon_Blasters; extern const WeaponType Dual_Photon_Blasters_Mojo; extern const WeaponType Dual_Photon_Blasters_Artanis; extern const WeaponType Anti_Matter_Missiles; extern const WeaponType Anti_Matter_Missiles_Mojo; extern const WeaponType Anti_Matter_Missiles_Artanis; extern const WeaponType Phase_Disruptor_Cannon; extern const WeaponType Phase_Disruptor_Cannon_Danimoth; extern const WeaponType Pulse_Cannon; extern const WeaponType STS_Photon_Cannon; extern const WeaponType STA_Photon_Cannon; extern const WeaponType Scarab; extern const WeaponType Neutron_Flare; extern const WeaponType Halo_Rockets; extern const WeaponType Corrosive_Acid; extern const WeaponType Subterranean_Spines; extern const WeaponType Warp_Blades; extern const WeaponType Warp_Blades_Hero; extern const WeaponType Warp_Blades_Zeratul; extern const WeaponType Yamato_Gun; extern const WeaponType Nuclear_Strike; extern const WeaponType Lockdown; extern const WeaponType EMP_Shockwave; extern const WeaponType Irradiate; extern const WeaponType Parasite; extern const WeaponType Spawn_Broodlings; extern const WeaponType Ensnare; extern const WeaponType Dark_Swarm; extern const WeaponType Plague; extern const WeaponType Consume; extern const WeaponType Stasis_Field; extern const WeaponType Psionic_Storm; extern const WeaponType Disruption_Web; extern const WeaponType Restoration; extern const WeaponType Mind_Control; extern const WeaponType Feedback; extern const WeaponType Optical_Flare; extern const WeaponType Maelstrom; extern const WeaponType None; extern const WeaponType Unknown; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI.cpp ================================================ #include namespace BWAPI { Game * Broodwar; } void BWAPI::BWAPI_init() { BWAPI::Races::init(); BWAPI::DamageTypes::init(); BWAPI::ExplosionTypes::init(); BWAPI::Orders::init(); BWAPI::TechTypes::init(); BWAPI::PlayerTypes::init(); BWAPI::UpgradeTypes::init(); BWAPI::WeaponTypes::init(); BWAPI::UnitSizeTypes::init(); BWAPI::UnitCommandTypes::init(); BWAPI::UnitTypes::init(); BWAPI::BulletTypes::init(); BWAPI::Errors::init(); BWAPI::Colors::init(); BWAPI::GameTypes::init(); } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BWAPI.h ================================================ #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 #include #include #include #include namespace BWAPI { /** You have to call this from your AIModule Dllmain function. * * \code * BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) * { * switch (ul_reason_for_call) * { * case DLL_PROCESS_ATTACH: * BWAPI::BWAPI_init(); * break; * case DLL_PROCESS_DETACH: * break; * } * * return TRUE; * } * \endcode */ void BWAPI_init(); } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Bitmap.cpp ================================================ #include namespace BWAPI { BitmapProxy::BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x) :data(data) ,width(width) ,height(height) ,x(x) {} Color BitmapProxy::operator[](int y) { unsigned int offs = y * this->width + this->x; if ( offs < (unsigned int)(this->width * this->height) ) return Color(this->data[offs]); return Color(0); } BitmapProxy Bitmap::operator[](int x) { return BitmapProxy(this->data, this->wid, this->ht, x); } unsigned short Bitmap::getWidth() { return this->wid; } unsigned short Bitmap::getHeight() { return this->ht; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/BulletType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingBulletType = true; std::string bulletTypeName[211]; std::map bulletTypeMap; std::set< BulletType > bulletTypeSet; namespace BulletTypes { const BulletType Melee(0); const BulletType Fusion_Cutter_Hit(141); const BulletType Gauss_Rifle_Hit(142); const BulletType C_10_Canister_Rifle_Hit(143); const BulletType Gemini_Missiles(144); const BulletType Fragmentation_Grenade(145); const BulletType Longbolt_Missile(146); const BulletType ATS_ATA_Laser_Battery(148); const BulletType Burst_Lasers(149); const BulletType Arclite_Shock_Cannon_Hit(150); const BulletType EMP_Missile(151); const BulletType Dual_Photon_Blasters_Hit(152); const BulletType Particle_Beam_Hit(153); const BulletType Anti_Matter_Missile(154); const BulletType Pulse_Cannon(155); const BulletType Psionic_Shockwave_Hit(156); const BulletType Psionic_Storm(157); const BulletType Yamato_Gun(158); const BulletType Phase_Disruptor(159); const BulletType STA_STS_Cannon_Overlay(160); const BulletType Sunken_Colony_Tentacle(161); const BulletType Acid_Spore(163); const BulletType Glave_Wurm(165); const BulletType Seeker_Spores(166); const BulletType Queen_Spell_Carrier(167); const BulletType Plague_Cloud(168); const BulletType Consume(169); const BulletType Needle_Spine_Hit(171); const BulletType Invisible(172); const BulletType Optical_Flare_Grenade(201); const BulletType Halo_Rockets(202); const BulletType Subterranean_Spines(203); const BulletType Corrosive_Acid_Shot(204); const BulletType Neutron_Flare(206); const BulletType None(209); const BulletType Unknown(210); void init() { bulletTypeName[Melee.getID()] = "Melee"; bulletTypeName[Fusion_Cutter_Hit.getID()] = "Fusion Cutter Hit"; bulletTypeName[Gauss_Rifle_Hit.getID()] = "Gauss Rifle Hit"; bulletTypeName[C_10_Canister_Rifle_Hit.getID()] = "C-10 Canister Rifle Hit"; bulletTypeName[Gemini_Missiles.getID()] = "Gemini Missiles"; bulletTypeName[Fragmentation_Grenade.getID()] = "Fragmentation Grenade"; bulletTypeName[Longbolt_Missile.getID()] = "Longbolt Missile"; bulletTypeName[ATS_ATA_Laser_Battery.getID()] = "ATS ATA Laser Battery"; bulletTypeName[Burst_Lasers.getID()] = "Burst Lasers"; bulletTypeName[Arclite_Shock_Cannon_Hit.getID()] = "Arclite Shock Cannon Hit"; bulletTypeName[EMP_Missile.getID()] = "EMP Missile"; bulletTypeName[Dual_Photon_Blasters_Hit.getID()] = "Dual Photon Blasters Hit"; bulletTypeName[Particle_Beam_Hit.getID()] = "Particle Beam Hit"; bulletTypeName[Anti_Matter_Missile.getID()] = "Anti-Matter Missile"; bulletTypeName[Pulse_Cannon.getID()] = "Pulse Cannon"; bulletTypeName[Psionic_Shockwave_Hit.getID()] = "Psionic Shockwave Hit"; bulletTypeName[Psionic_Storm.getID()] = "Psionic Storm"; bulletTypeName[Yamato_Gun.getID()] = "Yamato Gun"; bulletTypeName[Phase_Disruptor.getID()] = "Phase Disruptor"; bulletTypeName[STA_STS_Cannon_Overlay.getID()] = "STA STS Cannon Overlay"; bulletTypeName[Sunken_Colony_Tentacle.getID()] = "Sunken Colony Tentacle"; bulletTypeName[Acid_Spore.getID()] = "Acid Spore"; bulletTypeName[Glave_Wurm.getID()] = "Glave Wurm"; bulletTypeName[Seeker_Spores.getID()] = "Seeker Spores"; bulletTypeName[Queen_Spell_Carrier.getID()] = "Queen Spell Carrier"; bulletTypeName[Plague_Cloud.getID()] = "Plague Cloud"; bulletTypeName[Consume.getID()] = "Consume"; bulletTypeName[Needle_Spine_Hit.getID()] = "Needle Spine Hit"; bulletTypeName[Invisible.getID()] = "Invisible"; bulletTypeName[Optical_Flare_Grenade.getID()] = "Optical Flare Grenade"; bulletTypeName[Halo_Rockets.getID()] = "Halo Rockets"; bulletTypeName[Subterranean_Spines.getID()] = "Subterranean Spines"; bulletTypeName[Corrosive_Acid_Shot.getID()] = "Corrosive Acid Shot"; bulletTypeName[Neutron_Flare.getID()] = "Neutron Flare"; bulletTypeName[None.getID()] = "None"; bulletTypeName[Unknown.getID()] = "Unknown"; bulletTypeSet.insert(Melee); bulletTypeSet.insert(Fusion_Cutter_Hit); bulletTypeSet.insert(Gauss_Rifle_Hit); bulletTypeSet.insert(C_10_Canister_Rifle_Hit); bulletTypeSet.insert(Gemini_Missiles); bulletTypeSet.insert(Fragmentation_Grenade); bulletTypeSet.insert(Longbolt_Missile); bulletTypeSet.insert(ATS_ATA_Laser_Battery); bulletTypeSet.insert(Burst_Lasers); bulletTypeSet.insert(Arclite_Shock_Cannon_Hit); bulletTypeSet.insert(EMP_Missile); bulletTypeSet.insert(Dual_Photon_Blasters_Hit); bulletTypeSet.insert(Particle_Beam_Hit); bulletTypeSet.insert(Anti_Matter_Missile); bulletTypeSet.insert(Pulse_Cannon); bulletTypeSet.insert(Psionic_Shockwave_Hit); bulletTypeSet.insert(Psionic_Storm); bulletTypeSet.insert(Yamato_Gun); bulletTypeSet.insert(Phase_Disruptor); bulletTypeSet.insert(STA_STS_Cannon_Overlay); bulletTypeSet.insert(Sunken_Colony_Tentacle); bulletTypeSet.insert(Acid_Spore); bulletTypeSet.insert(Glave_Wurm); bulletTypeSet.insert(Seeker_Spores); bulletTypeSet.insert(Queen_Spell_Carrier); bulletTypeSet.insert(Plague_Cloud); bulletTypeSet.insert(Consume); bulletTypeSet.insert(Needle_Spine_Hit); bulletTypeSet.insert(Invisible); bulletTypeSet.insert(Optical_Flare_Grenade); bulletTypeSet.insert(Halo_Rockets); bulletTypeSet.insert(Subterranean_Spines); bulletTypeSet.insert(Corrosive_Acid_Shot); bulletTypeSet.insert(Neutron_Flare); bulletTypeSet.insert(None); bulletTypeSet.insert(Unknown); foreach(BulletType i, bulletTypeSet) { std::string name = i.getName(); fixName(&name); bulletTypeMap.insert(std::make_pair(name, i)); } initializingBulletType = false; } } BulletType::BulletType() { this->id = BulletTypes::None.id; } BulletType::BulletType(int id) { this->id = id; if (!initializingBulletType && (id < 0 || id >= 211 || bulletTypeName[id].length() == 0)) this->id = BulletTypes::Unknown.id; } BulletType::BulletType(const BulletType& other) { this->id = other.id; } BulletType& BulletType::operator=(const BulletType& other) { this->id = other.id; return *this; } bool BulletType::operator==(const BulletType& other) const { return this->id == other.id; } bool BulletType::operator!=(const BulletType& other) const { return this->id != other.id; } bool BulletType::operator<(const BulletType& other) const { return this->id < other.id; } int BulletType::getID() const { return this->id; } std::string BulletType::getName() const { return bulletTypeName[this->id]; } BulletType BulletTypes::getBulletType(std::string name) { fixName(&name); std::map::iterator i = bulletTypeMap.find(name); if (i == bulletTypeMap.end()) return BulletTypes::Unknown; return (*i).second; } std::set& BulletTypes::allBulletTypes() { return bulletTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Color.cpp ================================================ #include #include #include namespace BWAPI { int palette[256] = {0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x3a003a, 0x190019, 0x2c2418, 0x482414, 0x5c2c14, 0x703014, 0x683c24, 0x7c4018, 0x784c2c, 0xa80808, 0x8c5430, 0x846044, 0xa0541c, 0xc44c18, 0xbc6824, 0xb4703c, 0xd06420, 0xdc9434, 0xe09454, 0xecc454, 0x344428, 0x406c3c, 0x486c50, 0x4c8050, 0x508c5c, 0x5ca078, 0x000018, 0x001034, 0x000850, 0x243448, 0x304054, 0x14347c, 0x344c6c, 0x405874, 0x48688c, 0x00709c, 0x5880a4, 0x4068d4, 0x18acb8, 0x2424fc, 0x6494bc, 0x70a8cc, 0x8cc0d8, 0x94dcf4, 0xacdce8, 0xacfcfc, 0xccf8f8, 0xfcfc00, 0xf4e490, 0xfcfcc0, 0x0c0c0c, 0x181410, 0x1c1c20, 0x282830, 0x383024, 0x383c44, 0x4c4030, 0x4c4c4c, 0x5c5040, 0x585858, 0x686868, 0x78846c, 0x68946c, 0x74a47c, 0x98948c, 0x90b894, 0x98c4a8, 0xb0b0b0, 0xacccb0, 0xc4c0bc, 0xcce0d0, 0xf0f0f0, 0x1c1008, 0x28180c, 0x341008, 0x34200c, 0x381020, 0x342820, 0x443408, 0x483018, 0x600000, 0x542820, 0x504014, 0x5c5414, 0x840404, 0x684c34, 0x7c3830, 0x706420, 0x7c5050, 0xa4341c, 0x946c00, 0x985c40, 0x8c8034, 0x987454, 0xb85444, 0xb09018, 0xb0745c, 0xf40404, 0xc87854, 0xfc6854, 0xe0a484, 0xfc9468, 0xfccc2c, 0x10fc18, 0x0c0020, 0x1c1c2c, 0x24244c, 0x282c68, 0x2c3084, 0x2018b8, 0x343cac, 0x686894, 0x6490fc, 0x7cacfc, 0x00e4fc, 0x9c9040, 0xa89454, 0xbca45c, 0xccb860, 0xe8d880, 0xecc4b0, 0xfcfc38, 0xfcfc7c, 0xfcfca4, 0x080808, 0x101010, 0x181818, 0x282828, 0x343434, 0x4c3c38, 0x444444, 0x484858, 0x585868, 0x746838, 0x78645c, 0x60607c, 0x847474, 0x84849c, 0xac8c7c, 0xac9894, 0x9090b8, 0xb8b8e8, 0xf88c14, 0x10543c, 0x209070, 0x2cb494, 0x042064, 0x481c50, 0x083498, 0x683078, 0x88409c, 0x0c48cc, 0xbcb834, 0xdcdc3c, 0x100000, 0x240000, 0x340000, 0x480000, 0x601804, 0x8c2808, 0xc81818, 0xe02c2c, 0xe82020, 0xe85014, 0xfc2020, 0xe87824, 0xf8ac3c, 0x001400, 0x002800, 0x004400, 0x006400, 0x088008, 0x249824, 0x3c9c3c, 0x58b058, 0x68b868, 0x80c480, 0x94d494, 0x0c1424, 0x243c64, 0x305084, 0x385c94, 0x4874b4, 0x5484c4, 0x6094d4, 0x78b4ec, 0x141008, 0x18140c, 0x242c0c, 0x101018, 0x141420, 0x2c2c40, 0x444c68, 0x040404, 0x1c1810, 0x201c14, 0x24201c, 0x30281c, 0x40382c, 0x544838, 0x685c4c, 0x907c64, 0x282014, 0x302814, 0x342c18, 0x382c1c, 0x3c301c, 0x443824, 0x544430, 0x0c1004, 0x141804, 0x181c08, 0x1c2008, 0x20240c, 0x2c3410, 0x343c10, 0x404810, 0x202030, 0x28283c, 0x303448, 0x141414, 0x20181c, 0x282018, 0x241c24, 0x282424, 0x302c2c, 0x3c2c34, 0x3c383c, 0x483c30, 0x443440, 0x503c48, 0x5c5034, 0x2323ff, 0x2323ff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff }; namespace Colors { const Color Red(111); const Color Blue(165); const Color Teal(159); const Color Purple(156); const Color Orange(179); const Color Brown(19); const Color White(255); const Color Yellow(135); const Color Green(117); const Color Cyan(128); const Color Black(0); const Color Grey(74); std::list cell[8][8][8]; void init() { for(int i = 0; i < 256; ++i) { int redCell = (palette[i] >> 21) & 0x07; int greenCell = (palette[i] >> 13) & 0x07; int blueCell = (palette[i] >> 5) & 0x07; cell[redCell][greenCell][blueCell].push_back(i); } } } int min(int a, int b) { return a < b ? a : b; } int max(int a, int b) { return a > b ? a : b; } Color::Color() { this->id = 0; } Color::Color(int id) { this->id = id; } Color::Color(const Color& other) { this->id = other.id; } Color::Color(int red, int green, int blue) { int redCell = red >> 5; int greenCell = green >> 5; int blueCell = blue >> 5; int redCellS = max(redCell - 1, 0); int redCellF = min(redCell + 1, 7); int greenCellS = max(greenCell - 1, 0); int greenCellF = min(greenCell + 1, 7); int blueCellS = max(blueCell - 1, 0); int blueCellF = min(blueCell + 1, 7); int min_dist = 3 * 256 * 256; int best_id = -1; for(int rc = redCellS; rc <= redCellF; ++rc) { for(int gc = greenCellS; gc <= greenCellF; ++gc) { for(int bc = blueCellS; bc <= blueCellF; ++bc) { foreach(int id, Colors::cell[rc][gc][bc]) { int ired = (palette[id] >> 16) & 0xFF; int igreen = (palette[id] >> 8) & 0xFF; int iblue = (palette[id] >> 0) & 0xFF; int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue); if (distance < min_dist) { min_dist = distance; best_id = id; } } } } } if (best_id == -1) { int min_dist = 3 * 256 * 256; int best_id = -1; for(int id = 0; id < 255; ++id) { int ired = (palette[id] >> 16) & 0xFF; int igreen = (palette[id] >> 8) & 0xFF; int iblue = (palette[id] >> 0) & 0xFF; int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue); if (distance < min_dist) { min_dist = distance; best_id = id; } } } this->id = best_id; } Color& Color::operator=(const Color& other) { this->id = other.id; return *this; } bool Color::operator==(const Color& other) const { return palette[this->id] == palette[other.id]; } bool Color::operator!=(const Color& other) const { return palette[this->id] != palette[other.id]; } bool Color::operator<(const Color& other) const { return this->id < other.id; } int Color::getID() const { return this->id; } int Color::red() const { return (palette[this->id] >> 16) & 0xFF; } int Color::green() const { return (palette[this->id] >> 8) & 0xFF; } int Color::blue() const { return palette[this->id] & 0xFF; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Common.cpp ================================================ #include "Common.h" namespace BWAPI { void fixName(std::string *name) { for(unsigned int j = 0; j < name->length(); ++j) { if ( (*name)[j] == ' ') (*name)[j] = '_'; if ( (*name)[j] >= 'a' && (*name)[j] <= 'z') (*name)[j] += 'A'-'a'; } } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Common.h ================================================ #pragma once #include namespace BWAPI { void fixName(std::string *name); } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/DamageType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingDamageType = true; std::string damageTypeName[7]; std::map damageTypeMap; std::set< DamageType > damageTypeSet; namespace DamageTypes { const DamageType Independent(0); const DamageType Explosive(1); const DamageType Concussive(2); const DamageType Normal(3); const DamageType Ignore_Armor(4); const DamageType None(5); const DamageType Unknown(6); void init() { damageTypeName[Independent.getID()] = "Independent"; damageTypeName[Explosive.getID()] = "Explosive"; damageTypeName[Concussive.getID()] = "Concussive"; damageTypeName[Normal.getID()] = "Normal"; damageTypeName[Ignore_Armor.getID()] = "Ignore Armor"; damageTypeName[None.getID()] = "None"; damageTypeName[Unknown.getID()] = "Unknown"; damageTypeSet.insert(Independent); damageTypeSet.insert(Explosive); damageTypeSet.insert(Concussive); damageTypeSet.insert(Normal); damageTypeSet.insert(Ignore_Armor); damageTypeSet.insert(None); damageTypeSet.insert(Unknown); foreach(DamageType i, damageTypeSet) { std::string name = i.getName(); fixName(&name); damageTypeMap.insert(std::make_pair(name, i)); } initializingDamageType = false; } } DamageType::DamageType() { this->id = DamageTypes::None.id; } DamageType::DamageType(int id) { this->id = id; if (!initializingDamageType && (id < 0 || id >= 7)) this->id = DamageTypes::Unknown.id; } DamageType::DamageType(const DamageType& other) { this->id = other.id; } DamageType& DamageType::operator=(const DamageType& other) { this->id = other.id; return *this; } bool DamageType::operator==(const DamageType& other) const { return this->id == other.id; } bool DamageType::operator!=(const DamageType& other) const { return this->id != other.id; } bool DamageType::operator<(const DamageType& other) const { return this->id < other.id; } int DamageType::getID() const { return this->id; } std::string DamageType::getName() const { return damageTypeName[this->id]; } DamageType DamageTypes::getDamageType(std::string name) { fixName(&name); std::map::iterator i = damageTypeMap.find(name); if (i == damageTypeMap.end()) return DamageTypes::Unknown; return (*i).second; } std::set& DamageTypes::allDamageTypes() { return damageTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Error.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingError = true; std::string errorName[25]; std::map errorMap; std::set< Error > errorSet; namespace Errors { const Error Unit_Does_Not_Exist(0); const Error Unit_Not_Visible(1); const Error Unit_Not_Owned(2); const Error Unit_Busy(3); const Error Incompatible_UnitType(4); const Error Incompatible_TechType(5); const Error Incompatible_State(6); const Error Already_Researched(7); const Error Fully_Upgraded(8); const Error Currently_Researching(9); const Error Currently_Upgrading(10); const Error Insufficient_Minerals(11); const Error Insufficient_Gas(12); const Error Insufficient_Supply(13); const Error Insufficient_Energy(14); const Error Insufficient_Tech(15); const Error Insufficient_Ammo(16); const Error Insufficient_Space(17); const Error Unbuildable_Location(18); const Error Unreachable_Location(19); const Error Out_Of_Range(20); const Error Unable_To_Hit(21); const Error Access_Denied(22); const Error None(23); const Error Unknown(24); void init() { errorName[Unit_Does_Not_Exist.getID()] = "Unit Does Not Exist"; errorName[Unit_Not_Visible.getID()] = "Unit Not Visible"; errorName[Unit_Not_Owned.getID()] = "Unit Not Owned"; errorName[Unit_Busy.getID()] = "Unit Busy"; errorName[Incompatible_UnitType.getID()] = "Incompatible UnitType"; errorName[Incompatible_TechType.getID()] = "Incompatible TechType"; errorName[Incompatible_State.getID()] = "Incompatible State"; errorName[Already_Researched.getID()] = "Already Researched"; errorName[Fully_Upgraded.getID()] = "Fully Upgraded"; errorName[Currently_Researching.getID()] = "Currently Researching"; errorName[Currently_Upgrading.getID()] = "Currently Upgrading"; errorName[Insufficient_Minerals.getID()] = "Insufficient Minerals"; errorName[Insufficient_Gas.getID()] = "Insufficient Gas"; errorName[Insufficient_Supply.getID()] = "Insufficient Supply"; errorName[Insufficient_Energy.getID()] = "Insufficient Energy"; errorName[Insufficient_Tech.getID()] = "Insufficient Tech"; errorName[Insufficient_Ammo.getID()] = "Insufficient Ammo"; errorName[Insufficient_Space.getID()] = "Insufficient Space"; errorName[Unbuildable_Location.getID()] = "Unbuildable Location"; errorName[Unreachable_Location.getID()] = "Unreachable Location"; errorName[Out_Of_Range.getID()] = "Out Of Range"; errorName[Unable_To_Hit.getID()] = "Unable To Hit"; errorName[Access_Denied.getID()] = "Access Denied"; errorName[None.getID()] = "None"; errorName[Unknown.getID()] = "Unknown"; errorSet.insert(Unit_Does_Not_Exist); errorSet.insert(Unit_Not_Visible); errorSet.insert(Unit_Not_Owned); errorSet.insert(Unit_Busy); errorSet.insert(Incompatible_UnitType); errorSet.insert(Incompatible_TechType); errorSet.insert(Incompatible_State); errorSet.insert(Already_Researched); errorSet.insert(Fully_Upgraded); errorSet.insert(Currently_Researching); errorSet.insert(Currently_Upgrading); errorSet.insert(Insufficient_Minerals); errorSet.insert(Insufficient_Gas); errorSet.insert(Insufficient_Supply); errorSet.insert(Insufficient_Energy); errorSet.insert(Insufficient_Tech); errorSet.insert(Insufficient_Ammo); errorSet.insert(Insufficient_Space); errorSet.insert(Unbuildable_Location); errorSet.insert(Unreachable_Location); errorSet.insert(Out_Of_Range); errorSet.insert(Unable_To_Hit); errorSet.insert(Access_Denied); errorSet.insert(None); errorSet.insert(Unknown); foreach(Error i, errorSet) { std::string name = i.toString(); fixName(&name); errorMap.insert(std::make_pair(name, i)); } initializingError = false; } } Error::Error() { this->id = Errors::None.id; } Error::Error(int id) { this->id = id; if (!initializingError && (id < 0 || id >= 25)) this->id = Errors::Unknown.id; } Error::Error(const Error& other) { this->id = other.id; } Error& Error::operator=(const Error& other) { this->id = other.id; return *this; } bool Error::operator==(const Error& other) const { return this->id == other.id; } bool Error::operator!=(const Error& other) const { return this->id != other.id; } bool Error::operator<(const Error& other) const { return this->id < other.id; } int Error::getID() const { return this->id; } std::string Error::toString() const { return errorName[this->id]; } Error Errors::getError(std::string name) { fixName(&name); std::map::iterator i = errorMap.find(name); if (i == errorMap.end()) return Errors::Unknown; return (*i).second; } std::set& Errors::allErrors() { return errorSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Event.cpp ================================================ #include namespace BWAPI { Event::Event() : type(EventType::None), position(Positions::None), text(""), unit(NULL), player(NULL), isWinner(false) { } bool Event::operator==(const Event& other) { return (type == other.type && position == other.position && text == other.text && unit == other.unit && player == other.player && isWinner == other.isWinner); } Event Event::MatchStart() { Event e; e.type = EventType::MatchStart; return e; } Event Event::MatchEnd(bool isWinner) { Event e; e.type = EventType::MatchEnd; e.isWinner = isWinner; return e; } Event Event::MatchFrame() { Event e; e.type = EventType::MatchFrame; return e; } Event Event::MenuFrame() { Event e; e.type = EventType::MenuFrame; return e; } Event Event::SendText(std::string text) { Event e; e.type = EventType::SendText; e.text = text; return e; } Event Event::ReceiveText(Player* player, std::string text) { Event e; e.type = EventType::ReceiveText; e.player = player; e.text = text; return e; } Event Event::PlayerLeft(Player* player) { Event e; e.type = EventType::PlayerLeft; e.player = player; return e; } Event Event::NukeDetect(Position target) { Event e; e.type = EventType::NukeDetect; e.position = target; return e; } Event Event::UnitDiscover(Unit* unit) { Event e; e.type = EventType::UnitDiscover; e.unit = unit; return e; } Event Event::UnitEvade(Unit* unit) { Event e; e.type = EventType::UnitEvade; e.unit = unit; return e; } Event Event::UnitShow(Unit* unit) { Event e; e.type = EventType::UnitShow; e.unit = unit; return e; } Event Event::UnitHide(Unit* unit) { Event e; e.type = EventType::UnitHide; e.unit = unit; return e; } Event Event::UnitCreate(Unit* unit) { Event e; e.type = EventType::UnitCreate; e.unit = unit; return e; } Event Event::UnitDestroy(Unit* unit) { Event e; e.type = EventType::UnitDestroy; e.unit = unit; return e; } Event Event::UnitMorph(Unit* unit) { Event e; e.type = EventType::UnitMorph; e.unit = unit; return e; } Event Event::UnitRenegade(Unit* unit) { Event e; e.type = EventType::UnitRenegade; e.unit = unit; return e; } Event Event::SaveGame(std::string gameName) { Event e; e.type = EventType::SaveGame; e.text = gameName; return e; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/ExplosionType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingExplosionType = true; std::string explosionTypeName[26]; std::map explosionTypeMap; std::set< ExplosionType > explosionTypeSet; namespace ExplosionTypes { const ExplosionType None(0); const ExplosionType Normal(1); const ExplosionType Radial_Splash(2); const ExplosionType Enemy_Splash(3); const ExplosionType Lockdown(4); const ExplosionType Nuclear_Missile(5); const ExplosionType Parasite(6); const ExplosionType Broodlings(7); const ExplosionType EMP_Shockwave(8); const ExplosionType Irradiate(9); const ExplosionType Ensnare(10); const ExplosionType Plague(11); const ExplosionType Stasis_Field(12); const ExplosionType Dark_Swarm(13); const ExplosionType Consume(14); const ExplosionType Yamato_Gun(15); const ExplosionType Restoration(16); const ExplosionType Disruption_Web(17); const ExplosionType Corrosive_Acid(18); const ExplosionType Mind_Control(19); const ExplosionType Feedback(20); const ExplosionType Optical_Flare(21); const ExplosionType Maelstrom(22); const ExplosionType Air_Splash(24); const ExplosionType Unknown(25); void init() { explosionTypeName[None.getID()] = "None"; explosionTypeName[Normal.getID()] = "Normal"; explosionTypeName[Radial_Splash.getID()] = "Radial Splash"; explosionTypeName[Enemy_Splash.getID()] = "Enemy Splash"; explosionTypeName[Lockdown.getID()] = "Lockdown"; explosionTypeName[Nuclear_Missile.getID()] = "Nuclear Missile"; explosionTypeName[Parasite.getID()] = "Parasite"; explosionTypeName[Broodlings.getID()] = "Broodlings"; explosionTypeName[EMP_Shockwave.getID()] = "EMP Shockwave"; explosionTypeName[Irradiate.getID()] = "Irradiate"; explosionTypeName[Ensnare.getID()] = "Ensnare"; explosionTypeName[Plague.getID()] = "Plague"; explosionTypeName[Stasis_Field.getID()] = "Stasis Field"; explosionTypeName[Dark_Swarm.getID()] = "Dark Swarm"; explosionTypeName[Consume.getID()] = "Consume"; explosionTypeName[Yamato_Gun.getID()] = "Yamato Gun"; explosionTypeName[Restoration.getID()] = "Restoration"; explosionTypeName[Disruption_Web.getID()] = "Disruption Web"; explosionTypeName[Corrosive_Acid.getID()] = "Corrosive Acid"; explosionTypeName[Mind_Control.getID()] = "Mind Control"; explosionTypeName[Feedback.getID()] = "Feedback"; explosionTypeName[Optical_Flare.getID()] = "Optical Flare"; explosionTypeName[Maelstrom.getID()] = "Maelstrom"; explosionTypeName[Air_Splash.getID()] = "Air Splash"; explosionTypeName[Unknown.getID()] = "Unknown"; explosionTypeSet.insert(None); explosionTypeSet.insert(Normal); explosionTypeSet.insert(Radial_Splash); explosionTypeSet.insert(Enemy_Splash); explosionTypeSet.insert(Lockdown); explosionTypeSet.insert(Nuclear_Missile); explosionTypeSet.insert(Parasite); explosionTypeSet.insert(Broodlings); explosionTypeSet.insert(EMP_Shockwave); explosionTypeSet.insert(Irradiate); explosionTypeSet.insert(Ensnare); explosionTypeSet.insert(Plague); explosionTypeSet.insert(Stasis_Field); explosionTypeSet.insert(Dark_Swarm); explosionTypeSet.insert(Consume); explosionTypeSet.insert(Yamato_Gun); explosionTypeSet.insert(Restoration); explosionTypeSet.insert(Disruption_Web); explosionTypeSet.insert(Corrosive_Acid); explosionTypeSet.insert(Mind_Control); explosionTypeSet.insert(Feedback); explosionTypeSet.insert(Optical_Flare); explosionTypeSet.insert(Maelstrom); explosionTypeSet.insert(Air_Splash); explosionTypeSet.insert(Unknown); foreach(ExplosionType i, explosionTypeSet) { std::string name = i.getName(); fixName(&name); explosionTypeMap.insert(std::make_pair(name, i)); } initializingExplosionType = false; } } ExplosionType::ExplosionType() { this->id = ExplosionTypes::None.id; } ExplosionType::ExplosionType(int id) { this->id = id; if (!initializingExplosionType && (id < 0 || id >= 26)) this->id = ExplosionTypes::Unknown.id; } ExplosionType::ExplosionType(const ExplosionType& other) { this->id = other.id; } ExplosionType& ExplosionType::operator=(const ExplosionType& other) { this->id = other.id; return *this; } bool ExplosionType::operator==(const ExplosionType& other) const { return this->id == other.id; } bool ExplosionType::operator!=(const ExplosionType& other) const { return this->id != other.id; } bool ExplosionType::operator<(const ExplosionType& other) const { return this->id < other.id; } int ExplosionType::getID() const { return this->id; } std::string ExplosionType::getName() const { return explosionTypeName[this->id]; } ExplosionType ExplosionTypes::getExplosionType(std::string name) { fixName(&name); std::map::iterator i = explosionTypeMap.find(name); if (i == explosionTypeMap.end()) return ExplosionTypes::Unknown; return (*i).second; } std::set& ExplosionTypes::allExplosionTypes() { return explosionTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/GameType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingGameType = true; std::string gameTypeName[35]; std::map gameTypeMap; std::set< GameType > gameTypeSet; namespace GameTypes { const GameType Melee(2); const GameType Free_For_All(3); const GameType One_on_One(4); const GameType Capture_The_Flag(5); const GameType Greed(6); const GameType Slaughter(7); const GameType Sudden_Death(8); const GameType Ladder(9); const GameType Use_Map_Settings(10); const GameType Team_Melee(11); const GameType Team_Free_For_All(12); const GameType Team_Capture_The_Flag(13); const GameType Top_vs_Bottom(15); const GameType Pro_Gamer_League(32); const GameType None(33); const GameType Unknown(34); void init() { gameTypeName[Melee.getID()] = "Melee"; gameTypeName[Free_For_All.getID()] = "Free For All"; gameTypeName[One_on_One.getID()] = "One on One"; gameTypeName[Capture_The_Flag.getID()] = "Capture The Flag"; gameTypeName[Greed.getID()] = "Greed"; gameTypeName[Slaughter.getID()] = "Slaughter"; gameTypeName[Sudden_Death.getID()] = "Sudden Death"; gameTypeName[Ladder.getID()] = "Ladder"; gameTypeName[Use_Map_Settings.getID()] = "Use Map Settings"; gameTypeName[Team_Melee.getID()] = "Team Melee"; gameTypeName[Team_Free_For_All.getID()] = "Team Free For All"; gameTypeName[Team_Capture_The_Flag.getID()] = "Team Capture The Flag"; gameTypeName[Top_vs_Bottom.getID()] = "Top vs Bottom"; gameTypeName[Pro_Gamer_League.getID()] = "Pro Gamer League"; gameTypeName[None.getID()] = "None"; gameTypeName[Unknown.getID()] = "Unknown"; gameTypeSet.insert(Melee); gameTypeSet.insert(Free_For_All); gameTypeSet.insert(One_on_One); gameTypeSet.insert(Capture_The_Flag); gameTypeSet.insert(Greed); gameTypeSet.insert(Slaughter); gameTypeSet.insert(Sudden_Death); gameTypeSet.insert(Ladder); gameTypeSet.insert(Use_Map_Settings); gameTypeSet.insert(Team_Melee); gameTypeSet.insert(Team_Free_For_All); gameTypeSet.insert(Team_Capture_The_Flag); gameTypeSet.insert(Top_vs_Bottom); gameTypeSet.insert(Pro_Gamer_League); gameTypeSet.insert(None); gameTypeSet.insert(Unknown); foreach(GameType i, gameTypeSet) { std::string name = i.getName(); fixName(&name); gameTypeMap.insert(std::make_pair(name, i)); } initializingGameType = false; } } GameType::GameType() { this->id = GameTypes::None.id; } GameType::GameType(int id) { this->id = id; if (!initializingGameType && (id < 0 || id >= 35 || gameTypeName[id].length() == 0)) this->id = GameTypes::Unknown.id; } GameType::GameType(const GameType& other) { this->id = other.id; } GameType& GameType::operator=(const GameType& other) { this->id = other.id; return *this; } bool GameType::operator==(const GameType& other) const { return this->id == other.id; } bool GameType::operator!=(const GameType& other) const { return this->id != other.id; } bool GameType::operator<(const GameType& other) const { return this->id < other.id; } int GameType::getID() const { return this->id; } std::string GameType::getName() const { return gameTypeName[this->id]; } GameType GameTypes::getGameType(std::string name) { fixName(&name); std::map::iterator i = gameTypeMap.find(name); if (i == gameTypeMap.end()) return GameTypes::Unknown; return (*i).second; } std::set& GameTypes::allGameTypes() { return gameTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Order.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingOrder = true; std::string orderName[191]; std::map orderMap; std::set< Order > orderSet; namespace Orders { const Order Die(0); const Order Stop(1); const Order Guard(2); const Order PlayerGuard(3); const Order TurretGuard(4); const Order BunkerGuard(5); const Order Move(6); const Order AttackUnit(10); const Order AttackTile(12); const Order Hover(13); const Order AttackMove(14); const Order InfestedCommandCenter(15); const Order UnusedNothing(16); const Order UnusedPowerup(17); const Order TowerGuard(18); const Order VultureMine(20); const Order Nothing(23); const Order Nothing3(24); const Order CastInfestation(27); const Order InfestingCommandCenter(29); const Order PlaceBuilding(30); const Order BuildProtoss2(32); const Order ConstructingBuilding(33); const Order Repair(34); const Order PlaceAddon(36); const Order BuildAddon(37); const Order Train(38); const Order RallyPointUnit(39); const Order RallyPointTile(40); const Order ZergBirth(41); const Order ZergUnitMorph(42); const Order ZergBuildingMorph(43); const Order IncompleteBuilding(44); const Order BuildNydusExit(46); const Order EnterNydusCanal(47); const Order Follow(49); const Order Carrier(50); const Order ReaverCarrierMove(51); const Order CarrierIgnore2(55); const Order Reaver(58); const Order TrainFighter(63); const Order InterceptorAttack(64); const Order ScarabAttack(65); const Order RechargeShieldsUnit(66); const Order RechargeShieldsBattery(67); const Order ShieldBattery(68); const Order InterceptorReturn(69); const Order BuildingLand(71); const Order BuildingLiftOff(72); const Order DroneLiftOff(73); const Order LiftingOff(74); const Order ResearchTech(75); const Order Upgrade(76); const Order Larva(77); const Order SpawningLarva(78); const Order Harvest1(79); const Order Harvest2(80); const Order MoveToGas(81); const Order WaitForGas(82); const Order HarvestGas(83); const Order ReturnGas(84); const Order MoveToMinerals(85); const Order WaitForMinerals(86); const Order MiningMinerals(87); const Order Harvest3(88); const Order Harvest4(89); const Order ReturnMinerals(90); const Order Interrupted(91); const Order EnterTransport(92); const Order PickupIdle(93); const Order PickupTransport(94); const Order PickupBunker(95); const Order Pickup4(96); const Order PowerupIdle(97); const Order Sieging(98); const Order Unsieging(99); const Order InitCreepGrowth(101); const Order SpreadCreep(102); const Order StoppingCreepGrowth(103); const Order GuardianAspect(104); const Order ArchonWarp(105); const Order CompletingArchonsummon(106); const Order HoldPosition(107); const Order Cloak(109); const Order Decloak(110); const Order Unload(111); const Order MoveUnload(112); const Order FireYamatoGun(113); const Order CastLockdown(115); const Order Burrowing(116); const Order Burrowed(117); const Order Unburrowing(118); const Order CastDarkSwarm(119); const Order CastParasite(120); const Order CastSpawnBroodlings(121); const Order CastEMPShockwave(122); const Order NukeWait(123); const Order NukeTrain(124); const Order NukeLaunch(125); const Order NukeUnit(127); const Order CastNuclearStrike(128); const Order NukeTrack(129); const Order CloakNearbyUnits(131); const Order PlaceMine(132); const Order RightClickAction(133); const Order CastRecall(137); const Order TeleporttoLocation(138); const Order CastScannerSweep(139); const Order Scanner(140); const Order CastDefensiveMatrix(141); const Order CastPsionicStorm(142); const Order CastIrradiate(143); const Order CastPlague(144); const Order CastConsume(145); const Order CastEnsnare(146); const Order CastStasisField(147); const Order CastHallucination(148); const Order Hallucination2(149); const Order ResetCollision(150); const Order Patrol(152); const Order CTFCOPInit(153); const Order CTFCOP1(154); const Order CTFCOP2(155); const Order ComputerAI(156); const Order AtkMoveEP(157); const Order HarassMove(158); const Order AIPatrol(159); const Order GuardPost(160); const Order RescuePassive(161); const Order Neutral(162); const Order ComputerReturn(163); const Order SelfDestrucing(165); const Order Critter(166); const Order HiddenGun(167); const Order OpenDoor(168); const Order CloseDoor(169); const Order HideTrap(170); const Order RevealTrap(171); const Order Enabledoodad(172); const Order Disabledoodad(173); const Order Warpin(174); const Order Medic(175); const Order MedicHeal1(176); const Order HealMove(177); const Order MedicHeal2(179); const Order CastRestoration(180); const Order CastDisruptionWeb(181); const Order CastMindControl(182); const Order DarkArchonMeld(183); const Order CastFeedback(184); const Order CastOpticalFlare(185); const Order CastMaelstrom(186); const Order JunkYardDog(187); const Order Fatal(188); const Order None(189); const Order Unknown(190); void init() { orderName[Die.getID()] = "Die"; orderName[Stop.getID()] = "Stop"; orderName[Guard.getID()] = "Guard"; orderName[PlayerGuard.getID()] = "PlayerGuard"; orderName[TurretGuard.getID()] = "TurretGuard"; orderName[BunkerGuard.getID()] = "BunkerGuard"; orderName[Move.getID()] = "Move"; orderName[AttackUnit.getID()] = "AttackUnit"; orderName[AttackTile.getID()] = "AttackTile"; orderName[Hover.getID()] = "Hover"; orderName[AttackMove.getID()] = "AttackMove"; orderName[InfestedCommandCenter.getID()] = "InfestedCommandCenter"; orderName[UnusedNothing.getID()] = "UnusedNothing"; orderName[UnusedPowerup.getID()] = "UnusedPowerup"; orderName[TowerGuard.getID()] = "TowerGuard"; orderName[VultureMine.getID()] = "VultureMine"; orderName[Nothing.getID()] = "Nothing"; orderName[Nothing3.getID()] = "Nothing3"; orderName[CastInfestation.getID()] = "CastInfestation"; orderName[InfestingCommandCenter.getID()] = "InfestingCommandCenter"; orderName[PlaceBuilding.getID()] = "PlaceBuilding"; orderName[BuildProtoss2.getID()] = "BuildProtoss2"; orderName[ConstructingBuilding.getID()] = "ConstructingBuilding"; orderName[Repair.getID()] = "Repair"; orderName[PlaceAddon.getID()] = "PlaceAddon"; orderName[BuildAddon.getID()] = "BuildAddon"; orderName[Train.getID()] = "Train"; orderName[RallyPointUnit.getID()] = "RallyPointUnit"; orderName[RallyPointTile.getID()] = "RallyPointTile"; orderName[ZergBirth.getID()] = "ZergBirth"; orderName[ZergUnitMorph.getID()] = "ZergUnitMorph"; orderName[ZergBuildingMorph.getID()] = "ZergBuildingMorph"; orderName[IncompleteBuilding.getID()] = "IncompleteBuilding"; orderName[BuildNydusExit.getID()] = "BuildNydusExit"; orderName[EnterNydusCanal.getID()] = "EnterNydusCanal"; orderName[Follow.getID()] = "Follow"; orderName[Carrier.getID()] = "Carrier"; orderName[ReaverCarrierMove.getID()] = "ReaverCarrierMove"; orderName[CarrierIgnore2.getID()] = "CarrierIgnore2"; orderName[Reaver.getID()] = "Reaver"; orderName[TrainFighter.getID()] = "TrainFighter"; orderName[InterceptorAttack.getID()] = "InterceptorAttack"; orderName[ScarabAttack.getID()] = "ScarabAttack"; orderName[RechargeShieldsUnit.getID()] = "RechargeShieldsUnit"; orderName[RechargeShieldsBattery.getID()] = "RechargeShieldsBattery"; orderName[ShieldBattery.getID()] = "ShieldBattery"; orderName[InterceptorReturn.getID()] = "InterceptorReturn"; orderName[BuildingLand.getID()] = "BuildingLand"; orderName[BuildingLiftOff.getID()] = "BuildingLiftOff"; orderName[DroneLiftOff.getID()] = "DroneLiftOff"; orderName[LiftingOff.getID()] = "LiftingOff"; orderName[ResearchTech.getID()] = "ResearchTech"; orderName[Upgrade.getID()] = "Upgrade"; orderName[Larva.getID()] = "Larva"; orderName[SpawningLarva.getID()] = "SpawningLarva"; orderName[Harvest1.getID()] = "Harvest1"; orderName[Harvest2.getID()] = "Harvest2"; orderName[MoveToGas.getID()] = "MoveToGas"; orderName[WaitForGas.getID()] = "WaitForGas"; orderName[HarvestGas.getID()] = "HarvestGas"; orderName[ReturnGas.getID()] = "ReturnGas"; orderName[MoveToMinerals.getID()] = "MoveToMinerals"; orderName[WaitForMinerals.getID()] = "WaitForMinerals"; orderName[MiningMinerals.getID()] = "MiningMinerals"; orderName[Harvest3.getID()] = "Harvest3"; orderName[Harvest4.getID()] = "Harvest4"; orderName[ReturnMinerals.getID()] = "ReturnMinerals"; orderName[Interrupted.getID()] = "Interrupted"; orderName[EnterTransport.getID()] = "EnterTransport"; orderName[PickupIdle.getID()] = "PickupIdle"; orderName[PickupTransport.getID()] = "PickupTransport"; orderName[PickupBunker.getID()] = "PickupBunker"; orderName[Pickup4.getID()] = "Pickup4"; orderName[PowerupIdle.getID()] = "PowerupIdle"; orderName[Sieging.getID()] = "Sieging"; orderName[Unsieging.getID()] = "Unsieging"; orderName[InitCreepGrowth.getID()] = "InitCreepGrowth"; orderName[SpreadCreep.getID()] = "SpreadCreep"; orderName[StoppingCreepGrowth.getID()] = "StoppingCreepGrowth"; orderName[GuardianAspect.getID()] = "GuardianAspect"; orderName[ArchonWarp.getID()] = "ArchonWarp"; orderName[CompletingArchonsummon.getID()] = "CompletingArchonsummon"; orderName[HoldPosition.getID()] = "HoldPosition"; orderName[Cloak.getID()] = "Cloak"; orderName[Decloak.getID()] = "Decloak"; orderName[Unload.getID()] = "Unload"; orderName[MoveUnload.getID()] = "MoveUnload"; orderName[FireYamatoGun.getID()] = "FireYamatoGun"; orderName[CastLockdown.getID()] = "CastLockdown"; orderName[Burrowing.getID()] = "Burrowing"; orderName[Burrowed.getID()] = "Burrowed"; orderName[Unburrowing.getID()] = "Unburrowing"; orderName[CastDarkSwarm.getID()] = "CastDarkSwarm"; orderName[CastParasite.getID()] = "CastParasite"; orderName[CastSpawnBroodlings.getID()] = "CastSpawnBroodlings"; orderName[CastEMPShockwave.getID()] = "CastEMPShockwave"; orderName[NukeWait.getID()] = "NukeWait"; orderName[NukeTrain.getID()] = "NukeTrain"; orderName[NukeLaunch.getID()] = "NukeLaunch"; orderName[NukeUnit.getID()] = "NukeUnit"; orderName[CastNuclearStrike.getID()] = "CastNuclearStrike"; orderName[NukeTrack.getID()] = "NukeTrack"; orderName[CloakNearbyUnits.getID()] = "CloakNearbyUnits"; orderName[PlaceMine.getID()] = "PlaceMine"; orderName[RightClickAction.getID()] = "RightClickAction"; orderName[CastRecall.getID()] = "CastRecall"; orderName[TeleporttoLocation.getID()] = "TeleporttoLocation"; orderName[CastScannerSweep.getID()] = "CastScannerSweep"; orderName[Scanner.getID()] = "Scanner"; orderName[CastDefensiveMatrix.getID()] = "CastDefensiveMatrix"; orderName[CastPsionicStorm.getID()] = "CastPsionicStorm"; orderName[CastIrradiate.getID()] = "CastIrradiate"; orderName[CastPlague.getID()] = "CastPlague"; orderName[CastConsume.getID()] = "CastConsume"; orderName[CastEnsnare.getID()] = "CastEnsnare"; orderName[CastStasisField.getID()] = "CastStasisField"; orderName[CastHallucination.getID()] = "CastHallucination"; orderName[Hallucination2.getID()] = "Hallucination2"; orderName[ResetCollision.getID()] = "ResetCollision"; orderName[Patrol.getID()] = "Patrol"; orderName[CTFCOPInit.getID()] = "CTFCOPInit"; orderName[CTFCOP1.getID()] = "CTFCOP1"; orderName[CTFCOP2.getID()] = "CTFCOP2"; orderName[ComputerAI.getID()] = "ComputerAI"; orderName[AtkMoveEP.getID()] = "AtkMoveEP"; orderName[HarassMove.getID()] = "HarassMove"; orderName[AIPatrol.getID()] = "AIPatrol"; orderName[GuardPost.getID()] = "GuardPost"; orderName[RescuePassive.getID()] = "RescuePassive"; orderName[Neutral.getID()] = "Neutral"; orderName[ComputerReturn.getID()] = "ComputerReturn"; orderName[SelfDestrucing.getID()] = "SelfDestrucing"; orderName[Critter.getID()] = "Critter"; orderName[HiddenGun.getID()] = "HiddenGun"; orderName[OpenDoor.getID()] = "OpenDoor"; orderName[CloseDoor.getID()] = "CloseDoor"; orderName[HideTrap.getID()] = "HideTrap"; orderName[RevealTrap.getID()] = "RevealTrap"; orderName[Enabledoodad.getID()] = "Enabledoodad"; orderName[Disabledoodad.getID()] = "Disabledoodad"; orderName[Warpin.getID()] = "Warpin"; orderName[Medic.getID()] = "Medic"; orderName[MedicHeal1.getID()] = "MedicHeal1"; orderName[HealMove.getID()] = "HealMove"; orderName[MedicHeal2.getID()] = "MedicHeal2"; orderName[CastRestoration.getID()] = "CastRestoration"; orderName[CastDisruptionWeb.getID()] = "CastDisruptionWeb"; orderName[CastMindControl.getID()] = "CastMindControl"; orderName[DarkArchonMeld.getID()] = "DarkArchonMeld"; orderName[CastFeedback.getID()] = "CastFeedback"; orderName[CastOpticalFlare.getID()] = "CastOpticalFlare"; orderName[CastMaelstrom.getID()] = "CastMaelstrom"; orderName[JunkYardDog.getID()] = "JunkYardDog"; orderName[Fatal.getID()] = "Fatal"; orderName[None.getID()] = "None"; orderName[Unknown.getID()] = "Unknown"; orderSet.insert(Die); orderSet.insert(Stop); orderSet.insert(Guard); orderSet.insert(PlayerGuard); orderSet.insert(TurretGuard); orderSet.insert(BunkerGuard); orderSet.insert(Move); orderSet.insert(AttackUnit); orderSet.insert(AttackTile); orderSet.insert(Hover); orderSet.insert(AttackMove); orderSet.insert(InfestedCommandCenter); orderSet.insert(UnusedNothing); orderSet.insert(UnusedPowerup); orderSet.insert(TowerGuard); orderSet.insert(VultureMine); orderSet.insert(Nothing); orderSet.insert(Nothing3); orderSet.insert(CastInfestation); orderSet.insert(InfestingCommandCenter); orderSet.insert(PlaceBuilding); orderSet.insert(BuildProtoss2); orderSet.insert(ConstructingBuilding); orderSet.insert(Repair); orderSet.insert(PlaceAddon); orderSet.insert(BuildAddon); orderSet.insert(Train); orderSet.insert(RallyPointUnit); orderSet.insert(RallyPointTile); orderSet.insert(ZergBirth); orderSet.insert(ZergUnitMorph); orderSet.insert(ZergBuildingMorph); orderSet.insert(IncompleteBuilding); orderSet.insert(BuildNydusExit); orderSet.insert(EnterNydusCanal); orderSet.insert(Follow); orderSet.insert(Carrier); orderSet.insert(ReaverCarrierMove); orderSet.insert(CarrierIgnore2); orderSet.insert(Reaver); orderSet.insert(TrainFighter); orderSet.insert(InterceptorAttack); orderSet.insert(ScarabAttack); orderSet.insert(RechargeShieldsUnit); orderSet.insert(RechargeShieldsBattery); orderSet.insert(ShieldBattery); orderSet.insert(InterceptorReturn); orderSet.insert(BuildingLand); orderSet.insert(BuildingLiftOff); orderSet.insert(DroneLiftOff); orderSet.insert(LiftingOff); orderSet.insert(ResearchTech); orderSet.insert(Upgrade); orderSet.insert(Larva); orderSet.insert(SpawningLarva); orderSet.insert(Harvest1); orderSet.insert(Harvest2); orderSet.insert(MoveToGas); orderSet.insert(WaitForGas); orderSet.insert(HarvestGas); orderSet.insert(ReturnGas); orderSet.insert(MoveToMinerals); orderSet.insert(WaitForMinerals); orderSet.insert(MiningMinerals); orderSet.insert(Harvest3); orderSet.insert(Harvest4); orderSet.insert(ReturnMinerals); orderSet.insert(Interrupted); orderSet.insert(EnterTransport); orderSet.insert(PickupIdle); orderSet.insert(PickupTransport); orderSet.insert(PickupBunker); orderSet.insert(Pickup4); orderSet.insert(PowerupIdle); orderSet.insert(Sieging); orderSet.insert(Unsieging); orderSet.insert(InitCreepGrowth); orderSet.insert(SpreadCreep); orderSet.insert(StoppingCreepGrowth); orderSet.insert(GuardianAspect); orderSet.insert(ArchonWarp); orderSet.insert(CompletingArchonsummon); orderSet.insert(HoldPosition); orderSet.insert(Cloak); orderSet.insert(Decloak); orderSet.insert(Unload); orderSet.insert(MoveUnload); orderSet.insert(FireYamatoGun); orderSet.insert(CastLockdown); orderSet.insert(Burrowing); orderSet.insert(Burrowed); orderSet.insert(Unburrowing); orderSet.insert(CastDarkSwarm); orderSet.insert(CastParasite); orderSet.insert(CastSpawnBroodlings); orderSet.insert(CastEMPShockwave); orderSet.insert(NukeWait); orderSet.insert(NukeTrain); orderSet.insert(NukeLaunch); orderSet.insert(NukeUnit); orderSet.insert(CastNuclearStrike); orderSet.insert(NukeTrack); orderSet.insert(CloakNearbyUnits); orderSet.insert(PlaceMine); orderSet.insert(RightClickAction); orderSet.insert(CastRecall); orderSet.insert(TeleporttoLocation); orderSet.insert(CastScannerSweep); orderSet.insert(Scanner); orderSet.insert(CastDefensiveMatrix); orderSet.insert(CastPsionicStorm); orderSet.insert(CastIrradiate); orderSet.insert(CastPlague); orderSet.insert(CastConsume); orderSet.insert(CastEnsnare); orderSet.insert(CastStasisField); orderSet.insert(CastHallucination); orderSet.insert(Hallucination2); orderSet.insert(ResetCollision); orderSet.insert(Patrol); orderSet.insert(CTFCOPInit); orderSet.insert(CTFCOP1); orderSet.insert(CTFCOP2); orderSet.insert(ComputerAI); orderSet.insert(AtkMoveEP); orderSet.insert(HarassMove); orderSet.insert(AIPatrol); orderSet.insert(GuardPost); orderSet.insert(RescuePassive); orderSet.insert(Neutral); orderSet.insert(ComputerReturn); orderSet.insert(SelfDestrucing); orderSet.insert(Critter); orderSet.insert(HiddenGun); orderSet.insert(OpenDoor); orderSet.insert(CloseDoor); orderSet.insert(HideTrap); orderSet.insert(RevealTrap); orderSet.insert(Enabledoodad); orderSet.insert(Disabledoodad); orderSet.insert(Warpin); orderSet.insert(Medic); orderSet.insert(MedicHeal1); orderSet.insert(HealMove); orderSet.insert(MedicHeal2); orderSet.insert(CastRestoration); orderSet.insert(CastDisruptionWeb); orderSet.insert(CastMindControl); orderSet.insert(DarkArchonMeld); orderSet.insert(CastFeedback); orderSet.insert(CastOpticalFlare); orderSet.insert(CastMaelstrom); orderSet.insert(JunkYardDog); orderSet.insert(Fatal); orderSet.insert(None); orderSet.insert(Unknown); foreach(Order i, orderSet) { std::string name = i.getName(); fixName(&name); orderMap.insert(std::make_pair(name, i)); } initializingOrder = false; } } Order::Order() { this->id = Orders::None.id; } Order::Order(int id) { this->id = id; if (!initializingOrder && (id < 0 || id >= 191 || orderName[id].length() == 0)) this->id = Orders::Unknown.id; } Order::Order(const Order& other) { this->id = other.id; } Order& Order::operator=(const Order& other) { this->id = other.id; return *this; } bool Order::operator==(const Order& other) const { return this->id == other.id; } bool Order::operator!=(const Order& other) const { return this->id != other.id; } bool Order::operator<(const Order& other) const { return this->id < other.id; } int Order::getID() const { return this->id; } std::string Order::getName() const { return orderName[this->id]; } Order Orders::getOrder(std::string name) { fixName(&name); std::map::iterator i = orderMap.find(name); if (i == orderMap.end()) return Orders::Unknown; return (*i).second; } std::set& Orders::allOrders() { return orderSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/PlayerType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingPlayerType = true; std::string playerTypeName[13]; std::map playerTypeMap; std::set< PlayerType > playerTypeSet; namespace PlayerTypes { const PlayerType None(0); const PlayerType Computer(1); const PlayerType Player(2); const PlayerType RescuePassive(3); const PlayerType EitherPreferComputer(5); const PlayerType EitherPreferHuman(6); const PlayerType Neutral(7); const PlayerType Closed(8); const PlayerType PlayerLeft(10); const PlayerType ComputerLeft(11); const PlayerType Unknown(12); void init() { playerTypeName[None.getID()] = "None"; playerTypeName[Computer.getID()] = "Computer"; playerTypeName[Player.getID()] = "Player"; playerTypeName[RescuePassive.getID()] = "RescuePassive"; playerTypeName[EitherPreferComputer.getID()] = "EitherPreferComputer"; playerTypeName[EitherPreferHuman.getID()] = "EitherPreferHuman"; playerTypeName[Neutral.getID()] = "Neutral"; playerTypeName[Closed.getID()] = "Closed"; playerTypeName[PlayerLeft.getID()] = "PlayerLeft"; playerTypeName[ComputerLeft.getID()] = "ComputerLeft"; playerTypeName[Unknown.getID()] = "Unknown"; playerTypeSet.insert(None); playerTypeSet.insert(Computer); playerTypeSet.insert(Player); playerTypeSet.insert(RescuePassive); playerTypeSet.insert(EitherPreferComputer); playerTypeSet.insert(EitherPreferHuman); playerTypeSet.insert(Neutral); playerTypeSet.insert(Closed); playerTypeSet.insert(PlayerLeft); playerTypeSet.insert(ComputerLeft); playerTypeSet.insert(Unknown); foreach(PlayerType i, playerTypeSet) { std::string name = i.getName(); fixName(&name); playerTypeMap.insert(std::make_pair(name, i)); } initializingPlayerType = false; } } PlayerType::PlayerType() { this->id = PlayerTypes::None.id; } PlayerType::PlayerType(int id) { this->id = id; if (!initializingPlayerType && (id < 0 || id >= 13 || playerTypeName[id].length() == 0) ) this->id = PlayerTypes::Unknown.id; } PlayerType::PlayerType(const PlayerType& other) { this->id = other.id; } PlayerType& PlayerType::operator=(const PlayerType& other) { this->id = other.id; return *this; } bool PlayerType::operator==(const PlayerType& other) const { return this->id == other.id; } bool PlayerType::operator!=(const PlayerType& other) const { return this->id != other.id; } bool PlayerType::operator<(const PlayerType& other) const { return this->id < other.id; } int PlayerType::getID() const { return this->id; } std::string PlayerType::getName() const { return playerTypeName[this->id]; } PlayerType PlayerTypes::getPlayerType(std::string name) { fixName(&name); std::map::iterator i = playerTypeMap.find(name); if (i == playerTypeMap.end()) return PlayerTypes::Unknown; return (*i).second; } std::set& PlayerTypes::allPlayerTypes() { return playerTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Position.cpp ================================================ #include #include #include #include #include #include namespace BWAPI { namespace Positions { const Position Invalid(32000, 32000); const Position None(32000, 32032); const Position Unknown(32000, 32064); } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Position::Position() : _x(0) , _y(0) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Position::Position(const TilePosition& position) : _x(position.x()*TILE_SIZE) , _y(position.y()*TILE_SIZE) { } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- Position::Position(int x, int y) : _x(x) , _y(y) { } //---------------------------------------------- OPERATOR == ----------------------------------------------- bool Position::operator == (const Position& position) const { return this->x() == position.x() && this->y() == position.y(); } //---------------------------------------------- OPERATOR != ----------------------------------------------- bool Position::operator != (const Position& position) const { return this->x() != position.x() || this->y() != position.y(); } //---------------------------------------------- OPERATOR < ------------------------------------------------ bool Position::operator < (const Position& position) const { return this->x() < position.x() || (this->x() == position.x() && this->y() < position.y()); } //---------------------------------------------- IS VALID -------------------------------------------------- bool Position::isValid() const { return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth()*32 && _y < Broodwar->mapHeight()*32); } //---------------------------------------------------------------------------------------------------------- Position Position::operator+(const Position& position) const { return Position(this->x() + position.x(), this->y() + position.y()); } //---------------------------------------------------------------------------------------------------------- Position Position::operator-(const Position& position) const { return Position(this->x() - position.x(), this->y() - position.y()); } //-------------------------------------------- MAKE VALID -------------------------------------------------- Position& Position::makeValid() { if (_x > Broodwar->mapWidth()*32 - 1) _x = Broodwar->mapWidth()*32 - 1; if (_y > Broodwar->mapHeight()*32 - 1) _y = Broodwar->mapHeight()*32 - 1; if (_x < 0) _x = 0; if (_y < 0) _y = 0; return *this; } //---------------------------------------------------------------------------------------------------------- Position& Position::operator+=(const Position& position) { this->x() += position.x(); this->y() += position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- Position& Position::operator-=(const Position& position) { this->x() -= position.x(); this->y() -= position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- double Position::getDistance(const Position& position) const { return ((*this) - position).getLength(); } //---------------------------------------------------------------------------------------------------------- double Position::getApproxDistance(const Position& position) const { double min = abs(this->x() - position.x()); double max = abs(this->y() - position.y()); if (max < min) { double temp = min; min = max; max = temp; } if (min < max*0.25) return max; return min*0.4 + max*0.9; } //---------------------------------------------------------------------------------------------------------- double Position::getLength() const { double x = this->x(); double y = this->y(); return sqrt(x * x + y * y); } //---------------------------------------------------------------------------------------------------------- int& Position::x() { return this->_x; } //---------------------------------------------------------------------------------------------------------- int& Position::y() { return this->_y; } //---------------------------------------------------------------------------------------------------------- int Position::x() const { return this->_x; } //---------------------------------------------------------------------------------------------------------- int Position::y() const { return this->_y; } //---------------------------------------------------------------------------------------------------------- }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Race.cpp ================================================ #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingRace = true; class RaceInternal { public: void set(const char* name, UnitType worker, UnitType center, UnitType refinery, UnitType transport, UnitType supplyProvider) { if (initializingRace) { this->name = name; this->worker = worker; this->center = center; this->refinery = refinery; this->transport = transport; this->supplyProvider = supplyProvider; } } std::string name; UnitType worker; UnitType center; UnitType refinery; UnitType transport; UnitType supplyProvider; }; RaceInternal raceData[7]; std::map raceMap; std::set< Race > raceSet; namespace Races { const Race Zerg(0); const Race Terran(1); const Race Protoss(2); const Race Random(3); const Race Other(4); const Race None(5); const Race Unknown(6); void init() { raceData[Zerg.getID()].set( "Zerg", UnitTypes::Zerg_Drone, UnitTypes::Zerg_Hatchery, UnitTypes::Zerg_Extractor, UnitTypes::Zerg_Overlord, UnitTypes::Zerg_Overlord); raceData[Terran.getID()].set( "Terran", UnitTypes::Terran_SCV, UnitTypes::Terran_Command_Center, UnitTypes::Terran_Refinery, UnitTypes::Terran_Dropship, UnitTypes::Terran_Supply_Depot); raceData[Protoss.getID()].set("Protoss", UnitTypes::Protoss_Probe, UnitTypes::Protoss_Nexus, UnitTypes::Protoss_Assimilator, UnitTypes::Protoss_Shuttle, UnitTypes::Protoss_Pylon); raceData[Random.getID()].set( "Random", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceData[Other.getID()].set( "Other", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceData[None.getID()].set( "None", UnitTypes::None, UnitTypes::None, UnitTypes::None, UnitTypes::None, UnitTypes::None); raceData[Unknown.getID()].set("Unknown", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceSet.insert(Zerg); raceSet.insert(Terran); raceSet.insert(Protoss); raceSet.insert(Other); raceSet.insert(None); raceSet.insert(Unknown); foreach(Race i, raceSet) { std::string name = i.getName(); fixName(&name); raceMap.insert(std::make_pair(name, i)); } initializingRace = false; } } Race::Race() { this->id = Races::None.id; } Race::Race(int id) { this->id = id; if (!initializingRace && (id < 0 || id >= 7) ) this->id = Races::Unknown.id; } Race::Race(const Race& other) { this->id = other.id; } Race& Race::operator=(const Race& other) { this->id = other.id; return *this; } bool Race::operator==(const Race& other) const { return this->id == other.id; } bool Race::operator!=(const Race& other) const { return this->id != other.id; } bool Race::operator<(const Race& other) const { return this->id < other.id; } int Race::getID() const { return this->id; } std::string Race::getName() const { return raceData[this->id].name; } UnitType Race::getWorker() const { return raceData[this->id].worker; } UnitType Race::getCenter() const { return raceData[this->id].center; } UnitType Race::getRefinery() const { return raceData[this->id].refinery; } UnitType Race::getTransport() const { return raceData[this->id].transport; } UnitType Race::getSupplyProvider() const { return raceData[this->id].supplyProvider; } Race Races::getRace(std::string name) { fixName(&name); std::map::iterator i = raceMap.find(name); if (i == raceMap.end()) return Races::Unknown; return (*i).second; } std::set& Races::allRaces() { return raceSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/TechType.cpp ================================================ #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingTechType = true; class TechTypeInternal { public: TechTypeInternal() {valid = false;} void set(const char* name, int mineralPrice, int gasPrice, int researchTime, int energyUsed, UnitType whatResearches, Race race, WeaponType weapon, UnitType whatUses1, UnitType whatUses2=UnitTypes::None, UnitType whatUses3=UnitTypes::None, UnitType whatUses4=UnitTypes::None, UnitType whatUses5=UnitTypes::None, UnitType whatUses6=UnitTypes::None) { this->name = name; this->mineralPrice = mineralPrice; this->gasPrice = gasPrice; this->researchTime = researchTime; this->energyUsed = energyUsed; this->whatResearches = whatResearches; this->race = race; this->weapon = weapon; if (whatUses1 != UnitTypes::None) this->whatUses.insert(whatUses1); if (whatUses2 != UnitTypes::None) this->whatUses.insert(whatUses2); if (whatUses3 != UnitTypes::None) this->whatUses.insert(whatUses3); if (whatUses4 != UnitTypes::None) this->whatUses.insert(whatUses4); if (whatUses5 != UnitTypes::None) this->whatUses.insert(whatUses5); if (whatUses6 != UnitTypes::None) this->whatUses.insert(whatUses6); this->valid = true; } std::string name; int mineralPrice; int gasPrice; int researchTime; int energyUsed; UnitType whatResearches; Race race; WeaponType weapon; std::set whatUses; bool valid; }; TechTypeInternal techTypeData[47]; std::map techTypeMap; std::set< TechType > techTypeSet; namespace TechTypes { const TechType Stim_Packs(0); const TechType Lockdown(1); const TechType EMP_Shockwave(2); const TechType Spider_Mines(3); const TechType Scanner_Sweep(4); const TechType Tank_Siege_Mode(5); const TechType Defensive_Matrix(6); const TechType Irradiate(7); const TechType Yamato_Gun(8); const TechType Cloaking_Field(9); const TechType Personnel_Cloaking(10); const TechType Burrowing(11); const TechType Infestation(12); const TechType Spawn_Broodlings(13); const TechType Dark_Swarm(14); const TechType Plague(15); const TechType Consume(16); const TechType Ensnare(17); const TechType Parasite(18); const TechType Psionic_Storm(19); const TechType Hallucination(20); const TechType Recall(21); const TechType Stasis_Field(22); const TechType Archon_Warp(23); const TechType Restoration(24); const TechType Disruption_Web(25); const TechType Mind_Control(27); const TechType Dark_Archon_Meld(28); const TechType Feedback(29); const TechType Optical_Flare(30); const TechType Maelstrom(31); const TechType Lurker_Aspect(32); const TechType Healing(34); const TechType None(44); const TechType Unknown(45); const TechType Nuclear_Strike(46); void init() { techTypeData[Stim_Packs.getID()].set("Stim Packs" ,100,100,1200,0 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Marine, UnitTypes::Terran_Firebat, UnitTypes::Hero_Jim_Raynor_Marine, UnitTypes::Hero_Gui_Montag); techTypeData[Lockdown.getID()].set("Lockdown" ,200,200,1500,100,UnitTypes::Terran_Covert_Ops ,Races::Terran ,WeaponTypes::Lockdown ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan); techTypeData[EMP_Shockwave.getID()].set("EMP Shockwave" ,200,200,1800,100,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::EMP_Shockwave ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Spider_Mines.getID()].set("Spider Mines" ,100,100,1200,0 ,UnitTypes::Terran_Machine_Shop ,Races::Terran ,WeaponTypes::Spider_Mines ,UnitTypes::Terran_Vulture, UnitTypes::Hero_Jim_Raynor_Vulture); techTypeData[Scanner_Sweep.getID()].set("Scanner Sweep" ,0 ,0 ,0 ,50 ,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Comsat_Station); techTypeData[Tank_Siege_Mode.getID()].set("Tank Siege Mode" ,150,150,1200,0 ,UnitTypes::Terran_Machine_Shop ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Siege_Tank_Tank_Mode, UnitTypes::Terran_Siege_Tank_Siege_Mode, UnitTypes::Hero_Edmund_Duke_Tank_Mode, UnitTypes::Hero_Edmund_Duke_Siege_Mode); techTypeData[Defensive_Matrix.getID()].set("Defensive Matrix" ,0 ,0 ,0 ,100,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Irradiate.getID()].set("Irradiate" ,200,200,1200,75 ,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::Irradiate ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Yamato_Gun.getID()].set("Yamato Gun" ,100,100,1800,150,UnitTypes::Terran_Physics_Lab ,Races::Terran ,WeaponTypes::Yamato_Gun ,UnitTypes::Terran_Battlecruiser, UnitTypes::Hero_Gerard_DuGalle, UnitTypes::Hero_Hyperion, UnitTypes::Hero_Norad_II); techTypeData[Cloaking_Field.getID()].set("Cloaking Field" ,150,150,1500,25 ,UnitTypes::Terran_Control_Tower ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Wraith, UnitTypes::Hero_Tom_Kazansky); techTypeData[Personnel_Cloaking.getID()].set("Personnel Cloaking",100,100,1200,25 ,UnitTypes::Terran_Covert_Ops ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan, UnitTypes::Hero_Infested_Kerrigan); techTypeData[Burrowing.getID()].set("Burrowing" ,100,100,1200,0 ,UnitTypes::Zerg_Hatchery ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Drone, UnitTypes::Zerg_Zergling, UnitTypes::Zerg_Hydralisk, UnitTypes::Zerg_Defiler, UnitTypes::Zerg_Infested_Terran, UnitTypes::Zerg_Lurker); techTypeData[Infestation.getID()].set("Infestation" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Spawn_Broodlings.getID()].set("Spawn Broodlings" ,100,100,1200,150,UnitTypes::Zerg_Queens_Nest ,Races::Zerg ,WeaponTypes::Spawn_Broodlings,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Dark_Swarm.getID()].set("Dark Swarm" ,0 ,0 ,0 ,100,UnitTypes::None ,Races::Zerg ,WeaponTypes::Dark_Swarm ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Plague.getID()].set("Plague" ,200,200,1500,150,UnitTypes::Zerg_Defiler_Mound ,Races::Zerg ,WeaponTypes::Plague ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Consume.getID()].set("Consume" ,100,100,1500,0 ,UnitTypes::Zerg_Defiler_Mound ,Races::Zerg ,WeaponTypes::Consume ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Ensnare.getID()].set("Ensnare" ,100,100,1200,75 ,UnitTypes::Zerg_Queens_Nest ,Races::Zerg ,WeaponTypes::Ensnare ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Parasite.getID()].set("Parasite" ,0 ,0 ,0 ,75 ,UnitTypes::None ,Races::Zerg ,WeaponTypes::Parasite ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Psionic_Storm.getID()].set("Psionic Storm" ,200,200,1800,75 ,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Psionic_Storm ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar); techTypeData[Hallucination.getID()].set("Hallucination" ,150,150,1200,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar); techTypeData[Recall.getID()].set("Recall" ,150,150,1800,150,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth); techTypeData[Stasis_Field.getID()].set("Stasis Field" ,150,150,1500,100,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::Stasis_Field ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth); techTypeData[Archon_Warp.getID()].set("Archon Warp" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_High_Templar); techTypeData[Restoration.getID()].set("Restoration" ,100,100,1200,50 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::Restoration ,UnitTypes::Terran_Medic); techTypeData[Disruption_Web.getID()].set("Disruption Web" ,200,200,1200,125,UnitTypes::Protoss_Fleet_Beacon ,Races::Protoss,WeaponTypes::Disruption_Web ,UnitTypes::Protoss_Corsair, UnitTypes::Hero_Raszagal); techTypeData[Mind_Control.getID()].set("Mind Control" ,200,200,1800,150,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Mind_Control ,UnitTypes::Protoss_Dark_Archon); techTypeData[Dark_Archon_Meld.getID()].set("Dark Archon Meld" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_Dark_Templar); techTypeData[Feedback.getID()].set("Feedback" ,0 ,0 ,0 ,50 ,UnitTypes::None ,Races::Protoss,WeaponTypes::Feedback ,UnitTypes::Protoss_Dark_Archon); techTypeData[Optical_Flare.getID()].set("Optical Flare" ,100,100,1800,75 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::Optical_Flare ,UnitTypes::Terran_Medic); techTypeData[Maelstrom.getID()].set("Maelstrom" ,100,100,1500,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Maelstrom ,UnitTypes::Protoss_Dark_Archon); techTypeData[Lurker_Aspect.getID()].set("Lurker Aspect" ,200,200,1800,0 ,UnitTypes::Zerg_Hydralisk_Den ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Lurker); techTypeData[Healing.getID()].set("Healing" ,0 ,0 ,0 ,1 ,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Medic); techTypeData[None.getID()].set("None" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::None ,WeaponTypes::None ,UnitTypes::None); techTypeData[Unknown.getID()].set("Unknown" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Unknown,WeaponTypes::None ,UnitTypes::None); techTypeData[Nuclear_Strike.getID()].set("Nuclear Strike" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Terran ,WeaponTypes::Nuclear_Strike ,UnitTypes::Terran_Ghost); techTypeSet.insert(Stim_Packs); techTypeSet.insert(Lockdown); techTypeSet.insert(EMP_Shockwave); techTypeSet.insert(Spider_Mines); techTypeSet.insert(Scanner_Sweep); techTypeSet.insert(Tank_Siege_Mode); techTypeSet.insert(Defensive_Matrix); techTypeSet.insert(Irradiate); techTypeSet.insert(Yamato_Gun); techTypeSet.insert(Cloaking_Field); techTypeSet.insert(Personnel_Cloaking); techTypeSet.insert(Burrowing); techTypeSet.insert(Infestation); techTypeSet.insert(Spawn_Broodlings); techTypeSet.insert(Dark_Swarm); techTypeSet.insert(Plague); techTypeSet.insert(Consume); techTypeSet.insert(Ensnare); techTypeSet.insert(Parasite); techTypeSet.insert(Psionic_Storm); techTypeSet.insert(Hallucination); techTypeSet.insert(Recall); techTypeSet.insert(Stasis_Field); techTypeSet.insert(Archon_Warp); techTypeSet.insert(Restoration); techTypeSet.insert(Disruption_Web); techTypeSet.insert(Mind_Control); techTypeSet.insert(Dark_Archon_Meld); techTypeSet.insert(Feedback); techTypeSet.insert(Optical_Flare); techTypeSet.insert(Maelstrom); techTypeSet.insert(Lurker_Aspect); techTypeSet.insert(Healing); techTypeSet.insert(None); techTypeSet.insert(Unknown); techTypeSet.insert(Nuclear_Strike); foreach(TechType i, techTypeSet) { std::string name = i.getName(); fixName(&name); techTypeMap.insert(std::make_pair(name, i)); } initializingTechType = false; } } TechType::TechType() { this->id = TechTypes::None.id; } TechType::TechType(int id) { this->id = id; if (!initializingTechType && (id < 0 || id >= 47 || techTypeData[id].name.length() == 0)) this->id = TechTypes::Unknown.id; } TechType::TechType(const TechType& other) { this->id = other.id; } TechType& TechType::operator=(const TechType& other) { this->id = other.id; return *this; } bool TechType::operator==(const TechType& other) const { return this->id == other.id; } bool TechType::operator!=(const TechType& other) const { return this->id != other.id; } bool TechType::operator<(const TechType& other) const { return this->id < other.id; } int TechType::getID() const { return this->id; } std::string TechType::getName() const { return techTypeData[this->id].name; } Race TechType::getRace() const { return techTypeData[this->id].race; } int TechType::mineralPrice() const { return techTypeData[this->id].mineralPrice; } int TechType::gasPrice() const { return techTypeData[this->id].gasPrice; } int TechType::researchTime() const { return techTypeData[this->id].researchTime; } int TechType::energyUsed() const { return techTypeData[this->id].energyUsed; } UnitType TechType::whatResearches() const { return techTypeData[this->id].whatResearches; } WeaponType TechType::getWeapon() const { return techTypeData[this->id].weapon; } const std::set& TechType::whatUses() const { return techTypeData[this->id].whatUses; } TechType TechTypes::getTechType(std::string name) { fixName(&name); std::map::iterator i = techTypeMap.find(name); if (i == techTypeMap.end()) return TechTypes::Unknown; return (*i).second; } std::set& TechTypes::allTechTypes() { return techTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/TilePosition.cpp ================================================ #include #include #include #include #include namespace BWAPI { namespace TilePositions { const TilePosition Invalid(1000, 1000); const TilePosition None(1000, 1001); const TilePosition Unknown(1000, 1002); } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition() : _x(0) , _y(0) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition(int x, int y) : _x(x) , _y(y) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition(const Position& position) : _x(position.x() / TILE_SIZE) , _y(position.y() / TILE_SIZE) { } //---------------------------------------------- OPERATOR == ----------------------------------------------- bool TilePosition::operator == (const TilePosition& TilePosition) const { return this->x() == TilePosition.x() && this->y() == TilePosition.y(); } //---------------------------------------------- OPERATOR != ----------------------------------------------- bool TilePosition::operator != (const TilePosition& TilePosition) const { return this->x() != TilePosition.x() || this->y() != TilePosition.y(); } //---------------------------------------------- OPERATOR < ------------------------------------------------ bool TilePosition::operator < (const TilePosition& TilePosition) const { return this->x() < TilePosition.x() || (this->x() == TilePosition.x() && this->y() < TilePosition.y()); } //---------------------------------------------- IS VALID -------------------------------------------------- bool TilePosition::isValid() const { return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth() && _y < Broodwar->mapHeight()); } //---------------------------------------------------------------------------------------------------------- TilePosition TilePosition::operator+(const TilePosition& position) const { return TilePosition(this->x() + position.x(), this->y() + position.y()); } //---------------------------------------------------------------------------------------------------------- TilePosition TilePosition::operator-(const TilePosition& position) const { return TilePosition(this->x() - position.x(), this->y() - position.y()); } //-------------------------------------------- MAKE VALID -------------------------------------------------- TilePosition& TilePosition::makeValid() { if (_x > Broodwar->mapWidth() - 1) _x = Broodwar->mapWidth() - 1; if (_y > Broodwar->mapHeight() - 1) _y = Broodwar->mapHeight() - 1; if (_x < 0) _x = 0; if (_y < 0) _y = 0; return *this; } //---------------------------------------------------------------------------------------------------------- TilePosition& TilePosition::operator+=(const TilePosition& position) { this->x() += position.x(); this->y() += position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- TilePosition& TilePosition::operator-=(const TilePosition& position) { this->x() -= position.x(); this->y() -= position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- double TilePosition::getDistance(const TilePosition& position) const { return ((*this) - position).getLength(); } //---------------------------------------------------------------------------------------------------------- double TilePosition::getLength() const { double x = this->x(); double y = this->y(); return sqrt(x * x + y * y); } //---------------------------------------------------------------------------------------------------------- int& TilePosition::x() { return this->_x; } //---------------------------------------------------------------------------------------------------------- int& TilePosition::y() { return this->_y; } //---------------------------------------------------------------------------------------------------------- int TilePosition::x() const { return this->_x; } //---------------------------------------------------------------------------------------------------------- int TilePosition::y() const { return this->_y; } //---------------------------------------------------------------------------------------------------------- }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/UnitCommandType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitCommandType = true; std::string unitCommandTypeName[45]; std::map unitCommandTypeMap; std::set< UnitCommandType > unitCommandTypeSet; namespace UnitCommandTypes { const UnitCommandType Attack_Move(0); const UnitCommandType Attack_Unit(1); const UnitCommandType Build(2); const UnitCommandType Build_Addon(3); const UnitCommandType Train(4); const UnitCommandType Morph(5); const UnitCommandType Research(6); const UnitCommandType Upgrade(7); const UnitCommandType Set_Rally_Position(8); const UnitCommandType Set_Rally_Unit(9); const UnitCommandType Move(10); const UnitCommandType Patrol(11); const UnitCommandType Hold_Position(12); const UnitCommandType Stop(13); const UnitCommandType Follow(14); const UnitCommandType Gather(15); const UnitCommandType Return_Cargo(16); const UnitCommandType Repair(17); const UnitCommandType Burrow(18); const UnitCommandType Unburrow(19); const UnitCommandType Cloak(20); const UnitCommandType Decloak(21); const UnitCommandType Siege(22); const UnitCommandType Unsiege(23); const UnitCommandType Lift(24); const UnitCommandType Land(25); const UnitCommandType Load(26); const UnitCommandType Unload(27); const UnitCommandType Unload_All(28); const UnitCommandType Unload_All_Position(29); const UnitCommandType Right_Click_Position(30); const UnitCommandType Right_Click_Unit(31); const UnitCommandType Halt_Construction(32); const UnitCommandType Cancel_Construction(33); const UnitCommandType Cancel_Addon(34); const UnitCommandType Cancel_Train(35); const UnitCommandType Cancel_Train_Slot(36); const UnitCommandType Cancel_Morph(37); const UnitCommandType Cancel_Research(38); const UnitCommandType Cancel_Upgrade(39); const UnitCommandType Use_Tech(40); const UnitCommandType Use_Tech_Position(41); const UnitCommandType Use_Tech_Unit(42); const UnitCommandType None(43); const UnitCommandType Unknown(44); void init() { unitCommandTypeName[Attack_Move.getID()] = "Attack Move"; unitCommandTypeName[Attack_Unit.getID()] = "Attack Unit"; unitCommandTypeName[Build.getID()] = "Build"; unitCommandTypeName[Build_Addon.getID()] = "Build Addon"; unitCommandTypeName[Train.getID()] = "Train"; unitCommandTypeName[Morph.getID()] = "Morph"; unitCommandTypeName[Research.getID()] = "Research"; unitCommandTypeName[Upgrade.getID()] = "Upgrade"; unitCommandTypeName[Set_Rally_Position.getID()] = "Set Rally Position"; unitCommandTypeName[Set_Rally_Unit.getID()] = "Set Rally Unit"; unitCommandTypeName[Move.getID()] = "Move"; unitCommandTypeName[Patrol.getID()] = "Patrol"; unitCommandTypeName[Hold_Position.getID()] = "Hold Position"; unitCommandTypeName[Stop.getID()] = "Stop"; unitCommandTypeName[Follow.getID()] = "Follow"; unitCommandTypeName[Gather.getID()] = "Gather"; unitCommandTypeName[Return_Cargo.getID()] = "Return Cargo"; unitCommandTypeName[Repair.getID()] = "Repair"; unitCommandTypeName[Burrow.getID()] = "Burrow"; unitCommandTypeName[Unburrow.getID()] = "Unburrow"; unitCommandTypeName[Cloak.getID()] = "Cloak"; unitCommandTypeName[Decloak.getID()] = "Decloak"; unitCommandTypeName[Siege.getID()] = "Siege"; unitCommandTypeName[Unsiege.getID()] = "Unsiege"; unitCommandTypeName[Lift.getID()] = "Lift"; unitCommandTypeName[Land.getID()] = "Land"; unitCommandTypeName[Load.getID()] = "Load"; unitCommandTypeName[Unload.getID()] = "Unload"; unitCommandTypeName[Unload_All.getID()] = "Unload All"; unitCommandTypeName[Unload_All_Position.getID()] = "Unload All Position"; unitCommandTypeName[Right_Click_Position.getID()] = "Right Click Position"; unitCommandTypeName[Right_Click_Unit.getID()] = "Right Click Unit"; unitCommandTypeName[Halt_Construction.getID()] = "Halt Construction"; unitCommandTypeName[Cancel_Construction.getID()] = "Cancel Construction"; unitCommandTypeName[Cancel_Addon.getID()] = "Cancel Addon"; unitCommandTypeName[Cancel_Train.getID()] = "Cancel Train"; unitCommandTypeName[Cancel_Train_Slot.getID()] = "Cancel Train Slot"; unitCommandTypeName[Cancel_Morph.getID()] = "Cancel Morph"; unitCommandTypeName[Cancel_Research.getID()] = "Cancel Research"; unitCommandTypeName[Cancel_Upgrade.getID()] = "Cancel Upgrade"; unitCommandTypeName[Use_Tech.getID()] = "Use Tech"; unitCommandTypeName[Use_Tech_Position.getID()] = "Use Tech Position"; unitCommandTypeName[Use_Tech_Unit.getID()] = "Use Tech Unit"; unitCommandTypeName[None.getID()] = "None"; unitCommandTypeName[Unknown.getID()] = "Unknown"; unitCommandTypeSet.insert(Attack_Move); unitCommandTypeSet.insert(Attack_Unit); unitCommandTypeSet.insert(Build); unitCommandTypeSet.insert(Build_Addon); unitCommandTypeSet.insert(Train); unitCommandTypeSet.insert(Morph); unitCommandTypeSet.insert(Research); unitCommandTypeSet.insert(Upgrade); unitCommandTypeSet.insert(Set_Rally_Position); unitCommandTypeSet.insert(Set_Rally_Unit); unitCommandTypeSet.insert(Move); unitCommandTypeSet.insert(Patrol); unitCommandTypeSet.insert(Hold_Position); unitCommandTypeSet.insert(Stop); unitCommandTypeSet.insert(Follow); unitCommandTypeSet.insert(Gather); unitCommandTypeSet.insert(Return_Cargo); unitCommandTypeSet.insert(Repair); unitCommandTypeSet.insert(Burrow); unitCommandTypeSet.insert(Unburrow); unitCommandTypeSet.insert(Cloak); unitCommandTypeSet.insert(Decloak); unitCommandTypeSet.insert(Siege); unitCommandTypeSet.insert(Unsiege); unitCommandTypeSet.insert(Lift); unitCommandTypeSet.insert(Land); unitCommandTypeSet.insert(Load); unitCommandTypeSet.insert(Unload); unitCommandTypeSet.insert(Unload_All); unitCommandTypeSet.insert(Unload_All_Position); unitCommandTypeSet.insert(Right_Click_Position); unitCommandTypeSet.insert(Right_Click_Unit); unitCommandTypeSet.insert(Halt_Construction); unitCommandTypeSet.insert(Cancel_Construction); unitCommandTypeSet.insert(Cancel_Addon); unitCommandTypeSet.insert(Cancel_Train); unitCommandTypeSet.insert(Cancel_Train_Slot); unitCommandTypeSet.insert(Cancel_Morph); unitCommandTypeSet.insert(Cancel_Research); unitCommandTypeSet.insert(Cancel_Upgrade); unitCommandTypeSet.insert(Use_Tech); unitCommandTypeSet.insert(Use_Tech_Position); unitCommandTypeSet.insert(Use_Tech_Unit); unitCommandTypeSet.insert(None); unitCommandTypeSet.insert(Unknown); foreach(UnitCommandType i, unitCommandTypeSet) { std::string name = i.getName(); fixName(&name); unitCommandTypeMap.insert(std::make_pair(name, i)); } initializingUnitCommandType = false; } } UnitCommandType::UnitCommandType() { this->id = UnitCommandTypes::None.id; } UnitCommandType::UnitCommandType(int id) { this->id = id; if (!initializingUnitCommandType && (id < 0 || id >= 45)) this->id = UnitCommandTypes::Unknown.id; } UnitCommandType::UnitCommandType(const UnitCommandType& other) { this->id = other.id; } UnitCommandType& UnitCommandType::operator=(const UnitCommandType& other) { this->id = other.id; return *this; } bool UnitCommandType::operator==(const UnitCommandType& other) const { return this->id == other.id; } bool UnitCommandType::operator!=(const UnitCommandType& other) const { return this->id != other.id; } bool UnitCommandType::operator<(const UnitCommandType& other) const { return this->id < other.id; } int UnitCommandType::getID() const { return this->id; } std::string UnitCommandType::getName() const { return unitCommandTypeName[this->id]; } UnitCommandType UnitCommandTypes::getUnitCommandType(std::string name) { fixName(&name); std::map::iterator i = unitCommandTypeMap.find(name); if (i == unitCommandTypeMap.end()) return UnitCommandTypes::Unknown; return (*i).second; } std::set& UnitCommandTypes::allUnitCommandTypes() { return unitCommandTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/UnitSizeType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitSizeType = true; std::string unitSizeTypeName[6]; std::map unitSizeTypeMap; std::set< UnitSizeType > unitSizeTypeSet; namespace UnitSizeTypes { const UnitSizeType Independent(0); const UnitSizeType Small(1); const UnitSizeType Medium(2); const UnitSizeType Large(3); const UnitSizeType None(4); const UnitSizeType Unknown(5); void init() { unitSizeTypeName[Independent.getID()] = "Independent"; unitSizeTypeName[Small.getID()] = "Small"; unitSizeTypeName[Medium.getID()] = "Medium"; unitSizeTypeName[Large.getID()] = "Large"; unitSizeTypeName[None.getID()] = "None"; unitSizeTypeName[Unknown.getID()] = "Unknown"; unitSizeTypeSet.insert(Independent); unitSizeTypeSet.insert(Small); unitSizeTypeSet.insert(Medium); unitSizeTypeSet.insert(Large); unitSizeTypeSet.insert(None); unitSizeTypeSet.insert(Unknown); foreach(UnitSizeType i, unitSizeTypeSet) { std::string name = i.getName(); fixName(&name); unitSizeTypeMap.insert(std::make_pair(name, i)); } initializingUnitSizeType = false; } } UnitSizeType::UnitSizeType() { this->id = UnitSizeTypes::None.id; } UnitSizeType::UnitSizeType(int id) { this->id = id; if (!initializingUnitSizeType && (id < 0 || id >= 6)) this->id = UnitSizeTypes::Unknown.id; } UnitSizeType::UnitSizeType(const UnitSizeType& other) { this->id = other.id; } UnitSizeType& UnitSizeType::operator=(const UnitSizeType& other) { this->id = other.id; return *this; } bool UnitSizeType::operator==(const UnitSizeType& other) const { return this->id == other.id; } bool UnitSizeType::operator!=(const UnitSizeType& other) const { return this->id != other.id; } bool UnitSizeType::operator<(const UnitSizeType& other) const { return this->id < other.id; } int UnitSizeType::getID() const { return this->id; } std::string UnitSizeType::getName() const { return unitSizeTypeName[this->id]; } UnitSizeType UnitSizeTypes::getUnitSizeType(std::string name) { fixName(&name); std::map::iterator i = unitSizeTypeMap.find(name); if (i == unitSizeTypeMap.end()) return UnitSizeTypes::Unknown; return (*i).second; } std::set& UnitSizeTypes::allUnitSizeTypes() { return unitSizeTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/UnitType.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitType = true; class UnitTypeInternal { public: UnitTypeInternal() {valid = false;} void set(const char* name, Race race, bool isHero, UnitType whatBuilds, int whatBuildsAmt, UnitType requiredUnit1, UnitType requiredUnit2, TechType requiredTech, TechType ability1, TechType ability2, TechType ability3, TechType ability4, UpgradeType armorUpgrade, int maxHitPoints, int maxShields, int maxEnergy, int armor, int mineralPrice, int gasPrice, int buildTime, int supplyRequired, int supplyProvided, int spaceRequired, int spaceProvided, int buildScore, int destroyScore, UnitSizeType unitSizeType, int tileWidth, int tileHeight, int dimensionLeft, int dimensionUp, int dimensionRight, int dimensionDown, int seekRange, int sightRange, WeaponType groundWeapon, int maxGroundHits, WeaponType airWeapon, int maxAirHits, double topSpeed, int acceleration, int haltDistance, int turnRadius, bool canProduce, bool canMove, bool isFlyer, bool regeneratesHP, bool hasPermanentCloak, bool isInvincible, bool isOrganic, bool isMechanical, bool isRobotic, bool isDetector, bool isResourceContainer, bool isResourceDepot, bool isWorker, bool requiresPsi, bool requiresCreep, bool isTwoUnitsInOneEgg, bool isBurrowable, bool isCloakable, bool isBuilding, bool isAddon, bool isFlyingBuilding, bool isNeutral, bool isRefinery) { if (initializingUnitType) { this->name = name; this->race = race; this->isHero = isHero; this->whatBuilds = std::make_pair(whatBuilds, whatBuildsAmt); if ( whatBuilds != UnitTypes::None && whatBuildsAmt > 0 ) this->requiredUnits.insert(this->whatBuilds); if ( requiredUnit1 != UnitTypes::None ) this->requiredUnits.insert(std::make_pair(requiredUnit1, 1)); if ( requiredUnit2 != UnitTypes::None ) this->requiredUnits.insert(std::make_pair(requiredUnit2, 1)); this->requiredTech = requiredTech; if (ability1 != TechTypes::None) this->abilities.insert(ability1); if (ability2 != TechTypes::None) this->abilities.insert(ability2); if (ability3 != TechTypes::None) this->abilities.insert(ability3); if (ability4 != TechTypes::None) this->abilities.insert(ability4); this->cloakingTech = TechTypes::None; if ( this->abilities.find(TechTypes::Cloaking_Field) != this->abilities.end() ) cloakingTech = TechTypes::Cloaking_Field; if ( this->abilities.find(TechTypes::Personnel_Cloaking) != this->abilities.end() ) cloakingTech = TechTypes::Personnel_Cloaking; this->armorUpgrade = armorUpgrade; this->maxHitPoints = maxHitPoints; this->maxShields = maxShields; this->maxEnergy = maxEnergy; this->armor = armor; this->mineralPrice = mineralPrice; this->gasPrice = gasPrice; this->buildTime = buildTime; this->supplyRequired = supplyRequired; this->supplyProvided = supplyProvided; this->spaceRequired = spaceRequired; this->spaceProvided = spaceProvided; this->buildScore = buildScore; this->destroyScore = destroyScore; this->unitSizeType = unitSizeType; this->tileWidth = tileWidth; this->tileHeight = tileHeight; this->dimensionLeft = dimensionLeft; this->dimensionUp = dimensionUp; this->dimensionRight = dimensionRight; this->dimensionDown = dimensionDown; this->seekRange = seekRange; this->sightRange = sightRange; this->groundWeapon = groundWeapon; this->maxGroundHits = maxGroundHits; this->airWeapon = airWeapon; this->maxAirHits = maxAirHits; this->topSpeed = topSpeed; this->acceleration = acceleration; this->haltDistance = haltDistance; this->turnRadius = turnRadius; this->canProduce = canProduce; this->canAttack = groundWeapon != WeaponTypes::None || airWeapon != WeaponTypes::None; this->canMove = canMove; this->isFlyer = isFlyer; this->regeneratesHP = regeneratesHP; this->isSpellcaster = maxEnergy > 0; this->hasPermanentCloak = hasPermanentCloak; this->isInvincible = isInvincible; this->isOrganic = isOrganic; this->isMechanical = isMechanical; this->isRobotic = isRobotic; this->isDetector = isDetector; this->isResourceContainer = isResourceContainer; this->isResourceDepot = isResourceDepot; this->isWorker = isWorker; this->requiresPsi = requiresPsi; this->requiresCreep = requiresCreep; this->isTwoUnitsInOneEgg = isTwoUnitsInOneEgg; this->isBurrowable = isBurrowable; this->isCloakable = isCloakable; this->isBuilding = isBuilding; this->isAddon = isAddon; this->isFlyingBuilding = isFlyingBuilding; this->isNeutral = isNeutral; this->isRefinery = isRefinery; this->isSpecialBuilding = this->isBuilding && this->whatBuilds.second == 0; this->valid = true; } } std::string name; Race race; std::pair whatBuilds; std::map requiredUnits; TechType requiredTech; TechType cloakingTech; std::set abilities; std::set upgrades; UpgradeType armorUpgrade; int maxHitPoints; int maxShields; int maxEnergy; int armor; int mineralPrice; int gasPrice; int buildTime; int supplyRequired; int supplyProvided; int spaceRequired; int spaceProvided; int buildScore; int destroyScore; UnitSizeType unitSizeType; int tileWidth; int tileHeight; int dimensionLeft; int dimensionUp; int dimensionRight; int dimensionDown; int seekRange; int sightRange; WeaponType groundWeapon; int maxGroundHits; WeaponType airWeapon; int maxAirHits; double topSpeed; int acceleration; int haltDistance; int turnRadius; bool canProduce; bool canAttack; bool canMove; bool isFlyer; bool regeneratesHP; bool isSpellcaster; bool hasPermanentCloak; bool isInvincible; bool isOrganic; bool isMechanical; bool isRobotic; bool isDetector; bool isResourceContainer; bool isResourceDepot; bool isWorker; bool requiresPsi; bool requiresCreep; bool isTwoUnitsInOneEgg; bool isBurrowable; bool isCloakable; bool isBuilding; bool isAddon; bool isFlyingBuilding; bool isNeutral; bool isRefinery; bool isHero; bool isSpecialBuilding; bool valid; }; UnitTypeInternal unitTypeData[245]; std::map unitTypeMap; std::set< UnitType > unitTypeSet; namespace UnitTypes { const UnitType Terran_Marine(0); const UnitType Hero_Jim_Raynor_Marine(20); const UnitType Terran_Ghost(1); const UnitType Hero_Sarah_Kerrigan(16); const UnitType Hero_Samir_Duran(99); const UnitType Hero_Infested_Duran(104); const UnitType Hero_Alexei_Stukov(100); const UnitType Terran_Vulture(2); const UnitType Hero_Jim_Raynor_Vulture(19); const UnitType Terran_Goliath(3); const UnitType Hero_Alan_Schezar(17); const UnitType Terran_Siege_Tank_Tank_Mode(5); const UnitType Hero_Edmund_Duke_Tank_Mode(23); const UnitType Terran_SCV(7); const UnitType Terran_Wraith(8); const UnitType Hero_Tom_Kazansky(21); const UnitType Terran_Science_Vessel(9); const UnitType Hero_Magellan(22); const UnitType Terran_Dropship(11); const UnitType Terran_Battlecruiser(12); const UnitType Hero_Arcturus_Mengsk(27); const UnitType Hero_Hyperion(28); const UnitType Hero_Norad_II(29); const UnitType Hero_Gerard_DuGalle(102); const UnitType Terran_Vulture_Spider_Mine(13); const UnitType Terran_Nuclear_Missile(14); const UnitType Terran_Siege_Tank_Siege_Mode(30); const UnitType Hero_Edmund_Duke_Siege_Mode(25); const UnitType Terran_Firebat(32); const UnitType Hero_Gui_Montag(10); const UnitType Spell_Scanner_Sweep(33); const UnitType Terran_Medic(34); const UnitType Terran_Civilian(15); const UnitType Zerg_Larva(35); const UnitType Zerg_Egg(36); const UnitType Zerg_Zergling(37); const UnitType Hero_Devouring_One(54); const UnitType Hero_Infested_Kerrigan(51); const UnitType Zerg_Hydralisk(38); const UnitType Hero_Hunter_Killer(53); const UnitType Zerg_Ultralisk(39); const UnitType Hero_Torrasque(48); const UnitType Zerg_Broodling(40); const UnitType Zerg_Drone(41); const UnitType Zerg_Overlord(42); const UnitType Hero_Yggdrasill(57); const UnitType Zerg_Mutalisk(43); const UnitType Hero_Kukulza_Mutalisk(55); const UnitType Zerg_Guardian(44); const UnitType Hero_Kukulza_Guardian(56); const UnitType Zerg_Queen(45); const UnitType Hero_Matriarch(49); const UnitType Zerg_Defiler(46); const UnitType Hero_Unclean_One(52); const UnitType Zerg_Scourge(47); const UnitType Zerg_Infested_Terran(50); const UnitType Terran_Valkyrie(58); const UnitType Zerg_Cocoon(59); const UnitType Protoss_Corsair(60); const UnitType Hero_Raszagal(98); const UnitType Protoss_Dark_Templar(61); const UnitType Hero_Dark_Templar(74); const UnitType Hero_Zeratul(75); const UnitType Zerg_Devourer(62); const UnitType Protoss_Dark_Archon(63); const UnitType Protoss_Probe(64); const UnitType Protoss_Zealot(65); const UnitType Hero_Fenix_Zealot(77); const UnitType Protoss_Dragoon(66); const UnitType Hero_Fenix_Dragoon(78); const UnitType Protoss_High_Templar(67); const UnitType Hero_Tassadar(79); const UnitType Hero_Aldaris(87); const UnitType Protoss_Archon(68); const UnitType Hero_Tassadar_Zeratul_Archon(76); const UnitType Protoss_Shuttle(69); const UnitType Protoss_Scout(70); const UnitType Hero_Mojo(80); const UnitType Hero_Artanis(88); const UnitType Protoss_Arbiter(71); const UnitType Hero_Danimoth(86); const UnitType Protoss_Carrier(72); const UnitType Hero_Gantrithor(82); const UnitType Protoss_Interceptor(73); const UnitType Protoss_Reaver(83); const UnitType Hero_Warbringer(81); const UnitType Protoss_Observer(84); const UnitType Protoss_Scarab(85); const UnitType Critter_Rhynadon(89); const UnitType Critter_Bengalaas(90); const UnitType Critter_Scantid(93); const UnitType Critter_Kakaru(94); const UnitType Critter_Ragnasaur(95); const UnitType Critter_Ursadon(96); const UnitType Zerg_Lurker_Egg(97); const UnitType Zerg_Lurker(103); const UnitType Spell_Disruption_Web(105); const UnitType Terran_Command_Center(106); const UnitType Terran_Comsat_Station(107); const UnitType Terran_Nuclear_Silo(108); const UnitType Terran_Supply_Depot(109); const UnitType Terran_Refinery(110); const UnitType Terran_Barracks(111); const UnitType Terran_Academy(112); const UnitType Terran_Factory(113); const UnitType Terran_Starport(114); const UnitType Terran_Control_Tower(115); const UnitType Terran_Science_Facility(116); const UnitType Terran_Covert_Ops(117); const UnitType Terran_Physics_Lab(118); const UnitType Terran_Machine_Shop(120); const UnitType Terran_Engineering_Bay(122); const UnitType Terran_Armory(123); const UnitType Terran_Missile_Turret(124); const UnitType Terran_Bunker(125); const UnitType Special_Crashed_Norad_II(126); const UnitType Special_Ion_Cannon(127); const UnitType Zerg_Infested_Command_Center(130); const UnitType Zerg_Hatchery(131); const UnitType Zerg_Lair(132); const UnitType Zerg_Hive(133); const UnitType Zerg_Nydus_Canal(134); const UnitType Zerg_Hydralisk_Den(135); const UnitType Zerg_Defiler_Mound(136); const UnitType Zerg_Greater_Spire(137); const UnitType Zerg_Queens_Nest(138); const UnitType Zerg_Evolution_Chamber(139); const UnitType Zerg_Ultralisk_Cavern(140); const UnitType Zerg_Spire(141); const UnitType Zerg_Spawning_Pool(142); const UnitType Zerg_Creep_Colony(143); const UnitType Zerg_Spore_Colony(144); const UnitType Zerg_Sunken_Colony(146); const UnitType Special_Overmind_With_Shell(147); const UnitType Special_Overmind(148); const UnitType Zerg_Extractor(149); const UnitType Special_Mature_Chrysalis(150); const UnitType Special_Cerebrate(151); const UnitType Special_Cerebrate_Daggoth(152); const UnitType Protoss_Nexus(154); const UnitType Protoss_Robotics_Facility(155); const UnitType Protoss_Pylon(156); const UnitType Protoss_Assimilator(157); const UnitType Protoss_Observatory(159); const UnitType Protoss_Gateway(160); const UnitType Protoss_Photon_Cannon(162); const UnitType Protoss_Citadel_of_Adun(163); const UnitType Protoss_Cybernetics_Core(164); const UnitType Protoss_Templar_Archives(165); const UnitType Protoss_Forge(166); const UnitType Protoss_Stargate(167); const UnitType Special_Stasis_Cell_Prison(168); const UnitType Protoss_Fleet_Beacon(169); const UnitType Protoss_Arbiter_Tribunal(170); const UnitType Protoss_Robotics_Support_Bay(171); const UnitType Protoss_Shield_Battery(172); const UnitType Special_Khaydarin_Crystal_Form(173); const UnitType Special_Protoss_Temple(174); const UnitType Special_XelNaga_Temple(175); const UnitType Resource_Mineral_Field(176); const UnitType Resource_Vespene_Geyser(188); const UnitType Special_Warp_Gate(189); const UnitType Special_Psi_Disrupter(190); const UnitType Special_Power_Generator(200); const UnitType Special_Overmind_Cocoon(201); const UnitType Special_Zerg_Beacon(194); const UnitType Special_Terran_Beacon(195); const UnitType Special_Protoss_Beacon(196); const UnitType Special_Zerg_Flag_Beacon(197); const UnitType Special_Terran_Flag_Beacon(198); const UnitType Special_Protoss_Flag_Beacon(199); const UnitType Spell_Dark_Swarm(202); const UnitType Powerup_Uraj_Crystal(128); const UnitType Powerup_Khalis_Crystal(129); const UnitType Powerup_Flag(215); const UnitType Powerup_Young_Chrysalis(216); const UnitType Powerup_Psi_Emitter(217); const UnitType Powerup_Data_Disk(218); const UnitType Powerup_Khaydarin_Crystal(219); const UnitType None(228); const UnitType Unknown(229); void init() { unitTypeData[Terran_Marine.getID()].set("Terran Marine", Races::Terran, 0, Terran_Barracks, 1, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 50, 0, 360, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle, 1, WeaponTypes::Gauss_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Jim_Raynor_Marine.getID()].set("Hero Jim Raynor Marine", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 0, 3, 50, 0, 1, 0, 0, 1, 0, 0, 200, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Ghost.getID()].set("Terran Ghost", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, Terran_Covert_Ops, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Nuclear_Strike, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 45, 0, 200, 0, 25, 75, 750, 2, 0, 1, 0, 175, 350, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 288, WeaponTypes::C_10_Canister_Rifle, 1, WeaponTypes::C_10_Canister_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Sarah_Kerrigan.getID()].set("Hero Sarah Kerrigan", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 50, 150, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Samir_Duran.getID()].set("Hero Samir Duran", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 250, 2, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 320, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Infested_Duran.getID()].set("Hero Infested Duran", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Consume, TechTypes::None, UpgradeTypes::Zerg_Carapace, 300, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Alexei_Stukov.getID()].set("Hero Alexei Stukov", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Terran_Vulture.getID()].set("Terran Vulture", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 80, 0, 0, 0, 75, 0, 450, 4, 0, 2, 0, 75, 150, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Jim_Raynor_Vulture.getID()].set("Hero Jim Raynor Vulture", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 150, 0, 900, 0, 0, 2, 0, 0, 300, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade_Jim_Raynor, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Goliath.getID()].set("Terran Goliath", Races::Terran, 0, Terran_Factory, 1, Terran_Armory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 125, 0, 0, 1, 100, 50, 600, 4, 0, 2, 0, 200, 400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons, 1, WeaponTypes::Hellfire_Missile_Pack, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Alan_Schezar.getID()].set("Hero Alan Schezar", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 200, 100, 1200, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons_Alan_Schezar, 1, WeaponTypes::Hellfire_Missile_Pack_Alan_Schezar, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Siege_Tank_Tank_Mode.getID()].set("Terran Siege Tank Tank Mode", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 4, 0, 350, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Edmund_Duke_Tank_Mode.getID()].set("Hero Edmund Duke Tank Mode", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 4, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_SCV.getID()].set("Terran SCV", Races::Terran, 0, Terran_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Fusion_Cutter, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Wraith.getID()].set("Terran Wraith", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 120, 0, 200, 0, 150, 100, 900, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers, 1, WeaponTypes::Gemini_Missiles, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Tom_Kazansky.getID()].set("Hero Tom Kazansky", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 250, 4, 400, 200, 1800, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers_Tom_Kazansky, 1, WeaponTypes::Gemini_Missiles_Tom_Kazansky, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Terran_Science_Vessel.getID()].set("Terran Science Vessel", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Science_Facility, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 200, 1, 100, 225, 1200, 4, 0, 255, 0, 625, 1250, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Magellan.getID()].set("Hero Magellan", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 800, 0, 250, 4, 50, 600, 2400, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Dropship.getID()].set("Terran Dropship", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 150, 0, 0, 1, 100, 100, 750, 4, 0, 255, 8, 300, 600, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 5.47, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Battlecruiser.getID()].set("Terran Battlecruiser", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Physics_Lab, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 200, 3, 400, 300, 2000, 12, 0, 255, 0, 1200, 2400, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery, 1, WeaponTypes::ATA_Laser_Battery, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Arcturus_Mengsk.getID()].set("Hero Arcturus Mengsk", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 1000, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 256, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Hyperion.getID()].set("Hero Hyperion", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 850, 0, 250, 4, 800, 600, 2400, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hyperion, 1, WeaponTypes::ATA_Laser_Battery_Hyperion, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Norad_II.getID()].set("Hero Norad II", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gerard_DuGalle.getID()].set("Hero Gerard DuGalle", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Vulture_Spider_Mine.getID()].set("Terran Vulture Spider Mine", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 20, 0, 0, 0, 1, 0, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 7, 7, 7, 7, 96, 96, WeaponTypes::Spider_Mines, 1, WeaponTypes::None, 0, 16, 1, 1, 127, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Nuclear_Missile.getID()].set("Terran Nuclear Missile", Races::Terran, 0, Terran_Nuclear_Silo, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 0, 0, 0, 200, 200, 1500, 16, 0, 255, 0, 800, 0, UnitSizeTypes::Independent, 1, 1, 7, 14, 7, 14, 0, 96, WeaponTypes::None, 0, WeaponTypes::None, 0, 33.33, 33, 1103213, 127, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Siege_Tank_Siege_Mode.getID()].set("Terran Siege Tank Siege Mode", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 255, 0, 0, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Edmund_Duke_Siege_Mode.getID()].set("Hero Edmund Duke Siege Mode", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 255, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Firebat.getID()].set("Terran Firebat", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 50, 0, 0, 1, 50, 25, 360, 2, 0, 1, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gui_Montag.getID()].set("Hero Gui Montag", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 160, 0, 0, 3, 100, 50, 720, 0, 0, 1, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower_Gui_Montag, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Spell_Scanner_Sweep.getID()].set("Spell Scanner Sweep", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 13, 13, 13, 17, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Medic.getID()].set("Terran Medic", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Restoration, TechTypes::Optical_Flare, TechTypes::Healing, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 200, 1, 50, 25, 450, 2, 0, 1, 0, 125, 250, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 288, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Civilian.getID()].set("Terran Civilian", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Larva.getID()].set("Zerg Larva", Races::Zerg, 0, Zerg_Hatchery, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 25, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 1, 1, 20, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Egg.getID()].set("Zerg Egg", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Zergling.getID()].set("Zerg Zergling", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 35, 0, 0, 0, 50, 0, 420, 1, 0, 1, 0, 25, 50, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Devouring_One.getID()].set("Hero Devouring One", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 120, 0, 0, 3, 100, 0, 840, 0, 0, 1, 0, 0, 100, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws_Devouring_One, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Infested_Kerrigan.getID()].set("Hero Infested Kerrigan", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Personnel_Cloaking, TechTypes::Ensnare, TechTypes::Psionic_Storm, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 400, 0, 250, 2, 200, 300, 1500, 0, 0, 1, 0, 0, 4000, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 96, 288, WeaponTypes::Claws_Infested_Kerrigan, 1, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Zerg_Hydralisk.getID()].set("Zerg Hydralisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Hydralisk_Den, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 80, 0, 0, 0, 75, 25, 420, 2, 0, 2, 0, 125, 350, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 192, WeaponTypes::Needle_Spines, 1, WeaponTypes::Needle_Spines, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Hunter_Killer.getID()].set("Hero Hunter Killer", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 160, 0, 0, 2, 150, 50, 780, 0, 0, 2, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 256, WeaponTypes::Needle_Spines_Hunter_Killer, 1, WeaponTypes::Needle_Spines_Hunter_Killer, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Ultralisk.getID()].set("Zerg Ultralisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Ultralisk_Cavern, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 400, 0, 0, 1, 200, 200, 900, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Torrasque.getID()].set("Hero Torrasque", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 800, 0, 0, 4, 400, 400, 1800, 0, 0, 4, 0, 0, 2600, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades_Torrasque, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Broodling.getID()].set("Zerg Broodling", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 30, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 9, 9, 9, 9, 96, 160, WeaponTypes::Toxic_Spores, 1, WeaponTypes::None, 0, 6, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Drone.getID()].set("Zerg Drone", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 40, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Spines, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Overlord.getID()].set("Zerg Overlord", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 200, 0, 0, 0, 100, 0, 600, 0, 16, 255, 8, 100, 200, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Yggdrasill.getID()].set("Hero Yggdrasill", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 1000, 0, 0, 4, 200, 0, 1200, 0, 60, 255, 8, 0, 400, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Mutalisk.getID()].set("Zerg Mutalisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 0, 0, 100, 100, 600, 4, 0, 255, 0, 300, 600, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm, 1, WeaponTypes::Glave_Wurm, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Kukulza_Mutalisk.getID()].set("Hero Kukulza Mutalisk", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 0, 3, 200, 200, 1200, 0, 0, 255, 0, 0, 1200, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm_Kukulza, 1, WeaponTypes::Glave_Wurm_Kukulza, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Guardian.getID()].set("Zerg Guardian", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 150, 0, 0, 2, 50, 100, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Kukulza_Guardian.getID()].set("Hero Kukulza Guardian", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 400, 0, 0, 4, 100, 200, 1200, 0, 0, 255, 0, 0, 2200, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore_Kukulza, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Queen.getID()].set("Zerg Queen", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 200, 0, 100, 100, 750, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Matriarch.getID()].set("Hero Matriarch", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 250, 3, 200, 300, 1500, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Defiler.getID()].set("Zerg Defiler", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Defiler_Mound, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 80, 0, 200, 1, 50, 150, 750, 4, 0, 2, 0, 225, 450, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Unclean_One.getID()].set("Hero Unclean One", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 250, 0, 250, 3, 50, 200, 1500, 0, 0, 2, 0, 0, 900, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Scourge.getID()].set("Zerg Scourge", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 25, 0, 0, 0, 25, 75, 450, 1, 0, 255, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 12, 12, 11, 11, 96, 160, WeaponTypes::None, 0, WeaponTypes::Suicide_Scourge, 1, 6.67, 107, 13616, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Infested_Terran.getID()].set("Zerg Infested Terran", Races::Zerg, 0, Zerg_Infested_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 60, 0, 0, 0, 100, 50, 600, 2, 0, 1, 0, 200, 400, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 96, 160, WeaponTypes::Suicide_Infested_Terran, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Valkyrie.getID()].set("Terran Valkyrie", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Armory, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 0, 2, 250, 125, 750, 6, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 192, 256, WeaponTypes::None, 0, WeaponTypes::Halo_Rockets, 4, 6.6, 65, 21901, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Cocoon.getID()].set("Zerg Cocoon", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 1100, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Corsair.getID()].set("Protoss Corsair", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 80, 200, 1, 150, 100, 600, 4, 0, 255, 0, 350, 700, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Raszagal.getID()].set("Hero Raszagal", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 60, 250, 0, 150, 100, 750, 0, 0, 255, 0, 0, 1300, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dark_Templar.getID()].set("Protoss Dark Templar", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Dark_Archon_Meld, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 40, 0, 1, 125, 100, 750, 4, 0, 2, 0, 325, 650, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Dark_Templar.getID()].set("Hero Dark Templar", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 80, 0, 0, 150, 150, 750, 1, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Hero, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Zeratul.getID()].set("Hero Zeratul", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 60, 400, 0, 0, 100, 300, 1500, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Zeratul, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Devourer.getID()].set("Zerg Devourer", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 250, 0, 0, 2, 150, 50, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 224, 320, WeaponTypes::None, 0, WeaponTypes::Corrosive_Acid, 1, 5, 48, 17067, 30, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dark_Archon.getID()].set("Protoss Dark Archon", Races::Protoss, 0, Protoss_Dark_Templar, 2, None, None, TechTypes::None, TechTypes::Mind_Control, TechTypes::Feedback, TechTypes::Maelstrom, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 25, 200, 200, 1, 0, 0, 300, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 224, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Probe.getID()].set("Protoss Probe", Races::Protoss, 0, Protoss_Nexus, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 20, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 256, WeaponTypes::Particle_Beam, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Zealot.getID()].set("Protoss Zealot", Races::Protoss, 0, Protoss_Gateway, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 60, 0, 1, 100, 0, 600, 4, 0, 2, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Fenix_Zealot.getID()].set("Hero Fenix Zealot", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 2, 200, 0, 1200, 0, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades_Fenix, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dragoon.getID()].set("Protoss Dragoon", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 1, 125, 50, 750, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor, 1, WeaponTypes::Phase_Disruptor, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Fenix_Dragoon.getID()].set("Hero Fenix Dragoon", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 3, 300, 100, 1500, 0, 0, 4, 0, 0, 1000, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor_Fenix, 1, WeaponTypes::Phase_Disruptor_Fenix, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_High_Templar.getID()].set("Protoss High Templar", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::Archon_Warp, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 40, 200, 0, 50, 150, 750, 4, 0, 2, 0, 350, 700, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Tassadar.getID()].set("Hero Tassadar", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Aldaris.getID()].set("Hero Aldaris", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Archon.getID()].set("Protoss Archon", Races::Protoss, 0, Protoss_High_Templar, 2, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 10, 350, 0, 0, 0, 0, 300, 8, 0, 4, 0, 700, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave, 1, WeaponTypes::Psionic_Shockwave, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Tassadar_Zeratul_Archon.getID()].set("Hero Tassadar Zeratul Archon", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 800, 0, 3, 0, 0, 600, 0, 0, 4, 0, 0, 2800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Shuttle.getID()].set("Protoss Shuttle", Races::Protoss, 0, Protoss_Robotics_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 80, 60, 0, 1, 200, 0, 900, 4, 0, 255, 8, 200, 400, UnitSizeTypes::Large, 2, 1, 20, 16, 19, 15, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.43, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Scout.getID()].set("Protoss Scout", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 150, 100, 0, 0, 275, 125, 1200, 6, 0, 255, 0, 650, 1300, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 256, WeaponTypes::Dual_Photon_Blasters, 1, WeaponTypes::Anti_Matter_Missiles, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Mojo.getID()].set("Hero Mojo", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 400, 400, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2600, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Mojo, 1, WeaponTypes::Anti_Matter_Missiles_Mojo, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Artanis.getID()].set("Hero Artanis", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 250, 250, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2400, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Artanis, 1, WeaponTypes::Anti_Matter_Missiles_Artanis, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Arbiter.getID()].set("Protoss Arbiter", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Arbiter_Tribunal, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 200, 150, 200, 1, 100, 350, 2400, 8, 0, 255, 0, 1025, 2050, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon, 1, WeaponTypes::Phase_Disruptor_Cannon, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Danimoth.getID()].set("Hero Danimoth", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 600, 500, 250, 3, 50, 1000, 4800, 0, 0, 255, 0, 0, 4100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Carrier.getID()].set("Protoss Carrier", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Fleet_Beacon, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 300, 150, 0, 4, 350, 250, 2100, 12, 0, 255, 0, 950, 1900, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gantrithor.getID()].set("Hero Gantrithor", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 800, 500, 0, 4, 700, 600, 4200, 0, 0, 255, 0, 0, 3800, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Interceptor.getID()].set("Protoss Interceptor", Races::Protoss, 0, Protoss_Carrier, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 40, 0, 0, 25, 0, 300, 0, 0, 255, 0, 30, 60, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 128, 192, WeaponTypes::Pulse_Cannon, 1, WeaponTypes::Pulse_Cannon, 1, 13.33, 427, 13640, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Reaver.getID()].set("Protoss Reaver", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Robotics_Support_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 0, 200, 100, 1050, 8, 0, 4, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Warbringer.getID()].set("Hero Warbringer", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 200, 400, 0, 3, 400, 200, 1800, 0, 0, 4, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Observer.getID()].set("Protoss Observer", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Observatory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 20, 0, 0, 25, 75, 600, 2, 0, 255, 0, 225, 450, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Scarab.getID()].set("Protoss Scarab", Races::Protoss, 0, Protoss_Reaver, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 10, 0, 0, 15, 0, 105, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Small, 1, 1, 2, 2, 2, 2, 128, 160, WeaponTypes::Scarab, 1, WeaponTypes::None, 0, 16, 1, 1, 27, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Critter_Rhynadon.getID()].set("Critter Rhynadon", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Bengalaas.getID()].set("Critter Bengalaas", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Scantid.getID()].set("Critter Scantid", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Kakaru.getID()].set("Critter Kakaru", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 16, 51200, 14, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Ragnasaur.getID()].set("Critter Ragnasaur", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Ursadon.getID()].set("Critter Ursadon", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Zerg_Lurker_Egg.getID()].set("Zerg Lurker Egg", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Lurker.getID()].set("Zerg Lurker", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 125, 0, 0, 1, 50, 100, 600, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Medium, 1, 1, 15, 15, 16, 16, 192, 256, WeaponTypes::Subterranean_Spines, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Spell_Disruption_Web.getID()].set("Spell Disruption Web", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 250, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 4, 3, 60, 40, 59, 39, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Terran_Command_Center.getID()].set("Terran Command Center", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 400, 0, 1800, 0, 20, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Comsat_Station.getID()].set("Terran Comsat Station", Races::Terran, 0, Terran_Command_Center, 1, Terran_Academy, None, TechTypes::None, TechTypes::Scanner_Sweep, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 200, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Nuclear_Silo.getID()].set("Terran Nuclear Silo", Races::Terran, 0, Terran_Command_Center, 1, Terran_Science_Facility, Terran_Covert_Ops, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 100, 100, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Supply_Depot.getID()].set("Terran Supply Depot", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 100, 0, 600, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 38, 22, 38, 26, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Refinery.getID()].set("Terran Refinery", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 56, 32, 56, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Terran_Barracks.getID()].set("Terran Barracks", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 40, 56, 32, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Academy.getID()].set("Terran Academy", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 44, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Factory.getID()].set("Terran Factory", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 200, 100, 1200, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 56, 40, 56, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Starport.getID()].set("Terran Starport", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1300, 0, 0, 1, 150, 100, 1050, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Control_Tower.getID()].set("Terran Control Tower", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Science_Facility.getID()].set("Terran Science Facility", Races::Terran, 0, Terran_SCV, 1, Terran_Starport, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 150, 900, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 4, 3, 48, 38, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Covert_Ops.getID()].set("Terran Covert Ops", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Physics_Lab.getID()].set("Terran Physics Lab", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Machine_Shop.getID()].set("Terran Machine Shop", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 39, 24, 31, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Engineering_Bay.getID()].set("Terran Engineering Bay", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 125, 0, 900, 0, 0, 255, 0, 65, 195, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Armory.getID()].set("Terran Armory", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 50, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Missile_Turret.getID()].set("Terran Missile Turret", Races::Terran, 0, Terran_SCV, 1, Terran_Engineering_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 0, 0, 0, 75, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 32, 16, 16, 224, 352, WeaponTypes::None, 0, WeaponTypes::Longbolt_Missile, 1, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Bunker.getID()].set("Terran Bunker", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 350, 0, 0, 1, 100, 0, 450, 0, 0, 255, 4, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Crashed_Norad_II.getID()].set("Special Crashed Norad II", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 800, 600, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Ion_Cannon.getID()].set("Special Ion Cannon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 200, 0, 900, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Infested_Command_Center.getID()].set("Zerg Infested Command Center", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 1, 1, 1800, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Zerg_Hatchery.getID()].set("Zerg Hatchery", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 300, 0, 1800, 0, 2, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Lair.getID()].set("Zerg Lair", Races::Zerg, 0, Zerg_Hatchery, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1800, 0, 0, 1, 150, 100, 1500, 0, 2, 255, 0, 100, 1200, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Hive.getID()].set("Zerg Hive", Races::Zerg, 0, Zerg_Lair, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 200, 150, 1800, 0, 2, 255, 0, 100, 1500, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Nydus_Canal.getID()].set("Zerg Nydus Canal", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 150, 0, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Hydralisk_Den.getID()].set("Zerg Hydralisk Den", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 40, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Defiler_Mound.getID()].set("Zerg Defiler Mound", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 100, 900, 0, 0, 255, 0, 150, 450, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 4, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Greater_Spire.getID()].set("Zerg Greater Spire", Races::Zerg, 0, Zerg_Spire, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 100, 150, 1800, 0, 0, 255, 0, 200, 1350, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Queens_Nest.getID()].set("Zerg Queens Nest", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 150, 100, 900, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 38, 28, 32, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Evolution_Chamber.getID()].set("Zerg Evolution Chamber", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 75, 0, 600, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 3, 2, 44, 32, 32, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Ultralisk_Cavern.getID()].set("Zerg Ultralisk Cavern", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 200, 1200, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spire.getID()].set("Zerg Spire", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 200, 150, 1800, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spawning_Pool.getID()].set("Zerg Spawning Pool", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 200, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 3, 2, 36, 28, 40, 18, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Creep_Colony.getID()].set("Zerg Creep Colony", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 75, 0, 300, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spore_Colony.getID()].set("Zerg Spore Colony", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 50, 0, 300, 0, 0, 255, 0, 25, 195, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::None, 0, WeaponTypes::Seeker_Spores, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Sunken_Colony.getID()].set("Zerg Sunken Colony", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 0, 0, 2, 50, 0, 300, 0, 0, 255, 0, 40, 240, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::Subterranean_Tentacle, 1, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind_With_Shell.getID()].set("Special Overmind With Shell", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind.getID()].set("Special Overmind", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Extractor.getID()].set("Zerg Extractor", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 0, 600, 0, 0, 255, 0, 25, 75, UnitSizeTypes::Large, 4, 2, 64, 32, 63, 31, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Special_Mature_Chrysalis.getID()].set("Special Mature Chrysalis", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Cerebrate.getID()].set("Special Cerebrate", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Cerebrate_Daggoth.getID()].set("Special Cerebrate Daggoth", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Nexus.getID()].set("Protoss Nexus", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 750, 0, 1, 400, 0, 1800, 0, 18, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 56, 39, 56, 39, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Robotics_Facility.getID()].set("Protoss Robotics Facility", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 200, 1200, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 3, 2, 36, 16, 40, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Pylon.getID()].set("Protoss Pylon", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 300, 0, 0, 100, 0, 450, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 12, 16, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Assimilator.getID()].set("Protoss Assimilator", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Protoss_Observatory.getID()].set("Protoss Observatory", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 250, 0, 1, 50, 100, 450, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 44, 16, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Gateway.getID()].set("Protoss Gateway", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 0, 900, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 40, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Photon_Cannon.getID()].set("Protoss Photon Cannon", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Forge, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 100, 0, 0, 150, 0, 750, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 20, 16, 20, 16, 224, 352, WeaponTypes::STS_Photon_Cannon, 1, WeaponTypes::STA_Photon_Cannon, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Citadel_of_Adun.getID()].set("Protoss Citadel of Adun", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 900, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 3, 2, 24, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Cybernetics_Core.getID()].set("Protoss Cybernetics Core", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 0, 900, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Templar_Archives.getID()].set("Protoss Templar Archives", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Citadel_of_Adun, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 200, 900, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Forge.getID()].set("Protoss Forge", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 550, 550, 0, 1, 150, 0, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 36, 24, 36, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Stargate.getID()].set("Protoss Stargate", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 600, 0, 1, 150, 150, 1050, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Stasis_Cell_Prison.getID()].set("Special Stasis Cell Prison", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 150, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Fleet_Beacon.getID()].set("Protoss Fleet Beacon", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Stargate, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 300, 200, 900, 0, 0, 255, 0, 350, 1050, UnitSizeTypes::Large, 3, 2, 40, 32, 47, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Arbiter_Tribunal.getID()].set("Protoss Arbiter Tribunal", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 150, 900, 0, 0, 255, 0, 450, 1350, UnitSizeTypes::Large, 3, 2, 44, 28, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Robotics_Support_Bay.getID()].set("Protoss Robotics Support Bay", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 450, 0, 0, 255, 0, 125, 375, UnitSizeTypes::Large, 3, 2, 32, 32, 32, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Shield_Battery.getID()].set("Protoss Shield Battery", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 200, 200, 1, 100, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 16, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Khaydarin_Crystal_Form.getID()].set("Special Khaydarin Crystal Form", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Temple.getID()].set("Special Protoss Temple", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 7, 3, 112, 48, 111, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_XelNaga_Temple.getID()].set("Special XelNaga Temple", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1500, 500, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 5, 4, 80, 34, 79, 63, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Resource_Mineral_Field.getID()].set("Resource Mineral Field", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 2, 1, 32, 16, 31, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); unitTypeData[Resource_Vespene_Geyser.getID()].set("Resource Vespene Geyser", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 4, 2, 64, 32, 63, 31, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); unitTypeData[Special_Warp_Gate.getID()].set("Special Warp Gate", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 600, 200, 2400, 0, 0, 255, 0, 0, 2000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Psi_Disrupter.getID()].set("Special Psi Disrupter", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 1000, 400, 4800, 0, 0, 255, 0, 0, 3600, UnitSizeTypes::Large, 5, 3, 80, 38, 69, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Power_Generator.getID()].set("Special Power Generator", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 1, 200, 50, 2400, 0, 0, 255, 0, 0, 600, UnitSizeTypes::Large, 4, 3, 56, 28, 63, 43, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind_Cocoon.getID()].set("Special Overmind Cocoon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1000, 500, 2400, 0, 0, 255, 0, 0, 4000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Zerg_Beacon.getID()].set("Special Zerg Beacon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Terran_Beacon.getID()].set("Special Terran Beacon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Beacon.getID()].set("Special Protoss Beacon", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Zerg_Flag_Beacon.getID()].set("Special Zerg Flag Beacon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Terran_Flag_Beacon.getID()].set("Special Terran Flag Beacon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Flag_Beacon.getID()].set("Special Protoss Flag Beacon", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Spell_Dark_Swarm.getID()].set("Spell Dark Swarm", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 200, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 5, 5, 80, 80, 79, 79, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Powerup_Uraj_Crystal.getID()].set("Powerup Uraj Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Khalis_Crystal.getID()].set("Powerup Khalis Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Flag.getID()].set("Powerup Flag", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Young_Chrysalis.getID()].set("Powerup Young Chrysalis", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Psi_Emitter.getID()].set("Powerup Psi Emitter", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Data_Disk.getID()].set("Powerup Data Disk", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Khaydarin_Crystal.getID()].set("Powerup Khaydarin Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[None.getID()].set("None", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Unknown.getID()].set("Unknown", Races::Unknown, 0, Unknown, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); foreach(UpgradeType i, UpgradeTypes::allUpgradeTypes()) { foreach (UnitType ut, i.whatUses()) unitTypeData[ut.getID()].upgrades.insert(i); } unitTypeSet.insert(Terran_Marine); unitTypeSet.insert(Hero_Jim_Raynor_Marine); unitTypeSet.insert(Terran_Ghost); unitTypeSet.insert(Hero_Sarah_Kerrigan); unitTypeSet.insert(Hero_Samir_Duran); unitTypeSet.insert(Hero_Infested_Duran); unitTypeSet.insert(Hero_Alexei_Stukov); unitTypeSet.insert(Terran_Vulture); unitTypeSet.insert(Hero_Jim_Raynor_Vulture); unitTypeSet.insert(Terran_Goliath); unitTypeSet.insert(Hero_Alan_Schezar); unitTypeSet.insert(Terran_Siege_Tank_Tank_Mode); unitTypeSet.insert(Hero_Edmund_Duke_Tank_Mode); unitTypeSet.insert(Terran_SCV); unitTypeSet.insert(Terran_Wraith); unitTypeSet.insert(Hero_Tom_Kazansky); unitTypeSet.insert(Terran_Science_Vessel); unitTypeSet.insert(Hero_Magellan); unitTypeSet.insert(Terran_Dropship); unitTypeSet.insert(Terran_Battlecruiser); unitTypeSet.insert(Hero_Arcturus_Mengsk); unitTypeSet.insert(Hero_Hyperion); unitTypeSet.insert(Hero_Norad_II); unitTypeSet.insert(Hero_Gerard_DuGalle); unitTypeSet.insert(Terran_Vulture_Spider_Mine); unitTypeSet.insert(Terran_Nuclear_Missile); unitTypeSet.insert(Terran_Siege_Tank_Siege_Mode); unitTypeSet.insert(Hero_Edmund_Duke_Siege_Mode); unitTypeSet.insert(Terran_Firebat); unitTypeSet.insert(Hero_Gui_Montag); unitTypeSet.insert(Spell_Scanner_Sweep); unitTypeSet.insert(Terran_Medic); unitTypeSet.insert(Terran_Civilian); unitTypeSet.insert(Zerg_Larva); unitTypeSet.insert(Zerg_Egg); unitTypeSet.insert(Zerg_Zergling); unitTypeSet.insert(Hero_Devouring_One); unitTypeSet.insert(Hero_Infested_Kerrigan); unitTypeSet.insert(Zerg_Hydralisk); unitTypeSet.insert(Hero_Hunter_Killer); unitTypeSet.insert(Zerg_Ultralisk); unitTypeSet.insert(Hero_Torrasque); unitTypeSet.insert(Zerg_Broodling); unitTypeSet.insert(Zerg_Drone); unitTypeSet.insert(Zerg_Overlord); unitTypeSet.insert(Hero_Yggdrasill); unitTypeSet.insert(Zerg_Mutalisk); unitTypeSet.insert(Hero_Kukulza_Mutalisk); unitTypeSet.insert(Zerg_Guardian); unitTypeSet.insert(Hero_Kukulza_Guardian); unitTypeSet.insert(Zerg_Queen); unitTypeSet.insert(Hero_Matriarch); unitTypeSet.insert(Zerg_Defiler); unitTypeSet.insert(Hero_Unclean_One); unitTypeSet.insert(Zerg_Scourge); unitTypeSet.insert(Zerg_Infested_Terran); unitTypeSet.insert(Terran_Valkyrie); unitTypeSet.insert(Zerg_Cocoon); unitTypeSet.insert(Protoss_Corsair); unitTypeSet.insert(Hero_Raszagal); unitTypeSet.insert(Protoss_Dark_Templar); unitTypeSet.insert(Hero_Dark_Templar); unitTypeSet.insert(Hero_Zeratul); unitTypeSet.insert(Zerg_Devourer); unitTypeSet.insert(Protoss_Dark_Archon); unitTypeSet.insert(Protoss_Probe); unitTypeSet.insert(Protoss_Zealot); unitTypeSet.insert(Hero_Fenix_Zealot); unitTypeSet.insert(Protoss_Dragoon); unitTypeSet.insert(Hero_Fenix_Dragoon); unitTypeSet.insert(Protoss_High_Templar); unitTypeSet.insert(Hero_Tassadar); unitTypeSet.insert(Hero_Aldaris); unitTypeSet.insert(Protoss_Archon); unitTypeSet.insert(Hero_Tassadar_Zeratul_Archon); unitTypeSet.insert(Protoss_Shuttle); unitTypeSet.insert(Protoss_Scout); unitTypeSet.insert(Hero_Mojo); unitTypeSet.insert(Hero_Artanis); unitTypeSet.insert(Protoss_Arbiter); unitTypeSet.insert(Hero_Danimoth); unitTypeSet.insert(Protoss_Carrier); unitTypeSet.insert(Hero_Gantrithor); unitTypeSet.insert(Protoss_Interceptor); unitTypeSet.insert(Protoss_Reaver); unitTypeSet.insert(Hero_Warbringer); unitTypeSet.insert(Protoss_Observer); unitTypeSet.insert(Protoss_Scarab); unitTypeSet.insert(Critter_Rhynadon); unitTypeSet.insert(Critter_Bengalaas); unitTypeSet.insert(Critter_Scantid); unitTypeSet.insert(Critter_Kakaru); unitTypeSet.insert(Critter_Ragnasaur); unitTypeSet.insert(Critter_Ursadon); unitTypeSet.insert(Zerg_Lurker_Egg); unitTypeSet.insert(Zerg_Lurker); unitTypeSet.insert(Spell_Disruption_Web); unitTypeSet.insert(Terran_Command_Center); unitTypeSet.insert(Terran_Comsat_Station); unitTypeSet.insert(Terran_Nuclear_Silo); unitTypeSet.insert(Terran_Supply_Depot); unitTypeSet.insert(Terran_Refinery); unitTypeSet.insert(Terran_Barracks); unitTypeSet.insert(Terran_Academy); unitTypeSet.insert(Terran_Factory); unitTypeSet.insert(Terran_Starport); unitTypeSet.insert(Terran_Control_Tower); unitTypeSet.insert(Terran_Science_Facility); unitTypeSet.insert(Terran_Covert_Ops); unitTypeSet.insert(Terran_Physics_Lab); unitTypeSet.insert(Terran_Machine_Shop); unitTypeSet.insert(Terran_Engineering_Bay); unitTypeSet.insert(Terran_Armory); unitTypeSet.insert(Terran_Missile_Turret); unitTypeSet.insert(Terran_Bunker); unitTypeSet.insert(Special_Crashed_Norad_II); unitTypeSet.insert(Special_Ion_Cannon); unitTypeSet.insert(Zerg_Infested_Command_Center); unitTypeSet.insert(Zerg_Hatchery); unitTypeSet.insert(Zerg_Lair); unitTypeSet.insert(Zerg_Hive); unitTypeSet.insert(Zerg_Nydus_Canal); unitTypeSet.insert(Zerg_Hydralisk_Den); unitTypeSet.insert(Zerg_Defiler_Mound); unitTypeSet.insert(Zerg_Greater_Spire); unitTypeSet.insert(Zerg_Queens_Nest); unitTypeSet.insert(Zerg_Evolution_Chamber); unitTypeSet.insert(Zerg_Ultralisk_Cavern); unitTypeSet.insert(Zerg_Spire); unitTypeSet.insert(Zerg_Spawning_Pool); unitTypeSet.insert(Zerg_Creep_Colony); unitTypeSet.insert(Zerg_Spore_Colony); unitTypeSet.insert(Zerg_Sunken_Colony); unitTypeSet.insert(Special_Overmind_With_Shell); unitTypeSet.insert(Special_Overmind); unitTypeSet.insert(Zerg_Extractor); unitTypeSet.insert(Special_Mature_Chrysalis); unitTypeSet.insert(Special_Cerebrate); unitTypeSet.insert(Special_Cerebrate_Daggoth); unitTypeSet.insert(Protoss_Nexus); unitTypeSet.insert(Protoss_Robotics_Facility); unitTypeSet.insert(Protoss_Pylon); unitTypeSet.insert(Protoss_Assimilator); unitTypeSet.insert(Protoss_Observatory); unitTypeSet.insert(Protoss_Gateway); unitTypeSet.insert(Protoss_Photon_Cannon); unitTypeSet.insert(Protoss_Citadel_of_Adun); unitTypeSet.insert(Protoss_Cybernetics_Core); unitTypeSet.insert(Protoss_Templar_Archives); unitTypeSet.insert(Protoss_Forge); unitTypeSet.insert(Protoss_Stargate); unitTypeSet.insert(Special_Stasis_Cell_Prison); unitTypeSet.insert(Protoss_Fleet_Beacon); unitTypeSet.insert(Protoss_Arbiter_Tribunal); unitTypeSet.insert(Protoss_Robotics_Support_Bay); unitTypeSet.insert(Protoss_Shield_Battery); unitTypeSet.insert(Special_Khaydarin_Crystal_Form); unitTypeSet.insert(Special_Protoss_Temple); unitTypeSet.insert(Special_XelNaga_Temple); unitTypeSet.insert(Resource_Mineral_Field); unitTypeSet.insert(Resource_Vespene_Geyser); unitTypeSet.insert(Special_Warp_Gate); unitTypeSet.insert(Special_Psi_Disrupter); unitTypeSet.insert(Special_Power_Generator); unitTypeSet.insert(Special_Overmind_Cocoon); unitTypeSet.insert(Special_Zerg_Beacon); unitTypeSet.insert(Special_Terran_Beacon); unitTypeSet.insert(Special_Protoss_Beacon); unitTypeSet.insert(Special_Zerg_Flag_Beacon); unitTypeSet.insert(Special_Terran_Flag_Beacon); unitTypeSet.insert(Special_Protoss_Flag_Beacon); unitTypeSet.insert(Spell_Dark_Swarm); unitTypeSet.insert(Powerup_Uraj_Crystal); unitTypeSet.insert(Powerup_Khalis_Crystal); unitTypeSet.insert(Powerup_Flag); unitTypeSet.insert(Powerup_Young_Chrysalis); unitTypeSet.insert(Powerup_Psi_Emitter); unitTypeSet.insert(Powerup_Data_Disk); unitTypeSet.insert(Powerup_Khaydarin_Crystal); unitTypeSet.insert(None); unitTypeSet.insert(Unknown); foreach(UnitType i, unitTypeSet) { std::string name = i.getName(); fixName(&name); unitTypeMap.insert(std::make_pair(name, i)); } initializingUnitType = false; } } UnitType::UnitType() { this->id = UnitTypes::None.id; } UnitType::UnitType(int id) { this->id = id; if (!initializingUnitType && (id < 0 || id >= 230 || !unitTypeData[id].valid)) this->id = UnitTypes::Unknown.id; } UnitType::UnitType(const UnitType& other) { this->id = other.id; } UnitType& UnitType::operator=(const UnitType& other) { this->id = other.id; return *this; } bool UnitType::operator==(const UnitType& other) const { return this->id == other.id; } bool UnitType::operator!=(const UnitType& other) const { return this->id != other.id; } bool UnitType::operator<(const UnitType& other) const { return this->id < other.id; } int UnitType::getID() const { return this->id; } std::string UnitType::getName() const { return unitTypeData[this->id].name; } Race UnitType::getRace() const { return unitTypeData[this->id].race; } const std::pair< UnitType, int> UnitType::whatBuilds() const { return unitTypeData[this->id].whatBuilds; } const std::map< UnitType, int >& UnitType::requiredUnits() const { return unitTypeData[this->id].requiredUnits; } TechType UnitType::requiredTech() const { return unitTypeData[this->id].requiredTech; } TechType UnitType::cloakingTech() const { return unitTypeData[this->id].cloakingTech; } const std::set< TechType >& UnitType::abilities() const { return unitTypeData[this->id].abilities; } const std::set< UpgradeType >& UnitType::upgrades() const { return unitTypeData[this->id].upgrades; } UpgradeType UnitType::armorUpgrade() const { return unitTypeData[this->id].armorUpgrade; } int UnitType::maxHitPoints() const { return unitTypeData[this->id].maxHitPoints; } int UnitType::maxShields() const { return unitTypeData[this->id].maxShields; } int UnitType::maxEnergy() const { return unitTypeData[this->id].maxEnergy; } int UnitType::armor() const { return unitTypeData[this->id].armor; } int UnitType::mineralPrice() const { return unitTypeData[this->id].mineralPrice; } int UnitType::gasPrice() const { return unitTypeData[this->id].gasPrice; } int UnitType::buildTime() const { return unitTypeData[this->id].buildTime; } int UnitType::supplyRequired() const { return unitTypeData[this->id].supplyRequired; } int UnitType::supplyProvided() const { return unitTypeData[this->id].supplyProvided; } int UnitType::spaceRequired() const { return unitTypeData[this->id].spaceRequired; } int UnitType::spaceProvided() const { return unitTypeData[this->id].spaceProvided; } int UnitType::buildScore() const { return unitTypeData[this->id].buildScore; } int UnitType::destroyScore() const { return unitTypeData[this->id].destroyScore; } UnitSizeType UnitType::size() const { return unitTypeData[this->id].unitSizeType; } int UnitType::tileWidth() const { return unitTypeData[this->id].tileWidth; } int UnitType::tileHeight() const { return unitTypeData[this->id].tileHeight; } int UnitType::dimensionLeft() const { return unitTypeData[this->id].dimensionLeft; } int UnitType::dimensionUp() const { return unitTypeData[this->id].dimensionUp; } int UnitType::dimensionRight() const { return unitTypeData[this->id].dimensionRight; } int UnitType::dimensionDown() const { return unitTypeData[this->id].dimensionDown; } int UnitType::seekRange() const { return unitTypeData[this->id].seekRange; } int UnitType::sightRange() const { return unitTypeData[this->id].sightRange; } WeaponType UnitType::groundWeapon() const { return unitTypeData[this->id].groundWeapon; } int UnitType::maxGroundHits() const { return unitTypeData[this->id].maxGroundHits; } WeaponType UnitType::airWeapon() const { return unitTypeData[this->id].airWeapon; } int UnitType::maxAirHits() const { return unitTypeData[this->id].maxAirHits; } double UnitType::topSpeed() const { return unitTypeData[this->id].topSpeed; } int UnitType::acceleration() const { return unitTypeData[this->id].acceleration; } int UnitType::haltDistance() const { return unitTypeData[this->id].haltDistance; } int UnitType::turnRadius() const { return unitTypeData[this->id].turnRadius; } bool UnitType::canProduce() const { return unitTypeData[this->id].canProduce; } bool UnitType::canAttack() const { return unitTypeData[this->id].canAttack; } bool UnitType::canMove() const { return unitTypeData[this->id].canMove; } bool UnitType::isFlyer() const { return unitTypeData[this->id].isFlyer; } bool UnitType::regeneratesHP() const { return unitTypeData[this->id].regeneratesHP; } bool UnitType::isSpellcaster() const { return unitTypeData[this->id].isSpellcaster; } bool UnitType::hasPermanentCloak() const { return unitTypeData[this->id].hasPermanentCloak; } bool UnitType::isInvincible() const { return unitTypeData[this->id].isInvincible; } bool UnitType::isOrganic() const { return unitTypeData[this->id].isOrganic; } bool UnitType::isMechanical() const { return unitTypeData[this->id].isMechanical; } bool UnitType::isRobotic() const { return unitTypeData[this->id].isRobotic; } bool UnitType::isDetector() const { return unitTypeData[this->id].isDetector; } bool UnitType::isResourceContainer() const { return unitTypeData[this->id].isResourceContainer; } bool UnitType::isResourceDepot() const { return unitTypeData[this->id].isResourceDepot; } bool UnitType::isRefinery() const { return unitTypeData[this->id].isRefinery; } bool UnitType::isWorker() const { return unitTypeData[this->id].isWorker; } bool UnitType::requiresPsi() const { return unitTypeData[this->id].requiresPsi; } bool UnitType::requiresCreep() const { return unitTypeData[this->id].requiresCreep; } bool UnitType::isTwoUnitsInOneEgg() const { return unitTypeData[this->id].isTwoUnitsInOneEgg; } bool UnitType::isBurrowable() const { return unitTypeData[this->id].isBurrowable; } bool UnitType::isCloakable() const { return unitTypeData[this->id].isCloakable; } bool UnitType::isBuilding() const { return unitTypeData[this->id].isBuilding; } bool UnitType::isAddon() const { return unitTypeData[this->id].isAddon; } bool UnitType::isFlyingBuilding() const { return unitTypeData[this->id].isFlyingBuilding; } bool UnitType::isNeutral() const { return unitTypeData[this->id].isNeutral; } bool UnitType::isHero() const { return unitTypeData[this->id].isHero || this->id == UnitTypes::Hero_Dark_Templar.id || this->id == UnitTypes::Terran_Civilian.id; } bool UnitType::isPowerup() const { return this->id == UnitTypes::Powerup_Uraj_Crystal.id || this->id == UnitTypes::Powerup_Khalis_Crystal.id || (this->id >= UnitTypes::Powerup_Flag.id && this->id < UnitTypes::None.id); } bool UnitType::isBeacon() const { return this->id == UnitTypes::Special_Zerg_Beacon.id || this->id == UnitTypes::Special_Terran_Beacon.id || this->id == UnitTypes::Special_Protoss_Beacon.id; } bool UnitType::isFlagBeacon() const { return this->id == UnitTypes::Special_Zerg_Flag_Beacon.id || this->id == UnitTypes::Special_Terran_Flag_Beacon.id || this->id == UnitTypes::Special_Protoss_Flag_Beacon.id; } bool UnitType::isSpecialBuilding() const { return unitTypeData[this->id].isSpecialBuilding && this->id != UnitTypes::Zerg_Infested_Command_Center.id; } bool UnitType::isSpell() const { return this->id == UnitTypes::Spell_Dark_Swarm.id || this->id == UnitTypes::Spell_Disruption_Web.id || this->id == UnitTypes::Spell_Scanner_Sweep.id; } bool UnitType::producesLarva() const { return this->id == UnitTypes::Zerg_Hatchery.id || this->id == UnitTypes::Zerg_Lair.id || this->id == UnitTypes::Zerg_Hive.id; } UnitType UnitTypes::getUnitType(std::string name) { fixName(&name); std::map::iterator i = unitTypeMap.find(name); if (i == unitTypeMap.end()) return UnitTypes::Unknown; return (*i).second; } std::set& UnitTypes::allUnitTypes() { return unitTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/UpgradeType.cpp ================================================ #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUpgradeType = true; class UpgradeTypeInternal { public: UpgradeTypeInternal() {valid = false;} void set(const char* name, int mineralPriceBase, int mineralPriceFactor, int gasPriceBase, int gasPriceFactor, int upgradeTimeBase, int upgradeTimeFactor, BWAPI::UnitType whatUpgrades, Race race, BWAPI::UnitType whatUses, int maxRepeats) { if (initializingUpgradeType) { this->name = name; this->mineralPriceBase = mineralPriceBase; this->mineralPriceFactor = mineralPriceFactor; this->gasPriceBase = gasPriceBase; this->gasPriceFactor = gasPriceFactor; this->upgradeTimeBase = upgradeTimeBase; this->upgradeTimeFactor = upgradeTimeFactor; this->whatUpgrades = whatUpgrades; this->race = race; if (whatUses != UnitTypes::None) this->whatUses.insert(whatUses); this->maxRepeats = maxRepeats; this->valid = true; } } std::string name; int mineralPriceBase; int mineralPriceFactor; int gasPriceBase; int gasPriceFactor; int upgradeTimeBase; int upgradeTimeFactor; BWAPI::UnitType whatUpgrades; Race race; int maxRepeats; std::set whatUses; bool valid; }; UpgradeTypeInternal upgradeTypeData[63]; std::map upgradeTypeMap; std::set< UpgradeType > upgradeTypeSet; namespace UpgradeTypes { const UpgradeType Terran_Infantry_Armor(0); const UpgradeType Terran_Vehicle_Plating(1); const UpgradeType Terran_Ship_Plating(2); const UpgradeType Zerg_Carapace(3); const UpgradeType Zerg_Flyer_Carapace(4); const UpgradeType Protoss_Ground_Armor(5); const UpgradeType Protoss_Air_Armor(6); const UpgradeType Terran_Infantry_Weapons(7); const UpgradeType Terran_Vehicle_Weapons(8); const UpgradeType Terran_Ship_Weapons(9); const UpgradeType Zerg_Melee_Attacks(10); const UpgradeType Zerg_Missile_Attacks(11); const UpgradeType Zerg_Flyer_Attacks(12); const UpgradeType Protoss_Ground_Weapons(13); const UpgradeType Protoss_Air_Weapons(14); const UpgradeType Protoss_Plasma_Shields(15); const UpgradeType U_238_Shells(16); const UpgradeType Ion_Thrusters(17); const UpgradeType Titan_Reactor(19); const UpgradeType Ocular_Implants(20); const UpgradeType Moebius_Reactor(21); const UpgradeType Apollo_Reactor(22); const UpgradeType Colossus_Reactor(23); const UpgradeType Ventral_Sacs(24); const UpgradeType Antennae(25); const UpgradeType Pneumatized_Carapace(26); const UpgradeType Metabolic_Boost(27); const UpgradeType Adrenal_Glands(28); const UpgradeType Muscular_Augments(29); const UpgradeType Grooved_Spines(30); const UpgradeType Gamete_Meiosis(31); const UpgradeType Metasynaptic_Node(32); const UpgradeType Singularity_Charge(33); const UpgradeType Leg_Enhancements(34); const UpgradeType Scarab_Damage(35); const UpgradeType Reaver_Capacity(36); const UpgradeType Gravitic_Drive(37); const UpgradeType Sensor_Array(38); const UpgradeType Gravitic_Boosters(39); const UpgradeType Khaydarin_Amulet(40); const UpgradeType Apial_Sensors(41); const UpgradeType Gravitic_Thrusters(42); const UpgradeType Carrier_Capacity(43); const UpgradeType Khaydarin_Core(44); const UpgradeType Argus_Jewel(47); const UpgradeType Argus_Talisman(49); const UpgradeType Caduceus_Reactor(51); const UpgradeType Chitinous_Plating(52); const UpgradeType Anabolic_Synthesis(53); const UpgradeType Charon_Boosters(54); const UpgradeType None(61); const UpgradeType Unknown(62); void init() { upgradeTypeData[Terran_Infantry_Armor.getID()].set("Terran Infantry Armor" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Vehicle_Plating.getID()].set("Terran Vehicle Plating" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Ship_Plating.getID()].set("Terran Ship Plating" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Zerg_Carapace.getID()].set("Zerg Carapace" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Flyer_Carapace.getID()].set("Zerg Flyer Carapace" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Spire , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Protoss_Ground_Armor.getID()].set("Protoss Ground Armor" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Air_Armor.getID()].set("Protoss Air Armor" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Terran_Infantry_Weapons.getID()].set("Terran Infantry Weapons", 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Vehicle_Weapons.getID()].set("Terran Vehicle Weapons" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Ship_Weapons.getID()].set("Terran Ship Weapons" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Zerg_Melee_Attacks.getID()].set("Zerg Melee Attacks" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Missile_Attacks.getID()].set("Zerg Missile Attacks" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Flyer_Attacks.getID()].set("Zerg Flyer Attacks" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Zerg_Spire , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Protoss_Ground_Weapons.getID()].set("Protoss Ground Weapons" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Air_Weapons.getID()].set("Protoss Air Weapons" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Plasma_Shields.getID()].set("Protoss Plasma Shields" , 200, 100, 200, 100, 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[U_238_Shells.getID()].set("U-238 Shells" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Terran_Academy , Races::Terran , UnitTypes::Terran_Marine , 1); upgradeTypeData[Ion_Thrusters.getID()].set("Ion Thrusters" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Terran_Machine_Shop , Races::Terran , UnitTypes::Terran_Vulture , 1); upgradeTypeData[Titan_Reactor.getID()].set("Titan Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Science_Facility , Races::Terran , UnitTypes::Terran_Science_Vessel, 1); upgradeTypeData[Ocular_Implants.getID()].set("Ocular Implants" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Terran_Covert_Ops , Races::Terran , UnitTypes::Terran_Ghost , 1); upgradeTypeData[Moebius_Reactor.getID()].set("Moebius Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Covert_Ops , Races::Terran , UnitTypes::Terran_Ghost , 1); upgradeTypeData[Apollo_Reactor.getID()].set("Apollo Reactor" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Terran_Control_Tower , Races::Terran , UnitTypes::Terran_Wraith , 1); upgradeTypeData[Colossus_Reactor.getID()].set("Colossus Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Physics_Lab , Races::Terran , UnitTypes::Terran_Battlecruiser , 1); upgradeTypeData[Ventral_Sacs.getID()].set("Ventral Sacs" , 200, 0 , 200, 0 , 2400, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Antennae.getID()].set("Antennae" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Pneumatized_Carapace.getID()].set("Pneumatized Carapace" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Metabolic_Boost.getID()].set("Metabolic Boost" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Zerg_Spawning_Pool , Races::Zerg , UnitTypes::Zerg_Zergling , 1); upgradeTypeData[Adrenal_Glands.getID()].set("Adrenal Glands" , 200, 0 , 200, 0 , 1500, 0 , UnitTypes::Zerg_Spawning_Pool , Races::Zerg , UnitTypes::Zerg_Zergling , 1); upgradeTypeData[Muscular_Augments.getID()].set("Muscular Augments" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Zerg_Hydralisk_Den , Races::Zerg , UnitTypes::Zerg_Hydralisk , 1); upgradeTypeData[Grooved_Spines.getID()].set("Grooved Spines" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Zerg_Hydralisk_Den , Races::Zerg , UnitTypes::Zerg_Hydralisk , 1); upgradeTypeData[Gamete_Meiosis.getID()].set("Gamete Meiosis" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Zerg_Queens_Nest , Races::Zerg , UnitTypes::Zerg_Queen , 1); upgradeTypeData[Metasynaptic_Node.getID()].set("Metasynaptic Node" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Zerg_Defiler_Mound , Races::Zerg , UnitTypes::Zerg_Defiler , 1); upgradeTypeData[Singularity_Charge.getID()].set("Singularity Charge" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::Protoss_Dragoon , 1); upgradeTypeData[Leg_Enhancements.getID()].set("Leg Enhancements" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Citadel_of_Adun , Races::Protoss, UnitTypes::Protoss_Zealot , 1); upgradeTypeData[Scarab_Damage.getID()].set("Scarab Damage" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Scarab , 1); upgradeTypeData[Reaver_Capacity.getID()].set("Reaver Capacity" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Reaver , 1); upgradeTypeData[Gravitic_Drive.getID()].set("Gravitic Drive" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Shuttle , 1); upgradeTypeData[Sensor_Array.getID()].set("Sensor Array" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Observatory , Races::Protoss, UnitTypes::Protoss_Observer , 1); upgradeTypeData[Gravitic_Boosters.getID()].set("Gravitic Boosters" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Observatory , Races::Protoss, UnitTypes::Protoss_Observer , 1); upgradeTypeData[Khaydarin_Amulet.getID()].set("Khaydarin Amulet" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Templar_Archives , Races::Protoss, UnitTypes::Protoss_High_Templar , 1); upgradeTypeData[Apial_Sensors.getID()].set("Apial Sensors" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Scout , 1); upgradeTypeData[Gravitic_Thrusters.getID()].set("Gravitic Thrusters" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Scout , 1); upgradeTypeData[Carrier_Capacity.getID()].set("Carrier Capacity" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Carrier , 1); upgradeTypeData[Khaydarin_Core.getID()].set("Khaydarin Core" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Arbiter_Tribunal , Races::Protoss, UnitTypes::Protoss_Arbiter , 1); upgradeTypeData[Argus_Jewel.getID()].set("Argus Jewel" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Corsair , 1); upgradeTypeData[Argus_Talisman.getID()].set("Argus Talisman" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Templar_Archives , Races::Protoss, UnitTypes::Protoss_Dark_Archon , 1); upgradeTypeData[Caduceus_Reactor.getID()].set("Caduceus Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Academy , Races::Terran , UnitTypes::Terran_Medic , 1); upgradeTypeData[Chitinous_Plating.getID()].set("Chitinous Plating" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Ultralisk_Cavern , Races::Zerg , UnitTypes::Zerg_Ultralisk , 1); upgradeTypeData[Anabolic_Synthesis.getID()].set("Anabolic Synthesis" , 200, 0 , 200, 0 , 2000, 0 , UnitTypes::Zerg_Ultralisk_Cavern , Races::Zerg , UnitTypes::Zerg_Ultralisk , 1); upgradeTypeData[Charon_Boosters.getID()].set("Charon Boosters" , 100, 0 , 100, 0 , 2000, 0 , UnitTypes::Terran_Machine_Shop , Races::Terran , UnitTypes::Terran_Goliath , 1); upgradeTypeData[None.getID()].set("None" , 0 , 0 , 0 , 0 , 0 , 0 , UnitTypes::None , Races::None , UnitTypes::None , 0); upgradeTypeData[Unknown.getID()].set("Unknown" , 0 , 0 , 0 , 0 , 0 , 0 , UnitTypes::None , Races::Unknown, UnitTypes::None , 0); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Firebat); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Ghost); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Marine); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Medic); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_SCV); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Goliath); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Vulture); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Dropship); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Science_Vessel); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Wraith); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Broodling); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Defiler); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Drone); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Infested_Terran); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Larva); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Lurker); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Zergling); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Devourer); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Guardian); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Overlord); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Queen); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Scourge); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Archon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Probe); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Reaver); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Carrier); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Observer); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Firebat); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Ghost); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Marine); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Goliath); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Vulture); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Wraith); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Broodling); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Zergling); upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk); upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Lurker); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Devourer); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Guardian); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter_Tribunal); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Archon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Assimilator); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Carrier); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Citadel_of_Adun); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Cybernetics_Core); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Fleet_Beacon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Forge); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Gateway); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Nexus); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observatory); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observer); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Photon_Cannon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Probe); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Pylon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Reaver); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Facility); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Support_Bay); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scarab); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shield_Battery); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Stargate); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Templar_Archives); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeSet.insert(Terran_Infantry_Armor); upgradeTypeSet.insert(Terran_Vehicle_Plating); upgradeTypeSet.insert(Terran_Ship_Plating); upgradeTypeSet.insert(Zerg_Carapace); upgradeTypeSet.insert(Zerg_Flyer_Carapace); upgradeTypeSet.insert(Protoss_Ground_Armor); upgradeTypeSet.insert(Protoss_Air_Armor); upgradeTypeSet.insert(Terran_Infantry_Weapons); upgradeTypeSet.insert(Terran_Vehicle_Weapons); upgradeTypeSet.insert(Terran_Ship_Weapons); upgradeTypeSet.insert(Zerg_Melee_Attacks); upgradeTypeSet.insert(Zerg_Missile_Attacks); upgradeTypeSet.insert(Zerg_Flyer_Attacks); upgradeTypeSet.insert(Protoss_Ground_Weapons); upgradeTypeSet.insert(Protoss_Air_Weapons); upgradeTypeSet.insert(Protoss_Plasma_Shields); upgradeTypeSet.insert(U_238_Shells); upgradeTypeSet.insert(Ion_Thrusters); upgradeTypeSet.insert(Titan_Reactor); upgradeTypeSet.insert(Ocular_Implants); upgradeTypeSet.insert(Moebius_Reactor); upgradeTypeSet.insert(Apollo_Reactor); upgradeTypeSet.insert(Colossus_Reactor); upgradeTypeSet.insert(Ventral_Sacs); upgradeTypeSet.insert(Antennae); upgradeTypeSet.insert(Pneumatized_Carapace); upgradeTypeSet.insert(Metabolic_Boost); upgradeTypeSet.insert(Adrenal_Glands); upgradeTypeSet.insert(Muscular_Augments); upgradeTypeSet.insert(Grooved_Spines); upgradeTypeSet.insert(Gamete_Meiosis); upgradeTypeSet.insert(Metasynaptic_Node); upgradeTypeSet.insert(Singularity_Charge); upgradeTypeSet.insert(Leg_Enhancements); upgradeTypeSet.insert(Scarab_Damage); upgradeTypeSet.insert(Reaver_Capacity); upgradeTypeSet.insert(Gravitic_Drive); upgradeTypeSet.insert(Sensor_Array); upgradeTypeSet.insert(Gravitic_Boosters); upgradeTypeSet.insert(Khaydarin_Amulet); upgradeTypeSet.insert(Apial_Sensors); upgradeTypeSet.insert(Gravitic_Thrusters); upgradeTypeSet.insert(Carrier_Capacity); upgradeTypeSet.insert(Khaydarin_Core); upgradeTypeSet.insert(Argus_Jewel); upgradeTypeSet.insert(Argus_Talisman); upgradeTypeSet.insert(Caduceus_Reactor); upgradeTypeSet.insert(Chitinous_Plating); upgradeTypeSet.insert(Anabolic_Synthesis); upgradeTypeSet.insert(Charon_Boosters); upgradeTypeSet.insert(None); upgradeTypeSet.insert(Unknown); foreach(UpgradeType i, upgradeTypeSet) { std::string name = i.getName(); fixName(&name); upgradeTypeMap.insert(std::make_pair(name, i)); } initializingUpgradeType = false; } } UpgradeType::UpgradeType() { this->id = UpgradeTypes::None.id; } UpgradeType::UpgradeType(int id) { this->id = id; if (!initializingUpgradeType && (id < 0 || id >= 63 || !upgradeTypeData[id].valid) ) this->id = UpgradeTypes::Unknown.id; } UpgradeType::UpgradeType(const UpgradeType& other) { this->id = other.id; } UpgradeType& UpgradeType::operator=(const UpgradeType& other) { this->id = other.id; return *this; } bool UpgradeType::operator==(const UpgradeType& other) const { return this->id == other.id; } bool UpgradeType::operator!=(const UpgradeType& other) const { return this->id != other.id; } bool UpgradeType::operator<(const UpgradeType& other) const { return this->id < other.id; } int UpgradeType::getID() const { return this->id; } std::string UpgradeType::getName() const { return upgradeTypeData[this->id].name; } Race UpgradeType::getRace() const { return upgradeTypeData[this->id].race; } int UpgradeType::mineralPrice() const { return upgradeTypeData[this->id].mineralPriceBase; } int UpgradeType::mineralPriceFactor() const { return upgradeTypeData[this->id].mineralPriceFactor; } int UpgradeType::gasPrice() const { return upgradeTypeData[this->id].gasPriceBase; } int UpgradeType::gasPriceFactor() const { return upgradeTypeData[this->id].gasPriceFactor; } int UpgradeType::upgradeTime() const { return upgradeTypeData[this->id].upgradeTimeBase; } int UpgradeType::upgradeTimeFactor() const { return upgradeTypeData[this->id].upgradeTimeFactor; } UnitType UpgradeType::whatUpgrades() const { return upgradeTypeData[this->id].whatUpgrades; } const std::set& UpgradeType::whatUses() const { return upgradeTypeData[this->id].whatUses; } int UpgradeType::maxRepeats() const { return upgradeTypeData[this->id].maxRepeats; } UpgradeType UpgradeTypes::getUpgradeType(std::string name) { fixName(&name); std::map::iterator i = upgradeTypeMap.find(name); if (i == upgradeTypeMap.end()) return UpgradeTypes::Unknown; return (*i).second; } std::set& UpgradeTypes::allUpgradeTypes() { return upgradeTypeSet; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Bitmask.h ================================================ #pragma once /** Custom help classes not connected with the project */ namespace Util { /** * Representation of list of bool values using binary. * Size of the bitmask is always the same as Type (so it can be mapped in bw structurs) * This also means, that the bitmas has sizeof(Type)*8 values. */ template class BitMask { public : bool getBit(Type bit) const; void setBit(Type bit, bool val); Type value; }; //------------------------------------------------ GET BIT ------------------------------------------------- template bool BitMask::getBit(Type bit) const { return (value & bit) != 0; } //------------------------------------------------ SET BIT ------------------------------------------------- template void BitMask::setBit(Type bit, bool val) { if (val) value |= bit; else value &= ~bit; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Exceptions.cpp ================================================ #include "Exceptions.h" //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ GeneralException::GeneralException(const std::string &message) :message(message) { } //----------------------------------------------- GET MESSAGE ------------------------------------------------ const std::string GeneralException::getMessage(void) { return this->message; } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ FileException::FileException(const std::string &message) : GeneralException(message) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ ConfigException::ConfigException(const std::string &message) : GeneralException(message) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ XmlException::XmlException(const std::string& message, const std::string& fileName, const long lineNumber) :GeneralException(message) ,fileName(fileName) ,lineNumber(lineNumber) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ ParseException::ParseException(const std::string& message) :GeneralException(message) { } //------------------------------------------------------------------------------------------------------------ ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Exceptions.h ================================================ #pragma once #include class MultiString; /** * Represents any exception that can be thrown during to program run, * it doesn't contain expressions that can be thrown by tinyXml */ class GeneralException { private : /** * Represents the property key of the exception message, but in some special * cases, the messageKey can contain the message itself */ std::string message; public: /** Creates exception with the specified message */ GeneralException(const std::string &messageKey); const std::string getMessage(void); }; /** * Can be thrown when the configuration files are invalid, or contain invalid * information. */ class ConfigException : public GeneralException { public : ConfigException(const std::string &message); }; /** Can be thrown when some required files are not found. */ class FileException : public GeneralException { public : FileException(const std::string &message); }; /** Can be thrown when the xml file structure is invalid. */ class XmlException : public GeneralException { std::string fileName; long lineNumber; public : XmlException(const std::string& message, const std::string& fileName = "", const long lineNumber = 0); }; /** Can be thrown during parsin (non integer paremters that should be numbers for example) */ class ParseException : public GeneralException { public : ParseException(const std::string& message); }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/FileLogger.cpp ================================================ #include "FileLogger.h" #include namespace Util { //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- FileLogger::FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime) :Logger(logLevel) ,fileName(fileName + ".log") ,showTime(showTime) { } //------------------------------------------------- FLUSH -------------------------------------------------- bool FileLogger::flush(const char* data) { FILE *f = fopen(fileName.c_str(),"at"); if (!f) return false; if (showTime) { char time[9]; _strtime(time); fprintf(f, "%s ", time); } fprintf(f, "%s \n", data); fclose(f); return true; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/FileLogger.h ================================================ #pragma once #include "Logger.h" namespace Util { /** Mutation of logger that prints messages to file. */ class FileLogger : public Logger { public : FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime = true); protected : virtual bool flush(const char* data); private : std::string fileName; bool showTime; }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Foreach.h ================================================ #pragma once #define foreach(element, collection) for (element : collection) ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Gnu.h ================================================ #pragma once #ifdef __GNUC__ #include #define fprintf_s fprintf #define sprintf_s snprintf #define vsnprintf_s(buf, s1, s2, fmt, ap) vsnprintf(buf, s1, fmt, ap) #define memcpy_s(dest, ds, src, ss) memcpy(dest, src, ss) inline void strcpy_s(char* dest, size_t size, char* src) { size_t s = strlen(src); if(s > size - 1) { s = size - 1; } memcpy(dest, src, s); dest[s] = 0; } #endif ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/LogLevel.h ================================================ namespace Util { /** The level of detail of the log. */ namespace LogLevel { enum Enum { DontLog = 0, /**< No logs will be printed by logger with this logLevel specification. Shouldn't be used by the Logger#log for obvious reasons. */ Critical = 1, /**< Mostly errors, very important. */ Important = 2, /**< Bigger events. */ Normal = 2, /**< Normal events, like commands ordered etc. */ Commmon = 3, /**< Common things. */ Detailed = 4, /**< Detailed events mainly for investigation of problems. */ MicroDetailed = 5 /**< Super often occuring event's like calling common functions etc, used mainly for searching bugs. */ }; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Logger.cpp ================================================ #include "Logger.h" #include #include #include "FileLogger.h" #include "Foreach.h" #include "Gnu.h" namespace Util { Logger* Logger::globalLog = new FileLogger("global", LogLevel::MicroDetailed); char Logger::buffer[BUFFER_SIZE]; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Logger::Logger(LogLevel::Enum levelToLog) :levelToLog(levelToLog) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Logger::~Logger() { for (std::list::iterator i = this->connectedLoggers.begin(); i != this->connectedLoggers.end(); ++i) delete *i; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::log(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Normal, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logDetailed(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Detailed, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logCommon(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Commmon, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logImportant(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Important, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logCritical(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Critical, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logInternal(const char* message, LogLevel::Enum logLevel, va_list ap) { if (logLevel > this->levelToLog) return true; vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, message, ap); this->flushInternal(buffer); if (globalLog != NULL && this != globalLog) globalLog->logInternal(message, logLevel, ap); return true; } //-------------------------------------------- REGISTER LOGGER --------------------------------------------- void Logger::registerLogger(Logger* logger) { this->connectedLoggers.push_back(logger); } //---------------------------------------------------------------------------------------------------------- bool Logger::flushInternal(const char* buffer) { foreach (Logger* i, this->connectedLoggers) i->flush(buffer); return this->flush(buffer); } //---------------------------------------------------------------------------------------------------------- } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Logger.h ================================================ #pragma once #include #include #include #include #include "LogLevel.h" namespace Util { /** * Utility for logging debug output. * This class defines abstract logger interface, every descentant needs to define the flush function to be * instantiable. * Every kind of log should have it's own instance of this class, don't log different things to same log. * Different log instances can be later used to combine different logs with different detailLevels. */ class Logger { public : /** * Creates new logger. * @param levelToLog All log inputs with less importancy will be not * logged in this log */ Logger(LogLevel::Enum levelToLog); virtual ~Logger(); /** * Logs the message using printf formatting style. * This function use Normal Log level. * @param message message to be logged. * @param ... Parameters of the printf style format. */ bool log (const char* message, ...); bool logDetailed (const char* message, ...); bool logCommon (const char* message, ...); bool logImportant(const char* message, ...); bool logCritical (const char* message, ...); void registerLogger(Logger* logger); /** Every log message will be also posted to this global log. */ static Logger* globalLog; static bool deleteLogsAtStart; protected : virtual bool flush(const char* data) = 0; bool flushInternal(const char* data); private : bool logInternal(const char* message, LogLevel::Enum, va_list ap); LogLevel::Enum levelToLog; static const unsigned int BUFFER_SIZE = 2048; static char buffer[BUFFER_SIZE]; std::list connectedLoggers; }; }; ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/RectangleArray.h ================================================ #pragma once #include #include #include "Exceptions.h" namespace Util { /** * Template used for work with dynamically initialized array with dimension 2. */ template class RectangleArray { public : /** * Creates the array with the specified proportions. * @param width Width of the new array. * @param height Height of the new array. */ RectangleArray(unsigned int width = 1, unsigned int height = 1, Type* data = NULL); /** Copy constructor */ RectangleArray(const RectangleArray& rectangleArray); /** Destorys the array and deletes all content of array. */ ~RectangleArray(void); /** * Gets the width of the array. * @return width of the array. */ unsigned int getWidth(void) const; /** * Gets the height of the array. * @return height of the array. */ unsigned int getHeight(void) const; /** * Gets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @return item on the specified position. */ Type* getItem(unsigned int x, unsigned int y); inline Type* operator[](int i) { return this->getColumn(i); } inline Type const * const operator[](int i) const {return this->getColumn(i); } /** * Sets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @param item new value of the field. */ void setItem(unsigned int x, unsigned int y, Type *item); void resize(unsigned int width, unsigned int height); void printToFile(FILE* f); void saveToFile(const std::string& fileName); /** Sets all fields of the array to the specified value */ void setTo(const Type& value); void setBorderTo(const Type& value); private : bool owner; /** width of array */ unsigned int width; /** height of array */ unsigned int height; /** Array data, stored as linear array of size width*height */ Type *data; /** Pointers to begins of lines*/ Type **columns; /** * Gets data item on the specified index * @param index index of the data to be returned. */ Type getData(unsigned int index); /** * Gets the pointer in data to the beginning of line with the specified * index. * @param index index of the line. */ Type *getColumn(unsigned int index); /** * Gets the pointer in data to the beginning of line with the specified * index. * @param index index of the line. */ const Type *getColumn(unsigned int index) const; /** * Sets the width of the array. * @param width New width of the array. */ void setWidth(unsigned int width); /** * Sets the height of the array. * @param height New height of the array. */ void setHeight(unsigned int height); }; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RectangleArray::RectangleArray(unsigned int width, unsigned int height, Type* data) { this->setWidth(width); this->setHeight(height); this->owner = (data == NULL); if (this->owner) this->data = new Type[this->getWidth()*this->getHeight()]; else this->data = data; columns = new Type*[this->getWidth()]; unsigned int i = 0; for (unsigned int position = 0;i < width; i ++,position += height) columns[i] = &this->data[position]; } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RectangleArray::RectangleArray(const RectangleArray& rectangleArray) :owner(true) { this->setWidth(rectangleArray.getWidth()); this->setHeight(rectangleArray.getHeight()); this->data = new Type[this->getWidth()*this->getHeight()]; columns = new Type*[this->getWidth()]; unsigned int i = 0; for (unsigned int position = 0;i < width; i ++,position += height) columns[i] = &data[position]; memcpy(this->data, rectangleArray.data, sizeof(Type)*this->getWidth()*this->getHeight()); } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- template RectangleArray::~RectangleArray(void) { delete [] columns; if (this->owner) delete [] data; } //----------------------------------------------- GET WIDTH ------------------------------------------------ template unsigned int RectangleArray::getWidth(void) const { return this->width; } //----------------------------------------------- SET WIDTH ------------------------------------------------ template void RectangleArray::setWidth(unsigned int width) { this->width = width; } //----------------------------------------------- GET HEIGHT ----------------------------------------------- template unsigned int RectangleArray::getHeight(void) const { return this->height; } //----------------------------------------------- SET HEIGHT ----------------------------------------------- template void RectangleArray::setHeight(unsigned int height) { this->height = height; } //------------------------------------------------ GET ITEM ------------------------------------------------ template Type* RectangleArray::getItem(unsigned int x, unsigned int y) { return this->getColumn(x)[y]; } //------------------------------------------------ SET ITEM ------------------------------------------------ template void RectangleArray::setItem(unsigned int x, unsigned int y, Type* item) { this->getColumn(x)[y] = item; } //------------------------------------------------ GET LINE ------------------------------------------------ template Type* RectangleArray::getColumn(unsigned int index) { return columns[index]; } //------------------------------------------------ GET LINE ------------------------------------------------ template const Type* RectangleArray::getColumn(unsigned int index) const { return columns[index]; } //------------------------------------------------- RESIZE ------------------------------------------------- template void RectangleArray::resize(unsigned int width, unsigned int height) { if (!this->owner) throw GeneralException("Can't resize array that doesn't own the data"); if (this->getWidth() == width && this->getHeight() == height) return; delete [] this->columns; delete [] this->data; this->setWidth(width); this->setHeight(height); this->data = new Type[this->width * this->height]; this->columns = new Type*[this->width]; unsigned int i = 0; for (unsigned int position = 0;i < this->width; i ++,position += this->height) columns[i] = &data[position]; } //--------------------------------------------- PRINT TO FILE ---------------------------------------------- template void RectangleArray::printToFile(FILE* f) { for (unsigned int y = 0; y < this->getHeight(); y++) { for (unsigned int x = 0; x < this->getWidth(); x++) { char ch = this->getColumn(x)[y]; fprintf(f, "%c", ch); } fprintf(f, "\n"); } } //---------------------------------------------- SAVE TO FILE ---------------------------------------------- template void RectangleArray::saveToFile(const std::string& fileName) { FILE* f = fopen(fileName.c_str(), "wt"); if (!f) throw FileException("RectangleArray::saveToFile Couldn't open file " + fileName + "for writing"); this->printToFile(f); fclose(f); } //------------------------------------------------- SET TO ------------------------------------------------- template void RectangleArray::setTo(const Type& value) { for (unsigned int i = 0; i < this->getWidth()*this->getHeight(); i++) this->data[i] = value; } //--------------------------------------------- SET BORDER TO ---------------------------------------------- template void RectangleArray::setBorderTo(const Type& value) { for (unsigned int i = 0; i < this->width; i++) { this->getColumn(i)[0] = value; this->getColumn(i)[this->height - 1] = value; } for (unsigned int i = 0; i < this->height; i++) { this->getColumn(0)[i] = value; this->getColumn(this->width - 1)[i] = value; } } //---------------------------------------------------------------------------------------------------------- } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/RegionQuadTree.h ================================================ #pragma once #include namespace Util { /** * Structure representing 2D space containing objects of the specified type. This structure is optimised for * effective way of finding of objects in certain area. The top level of the structure contains single list * of all objects included, it divides into 2-4 partitions containing lists of units on respective quoters * of the space, and so on until sthe width/height size is reached. The structure works with list of * pointers of the type and doesn't act as owner, so removing items or deleting the whole quad tree will not * result in delatation of contained items. */ template class RegionQuadTree { public : /** * Creates the quad tree with the specified dimensions. * @param width Width of the highest detail level partition. * @param height Height of the highest detail level partition. */ RegionQuadTree(unsigned int width = 1, unsigned int height = 1); /** Destorys the array, but doesn't delete inserted objects. */ ~RegionQuadTree(void); /** * Gets the width of the array. * @return width of the array. */ unsigned int getWidth(void) const; /** * Gets the height of the array. * @return height of the array. */ unsigned int getHeight(void) const; /** * Gets list of items in the specified region. * @param x horizontal index of the region. * @param y vertical index of the region. * @return list of items on the specified region */ std::list* getItems(unsigned int x, unsigned int y, unsigned int level = 0); /** * Sets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @param item new value of the field. */ void addItem(unsigned int x, unsigned int y, Type *item); void clear(unsigned int x, unsigned int y); private : /** width of array */ unsigned int width; /** height of array */ unsigned int height; /** array of rectangle arrays of lists of objects. * The 1. item of the array corresponds with the lowest (most detailed) level of the region resolution. * Every other level correspons to 4 times less detailed resolution. */ RectangleArray >* data; /** depth = log2(max(width,height)), but is here for optimalisation reasons. */ unsigned int depth; }; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RegionQuadTree::RegionQuadTree(unsigned int width, unsigned int height) :width(width) ,height(height) ,depth(ceil(log2(max(width,height))) { this->data = new RectangleArray >[depth]; unsigned int localWidth = width; unsigned int localHeight = height; for (unsigned int i = 0; i < this->depth; i++) { this->data[i].resize(localWidth, localHeight); localWidth = (localWidth >= 2) (localWidth+1)/2 : 1; localHeight = (localHeight >=2) (localHeight+1)/2 : 1; } } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- template RectangleArray::~RectangleArray(void) { delete [] data; } //----------------------------------------------- GET WIDTH ------------------------------------------------ template unsigned int RectangleArray::getWidth(void) const { return this->width; } //----------------------------------------------- SET WIDTH ------------------------------------------------ template void RectangleArray::setWidth(unsigned int width) { this->width = width; } //----------------------------------------------- GET HEIGHT ----------------------------------------------- template unsigned int RectangleArray::getHeight(void) const { return this->height; } //------------------------------------------------ GET ITEM ------------------------------------------------ template std::list* getItems(unsigned int x, unsigned int y, unsigned int level = 0); { return this->data[level][x][y]; } //------------------------------------------------ ADD ITEM ------------------------------------------------ template void RectangleArray::addItem(unsigned int x, unsigned int y, Type* item) { for (unsigned int i = 0; i < this->depth; i++) this->data[i][x< void RectangleArray::clear(unsigned int x, unsigned int y) { for (unsigned int i = 0; i < this->depth; i++) this->data[i][x< #include #include "Exceptions.h" #include "Gnu.h" namespace Util { //--------------------------------------------- INT TO STRING ---------------------------------------------- std::string Strings::intToString(long value) { if (value == 0) return "0"; std::string returnValue; while (value != 0) { returnValue = (char) (48+(value % 10)) + returnValue; value/=10; } if (value >= 0) return returnValue; else return "-" + returnValue; } //--------------------------------------------- STRING TO INT ---------------------------------------------- unsigned long Strings::stringToInt(const std::string &input, const unsigned long begin, const int distance) { unsigned long returnValue = 0; for (unsigned long i = begin; i < distance + begin && i < input.size();i++) { if (!isdigit(input[i])) throw ParseException::ParseException("Strings::stringToInt - String " + input + " is not a number."); returnValue*=10; returnValue += (input[i] - '0'); } return returnValue; } //---------------------------------------- STRING TO VARIABLE NAME ----------------------------------------- std::string Strings::stringToVariableName(const std::string &input) { std::string variableName; for(unsigned int i=0;i= 1) return input[0]>='0' && input[0]<= '9'; return false; } //-------------------------------------------- ENDS WITH NUMBER -------------------------------------------- bool Strings::endsWithNumber(const std::string &input) { if (input.length() >= 1) return input[input.length() - 1]>='0' && input[input.length() - 1] <= '9'; return false; } //--------------------------------------------- LOAD FROM FILE --------------------------------------------- void Strings::loadFromFile(const std::string &fileName, std::string &target,const long bufferSize) { char* buffer = new char[bufferSize]; FILE* f = fopen(fileName.c_str(),"rt"); size_t fileSize; if (f) { fileSize = fread(buffer,1,bufferSize,f); fclose(f); buffer[fileSize] = 0; target = buffer; } else throw new FileException("Couldn't open file " + fileName); delete [] buffer; } //------------------------------------------------ TRIM ALL ------------------------------------------------ std::string Strings::trimAll(std::string input) { size_t length = input.size(); char* buffer = new char[length + 1]; long pos = 0; for (size_t i = 0;i < length;i++) { if (!isspace(input[i])) { buffer[pos] = input[i]; pos++; } } buffer[pos] = 0; std::string returnValue = buffer; delete [] buffer; return returnValue; } //------------------------------------------------ TRIM ALL ------------------------------------------------ std::string Strings::trim(std::string input) { size_t i, j; for (i = 0; i < input.length() && isspace(input[i]);i++); if (i == input.length()) return ""; for (j = input.length() - 1; j > 0 && isspace(input[j]);j--); if (i == 0 && j == input.length()) return input; else return input.substr(i,j - i + 1); } char Strings::buffer[STRING_UTIL_BUFFER_SIZE]; //----------------------------------------------- READ LINE ------------------------------------------------ std::string Strings::readLine(FILE* f) { std::string result; readNextBlock: int position = 0; fread(buffer, sizeof(char), 1, f); while (buffer[position] != 13 && buffer[position] != 10 && position < STRING_UTIL_BUFFER_SIZE - 1 && !feof(f)) { position++; fread(&buffer[position], 1, 1,f); } if (buffer[position] == 13 || buffer[position] == 10 || feof(f)) { buffer[position] = 0; result.append(buffer); return result; } else { buffer[position + 1] = 0; result.append(buffer); goto readNextBlock; } } //---------------------------------------------------------------------------------------------------------- const std::string& Strings::dereferenceString(const std::string* const input) { return *input; } //---------------------------------------------------------------------------------------------------------- RectangleArray Strings::makeBorder(const RectangleArray& input, bool coordinates) { int leftBorder = (int)log10((float)input.getHeight()) + 2; int topBorder = 3; RectangleArray returnValue = RectangleArray(input.getWidth() + leftBorder*2, input.getHeight() + topBorder*2); for (unsigned int x = 0; x < returnValue.getWidth(); x++) for (unsigned int y = 0; y < returnValue.getHeight(); y++) returnValue[x][y] = ' '; Strings::makeWindow(returnValue, leftBorder - 1, topBorder - 1, input.getWidth() + 2, input.getHeight() + 2); for (unsigned int x = 0; x < input.getWidth(); x++) for (unsigned int y = 0; y < input.getHeight(); y++) returnValue[x + leftBorder ][y + topBorder] = input[x][y]; for (unsigned int i = 0; i < input.getWidth(); i+=10) { Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, 0); Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, returnValue.getHeight() - 1); } for (unsigned int i = 0; i < input.getWidth(); i++) { Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, 1); Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, returnValue.getHeight() - 2); } for (unsigned int i = 0; i < input.getHeight(); i++) { Strings::printTo(returnValue, Strings::intToString(i), 0 , i + topBorder); Strings::printTo(returnValue, Strings::intToString(i), leftBorder + input.getWidth() + 1, i + topBorder); } return returnValue; } char Strings::FrameCharacters[2][6] = { { char(205), char(186), char(201), char(187), char(200), char(188) }, { char(196), char(179), char(218), char(191), char(192), char(217) } }; //---------------------------------------------------------------------------------------------------------- void Strings::makeWindow(RectangleArray& input, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int frameType) { for (unsigned int i = x + 1; i < x + width - 1 && x < input.getWidth(); i++) { input[i][y] = Strings::FrameCharacters[frameType][0]; input[i][y + height - 1] = Strings::FrameCharacters[frameType][0]; } for (unsigned int i = y + 1; i < y + height - 1 && y < input.getHeight(); i++) { input[x][i] = Strings::FrameCharacters[frameType][1]; input[x + width - 1][i] = Strings::FrameCharacters[frameType][1]; } input[x][y] = Strings::FrameCharacters[frameType][2]; input[x + width - 1][y] = Strings::FrameCharacters[frameType][3]; input[x][y + height - 1] = Strings::FrameCharacters[frameType][4]; input[x + width - 1][y + height- 1] = Strings::FrameCharacters[frameType][5]; } //------------------------------------------------ PRINT TO ------------------------------------------------ void Strings::printTo(RectangleArray& input, const std::string& text, unsigned int x, unsigned int y) { for (unsigned int i = 0; text[i] != 0; i++) input[x + i][y] = text[i]; } //---------------------------------------------- SPLIT STRING ---------------------------------------------- std::vector Strings::splitString(const std::string& input, const std::string& delimiters) { // Skip delims at beginning, find start of first token std::string::size_type lastPos = input.find_first_not_of(delimiters, 0); // Find next delimiter @ end of token std::string::size_type pos = input.find_first_of(delimiters, lastPos); // output vector std::vector tokens; while (std::string::npos != pos || std::string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(input.substr(lastPos, pos - lastPos)); // Skip delims. Note the "not_of". this is beginning of token lastPos = input.find_first_not_of(delimiters, pos); // Find next delimiter at end of token. pos = input.find_first_of(delimiters, lastPos); } return tokens; } //----------------------------------------------- GET BINARY ------------------------------------------------ template std::string Strings::getBinary(Type value) { std::string result; for (int i = 0; i < sizeof(Type)*8; i++) if (value & (1 << (sizeof(Type)*8-1-i))) result += "1"; else result += "0"; return result; } //----------------------------------------------- SKIP SPACE ------------------------------------------------ void Strings::skipSpace(const std::string& text, size_t& position) { while (isspace(text[position])) position ++; } //------------------------------------------------ READ WORD ------------------------------------------------ std::string Strings::readWord(const std::string& text, size_t& position) { std::string result; while (isalpha(text[position])) { result += text[position]; position++; } return result; } //------------------------------------------------ READ WORD ------------------------------------------------ std::string Strings::readNumber(const std::string& text, size_t& position) { std::string result; while (isdigit(text[position]) || text[position] == '.') { result += text[position]; position++; } return result; } const int BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; //----------------------------------------------------------------------------------------------------------- std::string Strings::ssprintf(const char* format, ...) { va_list ap; va_start(ap, format); vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, format, ap); va_end(ap); return buffer; } //----------------------------------------------------------------------------------------------------------- } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Strings.h ================================================ #pragma once #define STRING_UTIL_BUFFER_SIZE 100 #include #include #include "RectangleArray.h" namespace Util { /** Collection of std::string utilities */ class Strings { private : /** The class is abstract, so it has private constructor */ Strings(void); static char buffer[STRING_UTIL_BUFFER_SIZE]; public : /** * Gets textual representation of the specified number. * @param value Number to be converted to std::string. * @return Textual representation of the specified number. */ static std::string intToString(long value); /** * Converts textual representation of number to number. * @param input String containing number representation. * @param begin Position of the first caracter of the number in the input * std::string. * @param distance Maximum count of characters to read. * @return Returns textual representation of the specified std::string. * @throws ParseException if the text can't be converted to integer * (non-numerical characters) */ static unsigned long stringToInt(const std::string &input, const unsigned long begin = 0, const int distance = 9); static std::string stringToVariableName(const std::string &input); static void stringToFile(const std::string &input, FILE* f); static void saveToFile(const std::string &input, const std::string &fileName); static bool beginsWithNumber(const std::string &input); static bool endsWithNumber(const std::string &input); static std::string loadFromFile(FILE* f); static void loadFromFile(const std::string &fileName,std::string &Target,const long bufferSize); static std::string UTF8ToWindows1250(const std::string &input); static std::string Windows1250ToUTF8(const std::string &input); static std::string trimAll(std::string input); static std::string trim(std::string input); static std::string replace(const std::string &input, MultiString* values, const std::string &replacement); static RectangleArray makeBorder(const RectangleArray& input, bool coordinates = true); static char FrameCharacters[2][6]; static void makeWindow(RectangleArray& input, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int frameType = 0); static void printTo(RectangleArray& input, const std::string& text, unsigned int x, unsigned int y); /** * Reads one line from the input stream. * @param f Input stream. * @return Content of the line. */ static std::string readLine(FILE* f); static const std::string& dereferenceString(const std::string* const input); /** * convert input string into vector of string tokens. * * @note consecutive delimiters will be treated as single delimiter * @note delimiters are _not_ included in return data * * @param input string to be parsed * @param delimiters list of delimiters. * I was too lazy and took it from http://www.rosettacode.org/wiki/Tokenizing_A_String */ static std::vector splitString(const std::string& input, const std::string& delimiters = " \t"); template std::string getBinary(Type value); static void skipSpace(const std::string& text, size_t& position); /** Reads words consting of alphaNumeric characters */ static std::string readWord(const std::string& text, size_t& position); static std::string readNumber(const std::string& text, size_t& position); static std::string ssprintf(const char* format, ...); }; } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/Types.h ================================================ #pragma once typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned int u32; typedef signed int s32; typedef unsigned long long u64; typedef signed long long s64; typedef u8 _UNKNOWN; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef void* PVOID; typedef int BOOL; typedef void* HANDLE; #ifdef NULL #undef NULL #endif #define NULL 0 #define ever (;;) ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/sha1.cpp ================================================ /* Copyright (c) 2009, Micael Hildenborg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Micael Hildenborg nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Contributors: Gustav Several members in the gamedev.se forum. */ #include "sha1.h" #include namespace sha1 { namespace // local { inline const unsigned int rol(const unsigned int num, const unsigned int cnt) { return((num << cnt) | (num >> (32-cnt))); } void innerHash(unsigned int *result, unsigned int *w) { unsigned int save[5]; save[0]=result[0]; save[1]=result[1]; save[2]=result[2]; save[3]=result[3]; save[4]=result[4]; #define a result[0] #define b result[1] #define c result[2] #define d result[3] #define e result[4] int j=0; #define sha1macro(func,val) \ {const unsigned int t = rol(a, 5)+(func)+e+val+w[j]; \ e = d; d = c; \ c = rol(b, 30); \ b = a; a = t;} while(j<16) { sha1macro((b&c)|(~b&d),0x5A827999) j++; } while(j<20) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro((b&c)|(~b&d),0x5A827999) j++; } while(j<40) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro(b^c^d,0x6ED9EBA1) j++; } while(j<60) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro((b&c)|(b&d)|(c&d),0x8F1BBCDC) j++; } while(j<80) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro(b^c^d,0xCA62C1D6) j++; } #undef sha1macro #undef a #undef b #undef c #undef d #undef e result[0]+=save[0]; result[1]+=save[1]; result[2]+=save[2]; result[3]+=save[3]; result[4]+=save[4]; } } void calc(const void *src, const int bytelength, unsigned char *hash) { // Init the result array, and create references to the five unsigned integers for better readabillity. unsigned int result[5]={0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0}; const unsigned char *sarray=(const unsigned char*)src; // The variables unsigned int w[80]; int j,i,i1; j=0; // Loop through all complete 64byte blocks. for(i=0,i1=64; i<=(bytelength-64); i=i1,i1+=64) { int k=0; for(j=i;j>2]|=(unsigned int)sarray[j+i]<<((3-(j&3))<<3); } w[j>>2]|=0x80<<((3-(j&3))<<3); if(i1>=56) { innerHash(result,w); memset(w,0,sizeof(unsigned int)*16); } w[15]=bytelength<<3; innerHash(result,w); // Store hash in result pointer, and make sure we get in in the correct order on both endian models. for(i=20;--i>=0;) { hash[i]=(result[i>>2]>>(((3-i)&0x3)<<3))&0xFF; } } void toHexString(const unsigned char *hash, char *hexstring) { const char tab[]={"0123456789abcdef"}; for(int i=20;--i>=0;) { hexstring[i<<1]=tab[(hash[i]>>4)&0xF]; hexstring[(i<<1)+1]=tab[hash[i]&0xF]; } hexstring[40]=0; } } ================================================ FILE: BOSS/source/deprecated/bwapidata/include/Util/sha1.h ================================================ // sha1.h and sha1.cpp are from code.google.com/p/smallsha1/ /* Copyright (c) 2009, Micael Hildenborg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Micael Hildenborg nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SHA1_DEFINED #define SHA1_DEFINED namespace sha1 { /** @param src points to any kind of data to be hashed. @param bytelength the number of bytes to hash from the src pointer. @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. */ void calc(const void *src, const int bytelength, unsigned char *hash); /** @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. */ void toHexString(const unsigned char *hash, char *hexstring); }; // namespace sha1 #endif // SHA1_DEFINED ================================================ FILE: BOSS/source/deprecated/bwapidata/include/WeaponType.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingWeaponType = true; class WeaponTypeInternal { public: WeaponTypeInternal() {valid = false;} void set(const char* name, TechType techType, int damageAmount, int damageBonus, int damageCooldown, int damageFactor, UpgradeType upgradeType, DamageType damageType, ExplosionType explosionType, int minRange, int maxRange, int innerSplashRadius, int medianSplashRadius, int outerSplashRadius, bool targetsAir, bool targetsGround, bool targetsMechanical, bool targetsOrganic, bool targetsNonBuilding, bool targetsNonRobotic, bool targetsTerrain, bool targetsOrgOrMech, bool targetsOwn, UnitType whatUses) { if (initializingWeaponType) { this->name = name; this->techType = techType; this->damageAmount = damageAmount; this->damageBonus = damageBonus; this->damageCooldown = damageCooldown; this->damageFactor = damageFactor; this->upgradeType = upgradeType; this->damageType = damageType; this->explosionType = explosionType; this->minRange = minRange; this->maxRange = maxRange; this->innerSplashRadius = innerSplashRadius; this->medianSplashRadius = medianSplashRadius; this->outerSplashRadius = outerSplashRadius; this->targetsAir = targetsAir; this->targetsGround = targetsGround; this->targetsMechanical = targetsMechanical; this->targetsOrganic = targetsOrganic; this->targetsNonBuilding = targetsNonBuilding; this->targetsNonRobotic = targetsNonRobotic; this->targetsTerrain = targetsTerrain; this->targetsOrgOrMech = targetsOrgOrMech; this->targetsOwn = targetsOwn; this->whatUses = whatUses; this->valid = true; } } std::string name; TechType techType; UnitType whatUses; int damageAmount; int damageBonus; int damageCooldown; int damageFactor; UpgradeType upgradeType; DamageType damageType; ExplosionType explosionType; int minRange; int maxRange; int innerSplashRadius; int medianSplashRadius; int outerSplashRadius; bool targetsAir; bool targetsGround; bool targetsMechanical; bool targetsOrganic; bool targetsNonBuilding; bool targetsNonRobotic; bool targetsTerrain; bool targetsOrgOrMech; bool targetsOwn; bool valid; }; WeaponTypeInternal weaponTypeData[132]; std::map weaponTypeMap; std::set< WeaponType > weaponTypeSet; std::set< WeaponType > specialWeaponTypeSet; std::set< WeaponType > normalWeaponTypeSet; namespace WeaponTypes { const WeaponType Gauss_Rifle(0); const WeaponType Gauss_Rifle_Jim_Raynor(1); const WeaponType C_10_Canister_Rifle(2); const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan(3); const WeaponType C_10_Canister_Rifle_Samir_Duran(112); const WeaponType C_10_Canister_Rifle_Infested_Duran(113); const WeaponType C_10_Canister_Rifle_Alexei_Stukov(116); const WeaponType Fragmentation_Grenade(4); const WeaponType Fragmentation_Grenade_Jim_Raynor(5); const WeaponType Spider_Mines(6); const WeaponType Twin_Autocannons(7); const WeaponType Twin_Autocannons_Alan_Schezar(9); const WeaponType Hellfire_Missile_Pack(8); const WeaponType Hellfire_Missile_Pack_Alan_Schezar(10); const WeaponType Arclite_Cannon(11); const WeaponType Arclite_Cannon_Edmund_Duke(12); const WeaponType Fusion_Cutter(13); const WeaponType Gemini_Missiles(15); const WeaponType Gemini_Missiles_Tom_Kazansky(17); const WeaponType Burst_Lasers(16); const WeaponType Burst_Lasers_Tom_Kazansky(18); const WeaponType ATS_Laser_Battery(19); const WeaponType ATS_Laser_Battery_Hero(21); const WeaponType ATS_Laser_Battery_Hyperion(23); const WeaponType ATA_Laser_Battery(20); const WeaponType ATA_Laser_Battery_Hero(22); const WeaponType ATA_Laser_Battery_Hyperion(24); const WeaponType Flame_Thrower(25); const WeaponType Flame_Thrower_Gui_Montag(26); const WeaponType Arclite_Shock_Cannon(27); const WeaponType Arclite_Shock_Cannon_Edmund_Duke(28); const WeaponType Longbolt_Missile(29); const WeaponType Claws(35); const WeaponType Claws_Devouring_One(36); const WeaponType Claws_Infested_Kerrigan(37); const WeaponType Needle_Spines(38); const WeaponType Needle_Spines_Hunter_Killer(39); const WeaponType Kaiser_Blades(40); const WeaponType Kaiser_Blades_Torrasque(41); const WeaponType Toxic_Spores(42); const WeaponType Spines(43); const WeaponType Acid_Spore(46); const WeaponType Acid_Spore_Kukulza(47); const WeaponType Glave_Wurm(48); const WeaponType Glave_Wurm_Kukulza(49); const WeaponType Seeker_Spores(52); const WeaponType Subterranean_Tentacle(53); const WeaponType Suicide_Infested_Terran(54); const WeaponType Suicide_Scourge(55); const WeaponType Particle_Beam(62); const WeaponType Psi_Blades(64); const WeaponType Psi_Blades_Fenix(65); const WeaponType Phase_Disruptor(66); const WeaponType Phase_Disruptor_Fenix(67); const WeaponType Psi_Assault(69); const WeaponType Psionic_Shockwave(70); const WeaponType Psionic_Shockwave_TZ_Archon(71); const WeaponType Dual_Photon_Blasters(73); const WeaponType Dual_Photon_Blasters_Mojo(75); const WeaponType Dual_Photon_Blasters_Artanis(114); const WeaponType Anti_Matter_Missiles(74); const WeaponType Anti_Matter_Missiles_Mojo(76); const WeaponType Anti_Matter_Missiles_Artanis(115); const WeaponType Phase_Disruptor_Cannon(77); const WeaponType Phase_Disruptor_Cannon_Danimoth(78); const WeaponType Pulse_Cannon(79); const WeaponType STS_Photon_Cannon(80); const WeaponType STA_Photon_Cannon(81); const WeaponType Scarab(82); const WeaponType Subterranean_Spines(109); const WeaponType Warp_Blades(111); const WeaponType Warp_Blades_Hero(86); const WeaponType Warp_Blades_Zeratul(85); const WeaponType Neutron_Flare(100); const WeaponType Halo_Rockets(103); const WeaponType Yamato_Gun(30); const WeaponType Nuclear_Strike(31); const WeaponType Lockdown(32); const WeaponType EMP_Shockwave(33); const WeaponType Irradiate(34); const WeaponType Parasite(56); const WeaponType Spawn_Broodlings(57); const WeaponType Ensnare(58); const WeaponType Dark_Swarm(59); const WeaponType Plague(60); const WeaponType Consume(61); const WeaponType Stasis_Field(83); const WeaponType Psionic_Storm(84); const WeaponType Disruption_Web(101); const WeaponType Restoration(102); const WeaponType Corrosive_Acid(104); const WeaponType Mind_Control(105); const WeaponType Feedback(106); const WeaponType Optical_Flare(107); const WeaponType Maelstrom(108); const WeaponType None(130); const WeaponType Unknown(131); void init() { weaponTypeData[Gauss_Rifle.getID()].set("Gauss Rifle", TechTypes::None, 6, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Marine); weaponTypeData[Gauss_Rifle_Jim_Raynor.getID()].set("Gauss Rifle (Jim Raynor)", TechTypes::None, 18, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Marine); weaponTypeData[C_10_Canister_Rifle.getID()].set("C-10 Canister Rifle", TechTypes::None, 10, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[C_10_Canister_Rifle_Sarah_Kerrigan.getID()].set("C-10 Canister Rifle (Sarah Kerrigan)", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Sarah_Kerrigan); weaponTypeData[C_10_Canister_Rifle_Samir_Duran.getID()].set("C-10 Canister Rifle (Samir Duran)", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Samir_Duran); weaponTypeData[C_10_Canister_Rifle_Infested_Duran.getID()].set("C-10 Canister Rifle (Infested Duran)", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Duran); weaponTypeData[C_10_Canister_Rifle_Alexei_Stukov.getID()].set("C-10 Canister Rifle (Alexei Stukov)", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alexei_Stukov); weaponTypeData[Fragmentation_Grenade.getID()].set("Fragmentation Grenade", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Vulture); weaponTypeData[Fragmentation_Grenade_Jim_Raynor.getID()].set("Fragmentation Grenade (Jim Raynor)", TechTypes::None, 30, 2, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Vulture); weaponTypeData[Spider_Mines.getID()].set("Spider Mines", TechTypes::Spider_Mines, 125, 0, 22, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 10, 50, 75, 100, 0, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Vulture_Spider_Mine); weaponTypeData[Twin_Autocannons.getID()].set("Twin Autocannons", TechTypes::None, 12, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath); weaponTypeData[Twin_Autocannons_Alan_Schezar.getID()].set("Twin Autocannons (Alan Schezar)", TechTypes::None, 24, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar); weaponTypeData[Hellfire_Missile_Pack.getID()].set("Hellfire Missile Pack", TechTypes::None, 10, 2, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath); weaponTypeData[Hellfire_Missile_Pack_Alan_Schezar.getID()].set("Hellfire Missile Pack (Alan Schezar)", TechTypes::None, 20, 1, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar); weaponTypeData[Arclite_Cannon.getID()].set("Arclite Cannon", TechTypes::None, 30, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Tank_Mode); weaponTypeData[Arclite_Cannon_Edmund_Duke.getID()].set("Arclite Cannon (Edmund Duke)", TechTypes::None, 70, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Tank_Mode); weaponTypeData[Fusion_Cutter.getID()].set("Fusion Cutter", TechTypes::None, 5, 1, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_SCV); weaponTypeData[Gemini_Missiles.getID()].set("Gemini Missiles", TechTypes::None, 20, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith); weaponTypeData[Gemini_Missiles_Tom_Kazansky.getID()].set("Gemini Missiles (Tom Kazansky)", TechTypes::None, 40, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky); weaponTypeData[Burst_Lasers.getID()].set("Burst Lasers", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith); weaponTypeData[Burst_Lasers_Tom_Kazansky.getID()].set("Burst Lasers (Tom Kazansky)", TechTypes::None, 16, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky); weaponTypeData[ATS_Laser_Battery.getID()].set("ATS Laser Battery", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[ATS_Laser_Battery_Hero.getID()].set("ATS Laser Battery (Hero)", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II); weaponTypeData[ATS_Laser_Battery_Hyperion.getID()].set("ATS Laser Battery (Hyperion)", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion); weaponTypeData[ATA_Laser_Battery.getID()].set("ATA Laser Battery", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[ATA_Laser_Battery_Hero.getID()].set("ATA Laser Battery (Hero)", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II); weaponTypeData[ATA_Laser_Battery_Hyperion.getID()].set("ATA Laser Battery (Hyperion)", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion); weaponTypeData[Flame_Thrower.getID()].set("Flame Thrower", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat); weaponTypeData[Flame_Thrower_Gui_Montag.getID()].set("Flame Thrower (Gui Montag)", TechTypes::None, 16, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat); weaponTypeData[Arclite_Shock_Cannon.getID()].set("Arclite Shock Cannon", TechTypes::None, 70, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Siege_Mode); weaponTypeData[Arclite_Shock_Cannon_Edmund_Duke.getID()].set("Arclite Shock Cannon (Edmund Duke)", TechTypes::None, 150, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Siege_Mode); weaponTypeData[Longbolt_Missile.getID()].set("Longbolt Missile", TechTypes::None, 20, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Missile_Turret); weaponTypeData[Yamato_Gun.getID()].set("Yamato Gun", TechTypes::Yamato_Gun, 260, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Yamato_Gun, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[Nuclear_Strike.getID()].set("Nuclear Strike", TechTypes::Nuclear_Strike, 600, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Nuclear_Missile, 0, 3, 128, 192, 256, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[Lockdown.getID()].set("Lockdown", TechTypes::Lockdown, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::Lockdown, 0, 256, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[EMP_Shockwave.getID()].set("EMP Shockwave", TechTypes::EMP_Shockwave, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::EMP_Shockwave, 0, 256, 64, 64, 64, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel); weaponTypeData[Irradiate.getID()].set("Irradiate", TechTypes::Irradiate, 250, 0, 75, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Irradiate, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel); weaponTypeData[Claws.getID()].set("Claws", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Zergling); weaponTypeData[Claws_Devouring_One.getID()].set("Claws (Devouring One)", TechTypes::None, 10, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Devouring_One); weaponTypeData[Claws_Infested_Kerrigan.getID()].set("Claws (Infested Kerrigan)", TechTypes::None, 50, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Kerrigan); weaponTypeData[Needle_Spines.getID()].set("Needle Spines", TechTypes::None, 10, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Hydralisk); weaponTypeData[Needle_Spines_Hunter_Killer.getID()].set("Needle Spines (Hunter Killer)", TechTypes::None, 20, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hunter_Killer); weaponTypeData[Kaiser_Blades.getID()].set("Kaiser Blades", TechTypes::None, 20, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Ultralisk); weaponTypeData[Kaiser_Blades_Torrasque.getID()].set("Kaiser Blades (Torrasque)", TechTypes::None, 50, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Torrasque); weaponTypeData[Toxic_Spores.getID()].set("Toxic Spores", TechTypes::None, 4, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Broodling); weaponTypeData[Spines.getID()].set("Spines", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Drone); weaponTypeData[Acid_Spore.getID()].set("Acid Spore", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Guardian); weaponTypeData[Acid_Spore_Kukulza.getID()].set("Acid Spore (Kukulza)", TechTypes::None, 40, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Guardian); weaponTypeData[Glave_Wurm.getID()].set("Glave Wurm", TechTypes::None, 9, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Mutalisk); weaponTypeData[Glave_Wurm_Kukulza.getID()].set("Glave Wurm (Kukulza)", TechTypes::None, 18, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Mutalisk); weaponTypeData[Seeker_Spores.getID()].set("Seeker Spores", TechTypes::None, 15, 0, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Spore_Colony); weaponTypeData[Subterranean_Tentacle.getID()].set("Subterranean Tentacle", TechTypes::None, 40, 0, 32, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Sunken_Colony); weaponTypeData[Suicide_Infested_Terran.getID()].set("Suicide Infested Terran", TechTypes::None, 500, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 3, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Infested_Terran); weaponTypeData[Suicide_Scourge.getID()].set("Suicide Scourge", TechTypes::None, 110, 0, 1, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Scourge); weaponTypeData[Parasite.getID()].set("Parasite", TechTypes::Parasite, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Parasite, 0, 384, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Zerg_Queen); weaponTypeData[Spawn_Broodlings.getID()].set("Spawn Broodlings", TechTypes::Spawn_Broodlings, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Broodlings, 0, 288, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, UnitTypes::Zerg_Queen); weaponTypeData[Ensnare.getID()].set("Ensnare", TechTypes::Ensnare, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Ensnare, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Queen); weaponTypeData[Dark_Swarm.getID()].set("Dark Swarm", TechTypes::Dark_Swarm, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Dark_Swarm, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Defiler); weaponTypeData[Plague.getID()].set("Plague", TechTypes::Plague, 300, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Plague, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Defiler); weaponTypeData[Consume.getID()].set("Consume", TechTypes::Consume, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Consume, 0, 16, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, UnitTypes::Zerg_Defiler); weaponTypeData[Particle_Beam.getID()].set("Particle Beam", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Probe); weaponTypeData[Psi_Blades.getID()].set("Psi Blades", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Zealot); weaponTypeData[Psi_Blades_Fenix.getID()].set("Psi Blades (Fenix)", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Zealot); weaponTypeData[Phase_Disruptor.getID()].set("Phase Disruptor", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dragoon); weaponTypeData[Phase_Disruptor_Fenix.getID()].set("Phase Disruptor (Fenix)", TechTypes::None, 45, 2, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Dragoon); weaponTypeData[Psi_Assault.getID()].set("Psi Assault", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar); weaponTypeData[Psionic_Shockwave.getID()].set("Psionic Shockwave", TechTypes::None, 30, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Archon); weaponTypeData[Psionic_Shockwave_TZ_Archon.getID()].set("Psionic Shockwave (Tassadar/Zeratul Archon)", TechTypes::None, 60, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar_Zeratul_Archon); weaponTypeData[Dual_Photon_Blasters.getID()].set("Dual Photon Blasters", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout); weaponTypeData[Dual_Photon_Blasters_Mojo.getID()].set("Dual Photon Blasters (Mojo)", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo); weaponTypeData[Dual_Photon_Blasters_Artanis.getID()].set("Dual Photon Blasters (Artanis)", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis); weaponTypeData[Anti_Matter_Missiles.getID()].set("Anti-Matter Missiles", TechTypes::None, 14, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout); weaponTypeData[Anti_Matter_Missiles_Mojo.getID()].set("Anti-Matter Missiles (Mojo)", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo); weaponTypeData[Anti_Matter_Missiles_Artanis.getID()].set("Anti-Matter Missiles (Artanis)", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis); weaponTypeData[Phase_Disruptor_Cannon.getID()].set("Phase Disruptor Cannon", TechTypes::None, 10, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Arbiter); weaponTypeData[Phase_Disruptor_Cannon_Danimoth.getID()].set("Phase Disruptor Cannon (Danimoth)", TechTypes::None, 20, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Danimoth); weaponTypeData[Pulse_Cannon.getID()].set("Pulse Cannon", TechTypes::None, 6, 1, 1, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Interceptor); weaponTypeData[STS_Photon_Cannon.getID()].set("STS Photon Cannon", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon); weaponTypeData[STA_Photon_Cannon.getID()].set("STA Photon Cannon", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon); weaponTypeData[Scarab.getID()].set("Scarab", TechTypes::None, 100, 25, 1, 1, UpgradeTypes::Scarab_Damage, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 128, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scarab); weaponTypeData[Stasis_Field.getID()].set("Stasis Field", TechTypes::Stasis_Field, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Stasis_Field, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Arbiter); weaponTypeData[Psionic_Storm.getID()].set("Psionic Storm", TechTypes::Psionic_Storm, 14, 1, 45, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Radial_Splash, 0, 288, 48, 48, 48, 1, 1, 0, 0, 1, 0, 1, 0, 0, UnitTypes::Protoss_High_Templar); weaponTypeData[Neutron_Flare.getID()].set("Neutron Flare", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 160, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair); weaponTypeData[Disruption_Web.getID()].set("Disruption Web", TechTypes::Disruption_Web, 0, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Disruption_Web, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair); weaponTypeData[Restoration.getID()].set("Restoration", TechTypes::Restoration, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Restoration, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Medic); weaponTypeData[Halo_Rockets.getID()].set("Halo Rockets", TechTypes::None, 6, 1, 64, 2, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 192, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Valkyrie); weaponTypeData[Corrosive_Acid.getID()].set("Corrosive Acid", TechTypes::None, 25, 2, 100, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Explosive, ExplosionTypes::Corrosive_Acid, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Devourer); weaponTypeData[Mind_Control.getID()].set("Mind Control", TechTypes::Mind_Control, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Mind_Control, 0, 256, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Feedback.getID()].set("Feedback", TechTypes::Feedback, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Feedback, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Optical_Flare.getID()].set("Optical Flare", TechTypes::Optical_Flare, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Optical_Flare, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Medic); weaponTypeData[Maelstrom.getID()].set("Maelstrom", TechTypes::Maelstrom, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Maelstrom, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Subterranean_Spines.getID()].set("Subterranean Spines", TechTypes::None, 20, 2, 37, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 192, 20, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Lurker); weaponTypeData[Warp_Blades.getID()].set("Warp Blades", TechTypes::None, 40, 3, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dark_Templar); weaponTypeData[Warp_Blades_Hero.getID()].set("Warp Blades (Hero)", TechTypes::None, 45, 1, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Dark_Templar); weaponTypeData[Warp_Blades_Zeratul.getID()].set("Warp Blades (Zeratul)", TechTypes::None, 100, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Zeratul); weaponTypeData[None.getID()].set("None", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None); weaponTypeData[Unknown.getID()].set("Unknown", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None); weaponTypeSet.insert(Gauss_Rifle); weaponTypeSet.insert(Gauss_Rifle_Jim_Raynor); weaponTypeSet.insert(C_10_Canister_Rifle); weaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan); weaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran); weaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran); weaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov); weaponTypeSet.insert(Fragmentation_Grenade); weaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor); weaponTypeSet.insert(Spider_Mines); weaponTypeSet.insert(Twin_Autocannons); weaponTypeSet.insert(Twin_Autocannons_Alan_Schezar); weaponTypeSet.insert(Hellfire_Missile_Pack); weaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar); weaponTypeSet.insert(Arclite_Cannon); weaponTypeSet.insert(Arclite_Cannon_Edmund_Duke); weaponTypeSet.insert(Fusion_Cutter); weaponTypeSet.insert(Gemini_Missiles); weaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky); weaponTypeSet.insert(Burst_Lasers); weaponTypeSet.insert(Burst_Lasers_Tom_Kazansky); weaponTypeSet.insert(ATS_Laser_Battery); weaponTypeSet.insert(ATS_Laser_Battery_Hero); weaponTypeSet.insert(ATS_Laser_Battery_Hyperion); weaponTypeSet.insert(ATA_Laser_Battery); weaponTypeSet.insert(ATA_Laser_Battery_Hero); weaponTypeSet.insert(ATA_Laser_Battery_Hyperion); weaponTypeSet.insert(Flame_Thrower); weaponTypeSet.insert(Flame_Thrower_Gui_Montag); weaponTypeSet.insert(Arclite_Shock_Cannon); weaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke); weaponTypeSet.insert(Longbolt_Missile); weaponTypeSet.insert(Claws); weaponTypeSet.insert(Claws_Devouring_One); weaponTypeSet.insert(Claws_Infested_Kerrigan); weaponTypeSet.insert(Needle_Spines); weaponTypeSet.insert(Needle_Spines_Hunter_Killer); weaponTypeSet.insert(Kaiser_Blades); weaponTypeSet.insert(Kaiser_Blades_Torrasque); weaponTypeSet.insert(Toxic_Spores); weaponTypeSet.insert(Spines); weaponTypeSet.insert(Acid_Spore); weaponTypeSet.insert(Acid_Spore_Kukulza); weaponTypeSet.insert(Glave_Wurm); weaponTypeSet.insert(Glave_Wurm_Kukulza); weaponTypeSet.insert(Seeker_Spores); weaponTypeSet.insert(Subterranean_Tentacle); weaponTypeSet.insert(Suicide_Infested_Terran); weaponTypeSet.insert(Suicide_Scourge); weaponTypeSet.insert(Particle_Beam); weaponTypeSet.insert(Psi_Blades); weaponTypeSet.insert(Psi_Blades_Fenix); weaponTypeSet.insert(Phase_Disruptor); weaponTypeSet.insert(Phase_Disruptor_Fenix); weaponTypeSet.insert(Psi_Assault); weaponTypeSet.insert(Psionic_Shockwave); weaponTypeSet.insert(Psionic_Shockwave_TZ_Archon); weaponTypeSet.insert(Dual_Photon_Blasters); weaponTypeSet.insert(Dual_Photon_Blasters_Mojo); weaponTypeSet.insert(Dual_Photon_Blasters_Artanis); weaponTypeSet.insert(Anti_Matter_Missiles); weaponTypeSet.insert(Anti_Matter_Missiles_Mojo); weaponTypeSet.insert(Anti_Matter_Missiles_Artanis); weaponTypeSet.insert(Phase_Disruptor_Cannon); weaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth); weaponTypeSet.insert(Pulse_Cannon); weaponTypeSet.insert(STS_Photon_Cannon); weaponTypeSet.insert(STA_Photon_Cannon); weaponTypeSet.insert(Scarab); weaponTypeSet.insert(Neutron_Flare); weaponTypeSet.insert(Halo_Rockets); weaponTypeSet.insert(Corrosive_Acid); weaponTypeSet.insert(Subterranean_Spines); weaponTypeSet.insert(Warp_Blades); weaponTypeSet.insert(Warp_Blades_Hero); weaponTypeSet.insert(Warp_Blades_Zeratul); normalWeaponTypeSet.insert(Gauss_Rifle); normalWeaponTypeSet.insert(Gauss_Rifle_Jim_Raynor); normalWeaponTypeSet.insert(C_10_Canister_Rifle); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov); normalWeaponTypeSet.insert(Fragmentation_Grenade); normalWeaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor); normalWeaponTypeSet.insert(Spider_Mines); normalWeaponTypeSet.insert(Twin_Autocannons); normalWeaponTypeSet.insert(Twin_Autocannons_Alan_Schezar); normalWeaponTypeSet.insert(Hellfire_Missile_Pack); normalWeaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar); normalWeaponTypeSet.insert(Arclite_Cannon); normalWeaponTypeSet.insert(Arclite_Cannon_Edmund_Duke); normalWeaponTypeSet.insert(Fusion_Cutter); normalWeaponTypeSet.insert(Gemini_Missiles); normalWeaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky); normalWeaponTypeSet.insert(Burst_Lasers); normalWeaponTypeSet.insert(Burst_Lasers_Tom_Kazansky); normalWeaponTypeSet.insert(ATS_Laser_Battery); normalWeaponTypeSet.insert(ATS_Laser_Battery_Hero); normalWeaponTypeSet.insert(ATS_Laser_Battery_Hyperion); normalWeaponTypeSet.insert(ATA_Laser_Battery); normalWeaponTypeSet.insert(ATA_Laser_Battery_Hero); normalWeaponTypeSet.insert(ATA_Laser_Battery_Hyperion); normalWeaponTypeSet.insert(Flame_Thrower); normalWeaponTypeSet.insert(Flame_Thrower_Gui_Montag); normalWeaponTypeSet.insert(Arclite_Shock_Cannon); normalWeaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke); normalWeaponTypeSet.insert(Longbolt_Missile); normalWeaponTypeSet.insert(Claws); normalWeaponTypeSet.insert(Claws_Devouring_One); normalWeaponTypeSet.insert(Claws_Infested_Kerrigan); normalWeaponTypeSet.insert(Needle_Spines); normalWeaponTypeSet.insert(Needle_Spines_Hunter_Killer); normalWeaponTypeSet.insert(Kaiser_Blades); normalWeaponTypeSet.insert(Kaiser_Blades_Torrasque); normalWeaponTypeSet.insert(Toxic_Spores); normalWeaponTypeSet.insert(Spines); normalWeaponTypeSet.insert(Acid_Spore); normalWeaponTypeSet.insert(Acid_Spore_Kukulza); normalWeaponTypeSet.insert(Glave_Wurm); normalWeaponTypeSet.insert(Glave_Wurm_Kukulza); normalWeaponTypeSet.insert(Seeker_Spores); normalWeaponTypeSet.insert(Subterranean_Tentacle); normalWeaponTypeSet.insert(Suicide_Infested_Terran); normalWeaponTypeSet.insert(Suicide_Scourge); normalWeaponTypeSet.insert(Particle_Beam); normalWeaponTypeSet.insert(Psi_Blades); normalWeaponTypeSet.insert(Psi_Blades_Fenix); normalWeaponTypeSet.insert(Phase_Disruptor); normalWeaponTypeSet.insert(Phase_Disruptor_Fenix); normalWeaponTypeSet.insert(Psi_Assault); normalWeaponTypeSet.insert(Psionic_Shockwave); normalWeaponTypeSet.insert(Psionic_Shockwave_TZ_Archon); normalWeaponTypeSet.insert(Dual_Photon_Blasters); normalWeaponTypeSet.insert(Dual_Photon_Blasters_Mojo); normalWeaponTypeSet.insert(Dual_Photon_Blasters_Artanis); normalWeaponTypeSet.insert(Anti_Matter_Missiles); normalWeaponTypeSet.insert(Anti_Matter_Missiles_Mojo); normalWeaponTypeSet.insert(Anti_Matter_Missiles_Artanis); normalWeaponTypeSet.insert(Phase_Disruptor_Cannon); normalWeaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth); normalWeaponTypeSet.insert(Pulse_Cannon); normalWeaponTypeSet.insert(STS_Photon_Cannon); normalWeaponTypeSet.insert(STA_Photon_Cannon); normalWeaponTypeSet.insert(Scarab); normalWeaponTypeSet.insert(Neutron_Flare); normalWeaponTypeSet.insert(Halo_Rockets); normalWeaponTypeSet.insert(Corrosive_Acid); normalWeaponTypeSet.insert(Subterranean_Spines); normalWeaponTypeSet.insert(Warp_Blades); normalWeaponTypeSet.insert(Warp_Blades_Hero); normalWeaponTypeSet.insert(Warp_Blades_Zeratul); weaponTypeSet.insert(Yamato_Gun); weaponTypeSet.insert(Nuclear_Strike); weaponTypeSet.insert(Lockdown); weaponTypeSet.insert(EMP_Shockwave); weaponTypeSet.insert(Irradiate); weaponTypeSet.insert(Parasite); weaponTypeSet.insert(Spawn_Broodlings); weaponTypeSet.insert(Ensnare); weaponTypeSet.insert(Dark_Swarm); weaponTypeSet.insert(Plague); weaponTypeSet.insert(Consume); weaponTypeSet.insert(Stasis_Field); weaponTypeSet.insert(Psionic_Storm); weaponTypeSet.insert(Disruption_Web); weaponTypeSet.insert(Restoration); weaponTypeSet.insert(Mind_Control); weaponTypeSet.insert(Feedback); weaponTypeSet.insert(Optical_Flare); weaponTypeSet.insert(Maelstrom); specialWeaponTypeSet.insert(Yamato_Gun); specialWeaponTypeSet.insert(Nuclear_Strike); specialWeaponTypeSet.insert(Lockdown); specialWeaponTypeSet.insert(EMP_Shockwave); specialWeaponTypeSet.insert(Irradiate); specialWeaponTypeSet.insert(Parasite); specialWeaponTypeSet.insert(Spawn_Broodlings); specialWeaponTypeSet.insert(Ensnare); specialWeaponTypeSet.insert(Dark_Swarm); specialWeaponTypeSet.insert(Plague); specialWeaponTypeSet.insert(Consume); specialWeaponTypeSet.insert(Stasis_Field); specialWeaponTypeSet.insert(Psionic_Storm); specialWeaponTypeSet.insert(Disruption_Web); specialWeaponTypeSet.insert(Restoration); specialWeaponTypeSet.insert(Mind_Control); specialWeaponTypeSet.insert(Feedback); specialWeaponTypeSet.insert(Optical_Flare); specialWeaponTypeSet.insert(Maelstrom); weaponTypeSet.insert(None); weaponTypeSet.insert(Unknown); foreach(WeaponType i, weaponTypeSet) { std::string name = i.getName(); fixName(&name); weaponTypeMap.insert(std::make_pair(name, i)); } initializingWeaponType = false; } } WeaponType::WeaponType() { this->id = WeaponTypes::None.id; } WeaponType::WeaponType(int id) { this->id = id; if (!initializingWeaponType && (id < 0 || id >= 132 || !weaponTypeData[id].valid)) this->id = WeaponTypes::Unknown.id; } WeaponType::WeaponType(const WeaponType& other) { this->id = other.id; } WeaponType& WeaponType::operator=(const WeaponType& other) { this->id = other.id; return *this; } bool WeaponType::operator==(const WeaponType& other) const { return this->id == other.id; } bool WeaponType::operator!=(const WeaponType& other) const { return this->id != other.id; } bool WeaponType::operator<(const WeaponType& other) const { return this->id < other.id; } int WeaponType::getID() const { return this->id; } std::string WeaponType::getName() const { return weaponTypeData[this->id].name; } TechType WeaponType::getTech() const { return weaponTypeData[this->id].techType; } UnitType WeaponType::whatUses() const { return weaponTypeData[this->id].whatUses; } int WeaponType::damageAmount() const { return weaponTypeData[this->id].damageAmount; } int WeaponType::damageBonus() const { return weaponTypeData[this->id].damageBonus; } int WeaponType::damageCooldown() const { return weaponTypeData[this->id].damageCooldown; } int WeaponType::damageFactor() const { return weaponTypeData[this->id].damageFactor; } UpgradeType WeaponType::upgradeType() const { return weaponTypeData[this->id].upgradeType; } DamageType WeaponType::damageType() const { return weaponTypeData[this->id].damageType; } ExplosionType WeaponType::explosionType() const { return weaponTypeData[this->id].explosionType; } int WeaponType::minRange() const { return weaponTypeData[this->id].minRange; } int WeaponType::maxRange() const { return weaponTypeData[this->id].maxRange; } int WeaponType::innerSplashRadius() const { return weaponTypeData[this->id].innerSplashRadius; } int WeaponType::medianSplashRadius() const { return weaponTypeData[this->id].medianSplashRadius; } int WeaponType::outerSplashRadius() const { return weaponTypeData[this->id].outerSplashRadius; } bool WeaponType::targetsAir() const { return weaponTypeData[this->id].targetsAir; } bool WeaponType::targetsGround() const { return weaponTypeData[this->id].targetsGround; } bool WeaponType::targetsMechanical() const { return weaponTypeData[this->id].targetsMechanical; } bool WeaponType::targetsOrganic() const { return weaponTypeData[this->id].targetsOrganic; } bool WeaponType::targetsNonBuilding() const { return weaponTypeData[this->id].targetsNonBuilding; } bool WeaponType::targetsNonRobotic() const { return weaponTypeData[this->id].targetsNonRobotic; } bool WeaponType::targetsTerrain() const { return weaponTypeData[this->id].targetsTerrain; } bool WeaponType::targetsOrgOrMech() const { return weaponTypeData[this->id].targetsOrgOrMech; } bool WeaponType::targetsOwn() const { return weaponTypeData[this->id].targetsOwn; } WeaponType WeaponTypes::getWeaponType(std::string name) { fixName(&name); std::map::iterator i = weaponTypeMap.find(name); if (i == weaponTypeMap.end()) return WeaponTypes::Unknown; return (*i).second; } std::set& WeaponTypes::allWeaponTypes() { return weaponTypeSet; } std::set& WeaponTypes::normalWeaponTypes() { return weaponTypeSet; } std::set& WeaponTypes::specialWeaponTypes() { return weaponTypeSet; } } ================================================ FILE: BOSS/source/rapidjson/document.h ================================================ #include "../Common.h" #ifdef MCDS_FLASH_VERSION #pragma GCC system_header #endif #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ #include "reader.h" #include "internal/strfunc.h" #include // placement new #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #endif namespace rapidjson { /////////////////////////////////////////////////////////////////////////////// // GenericValue //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! A JSON value can be one of 7 types. This class is a variant type supporting these types. Use the Value if UTF8 and default allocator \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ #pragma pack (push, 4) template > class GenericValue { public: //! Name-value pair in an object. struct Member { GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. }; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef Member* MemberIterator; //!< Member iterator for iterating in object. typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. GenericValue() : flags_(kNullFlag) {} //! Copy constructor is not permitted. private: GenericValue(const GenericValue& rhs); public: //! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \param type Type of the value. \note Default content for number is zero. */ GenericValue(Type type) { static const unsigned defaultFlags[7] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag }; RAPIDJSON_ASSERT(type <= kNumberType); flags_ = defaultFlags[type]; memset(&data_, 0, sizeof(data_)); } //! Constructor for boolean value. GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {} //! Constructor for int value. GenericValue(int i) : flags_(kNumberIntFlag) { data_.n.i64 = i; if (i >= 0) flags_ |= kUintFlag | kUint64Flag; } //! Constructor for unsigned value. GenericValue(unsigned u) : flags_(kNumberUintFlag) { data_.n.u64 = u; if (!(u & 0x80000000)) flags_ |= kIntFlag | kInt64Flag; } //! Constructor for int64_t value. GenericValue(int64_t i64) : flags_(kNumberInt64Flag) { data_.n.i64 = i64; if (i64 >= 0) { flags_ |= kNumberUint64Flag; if (!(i64 & 0xFFFFFFFF00000000LL)) flags_ |= kUintFlag; if (!(i64 & 0xFFFFFFFF80000000LL)) flags_ |= kIntFlag; } else if (i64 >= -2147483648LL) flags_ |= kIntFlag; } //! Constructor for uint64_t value. GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) { data_.n.u64 = u64; if (!(u64 & 0x8000000000000000ULL)) flags_ |= kInt64Flag; if (!(u64 & 0xFFFFFFFF00000000ULL)) flags_ |= kUintFlag; if (!(u64 & 0xFFFFFFFF80000000ULL)) flags_ |= kIntFlag; } //! Constructor for double value. GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) { RAPIDJSON_ASSERT(s != NULL); flags_ = kConstStringFlag; data_.s.str = s; data_.s.length = length; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); } //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(flags_) { case kArrayFlag: for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) v->~GenericValue(); Allocator::Free(data_.a.elements); break; case kObjectFlag: for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) { m->name.~GenericValue(); m->value.~GenericValue(); } Allocator::Free(data_.o.members); break; case kCopyStringFlag: Allocator::Free(const_cast(data_.s.str)); break; } } } //@} //!@name Assignment operators //@{ //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) { RAPIDJSON_ASSERT(this != &rhs); this->~GenericValue(); memcpy(this, &rhs, sizeof(GenericValue)); rhs.flags_ = kNullFlag; return *this; } //! Assignment with primitive types. /*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch* \param value The value to be assigned. */ template GenericValue& operator=(T value) { this->~GenericValue(); new (this) GenericValue(value); return *this; } //@} //!@name Type //@{ Type GetType() const { return static_cast(flags_ & kTypeMask); } bool IsNull() const { return flags_ == kNullFlag; } bool IsFalse() const { return flags_ == kFalseFlag; } bool IsTrue() const { return flags_ == kTrueFlag; } bool IsBool() const { return (flags_ & kBoolFlag) != 0; } bool IsObject() const { return flags_ == kObjectFlag; } bool IsArray() const { return flags_ == kArrayFlag; } bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } bool IsInt() const { return (flags_ & kIntFlag) != 0; } bool IsUint() const { return (flags_ & kUintFlag) != 0; } bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } bool IsString() const { return (flags_ & kStringFlag) != 0; } //@} //!@name Null //@{ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } //@} //!@name Bool //@{ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } //@} //!@name Object //@{ //! Set this value as an empty object. GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the value associated with the object's name. GenericValue& operator[](const Ch* name) { if (Member* member = FindMember(name)) return member->value; else { static GenericValue NullValue; return NullValue; } } const GenericValue& operator[](const Ch* name) const { return const_cast(*this)[name]; } //! Member iterators. ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } //! Check whether a member exists in the object. bool HasMember(const Ch* name) const { return FindMember(name) != 0; } //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. \return The value itself for fluent API. \note The ownership of name and value will be transfered to this object if success. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); Object& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member)); } else { SizeType oldCapacity = o.capacity; o.capacity *= 2; o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)); } } o.members[o.size].name.RawAssign(name); o.members[o.size].value.RawAssign(value); o.size++; return *this; } GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) { GenericValue n(name, internal::StrLen(name), nameAllocator); return AddMember(n, value, allocator); } GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) { GenericValue n(name, internal::StrLen(name)); return AddMember(n, value, allocator); } template GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) { GenericValue n(name, internal::StrLen(name)); GenericValue v(value); return AddMember(n, v, allocator); } //! Remove a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note Removing member is implemented by moving the last member. So the ordering of members is changed. */ bool RemoveMember(const Ch* name) { RAPIDJSON_ASSERT(IsObject()); if (Member* m = FindMember(name)) { RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(data_.o.members != 0); Member* last = data_.o.members + (data_.o.size - 1); if (data_.o.size > 1 && m != last) { // Move the last one to this place m->name = last->name; m->value = last->value; } else { // Only one left, just destroy m->name.~GenericValue(); m->value.~GenericValue(); } --data_.o.size; return true; } return false; } //@} //!@name Array //@{ //! Set this value as an empty array. GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } //! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. */ void Clear() { RAPIDJSON_ASSERT(IsArray()); for (SizeType i = 0; i < data_.a.size; ++i) data_.a.elements[i].~GenericValue(); data_.a.size = 0; } //! Get an element from array by index. /*! \param index Zero-based index of element. \note \code Value a(kArrayType); a.PushBack(123); int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. int z = a[0u].GetInt(); // This works too. \endcode */ GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); return data_.a.elements[index]; } const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } //! Element iterator ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } ConstValueIterator Begin() const { return const_cast(*this).Begin(); } ConstValueIterator End() const { return const_cast(*this).End(); } //! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \param allocator The allocator for allocating memory. It must be the same one use previously. \return The value itself for fluent API. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); data_.a.capacity = newCapacity; } return *this; } //! Append a value at the end of the array. /*! \param value The value to be appended. \param allocator The allocator for allocating memory. It must be the same one use previously. \return The value itself for fluent API. \note The ownership of the value will be transfered to this object if success. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator); data_.a.elements[data_.a.size++].RawAssign(value); return *this; } template GenericValue& PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); } //! Remove the last element in the array. GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); data_.a.elements[--data_.a.size].~GenericValue(); return *this; } //@} //!@name Number //@{ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } //@} //!@name String //@{ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; } //! Get the length of string. /*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string pointer. \param length The length of source string, excluding the trailing null terminator. \return The value itself for fluent API. */ GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; } //! Set this value as a string without copying source string. /*! \param s source string pointer. \return The value itself for fluent API. */ GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); } //! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string. \param length The length of source string, excluding the trailing null terminator. \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator(). \return The value itself for fluent API. */ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; } //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator(). \return The value itself for fluent API. */ GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; } //@} //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. It can also be used to deep clone this value via GenericDocument, which is also a Handler. \tparam Handler type of handler. \param handler An object implementing concept Handler. */ template const GenericValue& Accept(Handler& handler) const { switch(GetType()) { case kNullType: handler.Null(); break; case kFalseType: handler.Bool(false); break; case kTrueType: handler.Bool(true); break; case kObjectType: handler.StartObject(); for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) { handler.String(m->name.data_.s.str, m->name.data_.s.length, false); m->value.Accept(handler); } handler.EndObject(data_.o.size); break; case kArrayType: handler.StartArray(); for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) v->Accept(handler); handler.EndArray(data_.a.size); break; case kStringType: handler.String(data_.s.str, data_.s.length, false); break; case kNumberType: if (IsInt()) handler.Int(data_.n.i.i); else if (IsUint()) handler.Uint(data_.n.u.u); else if (IsInt64()) handler.Int64(data_.n.i64); else if (IsUint64()) handler.Uint64(data_.n.u64); else handler.Double(data_.n.d); break; } return *this; } private: template friend class GenericDocument; enum { kBoolFlag = 0x100, kNumberFlag = 0x200, kIntFlag = 0x400, kUintFlag = 0x800, kInt64Flag = 0x1000, kUint64Flag = 0x2000, kDoubleFlag = 0x4000, kStringFlag = 0x100000, kCopyFlag = 0x200000, // Initial flags of different types. kNullFlag = kNullType, kTrueFlag = kTrueType | kBoolFlag, kFalseFlag = kFalseType | kBoolFlag, kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, kConstStringFlag = kStringType | kStringFlag, kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler }; static const SizeType kDefaultArrayCapacity = 16; static const SizeType kDefaultObjectCapacity = 16; struct String { const Ch* str; SizeType length; unsigned hashcode; //!< reserved }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; }i; struct U { unsigned u; char padding2[4]; }u; #else struct I { char padding[4]; int i; }i; struct U { char padding2[4]; unsigned u; }u; #endif int64_t i64; uint64_t u64; double d; }; // 8 bytes struct Object { Member* members; SizeType size; SizeType capacity; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode struct Array { GenericValue* elements; SizeType size; SizeType capacity; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; Number n; Object o; Array a; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode //! Find member by name. Member* FindMember(const Ch* name) { RAPIDJSON_ASSERT(name); RAPIDJSON_ASSERT(IsObject()); SizeType length = internal::StrLen(name); Object& o = data_.o; for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member) if (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0) return member; return 0; } const Member* FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) { flags_ = kArrayFlag; data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue)); memcpy(data_.a.elements, values, count * sizeof(GenericValue)); data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) { flags_ = kObjectFlag; data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member)); memcpy(data_.o.members, members, count * sizeof(Member)); data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(const Ch* s, SizeType length) { RAPIDJSON_ASSERT(s != NULL); flags_ = kConstStringFlag; data_.s.str = s; data_.s.length = length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) { RAPIDJSON_ASSERT(s != NULL); flags_ = kCopyStringFlag; data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch)); data_.s.length = length; memcpy(const_cast(data_.s.str), s, length * sizeof(Ch)); const_cast(data_.s.str)[length] = '\0'; } //! Assignment without calling destructor void RawAssign(GenericValue& rhs) { memcpy(this, &rhs, sizeof(GenericValue)); rhs.flags_ = kNullFlag; } Data data_; unsigned flags_; }; #pragma pack (pop) //! Value with UTF8 encoding. typedef GenericValue > Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument //! A document for parsing JSON text as DOM. /*! \implements Handler \tparam Encoding encoding for both parsing and string storage. \tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing. */ template > class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor /*! \param allocator Optional allocator for allocating stack memory. \param stackCapacity Initial capacity of stack in bytes. */ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {} //! Parse JSON text from an input stream. /*! \tparam parseFlags Combination of ParseFlag. \param stream Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(Stream& stream) { ValueType::SetNull(); // Remove existing root if exist GenericReader reader; if (reader.template Parse(stream, *this)) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. parseError_ = 0; errorOffset_ = 0; } else { parseError_ = reader.GetParseError(); errorOffset_ = reader.GetErrorOffset(); ClearStack(); } return *this; } //! Parse JSON text from a mutable string. /*! \tparam parseFlags Combination of ParseFlag. \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseInsitu(Ch* str) { GenericInsituStringStream s(str); return ParseStream(s); } //! Parse JSON text from a read-only string. /*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); } //! Whether a parse error was occured in the last parsing. bool HasParseError() const { return parseError_ != 0; } //! Get the message of parsing error. const char* GetParseError() const { return parseError_; } //! Get the offset in character of the parsing error. size_t GetErrorOffset() const { return errorOffset_; } //! Get the allocator of this document. Allocator& GetAllocator() { return stack_.GetAllocator(); } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: // Prohibit assignment GenericDocument& operator=(const GenericDocument&); friend class GenericReader; // for Reader to call the following private handler functions // Implementation of Handler void Null() { new (stack_.template Push()) ValueType(); } void Bool(bool b) { new (stack_.template Push()) ValueType(b); } void Int(int i) { new (stack_.template Push()) ValueType(i); } void Uint(unsigned i) { new (stack_.template Push()) ValueType(i); } void Int64(int64_t i) { new (stack_.template Push()) ValueType(i); } void Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); } void Double(double d) { new (stack_.template Push()) ValueType(d); } void String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); } void StartObject() { new (stack_.template Push()) ValueType(kObjectType); } void EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); } void StartArray() { new (stack_.template Push()) ValueType(kArrayType); } void EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop(elementCount); stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); } void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) (stack_.template Pop(1))->~ValueType(); else stack_.Clear(); } static const size_t kDefaultStackCapacity = 1024; internal::Stack stack_; const char* parseError_; size_t errorOffset_; }; typedef GenericDocument > Document; } // namespace rapidjson #ifdef _MSC_VER #pragma warning(pop) #endif #endif // RAPIDJSON_DOCUMENT_H_ ================================================ FILE: BOSS/source/rapidjson/filestream.h ================================================ #ifndef RAPIDJSON_FILESTREAM_H_ #define RAPIDJSON_FILESTREAM_H_ #include namespace rapidjson { //! Wrapper of C file stream for input or output. /*! This simple wrapper does not check the validity of the stream. \implements Stream */ class FileStream { public: typedef char Ch; //!< Character type. Only support char. FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); } char Peek() const { return current_; } char Take() { char c = current_; Read(); return c; } size_t Tell() const { return count_; } void Put(char c) { fputc(c, fp_); } // Not implemented char* PutBegin() { return 0; } size_t PutEnd(char*) { return 0; } private: void Read() { RAPIDJSON_ASSERT(fp_ != 0); int c = fgetc(fp_); if (c != EOF) { current_ = (char)c; count_++; } else current_ = '\0'; } FILE* fp_; char current_; size_t count_; }; } // namespace rapidjson #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: BOSS/source/rapidjson/internal/pow10.h ================================================ #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ namespace rapidjson { namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. \param n positive/negative exponent. Must <= 308. \return 10.0^n */ inline double Pow10(int n) { static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes 1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300, 1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280, 1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260, 1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240, 1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220, 1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200, 1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180, 1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160, 1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140, 1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120, 1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100, 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }; RAPIDJSON_ASSERT(n <= 308); return n < -308 ? 0.0 : e[n + 308]; } } // namespace internal } // namespace rapidjson #endif // RAPIDJSON_POW10_ ================================================ FILE: BOSS/source/rapidjson/internal/stack.h ================================================ #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ namespace rapidjson { namespace internal { /////////////////////////////////////////////////////////////////////////////// // Stack //! A type-unsafe stack for storing different types of data. /*! \tparam Allocator Allocator for allocating stack memory. */ template class Stack { public: Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) { RAPIDJSON_ASSERT(stack_capacity_ > 0); if (!allocator_) own_allocator_ = allocator_ = new Allocator(); stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_); stack_end_ = stack_ + stack_capacity_; } ~Stack() { Allocator::Free(stack_); delete own_allocator_; // Only delete if it is owned by the stack } void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; } template T* Push(size_t count = 1) { // Expand the stack if needed if (stack_top_ + sizeof(T) * count >= stack_end_) { size_t new_capacity = stack_capacity_ * 2; size_t size = GetSize(); size_t new_size = GetSize() + sizeof(T) * count; if (new_capacity < new_size) new_capacity = new_size; stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity); stack_capacity_ = new_capacity; stack_top_ = stack_ + size; stack_end_ = stack_ + stack_capacity_; } T* ret = (T*)stack_top_; stack_top_ += sizeof(T) * count; return ret; } template T* Pop(size_t count) { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stack_top_ -= count * sizeof(T); return (T*)stack_top_; } template T* Top() { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return (T*)(stack_top_ - sizeof(T)); } template T* Bottom() { return (T*)stack_; } Allocator& GetAllocator() { return *allocator_; } size_t GetSize() const { return stack_top_ - stack_; } size_t GetCapacity() const { return stack_capacity_; } private: Allocator* allocator_; Allocator* own_allocator_; char *stack_; char *stack_top_; char *stack_end_; size_t stack_capacity_; }; } // namespace internal } // namespace rapidjson #endif // RAPIDJSON_STACK_H_ ================================================ FILE: BOSS/source/rapidjson/internal/strfunc.h ================================================ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ namespace rapidjson { namespace internal { //! Custom strlen() which works on different character types. /*! \tparam Ch Character type (e.g. char, wchar_t, short) \param s Null-terminated input string. \return Number of characters in the string. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template inline SizeType StrLen(const Ch* s) { const Ch* p = s; while (*p != '\0') ++p; return SizeType(p - s); } } // namespace internal } // namespace rapidjson #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ ================================================ FILE: BOSS/source/rapidjson/prettywriter.h ================================================ #ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" namespace rapidjson { //! Writer with indentation and spacing. /*! \tparam Stream Type of ouptut stream. \tparam Encoding Encoding of both source strings and output. \tparam Allocator Type of allocator for allocating memory of stack. */ template, typename Allocator = MemoryPoolAllocator<> > class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor /*! \param stream Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of */ PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } //@name Implementation of Handler. //@{ PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; } PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; } PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; } PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; } PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; } PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; } PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; } PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kStringType); Base::WriteString(str, length); return *this; } PrettyWriter& StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); Base::WriteStartObject(); return *this; } PrettyWriter& EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::stream_.Put('\n'); WriteIndent(); } Base::WriteEndObject(); return *this; } PrettyWriter& StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); Base::WriteStartArray(); return *this; } PrettyWriter& EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::stream_.Put('\n'); WriteIndent(); } Base::WriteEndArray(); return *this; } //@} //! Simpler but slower overload. PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); } protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top(); if (level->inArray) { if (level->valueCount > 0) { Base::stream_.Put(','); // add comma if it is not the first element in array Base::stream_.Put('\n'); } else Base::stream_.Put('\n'); WriteIndent(); } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::stream_.Put(','); Base::stream_.Put('\n'); } else { Base::stream_.Put(':'); Base::stream_.Put(' '); } } else Base::stream_.Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(Base::stream_, indentChar_, count); } Ch indentChar_; unsigned indentCharCount_; }; } // namespace rapidjson #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: BOSS/source/rapidjson/rapidjson.h ================================================ #include "../Common.h" #ifdef MCDS_FLASH_VERSION #pragma GCC system_header #endif #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ // Copyright (c) 2011-2012 Milo Yip (miloyip@gmail.com) // Version 0.11 #include // malloc(), realloc(), free() #include // memcpy() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE // Here defines int64_t and uint64_t types in global namespace. // If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this. #ifndef RAPIDJSON_NO_INT64DEFINE #ifdef _MSC_VER typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #endif #endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! GCC provided macro for detecting endianness of the target machine. But other compilers may not have this. User can define RAPIDJSON_ENDIAN to either RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN. */ #ifndef RAPIDJSON_ENDIAN #ifdef __BYTE_ORDER__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #else #define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN #endif // __BYTE_ORDER__ #else #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise. #endif #endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD // Enable SSE2 optimization. //#define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. //#define RAPIDJSON_SSE42 #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) #define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_SIZETYPEDEFINE #ifndef RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { //! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t. /*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; } // namespace rapidjson #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ASSERT //! Assertion. /*! By default, rapidjson uses C assert() for assertion. User can override it by defining RAPIDJSON_ASSERT(x) macro. */ #ifndef RAPIDJSON_ASSERT #include #define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // Helpers #define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) namespace rapidjson { /////////////////////////////////////////////////////////////////////////////// // Allocator /*! \class rapidjson::Allocator \brief Concept for allocating, resizing and freeing memory block. Note that Malloc() and Realloc() are non-static but Free() is static. So if an allocator need to support Free(), it needs to put its pointer in the header of memory block. \code concept Allocator { static const bool kNeedFree; //!< Whether this allocator needs to call Free(). // Allocate a memory block. // \param size of the memory block in bytes. // \returns pointer to the memory block. void* Malloc(size_t size); // Resize a memory block. // \param originalPtr The pointer to current memory block. Null pointer is permitted. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) // \param newSize the new size in bytes. void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // Free a memory block. // \param pointer to the memory block. Null pointer is permitted. static void Free(void *ptr); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // CrtAllocator //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. \implements Allocator */ class CrtAllocator { public: static const bool kNeedFree = true; void* Malloc(size_t size) { return malloc(size); } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); } static void Free(void *ptr) { free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// // MemoryPoolAllocator //! Default memory allocator used by the parser and DOM. /*! This allocator allocate memory blocks from pre-allocated memory chunks. It does not free memory blocks. And Realloc() only allocate new memory. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. User may also supply a buffer as the first chunk. If the user-buffer is full then additional chunks are allocated by BaseAllocator. The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \implements Allocator */ template class MemoryPoolAllocator { public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { if (!baseAllocator_) ownBaseAllocator_ = baseAllocator_ = new BaseAllocator(); AddChunk(chunk_capacity_); } //! Constructor with user-supplied buffer. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. The user buffer will not be deallocated when this allocator is destructed. \param buffer User supplied buffer. \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); chunkHead_ = (ChunkHeader*)buffer; chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->size = 0; chunkHead_->next = 0; } //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ ~MemoryPoolAllocator() { Clear(); delete ownBaseAllocator_; } //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ size_t Capacity() { size_t capacity = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) capacity += c->capacity; return capacity; } //! Computes the memory blocks allocated. /*! \return total used bytes. */ size_t Size() { size_t size = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size += c->size; return size; } //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { size = (size + 3) & ~3; // Force aligning size to 4 if (chunkHead_->size + size > chunkHead_->capacity) AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size; RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0); // returned buffer is aligned to 4 chunkHead_->size += size; return buffer; } //! Resizes a memory block (concept Allocator) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { if (originalPtr == 0) return Malloc(newSize); // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { size_t increment = newSize - originalSize; increment = (increment + 3) & ~3; // Force aligning size to 4 if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0); // returned buffer is aligned to 4 return originalPtr; } } // Realloc process: allocate and copy memory, do not free original buffer. void* newBuffer = Malloc(newSize); RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. return memcpy(newBuffer, originalPtr, originalSize); } //! Frees a memory block (concept Allocator) static void Free(void *) {} // Do nothing private: //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. */ void AddChunk(size_t capacity) { ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity); chunk->capacity = capacity; chunk->size = 0; chunk->next = chunkHead_; chunkHead_ = chunk; } static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. */ struct ChunkHeader { size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t size; //!< Current size of allocated memory in bytes. ChunkHeader *next; //!< Next chunk in the linked list. }; ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. char *userBuffer_; //!< User supplied buffer. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; /////////////////////////////////////////////////////////////////////////////// // Encoding /*! \class rapidjson::Encoding \brief Concept for encoding of Unicode characters. \code concept Encoding { typename Ch; //! Type of character. //! \brief Encode a Unicode codepoint to a buffer. //! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. //! \returns the pointer to the next character after the encoded data. static Ch* Encode(Ch *buffer, unsigned codepoint); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // UTF8 //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 \tparam CharType Type for storing 8-bit UTF-8 data. Default is char. \implements Encoding */ template struct UTF8 { typedef CharType Ch; static Ch* Encode(Ch *buffer, unsigned codepoint) { if (codepoint <= 0x7F) *buffer++ = codepoint & 0xFF; else if (codepoint <= 0x7FF) { *buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF); *buffer++ = 0x80 | ((codepoint & 0x3F)); } else if (codepoint <= 0xFFFF) { *buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF); *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F); *buffer++ = 0x80 | (codepoint & 0x3F); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); *buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF); *buffer++ = 0x80 | ((codepoint >> 12) & 0x3F); *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F); *buffer++ = 0x80 | (codepoint & 0x3F); } return buffer; } }; /////////////////////////////////////////////////////////////////////////////// // UTF16 //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \implements Encoding */ template struct UTF16 { typedef CharType Ch; static Ch* Encode(Ch* buffer, unsigned codepoint) { if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair *buffer++ = static_cast(codepoint); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; *buffer++ = static_cast((v >> 10) + 0xD800); *buffer++ = (v & 0x3FF) + 0xDC00; } return buffer; } }; /////////////////////////////////////////////////////////////////////////////// // UTF32 //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 \tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \implements Encoding */ template struct UTF32 { typedef CharType Ch; static Ch *Encode(Ch* buffer, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); *buffer++ = codepoint; return buffer; } }; /////////////////////////////////////////////////////////////////////////////// // Stream /*! \class rapidjson::Stream \brief Concept for reading and writing characters. For read-only stream, no need to implement PutBegin(), Put() and PutEnd(). For write-only stream, only need to implement Put(). \code concept Stream { typename Ch; //!< Character type of the stream. //! Read the current character from stream without moving the read cursor. Ch Peek() const; //! Read the current character from stream and moving the read cursor to next character. Ch Take(); //! Get the current read cursor. //! \return Number of characters read from start. size_t Tell(); //! Begin writing operation at the current read pointer. //! \return The begin writer pointer. Ch* PutBegin(); //! Write a character. void Put(Ch c); //! End the writing operation. //! \param begin The begin write pointer returned by PutBegin(). //! \return Number of characters written. size_t PutEnd(Ch* begin); } \endcode */ //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { for (size_t i = 0; i < n; i++) stream.Put(c); } /////////////////////////////////////////////////////////////////////////////// // StringStream //! Read-only string stream. /*! \implements Stream */ template struct GenericStringStream { typedef typename Encoding::Ch Ch; GenericStringStream(const Ch *src) : src_(src), head_(src) {} Ch Peek() const { return *src_; } Ch Take() { return *src_++; } size_t Tell() const { return src_ - head_; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. }; typedef GenericStringStream > StringStream; /////////////////////////////////////////////////////////////////////////////// // InsituStringStream //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. \implements Stream */ template struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } Ch Take() { return *src_++; } size_t Tell() { return src_ - head_; } // Write Ch* PutBegin() { return dst_ = src_; } void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } size_t PutEnd(Ch* begin) { return dst_ - begin; } Ch* src_; Ch* dst_; Ch* head_; }; typedef GenericInsituStringStream > InsituStringStream; /////////////////////////////////////////////////////////////////////////////// // Type //! Type of JSON value enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6, //!< number }; } // namespace rapidjson #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: BOSS/source/rapidjson/reader.h ================================================ #include "../Common.h" #ifdef MCDS_FLASH_VERSION #pragma GCC system_header #endif #ifndef RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ // Copyright (c) 2011 Milo Yip (miloyip@gmail.com) // Version 0.1 #include "rapidjson.h" #include "internal/pow10.h" #include "internal/stack.h" #include #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #endif #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(msg, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ parseError_ = msg; \ errorOffset_ = offset; \ longjmp(jmpbuf_, 1); \ RAPIDJSON_MULTILINEMACRO_END #endif namespace rapidjson { /////////////////////////////////////////////////////////////////////////////// // ParseFlag //! Combination of parseFlags enum ParseFlag { kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer. kParseInsituFlag = 1 //!< In-situ(destructive) parsing. }; /////////////////////////////////////////////////////////////////////////////// // Handler /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. \code concept Handler { typename Ch; void Null(); void Bool(bool b); void Int(int i); void Uint(unsigned i); void Int64(int64_t i); void Uint64(uint64_t i); void Double(double d); void String(const Ch* str, SizeType length, bool copy); void StartObject(); void EndObject(SizeType memberCount); void StartArray(); void EndArray(SizeType elementCount); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // BaseReaderHandler //! Default implementation of Handler. /*! This can be used as base class of any reader handler. \implements Handler */ template > struct BaseReaderHandler { typedef typename Encoding::Ch Ch; void Default() {} void Null() { Default(); } void Bool(bool) { Default(); } void Int(int) { Default(); } void Uint(unsigned) { Default(); } void Int64(int64_t) { Default(); } void Uint64(uint64_t) { Default(); } void Double(double) { Default(); } void String(const Ch*, SizeType, bool) { Default(); } void StartObject() { Default(); } void EndObject(SizeType) { Default(); } void StartArray() { Default(); } void EndArray(SizeType) { Default(); } }; /////////////////////////////////////////////////////////////////////////////// // SkipWhitespace //! Skip the JSON white spaces in a stream. /*! \param stream A input stream for skipping white spaces. \note This function has SSE2/SSE4.2 specialization. */ template void SkipWhitespace(Stream& stream) { Stream s = stream; // Use a local copy for optimization while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') s.Take(); stream = s; } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { static const char whitespace[16] = " \n\r\t"; __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); for (;;) { __m128i s = _mm_loadu_si128((const __m128i *)p); unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); if (r == 0) // all 16 characters are whitespace p += 16; else { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; if (_BitScanForward(&offset, r)) return p + offset; #else if (r != 0) return p + __builtin_ffs(r) - 1; #endif } } } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { static const char whitespaces[4][17] = { " ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); for (;;) { __m128i s = _mm_loadu_si128((const __m128i *)p); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = ~_mm_movemask_epi8(x); if (r == 0) // all 16 characters are whitespace p += 16; else { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; if (_BitScanForward(&offset, r)) return p + offset; #else if (r != 0) return p + __builtin_ffs(r) - 1; #endif } } } #endif // RAPIDJSON_SSE2 #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& stream) { stream.src_ = const_cast(SkipWhitespace_SIMD(stream.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& stream) { stream.src_ = SkipWhitespace_SIMD(stream.src_); } #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator. /*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. It needs to allocate a stack for storing a single decoded string during non-destructive parsing. For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. \tparam Encoding Encoding of both the stream and the parse output. \tparam Allocator Allocator type for stack. */ template > class GenericReader { public: typedef typename Encoding::Ch Ch; //! Constructor. /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {} //! Parse JSON text. /*! \tparam parseFlags Combination of ParseFlag. \tparam Stream Type of input stream. \tparam Handler Type of handler which must implement Handler concept. \param stream Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template bool Parse(Stream& stream, Handler& handler) { parseError_ = 0; errorOffset_ = 0; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable #endif if (setjmp(jmpbuf_)) { #ifdef _MSC_VER #pragma warning(pop) #endif stack_.Clear(); return false; } SkipWhitespace(stream); if (stream.Peek() == '\0') RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell()); else { switch (stream.Peek()) { case '{': ParseObject(stream, handler); break; case '[': ParseArray(stream, handler); break; default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell()); } SkipWhitespace(stream); if (stream.Peek() != '\0') RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell()); } return true; } bool HasParseError() const { return parseError_ != 0; } const char* GetParseError() const { return parseError_; } size_t GetErrorOffset() const { return errorOffset_; } private: // Parse object: { string : value, ... } template void ParseObject(Stream& stream, Handler& handler) { RAPIDJSON_ASSERT(stream.Peek() == '{'); stream.Take(); // Skip '{' handler.StartObject(); SkipWhitespace(stream); if (stream.Peek() == '}') { stream.Take(); handler.EndObject(0); // empty object return; } for (SizeType memberCount = 0;;) { if (stream.Peek() != '"') { RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell()); break; } ParseString(stream, handler); SkipWhitespace(stream); if (stream.Take() != ':') { RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell()); break; } SkipWhitespace(stream); ParseValue(stream, handler); SkipWhitespace(stream); ++memberCount; switch(stream.Take()) { case ',': SkipWhitespace(stream); break; case '}': handler.EndObject(memberCount); return; default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell()); } } } // Parse array: [ value, ... ] template void ParseArray(Stream& stream, Handler& handler) { RAPIDJSON_ASSERT(stream.Peek() == '['); stream.Take(); // Skip '[' handler.StartArray(); SkipWhitespace(stream); if (stream.Peek() == ']') { stream.Take(); handler.EndArray(0); // empty array return; } for (SizeType elementCount = 0;;) { ParseValue(stream, handler); ++elementCount; SkipWhitespace(stream); switch (stream.Take()) { case ',': SkipWhitespace(stream); break; case ']': handler.EndArray(elementCount); return; default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell()); } } } template void ParseNull(Stream& stream, Handler& handler) { RAPIDJSON_ASSERT(stream.Peek() == 'n'); stream.Take(); if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l') handler.Null(); else RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); } template void ParseTrue(Stream& stream, Handler& handler) { RAPIDJSON_ASSERT(stream.Peek() == 't'); stream.Take(); if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e') handler.Bool(true); else RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell()); } template void ParseFalse(Stream& stream, Handler& handler) { RAPIDJSON_ASSERT(stream.Peek() == 'f'); stream.Take(); if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e') handler.Bool(false); else RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); } // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(Stream& stream) { Stream s = stream; // Use a local copy for optimization unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = s.Take(); codepoint <<= 4; codepoint += c; if (c >= '0' && c <= '9') codepoint -= '0'; else if (c >= 'A' && c <= 'F') codepoint -= 'A' - 10; else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1); } stream = s; // Restore stream return codepoint; } // Parse string, handling the prefix and suffix double quotes and escaping. template void ParseString(Stream& stream, Handler& handler) { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const Ch escape[256] = { Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 Stream s = stream; // Use a local copy for optimization RAPIDJSON_ASSERT(s.Peek() == '\"'); s.Take(); // Skip '\"' Ch *head; SizeType len; if (parseFlags & kParseInsituFlag) head = s.PutBegin(); else len = 0; #define RAPIDJSON_PUT(x) \ do { \ if (parseFlags & kParseInsituFlag) \ s.Put(x); \ else { \ *stack_.template Push() = x; \ ++len; \ } \ } while(false) for (;;) { Ch c = s.Take(); if (c == '\\') { // Escape Ch e = s.Take(); if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e]) RAPIDJSON_PUT(escape[(unsigned char)e]); else if (e == 'u') { // Unicode unsigned codepoint = ParseHex4(s); if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair if (s.Take() != '\\' || s.Take() != 'u') { RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2); return; } unsigned codepoint2 = ParseHex4(s); if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) { RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2); return; } codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } Ch buffer[4]; SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]); if (parseFlags & kParseInsituFlag) for (SizeType i = 0; i < count; i++) s.Put(buffer[i]); else { memcpy(stack_.template Push(count), buffer, count * sizeof(Ch)); len += count; } } else { RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1); return; } } else if (c == '"') { // Closing double quote if (parseFlags & kParseInsituFlag) { size_t length = s.PutEnd(head); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); RAPIDJSON_PUT('\0'); // null-terminate the string handler.String(head, SizeType(length), false); } else { RAPIDJSON_PUT('\0'); handler.String(stack_.template Pop(len), len - 1, true); } stream = s; // restore stream return; } else if (c == '\0') { RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1); return; } else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1); return; } else RAPIDJSON_PUT(c); // Normal character, just copy } #undef RAPIDJSON_PUT } template void ParseNumber(Stream& stream, Handler& handler) { Stream s = stream; // Local copy for optimization // Parse minus bool minus = false; if (s.Peek() == '-') { minus = true; s.Take(); } // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i; bool try64bit = false; if (s.Peek() == '0') { i = 0; s.Take(); } else if (s.Peek() >= '1' && s.Peek() <= '9') { i = s.Take() - '0'; if (minus) while (s.Peek() >= '0' && s.Peek() <= '9') { if (i >= 214748364) { // 2^31 = 2147483648 if (i != 214748364 || s.Peek() > '8') { try64bit = true; break; } } i = i * 10 + (s.Take() - '0'); } else while (s.Peek() >= '0' && s.Peek() <= '9') { if (i >= 429496729) { // 2^32 - 1 = 4294967295 if (i != 429496729 || s.Peek() > '5') { try64bit = true; break; } } i = i * 10 + (s.Take() - '0'); } } else { RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell()); return; } // Parse 64bit int uint64_t i64 = 0; bool useDouble = false; if (try64bit) { i64 = i; if (minus) while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808 if (i64 != 922337203685477580uLL || s.Peek() > '8') { useDouble = true; break; } i64 = i64 * 10 + (s.Take() - '0'); } else while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615 if (i64 != 1844674407370955161uLL || s.Peek() > '5') { useDouble = true; break; } i64 = i64 * 10 + (s.Take() - '0'); } } // Force double for big integer double d = 0.0; if (useDouble) { d = (double)i64; while (s.Peek() >= '0' && s.Peek() <= '9') { if (d >= 1E307) { RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); return; } d = d * 10 + (s.Take() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; if (s.Peek() == '.') { if (!useDouble) { d = try64bit ? (double)i64 : (double)i; useDouble = true; } s.Take(); if (s.Peek() >= '0' && s.Peek() <= '9') { d = d * 10 + (s.Take() - '0'); --expFrac; } else { RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell()); return; } while (s.Peek() >= '0' && s.Peek() <= '9') { if (expFrac > -16) { d = d * 10 + (s.Peek() - '0'); --expFrac; } s.Take(); } } // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (s.Peek() == 'e' || s.Peek() == 'E') { if (!useDouble) { d = try64bit ? (double)i64 : (double)i; useDouble = true; } s.Take(); bool expMinus = false; if (s.Peek() == '+') s.Take(); else if (s.Peek() == '-') { s.Take(); expMinus = true; } if (s.Peek() >= '0' && s.Peek() <= '9') { exp = s.Take() - '0'; while (s.Peek() >= '0' && s.Peek() <= '9') { exp = exp * 10 + (s.Take() - '0'); if (exp > 308) { RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); return; } } } else { RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell()); return; } if (expMinus) exp = -exp; } // Finish parsing, call event according to the type of number. if (useDouble) { d *= internal::Pow10(exp + expFrac); handler.Double(minus ? -d : d); } else { if (try64bit) { if (minus) handler.Int64(-(int64_t)i64); else handler.Uint64(i64); } else { if (minus) handler.Int(-(int)i); else handler.Uint(i); } } stream = s; // restore stream } // Parse any JSON value template void ParseValue(Stream& stream, Handler& handler) { switch (stream.Peek()) { case 'n': ParseNull (stream, handler); break; case 't': ParseTrue (stream, handler); break; case 'f': ParseFalse (stream, handler); break; case '"': ParseString(stream, handler); break; case '{': ParseObject(stream, handler); break; case '[': ParseArray (stream, handler); break; default : ParseNumber(stream, handler); } } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls. const char* parseError_; size_t errorOffset_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. typedef GenericReader > Reader; } // namespace rapidjson #ifdef _MSC_VER #pragma warning(pop) #endif #endif // RAPIDJSON_READER_H_ ================================================ FILE: BOSS/source/rapidjson/stringbuffer.h ================================================ #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ #include "rapidjson.h" #include "internal/stack.h" namespace rapidjson { //! Represents an in-memory output stream. /*! \tparam Encoding Encoding of the stream. \tparam Allocator type for allocating memory buffer. \implements Stream */ template struct GenericStringBuffer { typedef typename Encoding::Ch Ch; GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} void Put(Ch c) { *stack_.template Push() = c; } void Clear() { stack_.Clear(); } const char* GetString() const { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.template Pop(1); return stack_.template Bottom(); } size_t Size() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; }; typedef GenericStringBuffer > StringBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { memset(stream.stack_.Push(n), c, n * sizeof(c)); } } // namespace rapidjson #endif // RAPIDJSON_STRINGBUFFER_H_ ================================================ FILE: BOSS/source/rapidjson/writer.h ================================================ #include "../Common.h" #ifdef MCDS_FLASH_VERSION #pragma GCC system_header #endif #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ #include "rapidjson.h" #include "internal/stack.h" #include "internal/strfunc.h" #include // snprintf() or _sprintf_s() #include // placement new #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #endif namespace rapidjson { //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output stream. User may programmatically calls the functions of a writer to generate JSON text. On the other side, a writer can also be passed to objects that generates events, for example Reader::Parse() and Document::Accept(). \tparam Stream Type of ouptut stream. \tparam Encoding Encoding of both source strings and output. \implements Handler */ template, typename Allocator = MemoryPoolAllocator<> > class Writer { public: typedef typename Encoding::Ch Ch; Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {} //@name Implementation of Handler //@{ Writer& Null() { Prefix(kNullType); WriteNull(); return *this; } Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; } Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; } Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; } Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; } Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; } Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; } Writer& String(const Ch* str, SizeType length, bool copy = false) { (void)copy; Prefix(kStringType); WriteString(str, length); return *this; } Writer& StartObject() { Prefix(kObjectType); new (level_stack_.template Push()) Level(false); WriteStartObject(); return *this; } Writer& EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); level_stack_.template Pop(1); WriteEndObject(); return *this; } Writer& StartArray() { Prefix(kArrayType); new (level_stack_.template Push()) Level(true); WriteStartArray(); return *this; } Writer& EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); WriteEndArray(); return *this; } //@} //! Simpler but slower overload. Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); } protected: //! Information for each nested level struct Level { Level(bool inArray_) : inArray(inArray_), valueCount(0) {} bool inArray; //!< true if in array, otherwise in object size_t valueCount; //!< number of values in this level }; static const size_t kDefaultLevelDepth = 32; void WriteNull() { stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l'); } void WriteBool(bool b) { if (b) { stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e'); } else { stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e'); } } void WriteInt(int i) { if (i < 0) { stream_.Put('-'); i = -i; } WriteUint((unsigned)i); } void WriteUint(unsigned u) { char buffer[10]; char *p = buffer; do { *p++ = (u % 10) + '0'; u /= 10; } while (u > 0); do { --p; stream_.Put(*p); } while (p != buffer); } void WriteInt64(int64_t i64) { if (i64 < 0) { stream_.Put('-'); i64 = -i64; } WriteUint64((uint64_t)i64); } void WriteUint64(uint64_t u64) { char buffer[20]; char *p = buffer; do { *p++ = char(u64 % 10) + '0'; u64 /= 10; } while (u64 > 0); do { --p; stream_.Put(*p); } while (p != buffer); } //! \todo Optimization with custom double-to-string converter. void WriteDouble(double d) { char buffer[100]; #if _MSC_VER int ret = sprintf_s(buffer, sizeof(buffer), "%g", d); #else int ret = snprintf(buffer, sizeof(buffer), "%g", d); #endif RAPIDJSON_ASSERT(ret >= 1); for (int i = 0; i < ret; i++) stream_.Put(buffer[i]); } void WriteString(const Ch* str, SizeType length) { static const char hexDigits[] = "0123456789ABCDEF"; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 Z16, Z16, // 30~4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 }; stream_.Put('\"'); for (const Ch* p = str; p != str + length; ++p) { if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) { stream_.Put('\\'); stream_.Put(escape[(unsigned char)*p]); if (escape[(unsigned char)*p] == 'u') { stream_.Put('0'); stream_.Put('0'); stream_.Put(hexDigits[(*p) >> 4]); stream_.Put(hexDigits[(*p) & 0xF]); } } else stream_.Put(*p); } stream_.Put('\"'); } void WriteStartObject() { stream_.Put('{'); } void WriteEndObject() { stream_.Put('}'); } void WriteStartArray() { stream_.Put('['); } void WriteEndArray() { stream_.Put(']'); } void Prefix(Type type) { (void)type; if (level_stack_.GetSize() != 0) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) stream_.Put(','); // add comma if it is not the first element in array else // in object stream_.Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); } Stream& stream_; internal::Stack level_stack_; private: // Prohibit assignment for VC C4512 warning Writer& operator=(const Writer& w); }; } // namespace rapidjson #ifdef _MSC_VER #pragma warning(pop) #endif #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: License.md ================================================ The MIT License (MIT) Copyright (c) 2016 David Churchill 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. ================================================ FILE: README.md ================================================ **UAlbertaBot** - StarCraft AI Competition Bot - David Churchill (dave.churchill@gmail.com) **Update: 2021** - UAlbertaBot is not being actively maintained since early 2021 **Update: Feb 28, 2020** - UAlbertaBot now uses VS2019 - UAlbertaBot now uses BWAPI 4.4.0. To get it to compile, you have to compile BWAPI.lib and BWAPIClient.lib with VS2019 and put them in the BWAPI_INSTALL_DIR/lib/ folder - UAlbertaBot no longer uses BWTA - it is replaced with the custom BaseLocationManager from CommandCenter - UAlbertaBot now uses the Client .exe compilation method instead of module DLL - The bot will only work for the first game played after the .exe is run, so AUTO_RESTART won't work well. I'll fix this later - You can download StarCraft 1.16.1 here: http://ftp.blizzard.com/pub/broodwar/patches/PC/BW-1161.exe Please check out the [Wiki](https://github.com/davechurchill/ualbertabot/wiki) for full instructions and documentation! NOTE: If you're looking for a StarCraft II bot please check out [CommandCenter](https://github.com/davechurchill/commandcenter/) ================================================ FILE: SparCraft/.gitignore ================================================ VisualStudio/Release VisualStudio/Debug bin/SparCraft bin/*.txt bin/*.pdb bin/*.map bin/*.dll bin/*.exe source/*.o ================================================ FILE: SparCraft/LINUX_HOW_TO_COMPILE.txt ================================================ Compilation Instructions: 1. Install the required libraries libsdl2-dev libsdl2-image-dev 2. Clone the BWAPI github repository somewhere on your system git clone https://github.com/bwapi/bwapi.git 3. Edit the Makefile to point to the directory that you cloned BWAPI BWAPI_DIR=/where_you_cloned_to/bwapi/bwapi (yes, bwapi/bwapi) 4. If your BWAPI_DIR doesn't contain the file svnrev.h, you need to generate it using the vbs script in that dir (note: this may have to be done in windows, but you can just copy the generated .h files to Linux and it will work) 5. Run 'make' in the SparCraft directory, the binary will go to the 'SparCraft/bin' directory 6. cd to 'SparCraft/bin' and run './SparCraft ../sample_experiment/sample_exp.txt' Enjoy! ================================================ FILE: SparCraft/Makefile ================================================ CC=g++ BWAPI_DIR=/home/dave/facebook/bwapi/bwapi SDL_LDFLAGS=`sdl2-config --libs` SDL_CFLAGS=`sdl2-config --cflags` CFLAGS=-O3 -std=c++11 $(SDL_CFLAGS) LDFLAGS=-lGL -lGLU -lSDL2_image $(SDL_LDFLAGS) INCLUDES=-I$(BWAPI_DIR)/include -I$(BWAPI_DIR)/include/BWAPI -I$(BWAPI_DIR) SOURCES=$(wildcard $(BWAPI_DIR)/BWAPILIB/Source/*.cpp) $(wildcard $(BWAPI_DIR)/BWAPILIB/*.cpp) $(wildcard source/*.cpp) $(wildcard source/main/*.cpp) $(wildcard source/gui/*.cpp) OBJECTS=$(SOURCES:.cpp=.o) all:SparCraft SparCraft:$(OBJECTS) $(CC) $(OBJECTS) -o bin/$@ $(LDFLAGS) .cpp.o: $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ .cc.o: $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ ================================================ FILE: SparCraft/README.txt ================================================ SparCraft - 2013 David Churchill - dave.churchill@gmail.com For documentation please visit: https://code.google.com/p/sparcraft/ ================================================ FILE: SparCraft/VisualStudio/SparCraft.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SparCraft", "SparCraft.vcxproj", "{66236439-5968-4756-B2E7-8A29BEA99078}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SparCraft_main", "SparCraft_main.vcxproj", "{82E61B13-7AC5-447E-AD88-96D04D881F58}" ProjectSection(ProjectDependencies) = postProject {66236439-5968-4756-B2E7-8A29BEA99078} = {66236439-5968-4756-B2E7-8A29BEA99078} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.ActiveCfg = Debug|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.Build.0 = Debug|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.ActiveCfg = Debug|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.Build.0 = Debug|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.ActiveCfg = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.Build.0 = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.ActiveCfg = Release|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.Build.0 = Release|x64 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|Win32.ActiveCfg = Debug|Win32 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|Win32.Build.0 = Debug|Win32 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|x64.ActiveCfg = Debug|x64 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Debug|x64.Build.0 = Debug|x64 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|Win32.ActiveCfg = Release|Win32 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|Win32.Build.0 = Release|Win32 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|x64.ActiveCfg = Release|x64 {82E61B13-7AC5-447E-AD88-96D04D881F58}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: SparCraft/VisualStudio/SparCraft.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {66236439-5968-4756-B2E7-8A29BEA99078} StarcraftBuildOrderSearch Win32Proj $(VCTargetsPath11) StaticLibrary Unicode true v142 StaticLibrary Unicode v142 v110 v110 <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)\$(Configuration)\$(ProjectName)\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ true $(SolutionDir)\$(Configuration)\$(ProjectName)\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ false AllRules.ruleset AllRules.ruleset $(ProjectName)_d Disabled $(BWAPI_DIR)/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue true $(BWAPI_DIR)/lib/BWAPId.lib;$(EXTERNAL_LIB_DIR)/SDL.lib;$(EXTERNAL_LIB_DIR)/SDLmain.lib;$(EXTERNAL_LIB_DIR)/opengl32.lib;$(EXTERNAL_LIB_DIR)/SDL_image.lib;$(EXTERNAL_LIB_DIR)/SDL_gfx.lib;%(AdditionalDependencies) true Console MachineX86 /NODEFAULTLIB:msvcrt.lib %(AdditionalOptions) Full true $(BWAPI_DIR)\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase Speed true true Sync true $(BWAPI_DIR)/lib/BWAPI.lib;$(EXTERNAL_LIB_DIR)/SDL.lib;$(EXTERNAL_LIB_DIR)/SDLmain.lib;$(EXTERNAL_LIB_DIR)/opengl32.lib;$(EXTERNAL_LIB_DIR)/SDL_image.lib;$(EXTERNAL_LIB_DIR)/SDL_gfx.lib;%(AdditionalDependencies) true Console true true MachineX86 true true ================================================ FILE: SparCraft/VisualStudio/SparCraft.vcxproj.filters ================================================  search\AlphaBeta common simulation simulation util search\Greedy util search\AlphaBeta search\UCT search\Greedy simulation\players simulation\players\search simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\search simulation\players\script simulation\players\search simulation\players util simulation\players\script simulation\players\script simulation simulation\properties simulation\properties simulation\properties common data data util simulation search\AlphaBeta common common search\AlphaBeta search\AlphaBeta common common util simulation simulation util search\Greedy simulation util search\AlphaBeta search\UCT search\UCT search\Greedy util simulation\players simulation\players\search simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\script simulation\players\search simulation\players\script simulation\players\search search\UCT search\UCT search\UCT search\AlphaBeta simulation\players util simulation\players\script simulation\players\script simulation simulation simulation\properties simulation\properties simulation\properties util common data data util simulation search\AlphaBeta common common {6df7ca5f-a32b-4663-841c-e9c0167bef3b} {448e8c8d-4efd-44ab-9ca4-3da61d3aa047} {d817d60f-8a97-41a1-af70-0d73ee979248} {39cea388-a0ee-4dab-9c88-fc2c02a0d8c8} {273d10ab-4a07-439d-9142-aaf654ae5feb} {5d28a734-3947-4ec3-9f52-b1259520d851} {9aa7fe21-9e2a-421d-b8e6-1b132a0a0c23} {b11ab75e-596d-49f0-b7cd-18835583746c} {4a52919d-1927-49f9-964b-4c447699227a} {736c4997-5d98-40e6-a72f-f9075810344b} {2617c193-9e36-4c48-a76e-4ffcfee4093e} {c8b3aadc-390f-460b-af33-29a0570bb914} ================================================ FILE: SparCraft/VisualStudio/SparCraft_main.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {82E61B13-7AC5-447E-AD88-96D04D881F58} StarcraftBuildOrderSearch Win32Proj $(VCTargetsPath11) Application Unicode true v120 Application Unicode v120 v110 v110 <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)$(Configuration)\ $(Configuration)\ true ../bin/ $(Configuration)\ false AllRules.ruleset AllRules.ruleset SparCraft SparCraft Disabled $(SDL_IMAGE_DIR)/include;$(SDL_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue $(Configuration)/SparCraft/SparCraft_d.lib;$(BWAPI_DIR)/lib/BWAPId.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;../lib/opengl32.lib;%(AdditionalDependencies) true Console MachineX86 /NODEFAULTLIB:msvcrt.lib %(AdditionalOptions) Full true $(BWAPI_DIR)\include;$(SDL_DIR)\include;$(SDL_IMAGE_DIR)/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase Speed true true Sync $(Configuration)/SparCraft/SparCraft.lib;$(BWAPI_DIR)/lib/BWAPI.lib;../lib/SDL2.lib;../lib/SDL2_image.lib;../lib/opengl32.lib;%(AdditionalDependencies) true Console true true MachineX86 true true ================================================ FILE: SparCraft/VisualStudio/SparCraft_main.vcxproj.filters ================================================  gui gui gui gui gui gui {ceb05fc9-cc5d-4f5b-808d-c844862d2269} ================================================ FILE: SparCraft/VisualStudio/bwapidata.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {F4605815-8200-4F83-9B2B-AFEA163518F1} StarcraftBuildOrderSearch Win32Proj $(VCTargetsPath11) BWAPIData StaticLibrary Unicode true v120 StaticLibrary Unicode v110 v110 v110 <_ProjectFileVersion>10.0.30319.1 ../bwapidata/lib/ $(Configuration)\ true ../bwapidata/lib/ $(Configuration)\ false AllRules.ruleset AllRules.ruleset BWAPI BWAPId Disabled ../bwapidata/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue %(AdditionalDependencies) true Console MachineX86 /NODEFAULTLIB:msvcrt.lib %(AdditionalOptions) Full true ../bwapidata/include/;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase Speed true true Sync %(AdditionalDependencies) true Console true true MachineX86 true true ================================================ FILE: SparCraft/VisualStudio/bwapidata.vcxproj.filters ================================================  {6d542422-cbf6-48e3-a42a-5b613dbfb27b} {94969cc2-fa46-48b3-a799-699052395962} {5bf7fa35-3dae-4e58-a8e6-676b0e724c48} Util Util Util Util Util Util Util Util Util Util Util Util Util Util Util Util Util BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI\Client BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI BWAPI ================================================ FILE: SparCraft/VisualStudio/set_environment_variables.bat ================================================ @echo off echo Set SparCraft Windows Environment Variables echo Please edit this file before running for the first time pause setx BWAPI_DIR %CD%\bwapidata setx BOOST_DIR C:\libraries\boost_1_53_0 setx EXTERNAL_LIB_DIR c:\libraries\external_lib_dir setx SDL_DIR C:\libraries\SDL-1.2.15 setx SDL_IMAGE_DIR C:\libraries\SDL_image-1.2.12 setx SDL_GFX_DIR c:\libraries\SDL_gfx-2.0.23 pause ================================================ FILE: SparCraft/asset/images/command_icons/fix.bat ================================================ for %%f in (*.png) DO ( convert "%%f" -strip -resize 32x32! "%%f" ) ================================================ FILE: SparCraft/asset/images/units/fix.bat ================================================ for %%f in (*.png) DO ( convert "%%f" -strip "%%f" ) ================================================ FILE: SparCraft/bin/.gitkeep ================================================ ================================================ FILE: SparCraft/bwapidata/README.txt ================================================ bwapidata ---------------- This is used to compile SparCraft in a linux environment without having to worry about reconfiguring BWAPI This is a stripped-down version of BWAPI which contains only headers and .cpp files, without BWTA Used with permission from Adam Heinermann of the BWAPI project: https://code.google.com/p/bwapi/ ================================================ FILE: SparCraft/bwapidata/include/AIModule.cpp ================================================ #include namespace BWAPI { AIModule::AIModule() { } AIModule::~AIModule() { } void AIModule::onStart() { } void AIModule::onEnd(bool isWinner) { } void AIModule::onFrame() { } void AIModule::onSendText(std::string text) { } void AIModule::onReceiveText(Player* player, std::string text) { } void AIModule::onPlayerLeft(Player *player) { } void AIModule::onNukeDetect(Position target) { } void AIModule::onUnitDiscover(BWAPI::Unit* unit) { } void AIModule::onUnitEvade(BWAPI::Unit* unit) { } void AIModule::onUnitShow(BWAPI::Unit* unit) { } void AIModule::onUnitHide(BWAPI::Unit* unit) { } void AIModule::onUnitCreate(BWAPI::Unit* unit) { } void AIModule::onUnitDestroy(BWAPI::Unit* unit) { } void AIModule::onUnitMorph(BWAPI::Unit* unit) { } void AIModule::onUnitRenegade(BWAPI::Unit* unit) { } void AIModule::onSaveGame(std::string gameName) { } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/AIModule.h ================================================ #pragma once #include #include namespace BWAPI { class Unit; class Player; /** AIModule is a virtual class that is intended to be implemented or inherited by a custom AI class. * * \note * Using BWAPI in a different thread than the default one will produce unexpected results and possibly crash * the program. Multi-threaded AIs are possible so long as all BWAPI interaction is limited to the default * thread (during one of the call-backs). */ class AIModule { public: AIModule(); virtual ~AIModule(); /** BWAPI calls this at the start of a match. Typically an AI will execute set up code in this method * (initialize data structures, load build orders, etc). */ virtual void onStart(); /** BWAPI calls this at the end of the match. isWinner will be true if the AIModule won the game. If the * game is a replay, isWinner will always be false. */ virtual void onEnd(bool isWinner); /** BWAPI calls this on every logical frame in the game. */ virtual void onFrame(); /** If Flag::UserInput is enabled, BWAPI will call this each time a user enters a message into the chat. * */ virtual void onSendText(std::string text); /** BWAPI calls this when another player sends a message. */ virtual void onReceiveText(Player* player, std::string text); /** BWAPI calls this when a player leaves the game. */ virtual void onPlayerLeft(Player* player); /** BWAPI calls this when a nuclear launch has been detected. If the target position is visible, or if * Complete Map Information is enabled, the target position will also be provided. If Complete Map * Information is disabled and the target position is not visible, target will be set to * Positions::Unknown. */ virtual void onNukeDetect(Position target); /** BWAPI calls this when a unit becomes accessible. */ virtual void onUnitDiscover(Unit* unit); /** BWAPI calls this when a unit becomes inaccessible. */ virtual void onUnitEvade(Unit* unit); /** BWAPI calls this the instant a previously invisible unit becomes visible. The complete map * information flag has no effect on this callback. */ virtual void onUnitShow(Unit* unit); /** BWAPI calls this right before a unit becomes invisible, so if you want your non-cheating AI to * remember where it last saw a unit, this callback would be a good place to implement it. The complete * map information flag has no effect on this callback. */ virtual void onUnitHide(Unit* unit); /** BWAPI calls this when a unit is created. Note that this is NOT called when a unit changes type * (such as larva into egg or egg into drone). Building a refinery/assimilator/extractor will not * produce an onUnitCreate call since the vespene geyser changes to the unit type of the * refinery/assimilator/extractor. If Complete Map Information is enabled, this will also be called for * new units that are hidden by the fog of war. If the unit is visible upon creation, onUnitShow will be * called shortly after onUnitCreate is called. */ virtual void onUnitCreate(Unit* unit); /** BWAPI calls this when a unit dies or otherwise removed from the game (i.e. a mined out mineral * patch). When a zerg drone becomes an extractor, the Vespene geyser changes to the Zerg Extractor type * and the drone is removed. If Complete Map Information is enabled, this will also be called for units * that are hidden by the fog of war. If a unit that was visible gets destroyed, onUnitHide will be * called right before onUnitDestroy is called. */ virtual void onUnitDestroy(Unit* unit); /** BWAPI calls this when a unit changes type, such as from a Zerg Drone to a Zerg Hatchery, or from a * Terran Siege Tank Tank Mode to Terran Siege Tank Siege Mode. This is not called when the type changes * to or from UnitTypes::Unknown (which happens when a unit becomes visible or invisible). */ virtual void onUnitMorph(Unit* unit); /** BWAPI calls this when an accessible unit changes ownership. */ virtual void onUnitRenegade(Unit* unit); // TODO: Add Doxygen documentation virtual void onSaveGame(std::string gameName); }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Bitmap.h ================================================ #include #pragma once namespace BWAPI { class BitmapProxy { public: BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x); Color operator[](int y); private: unsigned char *data; unsigned short width; unsigned short height; int x; }; class Bitmap { public: BitmapProxy operator[](int x); unsigned short getWidth(); unsigned short getHeight(); private: unsigned short wid; unsigned short ht; unsigned char *data; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Bullet.h ================================================ #pragma once #include #include namespace BWAPI { class Player; class Unit; class Bullet { public: virtual int getID() const = 0; virtual Player* getPlayer() const = 0; virtual BulletType getType() const = 0; virtual Unit* getSource() const = 0; virtual Position getPosition() const = 0; virtual double getAngle() const = 0; virtual double getVelocityX() const = 0; virtual double getVelocityY() const = 0; virtual Unit* getTarget() const = 0; virtual Position getTargetPosition() const = 0; virtual int getRemoveTimer() const = 0; virtual bool exists() const = 0; virtual bool isVisible() const = 0; virtual bool isVisible(Player* player) const = 0; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/BulletType.h ================================================ #pragma once #include #include namespace BWAPI { class BulletType { public: BulletType(); BulletType(int id); BulletType(const BulletType& other); BulletType& operator=(const BulletType& other); bool operator==(const BulletType& other) const; bool operator!=(const BulletType& other) const; bool operator<(const BulletType& other) const; /** Returns the unique ID for this bullet type. */ int getID() const; /** Returns the name of this bullet type. */ std::string getName() const; private: int id; }; namespace BulletTypes { /** Given the name of an bullet type, getBulletType() will return the corresponding BulletType object. */ BulletType getBulletType(std::string name); /** Returns the set of all the BulletTypes. */ std::set& allBulletTypes(); void init(); extern const BulletType Melee; extern const BulletType Fusion_Cutter_Hit; extern const BulletType Gauss_Rifle_Hit; extern const BulletType C_10_Canister_Rifle_Hit; extern const BulletType Gemini_Missiles; extern const BulletType Fragmentation_Grenade; extern const BulletType Longbolt_Missile; extern const BulletType ATS_ATA_Laser_Battery; extern const BulletType Burst_Lasers; extern const BulletType Arclite_Shock_Cannon_Hit; extern const BulletType EMP_Missile; extern const BulletType Dual_Photon_Blasters_Hit; extern const BulletType Particle_Beam_Hit; extern const BulletType Anti_Matter_Missile; extern const BulletType Pulse_Cannon; extern const BulletType Psionic_Shockwave_Hit; extern const BulletType Psionic_Storm; extern const BulletType Yamato_Gun; extern const BulletType Phase_Disruptor; extern const BulletType STA_STS_Cannon_Overlay; extern const BulletType Sunken_Colony_Tentacle; extern const BulletType Acid_Spore; extern const BulletType Glave_Wurm; extern const BulletType Seeker_Spores; extern const BulletType Queen_Spell_Carrier; extern const BulletType Plague_Cloud; extern const BulletType Consume; extern const BulletType Needle_Spine_Hit; extern const BulletType Invisible; extern const BulletType Optical_Flare_Grenade; extern const BulletType Halo_Rockets; extern const BulletType Subterranean_Spines; extern const BulletType Corrosive_Acid_Shot; extern const BulletType Neutron_Flare; extern const BulletType None; extern const BulletType Unknown; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/BulletData.h ================================================ #pragma once namespace BWAPI { struct BulletData { int id; int player; int type; int source; int positionX; int positionY; double angle; double velocityX; double velocityY; int target; int targetPositionX; int targetPositionY; int removeTimer; bool exists; bool isVisible[9]; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/BulletImpl.h ================================================ #pragma once #include #include "BulletData.h" #include #include namespace BWAPI { class Player; class Unit; class BulletImpl : public Bullet { private: const BulletData* self; int index; public: BulletImpl(int index); virtual int getID() const; virtual Player* getPlayer() const; virtual BulletType getType() const; virtual Unit* getSource() const; virtual Position getPosition() const; virtual double getAngle() const; virtual double getVelocityX() const; virtual double getVelocityY() const; virtual Unit* getTarget() const; virtual Position getTargetPosition() const; virtual int getRemoveTimer() const; virtual bool exists() const; virtual bool isVisible() const; virtual bool isVisible(Player* player) const; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/Client.h ================================================ #pragma once #include #include "GameData.h" #include "GameImpl.h" #include "ForceImpl.h" #include "PlayerImpl.h" #include "UnitImpl.h" namespace BWAPI { class Client { public: Client(); ~Client(); GameData* data; bool isConnected(); bool connect(); void disconnect(); void update(); private: HANDLE pipeObjectHandle; HANDLE mapFileHandle; bool connected; }; extern Client BWAPIClient; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/Command.h ================================================ #pragma once #include "CommandType.h" namespace BWAPIC { struct Command { Command(CommandType::Enum _commandType, int _value1=0, int _value2=0) { type=_commandType; value1=_value1; value2=_value2; } CommandType::Enum type; int value1; int value2; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/CommandType.h ================================================ #pragma once /** * Used in UnitCommand */ namespace BWAPIC { namespace CommandType { enum Enum { None, SetScreenPosition, PingMinimap, EnableFlag, Printf, SendText, ChangeRace, StartGame, PauseGame, ResumeGame, LeaveGame, RestartGame, SetLocalSpeed, SetTextSize, SetLatCom, SetGui }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/Event.h ================================================ #pragma once #include #include namespace BWAPIC { struct Event { BWAPI::EventType::Enum type; int v1; int v2; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/ForceData.h ================================================ #pragma once namespace BWAPI { struct ForceData { char name[32]; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/ForceImpl.h ================================================ #pragma once #include #include "ForceData.h" #include #include namespace BWAPI { class Game; class Player; class Unit; class ForceImpl : public Force { private: const ForceData* self; int id; public: ForceImpl(int id); virtual int getID() const; virtual std::string getName() const; virtual std::set getPlayers() const; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/GameData.h ================================================ #pragma once #include "UnitCommand.h" #include "ForceData.h" #include "PlayerData.h" #include "UnitData.h" #include "BulletData.h" #include "Event.h" #include "Command.h" #include "Shape.h" namespace BWAPI { struct GameData { GameData(); int instanceID; //forces int forceCount; ForceData forces[5]; //players int playerCount; PlayerData players[12]; //units int initialUnitCount; UnitData units[10000]; //unit table int unitArray[1700]; //bullets BulletData bullets[100]; int gameType; int latency; int latencyFrames; int latencyTime; int remainingLatencyFrames; int remainingLatencyTime; int revision; bool isDebug; bool hasLatCom; int replayFrameCount; int frameCount; int fps; double averageFPS; // user input int mouseX; int mouseY; bool mouseState[3]; bool keyState[256]; int screenX; int screenY; bool flags[2]; // map int mapWidth; int mapHeight; char mapFileName[261]; //size based on broodwar memory char mapPathName[261]; //size based on broodwar memory char mapName[33]; //size based on broodwar memory char mapHash[41]; //tile data int getGroundHeight[256][256]; bool isWalkable[1024][1024]; bool isBuildable[256][256]; bool isVisible[256][256]; bool isExplored[256][256]; bool hasCreep[256][256]; unsigned short mapTileRegionId[256][256]; unsigned short mapSplitTilesMiniTileMask[5000]; unsigned short mapSplitTilesRegion1[5000]; unsigned short mapSplitTilesRegion2[5000]; unsigned short regionGroupIndex[5000]; // start locations int startLocationCount; int startLocationsX[8]; int startLocationsY[8]; // match mode bool isInGame; bool isMultiplayer; bool isBattleNet; bool isPaused; bool isReplay; //selected units int selectedUnitCount; int selectedUnits[12]; // players int self; //events from server to client int eventCount; BWAPIC::Event events[10000]; //strings (used in events, shapes, and commands) int stringCount; char strings[20000][256]; //shapes, commands, unitCommands, from client to server int shapeCount; BWAPIC::Shape shapes[20000]; int commandCount; BWAPIC::Command commands[20000]; int unitCommandCount; BWAPIC::UnitCommand unitCommands[20000]; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/GameImpl.h ================================================ #pragma once #include #include "GameData.h" #include "Client.h" #include "Shape.h" #include "Command.h" #include "UnitCommand.h" #include "ForceImpl.h" #include "PlayerImpl.h" #include "UnitImpl.h" #include "BulletImpl.h" #include #include #include #include namespace BWAPI { class Force; class Player; class Unit; class GameImpl : public Game { private : int addShape(BWAPIC::Shape &s); int addString(const char* text); int addText(BWAPIC::Shape &s, const char* text); int addCommand(BWAPIC::Command &c); void clearAll(); GameData* data; std::vector forceVector; std::vector playerVector; std::vector unitVector; std::vector bulletVector; std::set forces; std::set players; std::set accessibleUnits;//all units that are accessible (and definitely alive) //notDestroyedUnits - accessibleUnits = all units that may or may not be alive (status unknown) std::set minerals; std::set geysers; std::set neutralUnits; std::set staticMinerals; std::set staticGeysers; std::set staticNeutralUnits; std::set bullets; std::set selectedUnits; std::set pylons; std::set unitsOnTileData[256][256]; std::set< TilePosition > startLocations; std::list< Event > events; bool flagEnabled[2]; Player* thePlayer; Player* theEnemy; Error lastError; public : Event makeEvent(BWAPIC::Event e); int addUnitCommand(BWAPIC::UnitCommand& c); bool inGame; GameImpl(GameData* data); void onMatchStart(); void onMatchEnd(); void onMatchFrame(); const GameData* getGameData() const; std::set& getPlayerUnits(const Player* player); virtual std::set< Force* >& getForces(); virtual std::set< Player* >& getPlayers(); virtual std::set< Unit* >& getAllUnits(); virtual std::set< Unit* >& getMinerals(); virtual std::set< Unit* >& getGeysers(); virtual std::set< Unit* >& getNeutralUnits(); virtual std::set< Unit* >& getStaticMinerals(); virtual std::set< Unit* >& getStaticGeysers(); virtual std::set< Unit* >& getStaticNeutralUnits(); virtual std::set< Bullet* >& getBullets(); virtual std::list< Event>& getEvents(); virtual Force* getForce(int forceID); virtual Player* getPlayer(int playerID); virtual Unit* getUnit(int unitID); virtual Unit* indexToUnit(int unitIndex); virtual GameType getGameType(); virtual int getLatency(); virtual int getFrameCount(); virtual int getFPS(); virtual double getAverageFPS(); virtual BWAPI::Position getMousePosition(); virtual bool getMouseState(MouseButton button); virtual bool getMouseState(int button); virtual bool getKeyState(Key key); virtual bool getKeyState(int key); virtual BWAPI::Position getScreenPosition(); virtual void setScreenPosition(int x, int y); virtual void setScreenPosition(BWAPI::Position p); virtual void pingMinimap(int x, int y); virtual void pingMinimap(BWAPI::Position p); virtual bool isFlagEnabled(int flag); virtual void enableFlag(int flag); virtual std::set& unitsOnTile(int x, int y); virtual Error getLastError() const; virtual bool setLastError(BWAPI::Error e); virtual int mapWidth(); virtual int mapHeight(); virtual std::string mapFileName(); virtual std::string mapPathName(); virtual std::string mapName(); virtual std::string mapHash(); virtual bool isWalkable(int x, int y); virtual int getGroundHeight(int x, int y); virtual int getGroundHeight(TilePosition position); virtual bool isBuildable(int x, int y); virtual bool isBuildable(TilePosition position); virtual bool isVisible(int x, int y); virtual bool isVisible(TilePosition position); virtual bool isExplored(int x, int y); virtual bool isExplored(TilePosition position); virtual bool hasCreep(int x, int y); virtual bool hasCreep(TilePosition position); virtual bool hasPower(int x, int y, int tileWidth, int tileHeight); virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight); virtual bool canBuildHere(Unit* builder, TilePosition position, UnitType type, bool checkExplored = false); virtual bool canMake(Unit* builder, UnitType type); virtual bool canResearch(Unit* unit, TechType type); virtual bool canUpgrade(Unit* unit, UpgradeType type); virtual std::set< TilePosition >& getStartLocations(); virtual void printf(const char* text, ...); virtual void sendText(const char* text, ...); virtual void sendTextEx(bool toAllies, const char *format, ...); virtual void changeRace(BWAPI::Race race); virtual bool isInGame(); virtual bool isMultiplayer(); virtual bool isBattleNet(); virtual bool isPaused(); virtual bool isReplay(); virtual void startGame(); virtual void pauseGame(); virtual void resumeGame(); virtual void leaveGame(); virtual void restartGame(); virtual void setLocalSpeed(int speed = -1); virtual std::set& getSelectedUnits(); virtual Player* self(); virtual Player* enemy(); virtual void setTextSize(int size = 1); virtual void drawText(int ctype, int x, int y, const char* text, ...); virtual void drawTextMap(int x, int y, const char* text, ...); virtual void drawTextMouse(int x, int y, const char* text, ...); virtual void drawTextScreen(int x, int y, const char* text, ...); virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false); virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false); virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false); virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false); virtual void drawDot(int ctype, int x, int y, Color color); virtual void drawDotMap(int x, int y, Color color); virtual void drawDotMouse(int x, int y, Color color); virtual void drawDotScreen(int x, int y, Color color); virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color); virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color); virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color); virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color); virtual void *getScreenBuffer(); virtual int getLatencyFrames(); virtual int getLatencyTime(); virtual int getRemainingLatencyFrames(); virtual int getRemainingLatencyTime(); virtual int getRevision(); virtual bool isDebug(); virtual bool isLatComEnabled(); virtual void setLatCom(bool isEnabled); virtual int getReplayFrameCount(); virtual void setGUI(bool enabled = true); virtual int getInstanceNumber(); }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/PlayerData.h ================================================ #pragma once namespace BWAPI { struct PlayerData { char name[25]; int race; int type; int force; bool isAlly[12]; bool isEnemy[12]; bool isNeutral; int startLocationX; int startLocationY; bool isVictorious; bool isDefeated; bool leftGame; int minerals; int gas; int cumulativeMinerals; int cumulativeGas; int supplyTotal[3]; int supplyUsed[3]; int allUnitCount[230]; int completedUnitCount[230]; int deadUnitCount[230]; int killedUnitCount[230]; int upgradeLevel[63]; bool hasResearched[47]; bool isResearching[47]; bool isUpgrading[63]; int colorByte; int color; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/PlayerImpl.h ================================================ #pragma once #include #include "PlayerData.h" #include #include namespace BWAPI { class Unit; class Force; class PlayerImpl : public Player { private: int id; public: PlayerData* self; std::set units; void clear(); PlayerImpl(int id); virtual int getID() const; virtual std::string getName() const; virtual const std::set& getUnits() const; virtual Race getRace() const; virtual PlayerType getType() const; virtual Force* getForce() const; virtual bool isAlly(Player* player) const; virtual bool isEnemy(Player* player) const; virtual bool isNeutral() const; virtual TilePosition getStartLocation() const; virtual bool isVictorious() const; virtual bool isDefeated() const; virtual bool leftGame() const; virtual int minerals() const; virtual int gas() const; virtual int cumulativeMinerals() const; virtual int cumulativeGas() const; virtual int supplyTotal() const; virtual int supplyUsed() const; virtual int supplyTotal(Race race) const; virtual int supplyUsed(Race race) const; virtual int allUnitCount(UnitType unit) const; virtual int completedUnitCount(UnitType unit) const; virtual int incompleteUnitCount(UnitType unit) const; virtual int deadUnitCount(UnitType unit) const; virtual int killedUnitCount(UnitType unit) const; virtual int getUpgradeLevel(UpgradeType upgrade) const; virtual bool hasResearched(TechType tech) const; virtual bool isResearching(TechType tech) const; virtual bool isUpgrading(UpgradeType upgrade) const; virtual int maxEnergy(UnitType unit) const; virtual BWAPI::Color getColor() const; virtual int getTextColor() const; }; }; ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/Shape.h ================================================ #pragma once #include "ShapeType.h" namespace BWAPIC { struct Shape { Shape(ShapeType::Enum _shapeType, int _ctype, int _x1, int _y1, int _x2, int _y2, int _extra1, int _extra2, int _color, bool _isSolid) { type=_shapeType; ctype=_ctype; x1=_x1; y1=_y1; x2=_x2; y2=_y2; extra1=_extra1; extra2=_extra2; color=_color; isSolid=_isSolid; } ShapeType::Enum type; int ctype; int x1; int y1; int x2; int y2; int extra1; int extra2; int color; bool isSolid; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/ShapeType.h ================================================ #pragma once /** * Used in UnitCommand */ namespace BWAPIC { namespace ShapeType { enum Enum { None, Text, Box, Triangle, Circle, Ellipse, Dot, Line }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/UnitCommand.h ================================================ #pragma once #include /** * UnitOrder contains a single whole order */ namespace BWAPIC { struct UnitCommand { BWAPI::UnitCommandType type; int unitIndex; int targetIndex; int x; int y; int extra; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/UnitData.h ================================================ #pragma once namespace BWAPI { struct UnitData { int clearanceLevel; int id; int player; int type; int positionX; int positionY; double angle; double velocityX; double velocityY; int hitPoints; int lastHitPoints; int shields; int energy; int resources; int resourceGroup; int killCount; int scarabCount; int spiderMineCount; int groundWeaponCooldown; int airWeaponCooldown; int spellCooldown; int defenseMatrixPoints; int defenseMatrixTimer; int ensnareTimer; int irradiateTimer; int lockdownTimer; int maelstromTimer; int orderTimer; int plagueTimer; int removeTimer; int stasisTimer; int stimTimer; int buildType; int trainingQueueCount; int trainingQueue[5]; int tech; int upgrade; int remainingBuildTime; int remainingTrainTime; int remainingResearchTime; int remainingUpgradeTime; int buildUnit; int target; int targetPositionX; int targetPositionY; int order; int orderTarget; int secondaryOrder; int rallyPositionX; int rallyPositionY; int rallyUnit; int addon; int nydusExit; int powerUp; int transport; int carrier; int hatchery; bool exists; bool hasNuke; bool isAccelerating; bool isAttacking; bool isBeingGathered; bool isBlind; bool isBraking; bool isBurrowed; int carryResourceType; bool isCloaked; bool isCompleted; bool isConstructing; bool isDetected; bool isGathering; bool isHallucination; bool isIdle; bool isInterruptible; bool isLifted; bool isMorphing; bool isMoving; bool isParasited; bool isSelected; bool isStartingAttack; bool isStuck; bool isTraining; bool isUnderStorm; bool isUnpowered; bool isVisible[9]; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client/UnitImpl.h ================================================ #pragma once #include #include "UnitData.h" #include #include namespace BWAPI { class Player; class UnitImpl : public Unit { private: int id; UnitType initialType; int initialResources; int initialHitPoints; Position initialPosition; int lastOrderFrame; void* clientInfo; public: UnitData* self; std::set connectedUnits; std::set loadedUnits; void clear(); void saveInitialState(); UnitImpl(int id); virtual int getID() const; virtual Player* getPlayer() const; virtual UnitType getType() const; virtual Position getPosition() const; virtual TilePosition getTilePosition() const; virtual double getAngle() const; virtual double getVelocityX() const; virtual double getVelocityY() const; virtual int getHitPoints() const; virtual int getShields() const; virtual int getEnergy() const; virtual int getResources() const; virtual int getResourceGroup() const; virtual double getDistance(Unit* target) const; virtual double getDistance(Position target) const; virtual bool hasPath(Unit* target) const; virtual bool hasPath(Position target) const; virtual int getLastOrderFrame() const; virtual int getUpgradeLevel(UpgradeType upgrade) const; virtual UnitType getInitialType() const; virtual Position getInitialPosition() const; virtual TilePosition getInitialTilePosition() const; virtual int getInitialHitPoints() const; virtual int getInitialResources() const; virtual int getKillCount() const; virtual int getInterceptorCount() const; virtual int getScarabCount() const; virtual int getSpiderMineCount() const; virtual int getGroundWeaponCooldown() const; virtual int getAirWeaponCooldown() const; virtual int getSpellCooldown() const; virtual int getDefenseMatrixPoints() const; virtual int getDefenseMatrixTimer() const; virtual int getEnsnareTimer() const; virtual int getIrradiateTimer() const; virtual int getLockdownTimer() const; virtual int getMaelstromTimer() const; virtual int getOrderTimer() const; virtual int getPlagueTimer() const; virtual int getRemoveTimer() const; virtual int getStasisTimer() const; virtual int getStimTimer() const; virtual UnitType getBuildType() const; virtual std::list getTrainingQueue() const; virtual TechType getTech() const; virtual UpgradeType getUpgrade() const; virtual int getRemainingBuildTime() const; virtual int getRemainingTrainTime() const; virtual int getRemainingResearchTime() const; virtual int getRemainingUpgradeTime() const; virtual Unit* getBuildUnit() const; virtual Unit* getTarget() const; virtual Position getTargetPosition() const; virtual Order getOrder() const; virtual Unit* getOrderTarget() const; virtual Order getSecondaryOrder() const; virtual Position getRallyPosition() const; virtual Unit* getRallyUnit() const; virtual Unit* getAddon() const; virtual Unit* getNydusExit() const; virtual Unit* getPowerUp() const; virtual Unit* getTransport() const; virtual std::set getLoadedUnits() const; virtual Unit* getCarrier() const; virtual std::set getInterceptors() const; virtual Unit* getHatchery() const; virtual std::set getLarva() const; virtual bool exists() const; virtual bool hasNuke() const; virtual bool isAccelerating() const; virtual bool isAttacking() const; virtual bool isBeingConstructed() const; virtual bool isBeingGathered() const; virtual bool isBeingHealed() const; virtual bool isBlind() const; virtual bool isBraking() const; virtual bool isBurrowed() const; virtual bool isCarryingGas() const; virtual bool isCarryingMinerals() const; virtual bool isCloaked() const; virtual bool isCompleted() const; virtual bool isConstructing() const; virtual bool isDefenseMatrixed() const; virtual bool isDetected() const; virtual bool isEnsnared() const; virtual bool isFollowing() const; virtual bool isGatheringGas() const; virtual bool isGatheringMinerals() const; virtual bool isHallucination() const; virtual bool isHoldingPosition() const; virtual bool isIdle() const; virtual bool isInterruptible() const; virtual bool isIrradiated() const; virtual bool isLifted() const; virtual bool isLoaded() const; virtual bool isLockedDown() const; virtual bool isMaelstrommed() const; virtual bool isMorphing() const; virtual bool isMoving() const; virtual bool isParasited() const; virtual bool isPatrolling() const; virtual bool isPlagued() const; virtual bool isRepairing() const; virtual bool isResearching() const; virtual bool isSelected() const; virtual bool isSieged() const; virtual bool isStartingAttack() const; virtual bool isStasised() const; virtual bool isStimmed() const; virtual bool isStuck() const; virtual bool isTraining() const; virtual bool isUnderStorm() const; virtual bool isUnpowered() const; virtual bool isUpgrading() const; virtual bool isVisible() const; virtual bool isVisible(Player* player) const; virtual bool issueCommand(UnitCommand command); virtual bool attackMove(Position target); virtual bool attackUnit(Unit* target); virtual bool build(TilePosition target, UnitType type); virtual bool buildAddon(UnitType type); virtual bool train(UnitType type); virtual bool morph(UnitType type); virtual bool research(TechType tech); virtual bool upgrade(UpgradeType upgrade); virtual bool setRallyPoint(Position target); virtual bool setRallyPoint(Unit* target); virtual bool move(Position target); virtual bool patrol(Position target); virtual bool holdPosition(); virtual bool stop(); virtual bool follow(Unit* target); virtual bool gather(Unit* target); virtual bool returnCargo(); virtual bool repair(Unit* target); virtual bool burrow(); virtual bool unburrow(); virtual bool cloak(); virtual bool decloak(); virtual bool siege(); virtual bool unsiege(); virtual bool lift(); virtual bool land(TilePosition target); virtual bool load(Unit* target); virtual bool unload(Unit* target); virtual bool unloadAll(); virtual bool unloadAll(Position target); virtual bool rightClick(Position target); virtual bool rightClick(Unit* target); virtual bool haltConstruction(); virtual bool cancelConstruction(); virtual bool cancelAddon(); virtual bool cancelTrain(int slot = -2); virtual bool cancelMorph(); virtual bool cancelResearch(); virtual bool cancelUpgrade(); virtual bool useTech(TechType tech); virtual bool useTech(TechType tech, Position target); virtual bool useTech(TechType tech, Unit* target); virtual void setClientInfo(void* clientinfo); virtual void* getClientInfo() const; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Client.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Color.h ================================================ #pragma once #include #include namespace BWAPI { // TODO: Add color palette image and info about text color /** StarCraft uses a 256 color palette to render everything, so the colors we can use to draw shapes using * BWAPI is limited to the colors available in the Palette. */ class Color { public: Color(); /** Create a color using the specified index from the Broodwar color palette. */ Color(int id); Color(const Color& other); /** Create a color using the color in the palette that is closest to the RGB color specified. */ Color(int red, int green, int blue); /** Return the index of the color in the color palette. */ int getID() const; /** Return the red component of the color. */ int red() const; /** Return the green component of the color. */ int green() const; /** Return the blue component of the color. */ int blue() const; Color& operator=(const Color& other); bool operator==(const Color& other) const; bool operator!=(const Color& other) const; bool operator<(const Color& other) const; private: int id; }; /** While any color from the palette can be used, the following colors are available as short cuts. */ namespace Colors { void init(); extern const Color Red; extern const Color Blue; extern const Color Teal; extern const Color Purple; extern const Color Orange; extern const Color Brown; extern const Color White; extern const Color Yellow; extern const Color Green; extern const Color Cyan; extern const Color Black; extern const Color Grey; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Constants.h ================================================ #pragma once namespace BWAPI { /** Used for converting between TilePosition coordinates and Position coordinates. */ #define TILE_SIZE 32 #define PYLON_X_RADIUS 8 #define PYLON_Y_RADIUS 5 } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/CoordinateType.h ================================================ #pragma once namespace BWAPI { namespace CoordinateType { enum Enum { Screen = 1, /**< (0,0) corresponds to the top left corner of the screen. */ Map = 2, /**< (0,0) corresponds to the top left corner of the map. */ Mouse = 3, /**< (0,0) corresponds to the tip of the mouse . */ }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/DamageType.h ================================================ #pragma once #include #include namespace BWAPI { class DamageType { public: DamageType(); DamageType(int id); DamageType(const DamageType& other); DamageType& operator=(const DamageType& other); bool operator==(const DamageType& other) const; bool operator!=(const DamageType& other) const; bool operator<(const DamageType& other) const; /** Returns a unique ID for this damage type. */ int getID() const; /** Returns the name of this damage type. For example DamageTypes::Explosive.getName() will return * std::string("Explosive"). */ std::string getName() const; private: int id; }; namespace DamageTypes { /** Given the name of a damage type, this will return a corresponding DamageType object. For example, * DamageTypes::getDamageType("Concussive") will return DamageTypes::Concussive. */ DamageType getDamageType(std::string name); /** Returns the set of all the DamageTypes. */ std::set& allDamageTypes(); void init(); extern const DamageType Independent; extern const DamageType Explosive; extern const DamageType Concussive; extern const DamageType Normal; extern const DamageType Ignore_Armor; extern const DamageType None; extern const DamageType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Error.h ================================================ #pragma once #include #include namespace BWAPI { class UnitType; /** Functions in BWAPI may set an error code. To retrieve the error code, call Game::getLastError. */ class Error { public: Error(); Error(int id); Error(const Error& other); Error& operator=(const Error& other); bool operator==(const Error& other) const; bool operator!=(const Error& other) const; bool operator<(const Error& other) const; /** Returns a unique ID for this error. */ int getID() const; /** Returns the name of the error. For example Errors::Insufficient_Minerals?.toString() will return a * std::string object containing "Insufficient Minerals". */ std::string toString() const; private: int id; }; namespace Errors { /** Given the name of an error, this function will return the error code. For example: * Errors::getError("Unbuildable Location") will return Errors::Unbuildable_Location?. */ Error getError(std::string name); /** The set of all the error codes. */ std::set& allErrors(); void init(); /** Returned if you try to order a unit or get information from a unit that no longer exists. */ extern const Error Unit_Does_Not_Exist; /** Returned if you try to retrieve information about a unit that is not currently visible or is dead. */ extern const Error Unit_Not_Visible; /** Returned when attempting to order a unit that BWAPI does not own (i.e. can't order enemy army to go * away) */ extern const Error Unit_Not_Owned; /** Returned when trying to order a unit to do something when it is performing another order or is in a * state which prevents it from performing the desired order. For example, ordering a Terran Engineering * Bay to upgrade something while it is already upgrading something else will return this error. * Similarly, trying to train units from a factory that is lifted will return this error. */ extern const Error Unit_Busy; /** Returned if you do something weird like try to build a Pylon with an SCV, or train Vultures in a * Barracks, or order a Hydralisk to lay a spider mine. */ extern const Error Incompatible_UnitType; /** Returned when trying to use a tech type with the wrong Unit::useTech method. */ extern const Error Incompatible_TechType; /** Returned if you to do something like try to cancel an upgrade when the unit isn't upgrading. */ extern const Error Incompatible_State; /** Returned if you try to research something that is already researched. */ extern const Error Already_Researched; /** Returned if you try to upgrade something that is already fully upgraded. */ extern const Error Fully_Upgraded; /** Returned if you try to research something that is already being researched. */ extern const Error Currently_Researching; /** Returned if you try to upgrade something that is already being upgraded. */ extern const Error Currently_Upgrading; /** Returned if you try to train or build something without enough minerals. */ extern const Error Insufficient_Minerals; /** Returned if you try to train or build something without enough vespene gas. */ extern const Error Insufficient_Gas; /** Returned if you try to train something without enough supply. */ extern const Error Insufficient_Supply; /** Returned if you to do something like try to order a Defiler to cast a Dark Swarm without enough * energy. */ extern const Error Insufficient_Energy; /** Returned if you do something like try to train Medics when you don't have an Academy, or try to lay * Spider Mines before spider mines have been researched. */ extern const Error Insufficient_Tech; /** Returned if you do something like try to lay Spider Mines when your Vulture is out of Spider Mines. * Same thing with Reavers and Scarabs. */ extern const Error Insufficient_Ammo; /** Returned if you try to build something on unbuildable terrain (either from the buildability map data * or if a unit is in the way). For build tiles that are not visible, we could just use the buildability * map data and assume that no units are blocking it (to prevent cheating). */ extern const Error Insufficient_Space; /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out * of range. */ extern const Error Unbuildable_Location; /** Returned if you try to construct a building where the worker cannot reach based on static map data. */ extern const Error Unreachable_Location; /** Returned if you order an immovable unit, like a Protoss Photon Cannon, to attack a unit that is out of * range.*/ extern const Error Out_Of_Range; /** Returned if you do something like order a Vulture to attack a flying unit. */ extern const Error Unable_To_Hit; /** Returned if you try to get information that is not allowed with the given flag settings. For example, * trying to read the enemy's resource counts while the CompleteMapInformation? flag is not enabled will * return this error. Similarly, trying to read the coordinates of the screen or mouse while the UserInput * flag is not enabled will also return this error. */ extern const Error Access_Denied; /** Used when no error has been encountered. */ extern const Error None; /** Used when the error code is not recognized or can not be determined. */ extern const Error Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Event.h ================================================ #pragma once #include #include #include #include #include namespace BWAPI { class Event { public: Event(); bool operator==(const Event& other); static Event MatchStart(); static Event MatchEnd(bool isWinner); static Event MatchFrame(); static Event MenuFrame(); static Event SendText(std::string text); static Event ReceiveText(Player* player, std::string text); static Event PlayerLeft(Player* player); static Event NukeDetect(Position target); static Event UnitDiscover(Unit* unit); static Event UnitEvade(Unit* unit); static Event UnitShow(Unit* unit); static Event UnitHide(Unit* unit); static Event UnitCreate(Unit* unit); static Event UnitDestroy(Unit* unit); static Event UnitMorph(Unit* unit); static Event UnitRenegade(Unit* unit); static Event SaveGame(std::string gameName); EventType::Enum type; Position position; std::string text; Unit* unit; Player* player; bool isWinner; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/EventType.h ================================================ #pragma once namespace BWAPI { namespace EventType { enum Enum { MatchStart, MatchEnd, MatchFrame, MenuFrame, SendText, ReceiveText, PlayerLeft, NukeDetect, UnitDiscover, UnitEvade, UnitShow, UnitHide, UnitCreate, UnitDestroy, UnitMorph, UnitRenegade, SaveGame, None }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/ExplosionType.h ================================================ #pragma once #include #include namespace BWAPI { class ExplosionType { public: ExplosionType(); ExplosionType(int id); ExplosionType(const ExplosionType& other); ExplosionType& operator=(const ExplosionType& other); bool operator==(const ExplosionType& other) const; bool operator!=(const ExplosionType& other) const; bool operator<(const ExplosionType& other) const; /** Returns a unique ID for this explosion type. */ int getID() const; /** Returns the name of this explosion type. */ std::string getName() const; private: int id; }; namespace ExplosionTypes { /** Given a name of an explosion type, this will return the corresponding ExplosionType object. */ ExplosionType getExplosionType(std::string name); /** Returns the set of all ExplosionTypes. */ std::set& allExplosionTypes(); void init(); extern const ExplosionType None; extern const ExplosionType Normal; extern const ExplosionType Radial_Splash; extern const ExplosionType Enemy_Splash; extern const ExplosionType Lockdown; extern const ExplosionType Nuclear_Missile; extern const ExplosionType Parasite; extern const ExplosionType Broodlings; extern const ExplosionType EMP_Shockwave; extern const ExplosionType Irradiate; extern const ExplosionType Ensnare; extern const ExplosionType Plague; extern const ExplosionType Stasis_Field; extern const ExplosionType Dark_Swarm; extern const ExplosionType Consume; extern const ExplosionType Yamato_Gun; extern const ExplosionType Restoration; extern const ExplosionType Disruption_Web; extern const ExplosionType Corrosive_Acid; extern const ExplosionType Mind_Control; extern const ExplosionType Feedback; extern const ExplosionType Optical_Flare; extern const ExplosionType Maelstrom; extern const ExplosionType Air_Splash; extern const ExplosionType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Flag.h ================================================ #pragma once namespace BWAPI { namespace Flag { enum Enum { /** Enable to get information about all units on the map, not just the visible units. */ CompleteMapInformation = 0, /** Enable to get information from the user (what units are selected, chat messages the user enters, * etc) */ UserInput = 1, Max }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Force.h ================================================ #pragma once #include #include namespace BWAPI { class Player; /** The Force class is used to get information about each force in the match, such as the name of the force * and the set of players in the force. */ class Force { public : /** Returns a unique ID for the force. */ virtual int getID() const = 0; /** Returns the name of the force. */ virtual std::string getName() const = 0; /** Returns the set of players in the force. */ virtual std::set getPlayers() const = 0; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Game.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace BWAPI { class Force; class Player; class Unit; class Bullet; /** The abstract Game class is implemented by BWAPI and offers many methods for retrieving information * about the current Broodwar game, including the set of players, units, map information, as well as * information about the user, such as mouse position, screen position, and the current selection of * units. */ class Game { public : /** Returns the set of all forces in the match. */ virtual std::set< Force* >& getForces() = 0; /** Returns the set of all players in the match. Note that this includes the Neutral player, which owns * all the neutral units such as minerals, critters, etc. */ virtual std::set< Player* >& getPlayers() = 0; /** Returns all the visible units. If Flag::CompleteMapInformation is enabled, the set of all units * is returned, not just visible ones. Note that units inside refineries are not included in this set * yet. */ virtual std::set< Unit* >& getAllUnits() = 0; /** Returns the set of all accessible mineral patches. */ virtual std::set< Unit* >& getMinerals() = 0; /** Returns the set of all accessible vespene geysers. */ virtual std::set< Unit* >& getGeysers() = 0; /** Returns the set of all accessible neutral units. */ virtual std::set< Unit* >& getNeutralUnits() = 0; /** Returns the set of all mineral patches (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticMinerals() = 0; /** Returns the set of all vespene geysers (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticGeysers() = 0; /** Returns the set of all neutral units (including mined out and other inaccessible ones). */ virtual std::set< Unit* >& getStaticNeutralUnits() = 0; /** Returns all visible bullets. If Flag::CompleteMapInformation is enabled, the set of all bullets is * returned, not just visible ones. */ virtual std::set< Bullet* >& getBullets() = 0; /** Returns the list of events */ virtual std::list< Event >& getEvents() = 0; /** Returns the force with the given ID, or NULL if no force has the given ID */ virtual Force* getForce(int forceID) = 0; /** Returns the player with the given ID, or NULL if no player has the given ID */ virtual Player* getPlayer(int playerID) = 0; /** Returns the unit with the given ID, or NULL if no unit has the given ID */ virtual Unit* getUnit(int unitID) = 0; /** Returns a pointer to a Unit given an index. */ virtual Unit* indexToUnit(int unitIndex) = 0; /** Returns the game type */ virtual GameType getGameType() = 0; /** Returns the amount of latency the current game has. Currently only returns Latency::SinglePlayer, * Latency::LanLow, Latency::LanMedium, or Latency::LanHigh. */ virtual int getLatency() = 0; /** Returns the number of logical frames since the match started. If the game is paused, * Game::getFrameCount will not increase however AIModule::onFrame will still be called while paused. * On Fastest, there are about 23.8 - 24 frames per second. */ virtual int getFrameCount() = 0; /** Returns the Frames Per Second (FPS) that the game is currently running at */ virtual int getFPS() = 0; virtual double getAverageFPS() = 0; /** Returns the position of the mouse on the screen. Returns Positions::Unknown if Flag::UserInput is * disabled. */ virtual BWAPI::Position getMousePosition() = 0; /** Returns true if the specified mouse button is pressed. Returns false if Flag::UserInput is * disabled. */ virtual bool getMouseState(MouseButton button) = 0; /** \copydoc getMouseState(MouseButton) */ virtual bool getMouseState(int button) = 0; /** Returns true if the specified key is pressed. Returns false if Flag::UserInput is disabled. * Unfortunately this does not read the raw keyboard input yet - when you hold down a key, the * getKeyState function is true for a frame, then false for a few frames, and then alternates between * true and false (as if you were holding down the key in a text box). Hopefully this will be fixed in * a later version. */ virtual bool getKeyState(Key key) = 0; /** \copydoc getKeyState(Key) */ virtual bool getKeyState(int key) = 0; /** Returns the position of the top left corner of the screen on the map. Returns Positions::Unknown if * Flag::UserInput is disabled. */ virtual BWAPI::Position getScreenPosition() = 0; /** Moves the screen to the given position on the map. The position specified where the top left corner * of the screen will be. */ virtual void setScreenPosition(int x, int y) = 0; /** \copydoc setScreenPosition(int, int) */ virtual void setScreenPosition(BWAPI::Position p) = 0; /** Pings the given position on the minimap. */ virtual void pingMinimap(int x, int y) = 0; /** \copydoc pingMinimap(int, int) */ virtual void pingMinimap(BWAPI::Position p) = 0; /** Returns true if the given flag has been enabled. Note that flags can only be enabled at the * beginning of a match, during the AIModule::onStart callback. */ virtual bool isFlagEnabled(int flag) = 0; /** Enables the specified flag. Note that flags can only be enabled at the beginning of a match, during * the AIModule::onStart callback. */ virtual void enableFlag(int flag) = 0; /** Returns the set of units that are on the given build tile. Only returns accessible units on * accessible tiles. */ virtual std::set& unitsOnTile(int tileX, int tileY) = 0; /** Returns the last error that was set. If you try to order enemy units around, or morph bunkers into * lurkers, BWAPI will set error codes, which can be retrieved using this function. */ virtual Error getLastError() const = 0; /** Sets the last error code. */ virtual bool setLastError(BWAPI::Error e) = 0; /** Returns the width of the current map, in build tile units. To get the width of the current map in * walk tile units, multiply by 4. To get the width of the current map in Position units, multiply by * TILE_SIZE (which is 32). */ virtual int mapWidth() = 0; /** Returns the height of the current map, in build tile units. To get the height of the current map in * walk tile units, multiply by 4. To get the height of the current map in Position units, multiply by * TILE_SIZE (which is 32). */ virtual int mapHeight() = 0; /** Returns the file name of the current map. */ virtual std::string mapFileName() = 0; /** Returns the full path name of the current map. */ virtual std::string mapPathName() = 0; /** Returns the name/title of the current map. */ virtual std::string mapName() = 0; /** Returns the SHA-1 hash of the map file. */ virtual std::string mapHash() = 0; /** Returns true if the specified walk tile is walkable. The values of x and y are in walk tile * coordinates (different from build tile coordinates). Note that this just uses the static map data. * You will also need to make sure no ground units are on the coresponding build tile to see if its * currently walkable. To do this, see unitsOnTile. */ virtual bool isWalkable(int walkX, int walkY) = 0; /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */ virtual int getGroundHeight(int tileX, int tileY) = 0; /** Returns the ground height of the given build tile. 0 = normal, 1 = high ground. 2 = very high ground. */ virtual int getGroundHeight(TilePosition position) = 0; /** Returns true if the specified build tile is buildable. Note that this just uses the static map data. * You will also need to make sure no ground units on the tile to see if its currently buildable. To do * this, see unitsOnTile. */ virtual bool isBuildable(int tileX, int tileY) = 0; /** \copydoc isBuildable(int, int) */ virtual bool isBuildable(TilePosition position) = 0; /** Returns true if the specified build tile is visible. If the tile is concealed by fog of war, the * function will return false. */ virtual bool isVisible(int tileX, int tileY) = 0; /** \copydoc isVisible(int, int) */ virtual bool isVisible(TilePosition position) = 0; /** Returns true if the specified build tile has been explored (i.e. was visible at some point in the * match). */ virtual bool isExplored(int tileX, int tileY) = 0; /** \copydoc isExplored(int, int) */ virtual bool isExplored(TilePosition position) = 0; /** Returns true if the specified build tile has zerg creep on it. If the tile is concealed by fog of * war, the function will return false. */ virtual bool hasCreep(int tileX, int tileY) = 0; /** \copydoc hasCreep(int, int) */ virtual bool hasCreep(TilePosition position) = 0; /** Returns true if the given build location is powered by a nearby friendly pylon. */ virtual bool hasPower(int tileX, int tileY, int tileWidth, int tileHeight) = 0; /** \copydoc hasPower(int, int, int, int) */ virtual bool hasPower(TilePosition position, int tileWidth, int tileHeight) = 0; /** Returns true if the given unit type can be built at the given build tile position. Note the tile * position specifies the top left tile of the building. If builder is not null, the unit will be * discarded when determining whether or not any ground units are blocking the build location. */ virtual bool canBuildHere(Unit *builder, TilePosition position, UnitType type, bool checkExplored = false) = 0; /** Returns true if the AI player has enough resources, supply, tech, and required units in order to * make the given unit type. If builder is not null, canMake will return true only if the builder unit * can build the given unit type. */ virtual bool canMake(Unit *builder, UnitType type) = 0; /** Returns true if the AI player has enough resources required to research the given tech type. If unit * is not null, canResearch will return true only if the given unit can research the given tech type. */ virtual bool canResearch(Unit *unit, TechType type) = 0; /** Returns true if the AI player has enough resources required to upgrade the given upgrade type. If * unit is not null, canUpgrade will return true only if the given unit can upgrade the given upgrade * type. */ virtual bool canUpgrade(Unit *unit, UpgradeType type) = 0; /** Returns the set of starting locations for the given map. To determine the starting location for the * players in the current match, see Player::getStartLocation. */ virtual std::set< TilePosition >& getStartLocations() = 0; /** Prints text on the screen. Text is not sent to other players in multiplayer games. */ virtual void printf(const char *format, ...) = 0; /** Sends text to other players - as if it were entered in chat. In single player games and replays, * this will just print the text on the screen. If the game is a single player match and not a replay, * then this function can be used to execute cheat codes, i.e. Broodwar->sendText("show me the money"). */ virtual void sendText(const char *format, ...) = 0; virtual void sendTextEx(bool toAllies, const char *format, ...) = 0; /** Used to change the race while in a lobby. Note that there is no onLobbyEnter callback yet, so this * function cannot be used at this time. */ virtual void changeRace(Race race) = 0; /** Returns true if Broodwar is in a game. Returns false for lobby and menu screens */ virtual bool isInGame() = 0; /** Returns true if Broodwar is in a multiplayer game. Returns false for single player games and * replays. */ virtual bool isMultiplayer() = 0; /** Returns true if Broodwar is in a BNet multiplayer game. */ virtual bool isBattleNet() = 0; /** Returns true if Broodwar is paused. If the game is paused, Game::getFrameCount will continue to * increase and AIModule::onFrame will still be called while paused. */ virtual bool isPaused() = 0; /** Returns true if Broodwar is in a replay. */ virtual bool isReplay() = 0; /** Used to start the game while in a lobby. Note that there is no onLobbyEnter callback yet, so this * function cannot be used at this time. */ virtual void startGame() = 0; /** Pauses the game. If the game is paused, Game::getFrameCount will not increase however * AIModule::onFrame will still be called while paused. */ virtual void pauseGame() = 0; /** Resumes the game. */ virtual void resumeGame() = 0; /** Leaves the current match and goes to the after-game stats screen. */ virtual void leaveGame() = 0; /** Restarts the match. Works the same way as if you restarted the match from the menu screen. Only * available in single player mode. */ virtual void restartGame() = 0; /** Sets the speed of the game to the given number. Lower numbers are faster. 0 is the fastest speed * StarCraft can handle (which is about as fast as the fastest speed you can view a replay at). Any * negative value will reset the speed to the StarCraft default. */ virtual void setLocalSpeed(int speed = -1) = 0; /** Returns the set of units currently selected by the user in the GUI. If Flag?::UserInput? was not * enabled during the AIModule::onStart callback, this function will always return an empty set. */ virtual std::set& getSelectedUnits() = 0; /** Returns a pointer to the player that BWAPI controls. In replays this will return null. */ virtual Player* self() = 0; /** Returns a pointer to the enemy player. If there is more than one enemy, this returns a pointer to * just one enemy (see getPlayers and Player::isEnemy to get the other enemies). In replays this will * return NULL. */ virtual Player* enemy() = 0; virtual void setTextSize(int size = 1) = 0; /** Draws text on the screen at the given position. Text can be drawn in different colors by using the * following control characters: TODO: add image from wiki.*/ virtual void drawText(int ctype, int x, int y, const char* text, ...) = 0; virtual void drawTextMap(int x, int y, const char* text, ...) = 0; virtual void drawTextMouse(int x, int y, const char* text, ...) = 0; virtual void drawTextScreen(int x, int y, const char* text, ...) = 0; /** Draws a box on the screen, with the given color. If isSolid is true, the entire box will be * rendered, otherwise just the outline will be drawn. */ virtual void drawBox(int ctype, int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxMap(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxMouse(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; virtual void drawBoxScreen(int left, int top, int right, int bottom, Color color, bool isSolid = false) = 0; /** Draws a triangle on the screen. If isSolid is true, a solid triangle is drawn, otherwise just the * outline of the triangle will be drawn. */ virtual void drawTriangle(int ctype, int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleMap(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleMouse(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; virtual void drawTriangleScreen(int ax, int ay, int bx, int by, int cx, int cy, Color color, bool isSolid = false) = 0; /** Draws a circle on the screen, with the given color. If isSolid is true, a solid circle is drawn, * otherwise just the outline of a circle will be drawn. */ virtual void drawCircle(int ctype, int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleMap(int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleMouse(int x, int y, int radius, Color color, bool isSolid = false) = 0; virtual void drawCircleScreen(int x, int y, int radius, Color color, bool isSolid = false) = 0; /** Draws an ellipse on the screen, with the given color. If isSolid is true, a solid ellipse is drawn, * otherwise just the outline of an ellipse will be drawn. */ virtual void drawEllipse(int ctype, int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseMap(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseMouse(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; virtual void drawEllipseScreen(int x, int y, int xrad, int yrad, Color color, bool isSolid = false) = 0; /** Draws a dot on the screen at the given position with the given color. */ virtual void drawDot(int ctype, int x, int y, Color color) = 0; virtual void drawDotMap(int x, int y, Color color) = 0; virtual void drawDotMouse(int x, int y, Color color) = 0; virtual void drawDotScreen(int x, int y, Color color) = 0; /** Draws a line on the screen from (x1,y1) to (x2,y2) with the given color. */ virtual void drawLine(int ctype, int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineMap(int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineMouse(int x1, int y1, int x2, int y2, Color color) = 0; virtual void drawLineScreen(int x1, int y1, int x2, int y2, Color color) = 0; /** Retrieves the screen buffer for the game (excluding the HUD) */ virtual void *getScreenBuffer() = 0; /** Retrieves latency values for the game. Includes latency, speed, and mode */ virtual int getLatencyFrames() = 0; virtual int getLatencyTime() = 0; virtual int getRemainingLatencyFrames() = 0; virtual int getRemainingLatencyTime() = 0; /** Retrieves the current revision of BWAPI. */ virtual int getRevision() = 0; /** Retrieves the debug state of the BWAPI build. */ virtual bool isDebug() = 0; /** Returns true if latency compensation is enabled */ virtual bool isLatComEnabled() = 0; /** Use to enable or disable latency compensation. Default: Enabled */ virtual void setLatCom(bool isEnabled) = 0; /** Retrieves the number of frames in the replay */ virtual int getReplayFrameCount() = 0; /** Sets the rendering state of the Starcraft GUI */ virtual void setGUI(bool enabled = true) = 0; /** Retrieves the instance number recorded by BWAPI to identify which instance an AI module belongs to */ virtual int getInstanceNumber() = 0; }; extern Game* Broodwar; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/GameType.h ================================================ #pragma once #include #include namespace BWAPI { class GameType { public: GameType(); GameType(int id); GameType(const GameType& other); GameType& operator=(const GameType& other); bool operator==(const GameType& other) const; bool operator!=(const GameType& other) const; bool operator<(const GameType& other) const; /** Returns the unique ID for this game type. */ int getID() const; /** Returns the name of the game type. For example GameTypes::Melee.getName() will return an * std::string object containing "Melee". */ std::string getName() const; private: int id; }; namespace GameTypes { /** Given the name of a game type, this function will return the GameType. For example: * GameTypes::getGameType("Free For All") will return GameTypes::Free_For_All. */ GameType getGameType(std::string name); /** Returns the set of all the GameTypes. */ std::set& allGameTypes(); void init(); extern const GameType Melee; extern const GameType Free_For_All; extern const GameType One_on_One; extern const GameType Capture_The_Flag; extern const GameType Greed; extern const GameType Slaughter; extern const GameType Sudden_Death; extern const GameType Ladder; extern const GameType Use_Map_Settings; extern const GameType Team_Melee; extern const GameType Team_Free_For_All; extern const GameType Team_Capture_The_Flag; extern const GameType Top_vs_Bottom; extern const GameType Pro_Gamer_League; extern const GameType None; extern const GameType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Input.h ================================================ #pragma once namespace BWAPI { enum MouseButton { M_LEFT = 0, M_RIGHT = 1, M_MIDDLE = 2, }; enum Key { K_LBUTTON = 0x01, K_RBUTTON = 0x02, K_CANCEL = 0x03, K_MBUTTON = 0x04, K_XBUTTON1 = 0x05, K_XBUTTON2 = 0x06, K_BACK = 0x08, K_TAB = 0x09, K_CLEAR = 0x0C, K_RETURN = 0x0D, K_SHIFT = 0x10, K_CONTROL = 0x11, K_MENU = 0x12, K_PAUSE = 0x13, K_CAPITAL = 0x14, K_KANA = 0x15, K_HANGEUL = 0x15, K_HANGUL = 0x15, K_JUNJA = 0x17, K_FINAL = 0x18, K_HANJA = 0x19, K_KANJI = 0x19, K_ESCAPE = 0x1B, K_CONVERT = 0x1C, K_NONCONVERT = 0x1D, K_ACCEPT = 0x1E, K_MODECHANGE = 0x1F, K_SPACE = 0x20, K_PRIOR = 0x21, K_NEXT = 0x22, K_END = 0x23, K_HOME = 0x24, K_LEFT = 0x25, K_UP = 0x26, K_RIGHT = 0x27, K_DOWN = 0x28, K_SELECT = 0x29, K_PRINT = 0x2A, K_EXECUTE = 0x2B, K_SNAPSHOT = 0x2C, K_INSERT = 0x2D, K_DELETE = 0x2E, K_HELP = 0x2F, K_0 = 0x30, K_1 = 0x31, K_2 = 0x32, K_3 = 0x33, K_4 = 0x34, K_5 = 0x35, K_6 = 0x36, K_7 = 0x37, K_8 = 0x38, K_9 = 0x39, K_A = 0x41, K_B = 0x42, K_C = 0x43, K_D = 0x44, K_E = 0x45, K_F = 0x46, K_G = 0x47, K_H = 0x48, K_I = 0x49, K_J = 0x4A, K_K = 0x4B, K_L = 0x4C, K_M = 0x4D, K_N = 0x4E, K_O = 0x4F, K_P = 0x50, K_Q = 0x51, K_R = 0x52, K_S = 0x53, K_T = 0x54, K_U = 0x55, K_V = 0x56, K_W = 0x57, K_X = 0x58, K_Y = 0x59, K_Z = 0x5A, K_LWIN = 0x5B, K_RWIN = 0x5C, K_APPS = 0x5D, K_SLEEP = 0x5F, K_NUMPAD0 = 0x60, K_NUMPAD1 = 0x61, K_NUMPAD2 = 0x62, K_NUMPAD3 = 0x63, K_NUMPAD4 = 0x64, K_NUMPAD5 = 0x65, K_NUMPAD6 = 0x66, K_NUMPAD7 = 0x67, K_NUMPAD8 = 0x68, K_NUMPAD9 = 0x69, K_MULTIPLY = 0x6A, K_ADD = 0x6B, K_SEPARATOR = 0x6C, K_SUBTRACT = 0x6D, K_DECIMAL = 0x6E, K_DIVIDE = 0x6F, K_F1 = 0x70, K_F2 = 0x71, K_F3 = 0x72, K_F4 = 0x73, K_F5 = 0x74, K_F6 = 0x75, K_F7 = 0x76, K_F8 = 0x77, K_F9 = 0x78, K_F10 = 0x79, K_F11 = 0x7A, K_F12 = 0x7B, K_F13 = 0x7C, K_F14 = 0x7D, K_F15 = 0x7E, K_F16 = 0x7F, K_F17 = 0x80, K_F18 = 0x81, K_F19 = 0x82, K_F20 = 0x83, K_F21 = 0x84, K_F22 = 0x85, K_F23 = 0x86, K_F24 = 0x87, K_NUMLOCK = 0x90, K_SCROLL = 0x91, K_OEM_NEC_EQUAL = 0x92, K_OEM_FJ_JISHO = 0x92, K_OEM_FJ_MASSHOU = 0x93, K_OEM_FJ_TOUROKU = 0x94, K_OEM_FJ_LOYA = 0x95, K_OEM_FJ_ROYA = 0x96, K_LSHIFT = 0xA0, K_RSHIFT = 0xA1, K_LCONTROL = 0xA2, K_RCONTROL = 0xA3, K_LMENU = 0xA4, K_RMENU = 0xA5, K_BROWSER_BACK = 0xA6, K_BROWSER_FORWARD = 0xA7, K_BROWSER_REFRESH = 0xA8, K_BROWSER_STOP = 0xA9, K_BROWSER_SEARCH = 0xAA, K_BROWSER_FAVORITES = 0xAB, K_BROWSER_HOME = 0xAC, K_VOLUME_MUTE = 0xAD, K_VOLUME_DOWN = 0xAE, K_VOLUME_UP = 0xAF, K_MEDIA_NEXT_TRACK = 0xB0, K_MEDIA_PREV_TRACK = 0xB1, K_MEDIA_STOP = 0xB2, K_MEDIA_PLAY_PAUSE = 0xB3, K_LAUNCH_MAIL = 0xB4, K_LAUNCH_MEDIA_SELECT = 0xB5, K_LAUNCH_APP1 = 0xB6, K_LAUNCH_APP2 = 0xB7, K_OEM_1 = 0xBA, K_OEM_PLUS = 0xBB, K_OEM_COMMA = 0xBC, K_OEM_MINUS = 0xBD, K_OEM_PERIOD = 0xBE, K_OEM_2 = 0xBF, K_OEM_3 = 0xC0, K_OEM_4 = 0xDB, K_OEM_5 = 0xDC, K_OEM_6 = 0xDD, K_OEM_7 = 0xDE, K_OEM_8 = 0xDF, K_OEM_AX = 0xE1, K_OEM_102 = 0xE2, K_ICO_HELP = 0xE3, K_ICO_00 = 0xE4, K_PROCESSKEY = 0xE5, K_ICO_CLEAR = 0xE6, K_PACKET = 0xE7, K_OEM_RESET = 0xE9, K_OEM_JUMP = 0xEA, K_OEM_PA1 = 0xEB, K_OEM_PA2 = 0xEC, K_OEM_PA3 = 0xED, K_OEM_WSCTRL = 0xEE, K_OEM_CUSEL = 0xEF, K_OEM_ATTN = 0xF0, K_OEM_FINISH = 0xF1, K_OEM_COPY = 0xF2, K_OEM_AUTO = 0xF3, K_OEM_ENLW = 0xF4, K_OEM_BACKTAB = 0xF5, K_ATTN = 0xF6, K_CRSEL = 0xF7, K_EXSEL = 0xF8, K_EREOF = 0xF9, K_PLAY = 0xFA, K_ZOOM = 0xFB, K_NONAME = 0xFC, K_PA1 = 0xFD, K_OEM_CLEAR = 0xFE }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Latency.h ================================================ #pragma once namespace BWAPI { namespace Latency { enum Enum { SinglePlayer = 2, LanLow = 5, LanMedium = 7, LanHigh = 9, BattlenetLow = 14, BattlenetMedium = 19, BattlenetHigh = 24 }; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Order.h ================================================ #pragma once #include #include namespace BWAPI { /** To get detailed information about what a unit is doing, you can use the Unit::getOrder method, which * will return an Order object. Note that a single command, like gather minerals, can consist of several * orders ( MoveToMinerals, HarvestMinerals2, MiningMinerals, ReturnMinerals, etc) which will indicate what * state the unit is in while executing the command. For information about how to issue commands to units, * go to Unit. */ class Order { public: Order(); Order(int id); Order(const Order& other); Order& operator=(const Order& other); bool operator==(const Order& other) const; bool operator!=(const Order& other) const; bool operator<(const Order& other) const; /** Returns the unique ID for this order. */ int getID() const; /** Returns the name of this order. */ std::string getName() const; private: int id; }; namespace Orders { /** Given the name of an order, getOrder() will return the corresponding order object. */ Order getOrder(std::string name); /** Returns the set of all the Orders. */ std::set& allOrders(); void init(); extern const Order Die; extern const Order Stop; extern const Order Guard; extern const Order PlayerGuard; extern const Order TurretGuard; extern const Order BunkerGuard; extern const Order Move; extern const Order AttackUnit; extern const Order AttackTile; extern const Order Hover; extern const Order AttackMove; extern const Order InfestedCommandCenter; extern const Order UnusedNothing; extern const Order UnusedPowerup; extern const Order TowerGuard; extern const Order VultureMine; extern const Order Nothing; extern const Order Nothing3; extern const Order CastInfestation; extern const Order InfestingCommandCenter; extern const Order PlaceBuilding; extern const Order BuildProtoss2; extern const Order ConstructingBuilding; extern const Order Repair; extern const Order PlaceAddon; extern const Order BuildAddon; extern const Order Train; extern const Order RallyPointUnit; extern const Order RallyPointTile; extern const Order ZergBirth; extern const Order ZergUnitMorph; extern const Order ZergBuildingMorph; extern const Order IncompleteBuilding; extern const Order BuildNydusExit; extern const Order EnterNydusCanal; extern const Order Follow; extern const Order Carrier; extern const Order ReaverCarrierMove; extern const Order CarrierIgnore2; extern const Order Reaver; extern const Order TrainFighter; extern const Order InterceptorAttack; extern const Order ScarabAttack; extern const Order RechargeShieldsUnit; extern const Order RechargeShieldsBattery; extern const Order ShieldBattery; extern const Order InterceptorReturn; extern const Order BuildingLand; extern const Order BuildingLiftOff; extern const Order DroneLiftOff; extern const Order LiftingOff; extern const Order ResearchTech; extern const Order Upgrade; extern const Order Larva; extern const Order SpawningLarva; extern const Order Harvest1; extern const Order Harvest2; extern const Order MoveToGas; extern const Order WaitForGas; extern const Order HarvestGas; extern const Order ReturnGas; extern const Order MoveToMinerals; extern const Order WaitForMinerals; extern const Order MiningMinerals; extern const Order Harvest3; extern const Order Harvest4; extern const Order ReturnMinerals; extern const Order Interrupted; extern const Order EnterTransport; extern const Order PickupIdle; extern const Order PickupTransport; extern const Order PickupBunker; extern const Order Pickup4; extern const Order PowerupIdle; extern const Order Sieging; extern const Order Unsieging; extern const Order InitCreepGrowth; extern const Order SpreadCreep; extern const Order StoppingCreepGrowth; extern const Order GuardianAspect; extern const Order ArchonWarp; extern const Order CompletingArchonsummon; extern const Order HoldPosition; extern const Order Cloak; extern const Order Decloak; extern const Order Unload; extern const Order MoveUnload; extern const Order FireYamatoGun; extern const Order CastLockdown; extern const Order Burrowing; extern const Order Burrowed; extern const Order Unburrowing; extern const Order CastDarkSwarm; extern const Order CastParasite; extern const Order CastSpawnBroodlings; extern const Order CastEMPShockwave; extern const Order NukeWait; extern const Order NukeTrain; extern const Order NukeLaunch; extern const Order NukeUnit; extern const Order CastNuclearStrike; extern const Order NukeTrack; extern const Order CloakNearbyUnits; extern const Order PlaceMine; extern const Order RightClickAction; extern const Order CastRecall; extern const Order TeleporttoLocation; extern const Order CastScannerSweep; extern const Order Scanner; extern const Order CastDefensiveMatrix; extern const Order CastPsionicStorm; extern const Order CastIrradiate; extern const Order CastPlague; extern const Order CastConsume; extern const Order CastEnsnare; extern const Order CastStasisField; extern const Order CastHallucination; extern const Order Hallucination2; extern const Order ResetCollision; extern const Order Patrol; extern const Order CTFCOPInit; extern const Order CTFCOP1; extern const Order CTFCOP2; extern const Order ComputerAI; extern const Order AtkMoveEP; extern const Order HarassMove; extern const Order AIPatrol; extern const Order GuardPost; extern const Order RescuePassive; extern const Order Neutral; extern const Order ComputerReturn; extern const Order SelfDestrucing; extern const Order Critter; extern const Order HiddenGun; extern const Order OpenDoor; extern const Order CloseDoor; extern const Order HideTrap; extern const Order RevealTrap; extern const Order Enabledoodad; extern const Order Disabledoodad; extern const Order Warpin; extern const Order Medic; extern const Order MedicHeal1; extern const Order HealMove; extern const Order MedicHeal2; extern const Order CastRestoration; extern const Order CastDisruptionWeb; extern const Order CastMindControl; extern const Order DarkArchonMeld; extern const Order CastFeedback; extern const Order CastOpticalFlare; extern const Order CastMaelstrom; extern const Order JunkYardDog; extern const Order Fatal; extern const Order None; extern const Order Unknown; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Player.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include namespace BWAPI { class Unit; class Force; /** Each player in a match will have his or her own player instance. There is also a neutral player which * owns all the neutral units. */ class Player { public : /** Returns a unique ID for the player. */ virtual int getID() const = 0; /** Returns the name of the player. */ virtual std::string getName() const = 0; /** Returns the set of units the player own. Note that units loaded into Terran dropships, Terran * bunkers, Terran refineries, Protoss assimilators, and Zerg extractors are not yet included in the * set. */ virtual const std::set& getUnits() const = 0; /** Returns the race of the player. */ virtual Race getRace() const = 0; /** Returns the type of the player. */ virtual PlayerType getType() const = 0; /** Returns the force the player is on. */ virtual Force* getForce() const = 0; /** Returns true if other player is an ally of this player. */ virtual bool isAlly(Player* player) const = 0; /** Returns true if other player is an enemy of this player. */ virtual bool isEnemy(Player* player) const = 0; /** Returns true if the player is the neutral player. */ virtual bool isNeutral() const = 0; /** Returns the starting location of the player. If complete map information is disabled, this function * will return TilePositions::Unknown for enemy players. For the complete set of starting locations for * the current map, see Game::getStartLocations. */ virtual TilePosition getStartLocation() const = 0; /** Returns true if the player has achieved victory. */ virtual bool isVictorious() const = 0; /** Returns true if the player has been defeated. */ virtual bool isDefeated() const = 0; /** Returns true if the player left the game. */ virtual bool leftGame() const = 0; /** Returns the amount of minerals the player has. */ virtual int minerals() const = 0; /** Returns the amount of vespene gas the player has. */ virtual int gas() const = 0; /** Returns the cumulative amount of minerals the player has mined up to this point (including the 50 * minerals at the start of the game). */ virtual int cumulativeMinerals() const = 0; /** Returns the cumulative amount of gas the player has harvested up to this point. */ virtual int cumulativeGas() const = 0; // TODO: ground methods /** Returns the total amount of supply the player has. If a race is provided, the total supply for the * given race will be returned, otherwise the player's initial race will be used. Supply counts returned * by BWAPI are double what you would expect to see from playing the game. This is because zerglings * take up 0.5 in-game supply. */ virtual int supplyTotal() const = 0; virtual int supplyTotal(Race race) const = 0; /** Returns how much of the supply is actually being used by units. If a race is provided, the used * supply for the given race will be returned, otherwise the player's initial race will be used. Supply * counts returned by BWAPI are double what you would expect to see from playing the game. This is * because zerglings take up 0.5 in-game supply. */ virtual int supplyUsed() const = 0; virtual int supplyUsed(Race race) const = 0; /** Returns the number of all units of the given type. */ virtual int allUnitCount(UnitType unit) const = 0; /** Returns the number of completed units of the given type. */ virtual int completedUnitCount(UnitType unit) const = 0; /** Returns the number of incomplete units of the given type. */ virtual int incompleteUnitCount(UnitType unit) const = 0; /** Returns the number of dead units of the given type. */ virtual int deadUnitCount(UnitType unit) const = 0; /** Returns the number of killed units of the given type. */ virtual int killedUnitCount(UnitType unit) const = 0; /** Returns the player's current upgrade level of the given upgrade. To order a unit to upgrade a given * upgrade type, see Unit::upgrade. */ virtual int getUpgradeLevel(UpgradeType upgrade) const = 0; /** Returns true if the player has finished researching the given tech. To order a unit to research a * given tech type, see Unit::research. */ virtual bool hasResearched(TechType tech) const = 0; /** Returns true if the player is researching the given tech. To order a unit to research a given tech * type, see Unit::reseach. */ virtual bool isResearching(TechType tech) const = 0; /** Returns true if the player is upgrading the given upgrade. To order a unit to upgrade a given * upgrade type, see Unit::upgrade. */ virtual bool isUpgrading(UpgradeType upgrade) const = 0; /** Returns the max energy of the given unit type, taking into account upgrades */ virtual int maxEnergy(UnitType unit) const = 0; /** Returns the color of the player for drawing */ virtual BWAPI::Color getColor() const = 0; /** Returns the color of the player for text messages */ virtual int getTextColor() const = 0; }; }; ================================================ FILE: SparCraft/bwapidata/include/BWAPI/PlayerType.h ================================================ #pragma once #include #include namespace BWAPI { class PlayerType { public: PlayerType(); PlayerType(int id); PlayerType(const PlayerType& other); PlayerType& operator=(const PlayerType& other); bool operator==(const PlayerType& other) const; bool operator!=(const PlayerType& other) const; bool operator<(const PlayerType& other) const; /** Returns the unique ID for this player type. */ int getID() const; /** Returns the name of the player type. For example PlayerTypes::Computer.getName() will return an * std::string object containing "Computer". */ std::string getName() const; private: int id; }; namespace PlayerTypes { /** Given the name of a player type, this function will return the playertype. For example: * PlayerTypes::getPlayerType("Human") will return PlayerTypes::Human. */ PlayerType getPlayerType(std::string name); /** Returns the set of all the PlayerTypes. */ std::set& allPlayerTypes(); void init(); extern const PlayerType None; extern const PlayerType Computer; extern const PlayerType Player; extern const PlayerType RescuePassive; extern const PlayerType EitherPreferComputer; extern const PlayerType EitherPreferHuman; extern const PlayerType Neutral; extern const PlayerType Closed; extern const PlayerType PlayerLeft; extern const PlayerType ComputerLeft; extern const PlayerType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Position.h ================================================ #pragma once namespace BWAPI { class TilePosition; // TODO: Add doxygen documentation class Position { public : Position(); explicit Position(const TilePosition& position); Position(int x, int y); bool operator == (const Position& position) const; bool operator != (const Position& position) const; bool operator < (const Position& position) const; bool isValid() const; Position operator+(const Position& position) const; Position operator-(const Position& position) const; Position& makeValid(); Position& operator+=(const Position& position); Position& operator-=(const Position& position); double getDistance(const Position& position) const; double getApproxDistance(const Position& position) const; double getLength() const; int& x(); int& y(); int x() const; int y() const; private : int _x; int _y; }; namespace Positions { extern const Position Invalid; extern const Position None; extern const Position Unknown; } }; ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Race.h ================================================ #pragma once #include #include namespace BWAPI { class UnitType; class Race { public: Race(); Race(int id); Race(const Race& other); Race& operator=(const Race& other); bool operator==(const Race& other) const; bool operator!=(const Race& other) const; bool operator<(const Race& other) const; /** Returns a unique ID for this race. */ int getID() const; /** Returns the name of the race. For example Races::Terran.getName() will return a std::string object * containing "Terran". */ std::string getName() const; /** Returns the worker unit type for the given race. For example Races::Protoss.getWorker() will return * a pointer to UnitTypes::Protoss_Probe. */ UnitType getWorker() const; /** Returns the center unit type for the given race. For example Races::Terran.getCenter() will return a * pointer to UnitTypes::Terran_Command_Center. While there are three center types for Zerg * (Hatchery, Lair, and Hive), Races::Zerg.getCenter() will only return a pointer to * UnitTypes::Zerg_Hatchery, since it is the unit type needed to make a new center. */ UnitType getCenter() const; /** Returns the refinery unit type for the given race. For example: Races::Zerg.getRefinery() will * return a pointer to UnitTypes::Zerg_Extractor?. */ UnitType getRefinery() const; /** Returns the transport unit type for the given race. For example: Races::Protoss.getTransport() will * return a pointer to UnitTypes::Protoss_Shuttle. */ UnitType getTransport() const; /** Returns the main supply provider unit type for the given race. For example: * Races::Terran.getSupplyProvider() will return a pointer to UnitTypes::Terran_Supply_Depot?. */ UnitType getSupplyProvider() const; private: int id; }; namespace Races { /** Given the name of a race, this function will return the race type. For example: * Races::getRace("Zerg") will return Races::Zerg. */ Race getRace(std::string name); /** Returns the set of all the races, which are listed below. */ std::set& allRaces(); void init(); extern const Race Zerg; extern const Race Terran; extern const Race Protoss; extern const Race Random; extern const Race Other; extern const Race None; extern const Race Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/TechType.h ================================================ #pragma once #include #include #include namespace BWAPI { class UnitType; class WeaponType; class TechType { public: TechType(); TechType(int id); TechType(const TechType& other); TechType& operator=(const TechType& other); bool operator==(const TechType& other) const; bool operator!=(const TechType& other) const; bool operator<(const TechType& other) const; /** Returns the unique ID for this tech type. */ int getID() const; /** Returns the name of the tech type. */ std::string getName() const; /** Returns the race that uses the TechType. For example, TechTypes::Scanner_Sweep?.getRace() will * return Races::Terran. */ Race getRace() const; /** Returns the mineral cost of the tech type. */ int mineralPrice() const; /** Returns the vespene gas price of the tech type. */ int gasPrice() const; /** Returns the number of frames needed to research the tech type. */ int researchTime() const; /** Returns the amount of energy used each time this tech type is used. */ int energyUsed() const; /** Returns the type of unit that researches this tech type. If this tech type is available for free * (does not need to be researched), then this method will return UnitTypes::None. */ UnitType whatResearches() const; /** Returns the corresponding weapon for this tech type, or TechTypes::None if no corresponding weapon * exists. For example, TechTypes::Dark_Swarm.getWeapon() will return a pointer to * WeaponTypes::Dark_Swarm. */ WeaponType getWeapon() const; /** Returns the set of units that can use this tech type. Usually this will just be a set of one unit * type, however in some cases, such as TechTypes::Burrowing, several unit types will be returned. */ const std::set& whatUses() const; private: int id; }; namespace TechTypes { /** Given a string, this will return the tech type. */ TechType getTechType(std::string name); /** Returns the set of all the TechTypes. */ std::set& allTechTypes(); void init(); extern const TechType Stim_Packs; extern const TechType Lockdown; extern const TechType EMP_Shockwave; extern const TechType Spider_Mines; extern const TechType Scanner_Sweep; extern const TechType Tank_Siege_Mode; extern const TechType Defensive_Matrix; extern const TechType Irradiate; extern const TechType Yamato_Gun; extern const TechType Cloaking_Field; extern const TechType Personnel_Cloaking; extern const TechType Burrowing; extern const TechType Infestation; extern const TechType Spawn_Broodlings; extern const TechType Dark_Swarm; extern const TechType Plague; extern const TechType Consume; extern const TechType Ensnare; extern const TechType Parasite; extern const TechType Psionic_Storm; extern const TechType Hallucination; extern const TechType Recall; extern const TechType Stasis_Field; extern const TechType Archon_Warp; extern const TechType Restoration; extern const TechType Disruption_Web; extern const TechType Mind_Control; extern const TechType Dark_Archon_Meld; extern const TechType Feedback; extern const TechType Optical_Flare; extern const TechType Maelstrom; extern const TechType Lurker_Aspect; extern const TechType Healing; extern const TechType None; extern const TechType Unknown; extern const TechType Nuclear_Strike; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/TilePosition.h ================================================ #pragma once namespace BWAPI { class Position; // TODO: Add doxygen documentation class TilePosition { public : TilePosition(); explicit TilePosition(const Position& position); TilePosition(int x, int y); bool operator == (const TilePosition& TilePosition) const; bool operator != (const TilePosition& TilePosition) const; bool operator < (const TilePosition& TilePosition) const; bool isValid() const; TilePosition operator+(const TilePosition& position) const; TilePosition operator-(const TilePosition& position) const; TilePosition& makeValid(); TilePosition& operator+=(const TilePosition& position); TilePosition& operator-=(const TilePosition& position); double getDistance(const TilePosition& position) const; double getLength() const; int& x(); int& y(); int x() const; int y() const; private : int _x; int _y; }; namespace TilePositions { extern const TilePosition Invalid; extern const TilePosition None; extern const TilePosition Unknown; } }; ================================================ FILE: SparCraft/bwapidata/include/BWAPI/Unit.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include namespace BWAPI { class Player; /** The Unit class is used to get information about individual units as well as issue orders to units. Each * unit in the game has a unique Unit object, and Unit objects are not deleted until the end of the match * (so you don't need to worry about unit pointers becoming invalid). * * Every Unit in the game is either accessible or inaccessible. To determine if an AI can access a * particular unit, BWAPI checks to see if Flag::CompleteMapInformation? is enabled. So there are two cases * to consider - either the flag is enabled, or it is disabled: * * If Flag::CompleteMapInformation? is disabled, then a unit is accessible if and only if it is visible. * Note also that some properties of visible enemy units will not be made available to the AI (such as the * contents of visible enemy dropships). If a unit is not visible, Unit::exists will return false, * regardless of whether or not the unit exists. This is because absolutely no state information on * invisible enemy units is made available to the AI. To determine if an enemy unit has been destroyed, the * AI must watch for AIModule::onUnitDestroy messages from BWAPI, which is only called for visible units * which get destroyed. * * If Flag::CompleteMapInformation? is enabled, then all units that exist in the game are accessible, and * Unit::exists is accurate for all units. Similarly AIModule::onUnitDestroy messages are generated for all * units that get destroyed, not just visible ones. * * If a Unit is not accessible, in general the only the getInitial__ functions will be available to the AI. * However for units that were owned by the player, getPlayer and getType will continue to work for units * that have been destroyed. */ class Unit { public: /** Returns a unique ID for this unit. It simply casts the unit's address as an integer, since each unit * has a unique address. */ virtual int getID() const = 0; /** Returns a pointer to the player that owns this unit. */ virtual Player* getPlayer() const = 0; /** Returns the current type of the unit. */ virtual UnitType getType() const = 0; /** Returns the position of the unit on the map. */ virtual Position getPosition() const = 0; /** Returns the build tile position of the unit on the map. Useful if the unit is a building. The tile * position is of the top left corner of the building. */ virtual TilePosition getTilePosition() const = 0; /** Returns the direction the unit is facing, measured in radians. An angle of 0 means the unit is * facing east. */ virtual double getAngle() const = 0; /** Returns the x component of the unit's velocity, measured in pixels per frame. */ virtual double getVelocityX() const = 0; /** Returns the y component of the unit's velocity, measured in pixels per frame. */ virtual double getVelocityY() const = 0; /** Returns the unit's current amount of hit points. */ virtual int getHitPoints() const = 0; /** Returns the unit's current amount of shields. */ virtual int getShields() const = 0; /** Returns the unit's current amount of energy. */ virtual int getEnergy() const = 0; /** Returns the unit's current amount of containing resources. Useful for determining how much minerals * are left in a mineral patch, or how much gas is left in a geyser * (can also be called on a refinery/assimilator/extractor). */ virtual int getResources() const = 0; /** Retrieves the group ID of a resource. Can be used to identify which resources belong to an expansion. */ virtual int getResourceGroup() const = 0; /** Returns the edge-to-edge distance between the current unit and the target unit. */ virtual double getDistance(Unit* target) const = 0; /** Returns the distance from the edge of the current unit to the target position. */ virtual double getDistance(Position target) const = 0; /** Returns true if the unit is able to move to the target unit */ virtual bool hasPath(Unit* target) const = 0; /** Returns true if the unit is able to move to the target position */ virtual bool hasPath(Position target) const = 0; /** Retrieves the frame of the last successful order. Frame is comparable to Game::getFrameCount(). */ virtual int getLastOrderFrame() const = 0; /** Returns the player's current upgrade level for the given upgrade, if the unit is affected by this * upgrade.*/ virtual int getUpgradeLevel(UpgradeType upgrade) const = 0; /** Returns the initial type of the unit or Unknown if it wasn't a neutral unit at the beginning of the * game. */ virtual UnitType getInitialType() const = 0; /** Returns the initial position of the unit on the map, or Positions::Unknown if the unit wasn't a * neutral unit at the beginning of the game. */ virtual Position getInitialPosition() const = 0; /** Returns the initial build tile position of the unit on the map, or TilePositions::Unknown if the * unit wasn't a neutral unit at the beginning of the game. The tile position is of the top left corner * of the building. */ virtual TilePosition getInitialTilePosition() const = 0; /** Returns the unit's initial amount of hit points, or 0 if it wasn't a neutral unit at the beginning * of the game. */ virtual int getInitialHitPoints() const = 0; /** Returns the unit's initial amount of containing resources, or 0 if the unit wasn't a neutral unit * at the beginning of the game. */ virtual int getInitialResources() const = 0; /** Returns the unit's current kill count. */ virtual int getKillCount() const = 0; /** Returns the number of interceptors the Protoss Carrier has. */ virtual int getInterceptorCount() const = 0; /** Returns the number of scarabs in the Protoss Reaver. */ virtual int getScarabCount() const = 0; /** Returns the number of spider mines in the Terran Vulture. */ virtual int getSpiderMineCount() const = 0; /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready to attack. */ virtual int getGroundWeaponCooldown() const = 0; /** Returns unit's air weapon cooldown. It is 0 if the unit is ready to attack. */ virtual int getAirWeaponCooldown() const = 0; /** Returns unit's ground weapon cooldown. It is 0 if the unit is ready cast a spell. */ virtual int getSpellCooldown() const = 0; /** Returns the remaining hit points of the defense matrix. Initially a defense Matrix has 250 points. * \see Unit::getDefenseMatrixTimer, Unit::isDefenseMatrixed. */ virtual int getDefenseMatrixPoints() const = 0; /** Returns the time until the defense matrix wears off. 0 -> No defense Matrix present. */ virtual int getDefenseMatrixTimer() const = 0; /** Returns the time until the ensnare effect wears off. 0 -> No ensnare effect present. */ virtual int getEnsnareTimer() const = 0; /** Returns the time until the radiation wears off. 0 -> No radiation present. */ virtual int getIrradiateTimer() const = 0; /** Returns the time until the lockdown wears off. 0 -> No lockdown present. */ virtual int getLockdownTimer() const = 0; /** Returns the time until the maelstrom wears off. 0 -> No maelstrom present. */ virtual int getMaelstromTimer() const = 0; // TODO: add doc virtual int getOrderTimer() const = 0; /** Returns the time until the plague wears off. 0 -> No plague present. */ virtual int getPlagueTimer() const = 0; /** Returns the amount of time until the unit is removed, or 0 if the unit does not have a remove timer. * Used to determine how much time remains before hallucinated units, dark swarm, etc have until they * are removed. */ virtual int getRemoveTimer() const = 0; /** Returns the time until the stasis field wears off. 0 -> No stasis field present. */ virtual int getStasisTimer() const = 0; /** Returns the time until the stimpack wears off. 0 -> No stimpack boost present. */ virtual int getStimTimer() const = 0; /** Returns the building type a worker is about to construct. If the unit is a morphing Zerg unit or an * incomplete building, this returns the UnitType the unit is about to become upon completion.*/ virtual UnitType getBuildType() const = 0; /** Returns the list of units queued up to be trained. * \see Unit::train, Unit::cancelTrain, Unit::isTraining. */ virtual std::list getTrainingQueue() const = 0; /** Returns the tech that the unit is currently researching. If the unit is not researching anything, * TechTypes::None is returned. * \see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getRemainingResearchTime. */ virtual TechType getTech() const = 0; /** Returns the upgrade that the unit is currently upgrading. If the unit is not upgrading anything, * UpgradeTypes::None is returned. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getRemainingUpgradeTime. */ virtual UpgradeType getUpgrade() const = 0; /** Returns the remaining build time of a unit/building that is being constructed. */ virtual int getRemainingBuildTime() const = 0; /** Returns the remaining time of the unit that is currently being trained. If the unit is a Hatchery, * Lair, or Hive, this returns the amount of time until the next larva spawns, or 0 if the unit already * has 3 larva. */ virtual int getRemainingTrainTime() const = 0; /** Returns the amount of time until the unit is done researching its current tech. If the unit is not * researching anything, 0 is returned. * \see Unit::research, Unit::cancelResearch, Unit::isResearching, Unit::getTech. */ virtual int getRemainingResearchTime() const = 0; /** Returns the amount of time until the unit is done upgrading its current upgrade. If the unit is not * upgrading anything, 0 is returned. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::isUpgrading, Unit::getUpgrade. */ virtual int getRemainingUpgradeTime() const = 0; /** If the unit is an SCV that is constructing a building, this will return the building it is * constructing. If the unit is a Terran building that is being constructed, this will return the SCV * that is constructing it. */ virtual Unit* getBuildUnit() const = 0; /** Generally returns the appropriate target unit after issuing an order that accepts a target unit * (i.e. attack, repair, gather, follow, etc.). To check for a target that has been acquired * automatically (without issuing an order) see getOrderTarget. */ virtual Unit* getTarget() const = 0; /** Returns the target position the unit is moving to (provided a valid path to the target position * exists). */ virtual Position getTargetPosition() const = 0; // TODO: add doc virtual Order getOrder() const = 0; /** This is usually set when the low level unit AI acquires a new target automatically. For example if * an enemy probe comes in range of your marine, the marine will start attacking it, and getOrderTarget * will be set in this case, but not getTarget. */ virtual Unit* getOrderTarget() const = 0; virtual Order getSecondaryOrder() const = 0; /** Returns the position the building is rallied to. If the building does not produce units, * Positions::None is returned. * \see Unit::setRallyPoint, Unit::getRallyUnit. */ virtual Position getRallyPosition() const = 0; /** Returns the unit the building is rallied to. If the building is not rallied to any unit, NULL is * returned. * \see Unit::setRallyPoint, Unit::getRallyPosition. */ virtual Unit* getRallyUnit() const = 0; /** Returns the add-on of this unit, or NULL if the unit doesn't have an add-on. */ virtual Unit* getAddon() const = 0; /** Returns the corresponding connected nydus canal of this unit, or NULL if the unit does not have a * connected nydus canal. */ virtual Unit* getNydusExit() const = 0; /** Returns the power up the unit is holding, or NULL if the unit is not holding a power up */ virtual Unit* getPowerUp() const = 0; /** Returns the dropship, shuttle, overlord, or bunker that is this unit is loaded in to. */ virtual Unit* getTransport() const = 0; /** Returns a list of the units loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg * Overlord. */ virtual std::set getLoadedUnits() const = 0; /** For Protoss Interceptors, this returns the Carrier unit this Interceptor is controlled by. For all * other unit types this function returns NULL. */ virtual Unit* getCarrier() const = 0; /** Returns the set of interceptors controlled by this unit. If the unit has no interceptors, or is not * a Carrier, this function returns an empty set. */ virtual std::set getInterceptors() const = 0; /** For Zerg Larva, this returns the Hatchery, Lair, or Hive unit this Larva was spawned from. For all * other unit types this function returns NULL. */ virtual Unit* getHatchery() const = 0; /** Returns the set of larva spawned by this unit. If the unit has no larva, or is not a Hatchery, Lair, * or Hive, this function returns an empty set. Equivalent to clicking "Select Larva" from the Starcraft * GUI. */ virtual std::set getLarva() const = 0; /** * 3 cases to consider: * * - If exists() returns true, the unit exists. * - If exists() returns false and the unit is owned by self(), then the unit does not exist. * - If exists() returns false and the unit is not owned by self(), then the unit may or may not exist. * * \see Unit::isVisible. * */ virtual bool exists() const = 0; /* Returns true if the Nuclear Missile Silo has a nuke */ virtual bool hasNuke() const = 0; /** Returns true if the unit is currently accelerating. */ virtual bool isAccelerating() const = 0; // TODO: add doc virtual bool isAttacking() const = 0; /** Returns true if the unit is being constructed. Always true for incomplete Protoss and Zerg * buildings, and true for incomplete Terran buildings that have an SCV constructing them. If the SCV * halts construction, isBeingConstructed will return false. * * \see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isConstructing. */ virtual bool isBeingConstructed() const = 0; /** Returns true if the unit is a mineral patch or refinery that is being gathered. */ virtual bool isBeingGathered() const = 0; /** Returns true if the unit is currently being healed by a Terran Medic, or repaired by a Terran SCV. */ virtual bool isBeingHealed() const = 0; /** Returns true if the unit is currently blind from a Medic's Optical Flare. */ virtual bool isBlind() const = 0; /** Returns true if the unit is currently braking/slowing down. */ virtual bool isBraking() const = 0; /** Returns true if the unit is a Zerg unit that is current burrowed. * \see Unit::burrow, Unit::unburrow. */ virtual bool isBurrowed() const = 0; /** Returns true if the unit is a worker that is carrying gas. * \see Unit::returnCargo, Unit::isGatheringGas. */ virtual bool isCarryingGas() const = 0; /** Returns true if the unit is a worker that is carrying minerals. * \see Unit::returnCargo, Unit::isGatheringMinerals. */ virtual bool isCarryingMinerals() const = 0; /** Returns true if the unit is cloaked. * \see Unit::cloak, Unit::decloak. */ virtual bool isCloaked() const = 0; /** Returns true if the unit has been completed. */ virtual bool isCompleted() const = 0; /** Returns true when a unit has been issued an order to build a structure and is moving to the build * location. Also returns true for Terran SCVs while they construct a building. * \see Unit::build, Unit::cancelConstruction, Unit::haltConstruction, Unit::isBeingConstructed. */ virtual bool isConstructing() const = 0; /** Returns true if the unit has a defense matrix from a Terran Science Vessel. */ virtual bool isDefenseMatrixed() const = 0; /** Returns true if the unit is detected. */ virtual bool isDetected() const = 0; /** Returns true if the unit has been ensnared by a Zerg Queen. */ virtual bool isEnsnared() const = 0; /** Returns true if the unit is following another unit. * \see Unit::follow, Unit::getTarget. */ virtual bool isFollowing() const = 0; /** Returns true if the unit is in one of the four states for gathering gas (MoveToGas, WaitForGas, * HarvestGas, ReturnGas). * \see Unit::isCarryingGas. */ virtual bool isGatheringGas() const = 0; /** Returns true if the unit is in one of the four states for gathering minerals (MoveToMinerals, * WaitForMinerals, MiningMinerals, ReturnMinerals). * \see Unit::isCarryingMinerals. */ virtual bool isGatheringMinerals() const = 0; /** Returns true for hallucinated units, false for normal units. Returns true for hallucinated enemy * units only if Complete Map Information is enabled. * \see Unit::getRemoveTimer. */ virtual bool isHallucination() const = 0; /** Returns true if the unit is holding position * \see Unit::holdPosition. */ virtual bool isHoldingPosition() const = 0; /** Returns true if the unit is not doing anything. * \see Unit::stop. */ virtual bool isIdle() const = 0; /** Returns true if the unit can be interrupted. */ virtual bool isInterruptible() const = 0; /** Returns true if the unit is being irradiated by a Terran Science Vessel. * \see Unit::getIrradiateTimer. */ virtual bool isIrradiated() const = 0; /** Returns true if the unit is a Terran building that is currently lifted off the ground. * \see Unit::lift,Unit::land. */ virtual bool isLifted() const = 0; /** Return true if the unit is loaded into a Terran Bunker, Terran Dropship, Protoss Shuttle, or Zerg * Overlord. * \see Unit::load, Unit::unload, Unit::unloadAll. */ virtual bool isLoaded() const = 0; /** Returns true if the unit is locked down by a Terran Ghost. * \see Unit::getLockdownTimer. */ virtual bool isLockedDown() const = 0; /** Returns true if the unit is being maelstrommed. * \see Unit::getMaelstromTimer. */ virtual bool isMaelstrommed() const = 0; /** Returns true if the unit is a zerg unit that is morphing. * \see Unit::morph, Unit::cancelMorph, Unit::getBuildType, Unit::getRemainingBuildTime. */ virtual bool isMorphing() const = 0; /** Returns true if the unit is moving. * \see Unit::attackMove, Unit::stop. */ virtual bool isMoving() const = 0; /** Returns true if the unit has been parasited by some other player. */ virtual bool isParasited() const = 0; /** Returns true if the unit is patrolling between two positions. * \see Unit::patrol. */ virtual bool isPatrolling() const = 0; /** Returns true if the unit has been plagued by a Zerg Defiler. * \see Unit::getPlagueTimer. */ virtual bool isPlagued() const = 0; /** Returns true if the unit is a Terran SCV that is repairing or moving to repair another unit. */ virtual bool isRepairing() const = 0; /** Returns true if the unit is a building that is researching tech. See TechTypes for the complete list * of available techs in Broodwar. * \see Unit::research, Unit::cancelResearch, Unit::getTech, Unit::getRemainingResearchTime. */ virtual bool isResearching() const = 0; /** Returns true if the unit has been selected by the user via the starcraft GUI. Only available if you * enable Flag::UserInput during AIModule::onStart. * \see Game::getSelectedUnits. */ virtual bool isSelected() const = 0; /** Returns true if the unit is a Terran Siege Tank that is currently in Siege mode. * \see Unit::siege, Unit::unsiege. */ virtual bool isSieged() const = 0; /** Returns true if the unit is starting to attack. * \see Unit::attackUnit, Unit::getGroundWeaponCooldown, Unit::getAirWeaponCooldown. */ virtual bool isStartingAttack() const = 0; /** Returns true if the unit has been stasised by a Protoss Arbiter. * \see Unit::getStasisTimer. */ virtual bool isStasised() const = 0; /** Returns true if the unit is currently stimmed. * \see Unit::getStimTimer. */ virtual bool isStimmed() const = 0; /** Returns true if the unit is being pushed off of another unit */ virtual bool isStuck() const = 0; /** Returns true if the unit is training units (i.e. a Barracks training Marines). * \see Unit::train, Unit::getTrainingQueue, Unit::cancelTrain, Unit::getRemainingTrainTime. */ virtual bool isTraining() const = 0; /** Returns true if the unit is under a Protoss Psionic Storm. */ virtual bool isUnderStorm() const = 0; /** Returns true if the unit is a Protoss building that is unpowered because no pylons are in range. */ virtual bool isUnpowered() const = 0; /** Returns true if the unit is a building that is upgrading. See UpgradeTypes for the complete list * of available upgrades in Broodwar. * \see Unit::upgrade, Unit::cancelUpgrade, Unit::getUpgrade, Unit::getRemainingUpgradeTime. */ virtual bool isUpgrading() const = 0; /** Returns true if the unit is visible. If the CompleteMapInformation? cheat flag is enabled, existing * units hidden by the fog of war will be accessible, but isVisible will still return false. * \see Unit::exists. */ virtual bool isVisible() const = 0; virtual bool isVisible(Player* player) const = 0; /** Takes any unit command and calls the corresponding order that will execute it */ virtual bool issueCommand(UnitCommand command) = 0; /** Orders the unit to attack move to the specified location. */ virtual bool attackMove(Position target) = 0; /** Orders the unit to attack the specified unit. */ virtual bool attackUnit(Unit* target) = 0; /** Orders the unit to build the given unit type at the given position. Note that if the player does not * have enough resources when the unit attempts to place the building down, the order will fail. The * tile position specifies where the top left corner of the building will be placed. */ virtual bool build(TilePosition target, UnitType type) = 0; /** Orders the unit to build the given addon. The unit must be a Terran building that can have an addon * and the specified unit type must be an addon unit type. */ virtual bool buildAddon(UnitType type) = 0; /** Orders this unit to add the specified unit type to the training queue. Note that the player must * have sufficient resources to train. If you wish to make units from a hatchery, use getLarva to get * the larva associated with the hatchery and then call morph on the larva you want to morph. This * command can also be used to make interceptors and scarabs. */ virtual bool train(UnitType type) = 0; /** Orders the unit to morph into the specified unit type. Returns false if given a wrong type. * \see Unit::cancelMorph, Unit::isMorphing. */ virtual bool morph(UnitType type) = 0; /** Orders the unit to research the given tech type. * \see Unit::cancelResearch, Unit::Unit#isResearching, Unit::getRemainingResearchTime, Unit::getTech. */ virtual bool research(TechType tech) = 0; /** Orders the unit to upgrade the given upgrade type. * \see Unit::cancelUpgrade, Unit::Unit#isUpgrading, Unit::getRemainingUpgradeTime, Unit::getUpgrade. */ virtual bool upgrade(UpgradeType upgrade) = 0; /** Orders the unit to set its rally position to the specified position. * \see Unit::getRallyPosition, Unit::getRallyUnit. */ virtual bool setRallyPoint(Position target) = 0; /** Orders the unit to set its rally unit to the specified unit. * \see Unit::setRallyPosition, Unit::getRallyPosition, Unit::getRallyUnit. */ virtual bool setRallyPoint(Unit* target) = 0; /** Orders the unit to move from its current position to the specified position. * \see Unit::isMoving. */ virtual bool move(Position target) = 0; /** Orders the unit to patrol between its current position and the specified position. * \see Unit::isPatrolling. */ virtual bool patrol(Position target) = 0; /** Orders the unit to hold its position.*/ virtual bool holdPosition() = 0; /** Orders the unit to stop. */ virtual bool stop() = 0; /** Orders the unit to follow the specified unit. * \see Unit::isFollowing. */ virtual bool follow(Unit* target) = 0; /** Orders the unit to gather the specified unit (must be mineral or refinery type). * \see Unit::isGatheringGas, Unit::isGatheringMinerals. */ virtual bool gather(Unit* target) = 0; /** Orders the unit to return its cargo to a nearby resource depot such as a Command Center. Only * workers that are carrying minerals or gas can be ordered to return cargo. * \see Unit::isCarryingGas, Unit::isCarryingMinerals. */ virtual bool returnCargo() = 0; /** Orders the unit to repair the specified unit. Only Terran SCVs can be ordered to repair, and the * target must be a mechanical Terran unit or building. * \see Unit::isRepairing. */ virtual bool repair(Unit* target) = 0; /** Orders the unit to burrow. Either the unit must be a Zerg Lurker, or the unit must be a Zerg ground * unit and burrow tech must be researched. * \see: Unit::unburrow, Unit::isBurrowed. */ virtual bool burrow() = 0; /** Orders the burrowed unit to unburrow. * \see: Unit::burrow, Unit::isBurrowed. * */ virtual bool unburrow() = 0; /** Orders the unit to cloak. * \see: Unit::decloak, Unit::isCloaked. */ virtual bool cloak() = 0; /** Orders the unit to decloak. * \see: Unit::cloak, Unit::isCloaked. */ virtual bool decloak() = 0; /** Orders the unit to siege. Note: unit must be a Terran siege tank. * \see Unit::unsiege, Unit::isSieged. */ virtual bool siege() = 0; /** Orders the unit to unsiege. Note: unit must be a Terran siege tank. * \see: Unit::unsiege, Unit::isSieged. */ virtual bool unsiege() = 0; /** Orders the unit to lift. Note: unit must be a Terran building that can be lifted. * \see Unit::land, Unit::isLifted. */ virtual bool lift() = 0; /** Orders the unit to land. Note: unit must be a Terran building that is currently lifted. * \see Unit::lift, Unit::isLifted. */ virtual bool land(TilePosition target) = 0; /** Orders the unit to load the target unit. * \see Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool load(Unit* target) = 0; /** Orders the unit to unload the target unit. * \see Unit::load, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unload(Unit* target) = 0; /** Orders the unit to unload all loaded units at the unit's current position. * \see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unloadAll() = 0; /** Orders the unit to unload all loaded units at the specified location. Unit should be a Terran * Dropship, Protoss Shuttle, or Zerg Overlord. If the unit is a Terran Bunker, the units will be * unloaded right outside the bunker, like in the first version of unloadAll. * \see Unit::load, Unit::unload, Unit::unloadAll, Unit::getLoadedUnits, Unit:isLoaded. */ virtual bool unloadAll(Position target) = 0; /** Works like the right click in the GUI. */ virtual bool rightClick(Position target) = 0; /** Works like the right click in the GUI. Right click on a mineral patch to order a worker to mine, * right click on an enemy to attack it. */ virtual bool rightClick(Unit* target) = 0; /** Orders the SCV to stop constructing the building, and the building is left in a partially complete * state until it is canceled, destroyed, or completed. * \see Unit::isConstructing. */ virtual bool haltConstruction() = 0; /** Orders the building to stop being constructed. * \see Unit::beingConstructed. */ virtual bool cancelConstruction() = 0; /** Orders the unit to stop making the addon. */ virtual bool cancelAddon() = 0; /** Orders the unit to remove the specified unit from its training queue. * \see Unit::train, Unit::cancelTrain, Unit::isTraining, Unit::getTrainingQueue. */ virtual bool cancelTrain(int slot = -2) = 0; /** Orders the unit to stop morphing. * \see Unit::morph, Unit::isMorphing. */ virtual bool cancelMorph() = 0; /** Orders the unit to cancel a research in progress. * \see Unit::research, Unit::isResearching, Unit::getTech. */ virtual bool cancelResearch() = 0; /** Orders the unit to cancel an upgrade in progress. * \see Unit::upgrade, Unit::isUpgrading, Unit::getUpgrade. */ virtual bool cancelUpgrade() = 0; /** Orders the unit to use a tech not requiring a target (ie Stim Pack). Returns true if it is a valid * tech. */ virtual bool useTech(TechType tech) = 0; /** Orders the unit to use a tech requiring a position target (ie Dark Swarm). Returns true if it is a * valid tech.*/ virtual bool useTech(TechType tech, Position target) = 0; /** Orders the unit to use a tech requiring a unit target (ie Irradiate). Returns true if it is a valid * tech.*/ virtual bool useTech(TechType tech, Unit* target) = 0; /** Sets the unit's custom client info. The client is responsible for deallocation. */ virtual void setClientInfo(void* clientinfo) = 0; /** Returns the unit's custom client info. The client is responsible for deallocation. */ virtual void* getClientInfo() const = 0; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/UnitCommand.h ================================================ #pragma once #include #include #include #include #include #include namespace BWAPI { class Unit; class UnitCommand { public: UnitCommand() : target(NULL), x(0), y(0), extra(0) { type = UnitCommandTypes::None; } UnitCommand(Unit* source, UnitCommandType _type, Unit* _target, int _x, int _y, int _extra) : unit(source), type(_type), target(_target), x(_x), y(_y), extra(_extra) {} static UnitCommand attackMove(Unit* unit, Position target); static UnitCommand attackUnit(Unit* unit, Unit* target); static UnitCommand build(Unit* unit, TilePosition target, UnitType type); static UnitCommand buildAddon(Unit* unit, UnitType type); static UnitCommand train(Unit* unit, UnitType type); static UnitCommand morph(Unit* unit, UnitType type); static UnitCommand research(Unit* unit, TechType tech); static UnitCommand upgrade(Unit* unit, UpgradeType upgrade); static UnitCommand setRallyPosition(Unit* unit, Position target); static UnitCommand setRallyUnit(Unit* unit, Unit* target); static UnitCommand move(Unit* unit, Position target); static UnitCommand patrol(Unit* unit, Position target); static UnitCommand holdPosition(Unit* unit); static UnitCommand stop(Unit* unit); static UnitCommand follow(Unit* unit, Unit* target); static UnitCommand gather(Unit* unit, Unit* target); static UnitCommand returnCargo(Unit* unit); static UnitCommand repair(Unit* unit, Unit* target); static UnitCommand burrow(Unit* unit); static UnitCommand unburrow(Unit* unit); static UnitCommand cloak(Unit* unit); static UnitCommand decloak(Unit* unit); static UnitCommand siege(Unit* unit); static UnitCommand unsiege(Unit* unit); static UnitCommand lift(Unit* unit); static UnitCommand land(Unit* unit, TilePosition target); static UnitCommand load(Unit* unit, Unit* target); static UnitCommand unload(Unit* unit, Unit* target); static UnitCommand unloadAll(Unit* unit); static UnitCommand unloadAll(Unit* unit, Position target); static UnitCommand rightClick(Unit* unit, Position target); static UnitCommand rightClick(Unit* unit, Unit* target); static UnitCommand haltConstruction(Unit* unit); static UnitCommand cancelConstruction(Unit* unit); static UnitCommand cancelAddon(Unit* unit); static UnitCommand cancelTrain(Unit* unit, int slot = -2); static UnitCommand cancelMorph(Unit* unit); static UnitCommand cancelResearch(Unit* unit); static UnitCommand cancelUpgrade(Unit* unit); static UnitCommand useTech(Unit* unit,TechType tech); static UnitCommand useTech(Unit* unit,TechType tech, Position target); static UnitCommand useTech(Unit* unit,TechType tech, Unit* target); Unit* unit; UnitCommandType type; Unit* target; int x; int y; int extra; }; } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/UnitCommandType.h ================================================ #pragma once #include #include namespace BWAPI { class UnitCommandType { public: UnitCommandType(); UnitCommandType(int id); UnitCommandType(const UnitCommandType& other); UnitCommandType& operator=(const UnitCommandType& other); bool operator==(const UnitCommandType& other) const; bool operator!=(const UnitCommandType& other) const; bool operator<(const UnitCommandType& other) const; /** Returns a unique ID for this UnitCommandType. */ int getID() const; /** Returns the string corresponding to the UnitCommandType object. For example, * UnitCommandTypes::Set_Rally_Position.getName() returns std::string("Set Rally Position")*/ std::string getName() const; private: int id; }; namespace UnitCommandTypes { /** Given a string, this function returns the command type it refers to. For example, * UnitCommandTypes::getUnitCommandType("Attack Position") returns UnitCommandTypes::Attack_Position. */ UnitCommandType getUnitCommandType(std::string name); /** Returns the set of all the sizes, which are listed below: */ std::set& allUnitCommandTypes(); void init(); extern const UnitCommandType Attack_Move; extern const UnitCommandType Attack_Unit; extern const UnitCommandType Build; extern const UnitCommandType Build_Addon; extern const UnitCommandType Train; extern const UnitCommandType Morph; extern const UnitCommandType Research; extern const UnitCommandType Upgrade; extern const UnitCommandType Set_Rally_Position; extern const UnitCommandType Set_Rally_Unit; extern const UnitCommandType Move; extern const UnitCommandType Patrol; extern const UnitCommandType Hold_Position; extern const UnitCommandType Stop; extern const UnitCommandType Follow; extern const UnitCommandType Gather; extern const UnitCommandType Return_Cargo; extern const UnitCommandType Repair; extern const UnitCommandType Burrow; extern const UnitCommandType Unburrow; extern const UnitCommandType Cloak; extern const UnitCommandType Decloak; extern const UnitCommandType Siege; extern const UnitCommandType Unsiege; extern const UnitCommandType Lift; extern const UnitCommandType Land; extern const UnitCommandType Load; extern const UnitCommandType Unload; extern const UnitCommandType Unload_All; extern const UnitCommandType Unload_All_Position; extern const UnitCommandType Right_Click_Position; extern const UnitCommandType Right_Click_Unit; extern const UnitCommandType Halt_Construction; extern const UnitCommandType Cancel_Construction; extern const UnitCommandType Cancel_Addon; extern const UnitCommandType Cancel_Train; extern const UnitCommandType Cancel_Train_Slot; extern const UnitCommandType Cancel_Morph; extern const UnitCommandType Cancel_Research; extern const UnitCommandType Cancel_Upgrade; extern const UnitCommandType Use_Tech; extern const UnitCommandType Use_Tech_Position; extern const UnitCommandType Use_Tech_Unit; extern const UnitCommandType None; extern const UnitCommandType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/UnitSizeType.h ================================================ #pragma once #include #include namespace BWAPI { class UnitSizeType { public: UnitSizeType(); UnitSizeType(int id); UnitSizeType(const UnitSizeType& other); UnitSizeType& operator=(const UnitSizeType& other); bool operator==(const UnitSizeType& other) const; bool operator!=(const UnitSizeType& other) const; bool operator<(const UnitSizeType& other) const; /** Returns a unique ID for this UnitSizeType. */ int getID() const; /** Returns the string corresponding to the UnitSizeType object. For example, * UnitSizeTypes::Medium.getName() returns std::string("Medium")*/ std::string getName() const; private: int id; }; namespace UnitSizeTypes { /** Given a string, this function returns the size type it refers to. For example, * UnitSizeTypes::getUnitSizeType("Small") returns UnitSizeTypes::Small. */ UnitSizeType getUnitSizeType(std::string name); /** Returns the set of all the sizes, which are listed below: */ std::set& allUnitSizeTypes(); void init(); extern const UnitSizeType Independent; extern const UnitSizeType Small; extern const UnitSizeType Medium; extern const UnitSizeType Large; extern const UnitSizeType None; extern const UnitSizeType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/UnitType.h ================================================ #pragma once #include #include #include #include #include namespace BWAPI { class TechType; class UpgradeType; class WeaponType; /** The UnitType class is used to get information about a particular type of unit, such as the build time * of a Lurker, or the mineral price of an Ultralisk. TODO Add the unittype table from the wiki*/ class UnitType { public: UnitType(); UnitType(int id); UnitType(const UnitType& other); UnitType& operator=(const UnitType& other); bool operator==(const UnitType& other) const; bool operator!=(const UnitType& other) const; bool operator<(const UnitType& other) const; /** Returns a unique ID for this unit type. */ int getID() const; /** Returns the name of the unit. */ std::string getName() const; /** Returns the race that the unit belongs to. For example UnitTypes::Terran_SCV.getRace() will return * Races::Terran. */ Race getRace() const; /** Returns what builds this unit type. The second number will usually be 1 unless the unit type is * Protoss_Archon or Protoss_Dark_Archon. Units that cannot be created, such as critters and mineral * fields, will return a pair where the unit type is UnitTypes::None, and the second component is 0. * * Example: UnitTypes::Terran_Marine.whatBuilds() will return an std::pair, where the first component * is UnitTypes::Terran_Barracks. */ const std::pair< UnitType, int > whatBuilds() const; /** Returns the units the player is required to have before it can train or build the given unit type. * * Example: UnitTypes::Terran_Battlecruiser.requiredUnits() will return a map of three keys: * UnitTypes::Terran_Starport, UnitTypes::Terran_Control_Tower, and UnitTypes::Terran_Physics_Lab. */ const std::map< UnitType, int >& requiredUnits() const; /** Included in the API for completeness, since the only units that actually needs tech to be trained * are the Zerg_Lurker and Zerg_Lurker_Egg. The tech type needed is TechTypes::Lurker_Aspect. */ TechType requiredTech() const; /** Returns the tech used to cloak the unit, or TechTypes::None if the unit cannot cloak or is permanently cloaked */ TechType cloakingTech() const; /** Returns the set of tech types this unit can use, provided the tech types have been researched and * the unit has enough energy. */ const std::set< TechType >& abilities() const; /** Returns the set of upgrade types that can affect this unit. */ const std::set< UpgradeType >& upgrades() const; /** Returns the upgrade that increase's the unit's armor, or UpgradeTypes::None if no upgrade * increase's this unit's armor. For example UnitTypes::Terran_Marine.armorUpgrade() will return a * pointer to UpgradeTypes::Terran_Infantry_Armor. */ UpgradeType armorUpgrade() const; /** Returns the maximum amount of hit points the unit type can have. */ int maxHitPoints() const; /** Returns the maximum amount of shields the unit type can have. */ int maxShields() const; /** Returns the maximum amount of energy the unit type can have. */ int maxEnergy() const; /** Returns the amount of armor the non-upgraded unit type has. */ int armor() const; /** Returns the mineral price of the unit. * * Example: UnitTypes::Siege_Tank_Tank_Mode.mineralPrice() returns 150. */ int mineralPrice() const; /** UnitTypes::Siege_Tank_Tank_Mode.gasPrice() returns 100. */ int gasPrice() const; /** Returns the number of frames needed to make this unit type. */ int buildTime() const; /** Returns the amount of supply used by this unit. Supply counts returned by BWAPI are double what you * would expect to see from playing the game. This is because zerglings take up 0.5 in-game supply. */ int supplyRequired() const; /** Returns the amount of supply produced by this unit (i.e. for a Protoss_Pylon). Supply counts * returned by BWAPI are double what you would expect to see from playing the game. This is because * zerglings take up 0.5 in-game supply. */ int supplyProvided() const; /** Returns the amount of space this unit type takes up inside a bunker or transport unit. */ int spaceRequired() const; /** Returns the amount of space this unit type provides. */ int spaceProvided() const; /** Returns the score which is used to determine the total scores in the after-game stats screen. */ int buildScore() const; /** Returns the score which is used to determine the total scores in the after-game stats screen. */ int destroyScore() const; /** Returns the size of the unit - either Small, Medium, Large, or Independent. */ UnitSizeType size() const; /** Returns the tile width of the unit. Useful for determining the size of buildings. For example * UnitTypes::Terran_Supply_Depot.tileWidth() will return 3. */ int tileWidth() const; /** Returns the tile height of the unit. Useful for determining the size of buildings. For example * UnitTypes::Terran_Supply_Depot.tileHeight() will return 2. */ int tileHeight() const; /** Distance from the center of the unit to the left edge of the unit, measured in pixels. */ int dimensionLeft() const; /** Distance from the center of the unit to the top edge of the unit, measured in pixels. */ int dimensionUp() const; /** Distance from the center of the unit to the right edge of the unit, measured in pixels. */ int dimensionRight() const; /** Distance from the center of the unit to the bottom edge of the unit, measured in pixels. */ int dimensionDown() const; /** Returns the range at which the unit will start targeting enemy units, measured in pixels. */ int seekRange() const; /** Returns how far the un-upgraded unit type can see into the fog of war, measured in pixels. */ int sightRange() const; /** Returns the unit's ground weapon. */ WeaponType groundWeapon() const; // TODO: add doc int maxGroundHits() const; /** Returns the unit's air weapon. */ WeaponType airWeapon() const; // TODO: add doc int maxAirHits() const; /** Returns the unit's non-upgraded top speed in pixels per frame. For Terran buildings that can lift * off and the Zerg Infested Command Center, this returns how fast the building moves when it is * lifted. */ double topSpeed() const; /** Returns how fast the unit can accelerate to its top speed. What units this quantity is measured in * is currently unknown. */ int acceleration() const; /** Related to how fast the unit can halt. What units this quantity is measured in is currently * unknown. */ int haltDistance() const; /** Related to how fast the unit can turn. What units this quantity is measured in is currently * unknown. */ int turnRadius() const; /** Returns true if the unit can train other units. For example, UnitTypes::Terran_Barracks.canProduce() * will return true, while UnitTypes::Terran_Marine?.canProduce() will return false. This is also true * for two non-building units: Protoss Carrier (can produce interceptors) and Protoss Reaver * (can produce scarabs). */ bool canProduce() const; /** Returns true if the unit can attack (either ground or air). Returns false for units that can only * inflict damage via special abilities (such as Protoss High Templar). */ bool canAttack() const; /** Returns true if the unit can move. Note that buildings will return false, even Terran buildings * which can move once lifted. */ bool canMove() const; /** Returns true for flying/air units. */ bool isFlyer() const; /** Returns true for units that regenerate health (i.e. zerg units). */ bool regeneratesHP() const; /** Returns true if the unit type is capable of casting spells / using technology. */ bool isSpellcaster() const; /** Returns true for the two units that are permanently cloaked - Protoss Observer and Protoss Dark * Templar. */ bool hasPermanentCloak() const; /** Returns true for units that cannot be destroyed (i.e. Terran Nuclear Missile, Mineral Field, * Vespene Geyser, etc) */ bool isInvincible() const; /** Returns true if the unit is organic, such as a Terran Marine. */ bool isOrganic() const; /** Returns true if the unit is mechanical such as a Terran Vulture. */ bool isMechanical() const; /** Returns true for the four robotic Protoss units - Probe, Shuttle, Reaver, and Observer. */ bool isRobotic() const; /** Returns true for the seven units that can detect cloaked units - Terran Science Vessel, Spell * Scanner Sweep, Zerg Overlord, Protoss Observer, Terran Missile Turret, Zerg Spore Colony, and Protoss * Photon Cannon. */ bool isDetector() const; /** Returns true for the five units that hold resources - Mineral Field, Vespene Geyser, * Terran Refinery, Zerg Extractor, and Protoss Assimilator. */ bool isResourceContainer() const; /** Returns true for the five units that can accept resources - Terran Command Center, Protoss Nexus, * Zerg Hatchery, Zerg Lair, and Zerg Hive. */ bool isResourceDepot() const; /** Returns true for Terran Refinery, Zerg Extractor, and Protoss Assimilator. */ bool isRefinery() const; /** Returns true for Protoss Probe, Terran SCV, and Zerg Drone. */ bool isWorker() const; /** Returns true for buildings that must be near a pylon to be constructed. */ bool requiresPsi() const; /** Returns true for buildings that can only be built on zerg creep. */ bool requiresCreep() const; /** Returns true for Zergling and Scourge. */ bool isTwoUnitsInOneEgg() const; /** Returns true for Zerg Lurker and units that can burrow when burrow tech is researched. */ bool isBurrowable() const; /** Returns true for units that can be cloaked - Terran Ghost and Terran Wraith. Does not include units * which have permanent cloak (Protoss Observer and Protoss Dark Templar). */ bool isCloakable() const; /** Returns true if the unit is a building (also true for mineral field and vespene geyser). */ bool isBuilding() const; /** Returns true if the unit is an add-on, such as a Terran Comsat Station. */ bool isAddon() const; /** Returns true for Terran buildings that can lift off (i.e. Barracks). */ bool isFlyingBuilding() const; /** Returns true if the unit is neutral, such as a critter or mineral field. */ bool isNeutral() const; /** Returns true if the unit is a Hero unit. */ bool isHero() const; /** Returns true if the unit is a Powerup unit. */ bool isPowerup() const; /** Returns true if the unit is a regular Beacon. */ bool isBeacon() const; /** Returns true if the unit is a flag Beacon. */ bool isFlagBeacon() const; /** Returns true if the unit is a special building. */ bool isSpecialBuilding() const; /** Returns true if the unit is a spell unit. */ bool isSpell() const; /** Returns true if the unit produces larva. */ bool producesLarva() const; private: int id; }; namespace UnitTypes { /** Given the name of a unit type, this function will return the unit type. * For example, UnitTypes::getUnitType("Terran Marine") will return UnitTypes::Terran_Marine. */ UnitType getUnitType(std::string name); /** Returns the set of all the UnitTypes. */ std::set& allUnitTypes(); void init(); extern const UnitType Terran_Marine; extern const UnitType Hero_Jim_Raynor_Marine; extern const UnitType Terran_Ghost; extern const UnitType Hero_Sarah_Kerrigan; extern const UnitType Hero_Samir_Duran; extern const UnitType Hero_Infested_Duran; extern const UnitType Hero_Alexei_Stukov; extern const UnitType Terran_Vulture; extern const UnitType Hero_Jim_Raynor_Vulture; extern const UnitType Terran_Goliath; extern const UnitType Hero_Alan_Schezar; extern const UnitType Terran_Siege_Tank_Tank_Mode; extern const UnitType Hero_Edmund_Duke_Tank_Mode; extern const UnitType Terran_SCV; extern const UnitType Terran_Wraith; extern const UnitType Hero_Tom_Kazansky; extern const UnitType Terran_Science_Vessel; extern const UnitType Hero_Magellan; extern const UnitType Terran_Dropship; extern const UnitType Terran_Battlecruiser; extern const UnitType Hero_Arcturus_Mengsk; extern const UnitType Hero_Hyperion; extern const UnitType Hero_Norad_II; extern const UnitType Hero_Gerard_DuGalle; extern const UnitType Terran_Vulture_Spider_Mine; extern const UnitType Terran_Nuclear_Missile; extern const UnitType Terran_Siege_Tank_Siege_Mode; extern const UnitType Hero_Edmund_Duke_Siege_Mode; extern const UnitType Terran_Firebat; extern const UnitType Hero_Gui_Montag; extern const UnitType Spell_Scanner_Sweep; extern const UnitType Terran_Medic; extern const UnitType Terran_Civilian; extern const UnitType Zerg_Larva; extern const UnitType Zerg_Egg; extern const UnitType Zerg_Zergling; extern const UnitType Hero_Devouring_One; extern const UnitType Hero_Infested_Kerrigan; extern const UnitType Zerg_Hydralisk; extern const UnitType Hero_Hunter_Killer; extern const UnitType Zerg_Ultralisk; extern const UnitType Hero_Torrasque; extern const UnitType Zerg_Broodling; extern const UnitType Zerg_Drone; extern const UnitType Zerg_Overlord; extern const UnitType Hero_Yggdrasill; extern const UnitType Zerg_Mutalisk; extern const UnitType Hero_Kukulza_Mutalisk; extern const UnitType Zerg_Guardian; extern const UnitType Hero_Kukulza_Guardian; extern const UnitType Zerg_Queen; extern const UnitType Hero_Matriarch; extern const UnitType Zerg_Defiler; extern const UnitType Hero_Unclean_One; extern const UnitType Zerg_Scourge; extern const UnitType Zerg_Infested_Terran; extern const UnitType Terran_Valkyrie; extern const UnitType Zerg_Cocoon; extern const UnitType Protoss_Corsair; extern const UnitType Hero_Raszagal; extern const UnitType Protoss_Dark_Templar; extern const UnitType Hero_Dark_Templar; extern const UnitType Hero_Zeratul; extern const UnitType Zerg_Devourer; extern const UnitType Protoss_Dark_Archon; extern const UnitType Protoss_Probe; extern const UnitType Protoss_Zealot; extern const UnitType Hero_Fenix_Zealot; extern const UnitType Protoss_Dragoon; extern const UnitType Hero_Fenix_Dragoon; extern const UnitType Protoss_High_Templar; extern const UnitType Hero_Tassadar; extern const UnitType Hero_Aldaris; extern const UnitType Protoss_Archon; extern const UnitType Hero_Tassadar_Zeratul_Archon; extern const UnitType Protoss_Shuttle; extern const UnitType Protoss_Scout; extern const UnitType Hero_Mojo; extern const UnitType Hero_Artanis; extern const UnitType Protoss_Arbiter; extern const UnitType Hero_Danimoth; extern const UnitType Protoss_Carrier; extern const UnitType Hero_Gantrithor; extern const UnitType Protoss_Interceptor; extern const UnitType Protoss_Reaver; extern const UnitType Hero_Warbringer; extern const UnitType Protoss_Observer; extern const UnitType Protoss_Scarab; extern const UnitType Critter_Rhynadon; extern const UnitType Critter_Bengalaas; extern const UnitType Critter_Scantid; extern const UnitType Critter_Kakaru; extern const UnitType Critter_Ragnasaur; extern const UnitType Critter_Ursadon; extern const UnitType Zerg_Lurker_Egg; extern const UnitType Zerg_Lurker; extern const UnitType Spell_Disruption_Web; extern const UnitType Terran_Command_Center; extern const UnitType Terran_Comsat_Station; extern const UnitType Terran_Nuclear_Silo; extern const UnitType Terran_Supply_Depot; extern const UnitType Terran_Refinery; extern const UnitType Terran_Barracks; extern const UnitType Terran_Academy; extern const UnitType Terran_Factory; extern const UnitType Terran_Starport; extern const UnitType Terran_Control_Tower; extern const UnitType Terran_Science_Facility; extern const UnitType Terran_Covert_Ops; extern const UnitType Terran_Physics_Lab; extern const UnitType Terran_Machine_Shop; extern const UnitType Terran_Engineering_Bay; extern const UnitType Terran_Armory; extern const UnitType Terran_Missile_Turret; extern const UnitType Terran_Bunker; extern const UnitType Special_Crashed_Norad_II; extern const UnitType Special_Ion_Cannon; extern const UnitType Zerg_Infested_Command_Center; extern const UnitType Zerg_Hatchery; extern const UnitType Zerg_Lair; extern const UnitType Zerg_Hive; extern const UnitType Zerg_Nydus_Canal; extern const UnitType Zerg_Hydralisk_Den; extern const UnitType Zerg_Defiler_Mound; extern const UnitType Zerg_Greater_Spire; extern const UnitType Zerg_Queens_Nest; extern const UnitType Zerg_Evolution_Chamber; extern const UnitType Zerg_Ultralisk_Cavern; extern const UnitType Zerg_Spire; extern const UnitType Zerg_Spawning_Pool; extern const UnitType Zerg_Creep_Colony; extern const UnitType Zerg_Spore_Colony; extern const UnitType Zerg_Sunken_Colony; extern const UnitType Special_Overmind_With_Shell; extern const UnitType Special_Overmind; extern const UnitType Zerg_Extractor; extern const UnitType Special_Mature_Chrysalis; extern const UnitType Special_Cerebrate; extern const UnitType Special_Cerebrate_Daggoth; extern const UnitType Protoss_Nexus; extern const UnitType Protoss_Robotics_Facility; extern const UnitType Protoss_Pylon; extern const UnitType Protoss_Assimilator; extern const UnitType Protoss_Observatory; extern const UnitType Protoss_Gateway; extern const UnitType Protoss_Photon_Cannon; extern const UnitType Protoss_Citadel_of_Adun; extern const UnitType Protoss_Cybernetics_Core; extern const UnitType Protoss_Templar_Archives; extern const UnitType Protoss_Forge; extern const UnitType Protoss_Stargate; extern const UnitType Special_Stasis_Cell_Prison; extern const UnitType Protoss_Fleet_Beacon; extern const UnitType Protoss_Arbiter_Tribunal; extern const UnitType Protoss_Robotics_Support_Bay; extern const UnitType Protoss_Shield_Battery; extern const UnitType Special_Khaydarin_Crystal_Form; extern const UnitType Special_Protoss_Temple; extern const UnitType Special_XelNaga_Temple; extern const UnitType Resource_Mineral_Field; extern const UnitType Resource_Vespene_Geyser; extern const UnitType Special_Warp_Gate; extern const UnitType Special_Psi_Disrupter; extern const UnitType Special_Power_Generator; extern const UnitType Special_Overmind_Cocoon; extern const UnitType Special_Zerg_Beacon; extern const UnitType Special_Terran_Beacon; extern const UnitType Special_Protoss_Beacon; extern const UnitType Special_Zerg_Flag_Beacon; extern const UnitType Special_Terran_Flag_Beacon; extern const UnitType Special_Protoss_Flag_Beacon; extern const UnitType Spell_Dark_Swarm; extern const UnitType Powerup_Uraj_Crystal; extern const UnitType Powerup_Khalis_Crystal; extern const UnitType Powerup_Flag; extern const UnitType Powerup_Young_Chrysalis; extern const UnitType Powerup_Psi_Emitter; extern const UnitType Powerup_Data_Disk; extern const UnitType Powerup_Khaydarin_Crystal; extern const UnitType None; extern const UnitType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/UpgradeType.h ================================================ #pragma once #include #include #include namespace BWAPI { class UnitType; class UpgradeType { public: UpgradeType(); UpgradeType(int id); UpgradeType(const UpgradeType& other); UpgradeType& operator=(const UpgradeType& other); bool operator==(const UpgradeType& other) const; bool operator!=(const UpgradeType& other) const; bool operator<(const UpgradeType& other) const; /** Returns the unique ID for this upgrade type. */ int getID() const; /** Returns the name for the upgrade type. */ std::string getName() const; /** Returns the race the upgrade is for. For example, UpgradeTypes::Terran_Infantry_Armor.getRace() * will return Races::Terran. */ Race getRace() const; /** Returns the mineral price for the first upgrade. */ int mineralPrice() const; /** Returns the amount that the mineral price increases for each additional upgrade. */ int mineralPriceFactor() const; /** Returns the vespene gas price for the first upgrade. */ int gasPrice() const; /** Returns the amount that the vespene gas price increases for each additional upgrade. */ int gasPriceFactor() const; /** Returns the number of frames needed to research the first upgrade. */ int upgradeTime() const; /** Returns the number of frames that the upgrade time increases for each additional upgrade. */ int upgradeTimeFactor() const; /** Returns the maximum number of times the upgrade can be researched. */ int maxRepeats() const; /** Returns the type of unit that researches the upgrade. */ UnitType whatUpgrades() const; /** Returns the set of units that are affected by this upgrade. */ const std::set& whatUses() const; private: int id; }; namespace UpgradeTypes { /** Given a string, this will return the upgrade type. */ UpgradeType getUpgradeType(std::string name); /** Returns the set of all the UpgradeTypes. */ std::set& allUpgradeTypes(); void init(); extern const UpgradeType Terran_Infantry_Armor; extern const UpgradeType Terran_Vehicle_Plating; extern const UpgradeType Terran_Ship_Plating; extern const UpgradeType Zerg_Carapace; extern const UpgradeType Zerg_Flyer_Carapace; extern const UpgradeType Protoss_Ground_Armor; extern const UpgradeType Protoss_Air_Armor; extern const UpgradeType Terran_Infantry_Weapons; extern const UpgradeType Terran_Vehicle_Weapons; extern const UpgradeType Terran_Ship_Weapons; extern const UpgradeType Zerg_Melee_Attacks; extern const UpgradeType Zerg_Missile_Attacks; extern const UpgradeType Zerg_Flyer_Attacks; extern const UpgradeType Protoss_Ground_Weapons; extern const UpgradeType Protoss_Air_Weapons; extern const UpgradeType Protoss_Plasma_Shields; extern const UpgradeType U_238_Shells; extern const UpgradeType Ion_Thrusters; extern const UpgradeType Titan_Reactor; extern const UpgradeType Ocular_Implants; extern const UpgradeType Moebius_Reactor; extern const UpgradeType Apollo_Reactor; extern const UpgradeType Colossus_Reactor; extern const UpgradeType Ventral_Sacs; extern const UpgradeType Antennae; extern const UpgradeType Pneumatized_Carapace; extern const UpgradeType Metabolic_Boost; extern const UpgradeType Adrenal_Glands; extern const UpgradeType Muscular_Augments; extern const UpgradeType Grooved_Spines; extern const UpgradeType Gamete_Meiosis; extern const UpgradeType Metasynaptic_Node; extern const UpgradeType Singularity_Charge; extern const UpgradeType Leg_Enhancements; extern const UpgradeType Scarab_Damage; extern const UpgradeType Reaver_Capacity; extern const UpgradeType Gravitic_Drive; extern const UpgradeType Sensor_Array; extern const UpgradeType Gravitic_Boosters; extern const UpgradeType Khaydarin_Amulet; extern const UpgradeType Apial_Sensors; extern const UpgradeType Gravitic_Thrusters; extern const UpgradeType Carrier_Capacity; extern const UpgradeType Khaydarin_Core; extern const UpgradeType Argus_Jewel; extern const UpgradeType Argus_Talisman; extern const UpgradeType Caduceus_Reactor; extern const UpgradeType Chitinous_Plating; extern const UpgradeType Anabolic_Synthesis; extern const UpgradeType Charon_Boosters; extern const UpgradeType None; extern const UpgradeType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI/WeaponType.h ================================================ #pragma once #include #include namespace BWAPI { class TechType; class UpgradeType; class DamageType; class ExplosionType; class WeaponType { public: WeaponType(); WeaponType(int id); WeaponType(const WeaponType& other); WeaponType& operator=(const WeaponType& other); bool operator==(const WeaponType& other) const; bool operator!=(const WeaponType& other) const; bool operator<(const WeaponType& other) const; /** Returns a unique ID for this weapon type. */ int getID() const; /** Returns the name of the weapon. */ std::string getName() const; /** Returns the tech type that must be researched before this weapon can be used, or TechTypes::None if * no tech type is required. */ TechType getTech() const; /** Returns the unit that can use this weapon. */ UnitType whatUses() const; /** Returns the amount of damage that this weapon deals per attack. */ int damageAmount() const; // TODO: add doc int damageBonus() const; /** Returns the amount of cooldown time between attacks. */ int damageCooldown() const; /** Returns the amount that the damage increases per upgrade. * \see WeaponType::upgradeType. */ int damageFactor() const; /** Returns the upgrade type that can be upgraded to increase the attack damage. */ UpgradeType upgradeType() const; /** Returns the type of damage that this weapon uses (i.e. concussive, normal, explosive, etc). */ DamageType damageType() const; /** Returns the type of explosion that this weapon uses. */ ExplosionType explosionType() const; /** Returns the minimum attack range of the weapon, measured in pixels, 0 for most things except * WeaponTypes::Arclite_Shock_Cannon (the weapon of the Terran Siege Tank in Siege Mode). */ int minRange() const; /** Returns the maximum attack range of the weapon, measured in pixels. */ int maxRange() const; /** Inner radius used in splash damage calculations. */ int innerSplashRadius() const; /** Median radius used in splash damage calculations. */ int medianSplashRadius() const; /** Outer radius used in splash damage calculations. */ int outerSplashRadius() const; /** Returns true if this weapon can attack air units. */ bool targetsAir() const; // TODO: group these methods /** Returns true if this weapon can attack ground units. */ bool targetsGround() const; bool targetsMechanical() const; bool targetsOrganic() const; bool targetsNonBuilding() const; bool targetsNonRobotic() const; bool targetsTerrain() const; bool targetsOrgOrMech() const; bool targetsOwn() const; private: int id; }; namespace WeaponTypes { /** Given the name of a weapon, this will return the corresponding weapon type object. */ WeaponType getWeaponType(std::string name); /** Returns the set of all the WeaponTypes. */ std::set& allWeaponTypes(); /** Returns the set of all normal weapons in WeaponTypes. */ std::set& normalWeaponTypes(); /** Returns the set of all special weapons in WeaponTypes. */ std::set& specialWeaponTypes(); void init(); extern const WeaponType Gauss_Rifle; extern const WeaponType Gauss_Rifle_Jim_Raynor; extern const WeaponType C_10_Canister_Rifle; extern const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan; extern const WeaponType C_10_Canister_Rifle_Samir_Duran; extern const WeaponType C_10_Canister_Rifle_Infested_Duran; extern const WeaponType C_10_Canister_Rifle_Alexei_Stukov; extern const WeaponType Fragmentation_Grenade; extern const WeaponType Fragmentation_Grenade_Jim_Raynor; extern const WeaponType Spider_Mines; extern const WeaponType Twin_Autocannons; extern const WeaponType Twin_Autocannons_Alan_Schezar; extern const WeaponType Hellfire_Missile_Pack; extern const WeaponType Hellfire_Missile_Pack_Alan_Schezar; extern const WeaponType Arclite_Cannon; extern const WeaponType Arclite_Cannon_Edmund_Duke; extern const WeaponType Fusion_Cutter; extern const WeaponType Gemini_Missiles; extern const WeaponType Gemini_Missiles_Tom_Kazansky; extern const WeaponType Burst_Lasers; extern const WeaponType Burst_Lasers_Tom_Kazansky; extern const WeaponType ATS_Laser_Battery; extern const WeaponType ATS_Laser_Battery_Hero; extern const WeaponType ATS_Laser_Battery_Hyperion; extern const WeaponType ATA_Laser_Battery; extern const WeaponType ATA_Laser_Battery_Hero; extern const WeaponType ATA_Laser_Battery_Hyperion; extern const WeaponType Flame_Thrower; extern const WeaponType Flame_Thrower_Gui_Montag; extern const WeaponType Arclite_Shock_Cannon; extern const WeaponType Arclite_Shock_Cannon_Edmund_Duke; extern const WeaponType Longbolt_Missile; extern const WeaponType Claws; extern const WeaponType Claws_Devouring_One; extern const WeaponType Claws_Infested_Kerrigan; extern const WeaponType Needle_Spines; extern const WeaponType Needle_Spines_Hunter_Killer; extern const WeaponType Kaiser_Blades; extern const WeaponType Kaiser_Blades_Torrasque; extern const WeaponType Toxic_Spores; extern const WeaponType Spines; extern const WeaponType Acid_Spore; extern const WeaponType Acid_Spore_Kukulza; extern const WeaponType Glave_Wurm; extern const WeaponType Glave_Wurm_Kukulza; extern const WeaponType Seeker_Spores; extern const WeaponType Subterranean_Tentacle; extern const WeaponType Suicide_Infested_Terran; extern const WeaponType Suicide_Scourge; extern const WeaponType Particle_Beam; extern const WeaponType Psi_Blades; extern const WeaponType Psi_Blades_Fenix; extern const WeaponType Phase_Disruptor; extern const WeaponType Phase_Disruptor_Fenix; extern const WeaponType Psi_Assault; extern const WeaponType Psionic_Shockwave; extern const WeaponType Psionic_Shockwave_TZ_Archon; extern const WeaponType Dual_Photon_Blasters; extern const WeaponType Dual_Photon_Blasters_Mojo; extern const WeaponType Dual_Photon_Blasters_Artanis; extern const WeaponType Anti_Matter_Missiles; extern const WeaponType Anti_Matter_Missiles_Mojo; extern const WeaponType Anti_Matter_Missiles_Artanis; extern const WeaponType Phase_Disruptor_Cannon; extern const WeaponType Phase_Disruptor_Cannon_Danimoth; extern const WeaponType Pulse_Cannon; extern const WeaponType STS_Photon_Cannon; extern const WeaponType STA_Photon_Cannon; extern const WeaponType Scarab; extern const WeaponType Neutron_Flare; extern const WeaponType Halo_Rockets; extern const WeaponType Corrosive_Acid; extern const WeaponType Subterranean_Spines; extern const WeaponType Warp_Blades; extern const WeaponType Warp_Blades_Hero; extern const WeaponType Warp_Blades_Zeratul; extern const WeaponType Yamato_Gun; extern const WeaponType Nuclear_Strike; extern const WeaponType Lockdown; extern const WeaponType EMP_Shockwave; extern const WeaponType Irradiate; extern const WeaponType Parasite; extern const WeaponType Spawn_Broodlings; extern const WeaponType Ensnare; extern const WeaponType Dark_Swarm; extern const WeaponType Plague; extern const WeaponType Consume; extern const WeaponType Stasis_Field; extern const WeaponType Psionic_Storm; extern const WeaponType Disruption_Web; extern const WeaponType Restoration; extern const WeaponType Mind_Control; extern const WeaponType Feedback; extern const WeaponType Optical_Flare; extern const WeaponType Maelstrom; extern const WeaponType None; extern const WeaponType Unknown; } } ================================================ FILE: SparCraft/bwapidata/include/BWAPI.cpp ================================================ #include namespace BWAPI { Game * Broodwar; } void BWAPI::BWAPI_init() { BWAPI::Races::init(); BWAPI::DamageTypes::init(); BWAPI::ExplosionTypes::init(); BWAPI::Orders::init(); BWAPI::TechTypes::init(); BWAPI::PlayerTypes::init(); BWAPI::UpgradeTypes::init(); BWAPI::WeaponTypes::init(); BWAPI::UnitSizeTypes::init(); BWAPI::UnitCommandTypes::init(); BWAPI::UnitTypes::init(); BWAPI::BulletTypes::init(); BWAPI::Errors::init(); BWAPI::Colors::init(); BWAPI::GameTypes::init(); } ================================================ FILE: SparCraft/bwapidata/include/BWAPI.h ================================================ #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 #include #include #include #include namespace BWAPI { /** You have to call this from your AIModule Dllmain function. * * \code * BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) * { * switch (ul_reason_for_call) * { * case DLL_PROCESS_ATTACH: * BWAPI::BWAPI_init(); * break; * case DLL_PROCESS_DETACH: * break; * } * * return TRUE; * } * \endcode */ void BWAPI_init(); } ================================================ FILE: SparCraft/bwapidata/include/Bitmap.cpp ================================================ #include namespace BWAPI { BitmapProxy::BitmapProxy(unsigned char *data, unsigned short width, unsigned short height, int x) :data(data) ,width(width) ,height(height) ,x(x) {} Color BitmapProxy::operator[](int y) { unsigned int offs = y * this->width + this->x; if ( offs < (unsigned int)(this->width * this->height) ) return Color(this->data[offs]); return Color(0); } BitmapProxy Bitmap::operator[](int x) { return BitmapProxy(this->data, this->wid, this->ht, x); } unsigned short Bitmap::getWidth() { return this->wid; } unsigned short Bitmap::getHeight() { return this->ht; } } ================================================ FILE: SparCraft/bwapidata/include/BulletType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingBulletType = true; std::string bulletTypeName[211]; std::map bulletTypeMap; std::set< BulletType > bulletTypeSet; namespace BulletTypes { const BulletType Melee(0); const BulletType Fusion_Cutter_Hit(141); const BulletType Gauss_Rifle_Hit(142); const BulletType C_10_Canister_Rifle_Hit(143); const BulletType Gemini_Missiles(144); const BulletType Fragmentation_Grenade(145); const BulletType Longbolt_Missile(146); const BulletType ATS_ATA_Laser_Battery(148); const BulletType Burst_Lasers(149); const BulletType Arclite_Shock_Cannon_Hit(150); const BulletType EMP_Missile(151); const BulletType Dual_Photon_Blasters_Hit(152); const BulletType Particle_Beam_Hit(153); const BulletType Anti_Matter_Missile(154); const BulletType Pulse_Cannon(155); const BulletType Psionic_Shockwave_Hit(156); const BulletType Psionic_Storm(157); const BulletType Yamato_Gun(158); const BulletType Phase_Disruptor(159); const BulletType STA_STS_Cannon_Overlay(160); const BulletType Sunken_Colony_Tentacle(161); const BulletType Acid_Spore(163); const BulletType Glave_Wurm(165); const BulletType Seeker_Spores(166); const BulletType Queen_Spell_Carrier(167); const BulletType Plague_Cloud(168); const BulletType Consume(169); const BulletType Needle_Spine_Hit(171); const BulletType Invisible(172); const BulletType Optical_Flare_Grenade(201); const BulletType Halo_Rockets(202); const BulletType Subterranean_Spines(203); const BulletType Corrosive_Acid_Shot(204); const BulletType Neutron_Flare(206); const BulletType None(209); const BulletType Unknown(210); void init() { bulletTypeName[Melee.getID()] = "Melee"; bulletTypeName[Fusion_Cutter_Hit.getID()] = "Fusion Cutter Hit"; bulletTypeName[Gauss_Rifle_Hit.getID()] = "Gauss Rifle Hit"; bulletTypeName[C_10_Canister_Rifle_Hit.getID()] = "C-10 Canister Rifle Hit"; bulletTypeName[Gemini_Missiles.getID()] = "Gemini Missiles"; bulletTypeName[Fragmentation_Grenade.getID()] = "Fragmentation Grenade"; bulletTypeName[Longbolt_Missile.getID()] = "Longbolt Missile"; bulletTypeName[ATS_ATA_Laser_Battery.getID()] = "ATS ATA Laser Battery"; bulletTypeName[Burst_Lasers.getID()] = "Burst Lasers"; bulletTypeName[Arclite_Shock_Cannon_Hit.getID()] = "Arclite Shock Cannon Hit"; bulletTypeName[EMP_Missile.getID()] = "EMP Missile"; bulletTypeName[Dual_Photon_Blasters_Hit.getID()] = "Dual Photon Blasters Hit"; bulletTypeName[Particle_Beam_Hit.getID()] = "Particle Beam Hit"; bulletTypeName[Anti_Matter_Missile.getID()] = "Anti-Matter Missile"; bulletTypeName[Pulse_Cannon.getID()] = "Pulse Cannon"; bulletTypeName[Psionic_Shockwave_Hit.getID()] = "Psionic Shockwave Hit"; bulletTypeName[Psionic_Storm.getID()] = "Psionic Storm"; bulletTypeName[Yamato_Gun.getID()] = "Yamato Gun"; bulletTypeName[Phase_Disruptor.getID()] = "Phase Disruptor"; bulletTypeName[STA_STS_Cannon_Overlay.getID()] = "STA STS Cannon Overlay"; bulletTypeName[Sunken_Colony_Tentacle.getID()] = "Sunken Colony Tentacle"; bulletTypeName[Acid_Spore.getID()] = "Acid Spore"; bulletTypeName[Glave_Wurm.getID()] = "Glave Wurm"; bulletTypeName[Seeker_Spores.getID()] = "Seeker Spores"; bulletTypeName[Queen_Spell_Carrier.getID()] = "Queen Spell Carrier"; bulletTypeName[Plague_Cloud.getID()] = "Plague Cloud"; bulletTypeName[Consume.getID()] = "Consume"; bulletTypeName[Needle_Spine_Hit.getID()] = "Needle Spine Hit"; bulletTypeName[Invisible.getID()] = "Invisible"; bulletTypeName[Optical_Flare_Grenade.getID()] = "Optical Flare Grenade"; bulletTypeName[Halo_Rockets.getID()] = "Halo Rockets"; bulletTypeName[Subterranean_Spines.getID()] = "Subterranean Spines"; bulletTypeName[Corrosive_Acid_Shot.getID()] = "Corrosive Acid Shot"; bulletTypeName[Neutron_Flare.getID()] = "Neutron Flare"; bulletTypeName[None.getID()] = "None"; bulletTypeName[Unknown.getID()] = "Unknown"; bulletTypeSet.insert(Melee); bulletTypeSet.insert(Fusion_Cutter_Hit); bulletTypeSet.insert(Gauss_Rifle_Hit); bulletTypeSet.insert(C_10_Canister_Rifle_Hit); bulletTypeSet.insert(Gemini_Missiles); bulletTypeSet.insert(Fragmentation_Grenade); bulletTypeSet.insert(Longbolt_Missile); bulletTypeSet.insert(ATS_ATA_Laser_Battery); bulletTypeSet.insert(Burst_Lasers); bulletTypeSet.insert(Arclite_Shock_Cannon_Hit); bulletTypeSet.insert(EMP_Missile); bulletTypeSet.insert(Dual_Photon_Blasters_Hit); bulletTypeSet.insert(Particle_Beam_Hit); bulletTypeSet.insert(Anti_Matter_Missile); bulletTypeSet.insert(Pulse_Cannon); bulletTypeSet.insert(Psionic_Shockwave_Hit); bulletTypeSet.insert(Psionic_Storm); bulletTypeSet.insert(Yamato_Gun); bulletTypeSet.insert(Phase_Disruptor); bulletTypeSet.insert(STA_STS_Cannon_Overlay); bulletTypeSet.insert(Sunken_Colony_Tentacle); bulletTypeSet.insert(Acid_Spore); bulletTypeSet.insert(Glave_Wurm); bulletTypeSet.insert(Seeker_Spores); bulletTypeSet.insert(Queen_Spell_Carrier); bulletTypeSet.insert(Plague_Cloud); bulletTypeSet.insert(Consume); bulletTypeSet.insert(Needle_Spine_Hit); bulletTypeSet.insert(Invisible); bulletTypeSet.insert(Optical_Flare_Grenade); bulletTypeSet.insert(Halo_Rockets); bulletTypeSet.insert(Subterranean_Spines); bulletTypeSet.insert(Corrosive_Acid_Shot); bulletTypeSet.insert(Neutron_Flare); bulletTypeSet.insert(None); bulletTypeSet.insert(Unknown); foreach(BulletType i, bulletTypeSet) { std::string name = i.getName(); fixName(&name); bulletTypeMap.insert(std::make_pair(name, i)); } initializingBulletType = false; } } BulletType::BulletType() { this->id = BulletTypes::None.id; } BulletType::BulletType(int id) { this->id = id; if (!initializingBulletType && (id < 0 || id >= 211 || bulletTypeName[id].length() == 0)) this->id = BulletTypes::Unknown.id; } BulletType::BulletType(const BulletType& other) { this->id = other.id; } BulletType& BulletType::operator=(const BulletType& other) { this->id = other.id; return *this; } bool BulletType::operator==(const BulletType& other) const { return this->id == other.id; } bool BulletType::operator!=(const BulletType& other) const { return this->id != other.id; } bool BulletType::operator<(const BulletType& other) const { return this->id < other.id; } int BulletType::getID() const { return this->id; } std::string BulletType::getName() const { return bulletTypeName[this->id]; } BulletType BulletTypes::getBulletType(std::string name) { fixName(&name); std::map::iterator i = bulletTypeMap.find(name); if (i == bulletTypeMap.end()) return BulletTypes::Unknown; return (*i).second; } std::set& BulletTypes::allBulletTypes() { return bulletTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/Color.cpp ================================================ #include #include #include namespace BWAPI { int palette[256] = {0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x3a003a, 0x190019, 0x2c2418, 0x482414, 0x5c2c14, 0x703014, 0x683c24, 0x7c4018, 0x784c2c, 0xa80808, 0x8c5430, 0x846044, 0xa0541c, 0xc44c18, 0xbc6824, 0xb4703c, 0xd06420, 0xdc9434, 0xe09454, 0xecc454, 0x344428, 0x406c3c, 0x486c50, 0x4c8050, 0x508c5c, 0x5ca078, 0x000018, 0x001034, 0x000850, 0x243448, 0x304054, 0x14347c, 0x344c6c, 0x405874, 0x48688c, 0x00709c, 0x5880a4, 0x4068d4, 0x18acb8, 0x2424fc, 0x6494bc, 0x70a8cc, 0x8cc0d8, 0x94dcf4, 0xacdce8, 0xacfcfc, 0xccf8f8, 0xfcfc00, 0xf4e490, 0xfcfcc0, 0x0c0c0c, 0x181410, 0x1c1c20, 0x282830, 0x383024, 0x383c44, 0x4c4030, 0x4c4c4c, 0x5c5040, 0x585858, 0x686868, 0x78846c, 0x68946c, 0x74a47c, 0x98948c, 0x90b894, 0x98c4a8, 0xb0b0b0, 0xacccb0, 0xc4c0bc, 0xcce0d0, 0xf0f0f0, 0x1c1008, 0x28180c, 0x341008, 0x34200c, 0x381020, 0x342820, 0x443408, 0x483018, 0x600000, 0x542820, 0x504014, 0x5c5414, 0x840404, 0x684c34, 0x7c3830, 0x706420, 0x7c5050, 0xa4341c, 0x946c00, 0x985c40, 0x8c8034, 0x987454, 0xb85444, 0xb09018, 0xb0745c, 0xf40404, 0xc87854, 0xfc6854, 0xe0a484, 0xfc9468, 0xfccc2c, 0x10fc18, 0x0c0020, 0x1c1c2c, 0x24244c, 0x282c68, 0x2c3084, 0x2018b8, 0x343cac, 0x686894, 0x6490fc, 0x7cacfc, 0x00e4fc, 0x9c9040, 0xa89454, 0xbca45c, 0xccb860, 0xe8d880, 0xecc4b0, 0xfcfc38, 0xfcfc7c, 0xfcfca4, 0x080808, 0x101010, 0x181818, 0x282828, 0x343434, 0x4c3c38, 0x444444, 0x484858, 0x585868, 0x746838, 0x78645c, 0x60607c, 0x847474, 0x84849c, 0xac8c7c, 0xac9894, 0x9090b8, 0xb8b8e8, 0xf88c14, 0x10543c, 0x209070, 0x2cb494, 0x042064, 0x481c50, 0x083498, 0x683078, 0x88409c, 0x0c48cc, 0xbcb834, 0xdcdc3c, 0x100000, 0x240000, 0x340000, 0x480000, 0x601804, 0x8c2808, 0xc81818, 0xe02c2c, 0xe82020, 0xe85014, 0xfc2020, 0xe87824, 0xf8ac3c, 0x001400, 0x002800, 0x004400, 0x006400, 0x088008, 0x249824, 0x3c9c3c, 0x58b058, 0x68b868, 0x80c480, 0x94d494, 0x0c1424, 0x243c64, 0x305084, 0x385c94, 0x4874b4, 0x5484c4, 0x6094d4, 0x78b4ec, 0x141008, 0x18140c, 0x242c0c, 0x101018, 0x141420, 0x2c2c40, 0x444c68, 0x040404, 0x1c1810, 0x201c14, 0x24201c, 0x30281c, 0x40382c, 0x544838, 0x685c4c, 0x907c64, 0x282014, 0x302814, 0x342c18, 0x382c1c, 0x3c301c, 0x443824, 0x544430, 0x0c1004, 0x141804, 0x181c08, 0x1c2008, 0x20240c, 0x2c3410, 0x343c10, 0x404810, 0x202030, 0x28283c, 0x303448, 0x141414, 0x20181c, 0x282018, 0x241c24, 0x282424, 0x302c2c, 0x3c2c34, 0x3c383c, 0x483c30, 0x443440, 0x503c48, 0x5c5034, 0x2323ff, 0x2323ff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff }; namespace Colors { const Color Red(111); const Color Blue(165); const Color Teal(159); const Color Purple(156); const Color Orange(179); const Color Brown(19); const Color White(255); const Color Yellow(135); const Color Green(117); const Color Cyan(128); const Color Black(0); const Color Grey(74); std::list cell[8][8][8]; void init() { for(int i = 0; i < 256; ++i) { int redCell = (palette[i] >> 21) & 0x07; int greenCell = (palette[i] >> 13) & 0x07; int blueCell = (palette[i] >> 5) & 0x07; cell[redCell][greenCell][blueCell].push_back(i); } } } int min(int a, int b) { return a < b ? a : b; } int max(int a, int b) { return a > b ? a : b; } Color::Color() { this->id = 0; } Color::Color(int id) { this->id = id; } Color::Color(const Color& other) { this->id = other.id; } Color::Color(int red, int green, int blue) { int redCell = red >> 5; int greenCell = green >> 5; int blueCell = blue >> 5; int redCellS = max(redCell - 1, 0); int redCellF = min(redCell + 1, 7); int greenCellS = max(greenCell - 1, 0); int greenCellF = min(greenCell + 1, 7); int blueCellS = max(blueCell - 1, 0); int blueCellF = min(blueCell + 1, 7); int min_dist = 3 * 256 * 256; int best_id = -1; for(int rc = redCellS; rc <= redCellF; ++rc) { for(int gc = greenCellS; gc <= greenCellF; ++gc) { for(int bc = blueCellS; bc <= blueCellF; ++bc) { foreach(int id, Colors::cell[rc][gc][bc]) { int ired = (palette[id] >> 16) & 0xFF; int igreen = (palette[id] >> 8) & 0xFF; int iblue = (palette[id] >> 0) & 0xFF; int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue); if (distance < min_dist) { min_dist = distance; best_id = id; } } } } } if (best_id == -1) { int min_dist = 3 * 256 * 256; int best_id = -1; for(int id = 0; id < 255; ++id) { int ired = (palette[id] >> 16) & 0xFF; int igreen = (palette[id] >> 8) & 0xFF; int iblue = (palette[id] >> 0) & 0xFF; int distance = (red - ired) * (red - ired) + (green - igreen) * (green - igreen) + (blue - iblue) * (blue - iblue); if (distance < min_dist) { min_dist = distance; best_id = id; } } } this->id = best_id; } Color& Color::operator=(const Color& other) { this->id = other.id; return *this; } bool Color::operator==(const Color& other) const { return palette[this->id] == palette[other.id]; } bool Color::operator!=(const Color& other) const { return palette[this->id] != palette[other.id]; } bool Color::operator<(const Color& other) const { return this->id < other.id; } int Color::getID() const { return this->id; } int Color::red() const { return (palette[this->id] >> 16) & 0xFF; } int Color::green() const { return (palette[this->id] >> 8) & 0xFF; } int Color::blue() const { return palette[this->id] & 0xFF; } } ================================================ FILE: SparCraft/bwapidata/include/Common.cpp ================================================ #include "Common.h" namespace BWAPI { void fixName(std::string *name) { for(unsigned int j = 0; j < name->length(); ++j) { if ( (*name)[j] == ' ') (*name)[j] = '_'; if ( (*name)[j] >= 'a' && (*name)[j] <= 'z') (*name)[j] += 'A'-'a'; } } } ================================================ FILE: SparCraft/bwapidata/include/Common.h ================================================ #pragma once #include namespace BWAPI { void fixName(std::string *name); } ================================================ FILE: SparCraft/bwapidata/include/DamageType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingDamageType = true; std::string damageTypeName[7]; std::map damageTypeMap; std::set< DamageType > damageTypeSet; namespace DamageTypes { const DamageType Independent(0); const DamageType Explosive(1); const DamageType Concussive(2); const DamageType Normal(3); const DamageType Ignore_Armor(4); const DamageType None(5); const DamageType Unknown(6); void init() { damageTypeName[Independent.getID()] = "Independent"; damageTypeName[Explosive.getID()] = "Explosive"; damageTypeName[Concussive.getID()] = "Concussive"; damageTypeName[Normal.getID()] = "Normal"; damageTypeName[Ignore_Armor.getID()] = "Ignore Armor"; damageTypeName[None.getID()] = "None"; damageTypeName[Unknown.getID()] = "Unknown"; damageTypeSet.insert(Independent); damageTypeSet.insert(Explosive); damageTypeSet.insert(Concussive); damageTypeSet.insert(Normal); damageTypeSet.insert(Ignore_Armor); damageTypeSet.insert(None); damageTypeSet.insert(Unknown); foreach(DamageType i, damageTypeSet) { std::string name = i.getName(); fixName(&name); damageTypeMap.insert(std::make_pair(name, i)); } initializingDamageType = false; } } DamageType::DamageType() { this->id = DamageTypes::None.id; } DamageType::DamageType(int id) { this->id = id; if (!initializingDamageType && (id < 0 || id >= 7)) this->id = DamageTypes::Unknown.id; } DamageType::DamageType(const DamageType& other) { this->id = other.id; } DamageType& DamageType::operator=(const DamageType& other) { this->id = other.id; return *this; } bool DamageType::operator==(const DamageType& other) const { return this->id == other.id; } bool DamageType::operator!=(const DamageType& other) const { return this->id != other.id; } bool DamageType::operator<(const DamageType& other) const { return this->id < other.id; } int DamageType::getID() const { return this->id; } std::string DamageType::getName() const { return damageTypeName[this->id]; } DamageType DamageTypes::getDamageType(std::string name) { fixName(&name); std::map::iterator i = damageTypeMap.find(name); if (i == damageTypeMap.end()) return DamageTypes::Unknown; return (*i).second; } std::set& DamageTypes::allDamageTypes() { return damageTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/Error.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingError = true; std::string errorName[25]; std::map errorMap; std::set< Error > errorSet; namespace Errors { const Error Unit_Does_Not_Exist(0); const Error Unit_Not_Visible(1); const Error Unit_Not_Owned(2); const Error Unit_Busy(3); const Error Incompatible_UnitType(4); const Error Incompatible_TechType(5); const Error Incompatible_State(6); const Error Already_Researched(7); const Error Fully_Upgraded(8); const Error Currently_Researching(9); const Error Currently_Upgrading(10); const Error Insufficient_Minerals(11); const Error Insufficient_Gas(12); const Error Insufficient_Supply(13); const Error Insufficient_Energy(14); const Error Insufficient_Tech(15); const Error Insufficient_Ammo(16); const Error Insufficient_Space(17); const Error Unbuildable_Location(18); const Error Unreachable_Location(19); const Error Out_Of_Range(20); const Error Unable_To_Hit(21); const Error Access_Denied(22); const Error None(23); const Error Unknown(24); void init() { errorName[Unit_Does_Not_Exist.getID()] = "Unit Does Not Exist"; errorName[Unit_Not_Visible.getID()] = "Unit Not Visible"; errorName[Unit_Not_Owned.getID()] = "Unit Not Owned"; errorName[Unit_Busy.getID()] = "Unit Busy"; errorName[Incompatible_UnitType.getID()] = "Incompatible UnitType"; errorName[Incompatible_TechType.getID()] = "Incompatible TechType"; errorName[Incompatible_State.getID()] = "Incompatible State"; errorName[Already_Researched.getID()] = "Already Researched"; errorName[Fully_Upgraded.getID()] = "Fully Upgraded"; errorName[Currently_Researching.getID()] = "Currently Researching"; errorName[Currently_Upgrading.getID()] = "Currently Upgrading"; errorName[Insufficient_Minerals.getID()] = "Insufficient Minerals"; errorName[Insufficient_Gas.getID()] = "Insufficient Gas"; errorName[Insufficient_Supply.getID()] = "Insufficient Supply"; errorName[Insufficient_Energy.getID()] = "Insufficient Energy"; errorName[Insufficient_Tech.getID()] = "Insufficient Tech"; errorName[Insufficient_Ammo.getID()] = "Insufficient Ammo"; errorName[Insufficient_Space.getID()] = "Insufficient Space"; errorName[Unbuildable_Location.getID()] = "Unbuildable Location"; errorName[Unreachable_Location.getID()] = "Unreachable Location"; errorName[Out_Of_Range.getID()] = "Out Of Range"; errorName[Unable_To_Hit.getID()] = "Unable To Hit"; errorName[Access_Denied.getID()] = "Access Denied"; errorName[None.getID()] = "None"; errorName[Unknown.getID()] = "Unknown"; errorSet.insert(Unit_Does_Not_Exist); errorSet.insert(Unit_Not_Visible); errorSet.insert(Unit_Not_Owned); errorSet.insert(Unit_Busy); errorSet.insert(Incompatible_UnitType); errorSet.insert(Incompatible_TechType); errorSet.insert(Incompatible_State); errorSet.insert(Already_Researched); errorSet.insert(Fully_Upgraded); errorSet.insert(Currently_Researching); errorSet.insert(Currently_Upgrading); errorSet.insert(Insufficient_Minerals); errorSet.insert(Insufficient_Gas); errorSet.insert(Insufficient_Supply); errorSet.insert(Insufficient_Energy); errorSet.insert(Insufficient_Tech); errorSet.insert(Insufficient_Ammo); errorSet.insert(Insufficient_Space); errorSet.insert(Unbuildable_Location); errorSet.insert(Unreachable_Location); errorSet.insert(Out_Of_Range); errorSet.insert(Unable_To_Hit); errorSet.insert(Access_Denied); errorSet.insert(None); errorSet.insert(Unknown); foreach(Error i, errorSet) { std::string name = i.toString(); fixName(&name); errorMap.insert(std::make_pair(name, i)); } initializingError = false; } } Error::Error() { this->id = Errors::None.id; } Error::Error(int id) { this->id = id; if (!initializingError && (id < 0 || id >= 25)) this->id = Errors::Unknown.id; } Error::Error(const Error& other) { this->id = other.id; } Error& Error::operator=(const Error& other) { this->id = other.id; return *this; } bool Error::operator==(const Error& other) const { return this->id == other.id; } bool Error::operator!=(const Error& other) const { return this->id != other.id; } bool Error::operator<(const Error& other) const { return this->id < other.id; } int Error::getID() const { return this->id; } std::string Error::toString() const { return errorName[this->id]; } Error Errors::getError(std::string name) { fixName(&name); std::map::iterator i = errorMap.find(name); if (i == errorMap.end()) return Errors::Unknown; return (*i).second; } std::set& Errors::allErrors() { return errorSet; } } ================================================ FILE: SparCraft/bwapidata/include/Event.cpp ================================================ #include namespace BWAPI { Event::Event() : type(EventType::None), position(Positions::None), text(""), unit(NULL), player(NULL), isWinner(false) { } bool Event::operator==(const Event& other) { return (type == other.type && position == other.position && text == other.text && unit == other.unit && player == other.player && isWinner == other.isWinner); } Event Event::MatchStart() { Event e; e.type = EventType::MatchStart; return e; } Event Event::MatchEnd(bool isWinner) { Event e; e.type = EventType::MatchEnd; e.isWinner = isWinner; return e; } Event Event::MatchFrame() { Event e; e.type = EventType::MatchFrame; return e; } Event Event::MenuFrame() { Event e; e.type = EventType::MenuFrame; return e; } Event Event::SendText(std::string text) { Event e; e.type = EventType::SendText; e.text = text; return e; } Event Event::ReceiveText(Player* player, std::string text) { Event e; e.type = EventType::ReceiveText; e.player = player; e.text = text; return e; } Event Event::PlayerLeft(Player* player) { Event e; e.type = EventType::PlayerLeft; e.player = player; return e; } Event Event::NukeDetect(Position target) { Event e; e.type = EventType::NukeDetect; e.position = target; return e; } Event Event::UnitDiscover(Unit* unit) { Event e; e.type = EventType::UnitDiscover; e.unit = unit; return e; } Event Event::UnitEvade(Unit* unit) { Event e; e.type = EventType::UnitEvade; e.unit = unit; return e; } Event Event::UnitShow(Unit* unit) { Event e; e.type = EventType::UnitShow; e.unit = unit; return e; } Event Event::UnitHide(Unit* unit) { Event e; e.type = EventType::UnitHide; e.unit = unit; return e; } Event Event::UnitCreate(Unit* unit) { Event e; e.type = EventType::UnitCreate; e.unit = unit; return e; } Event Event::UnitDestroy(Unit* unit) { Event e; e.type = EventType::UnitDestroy; e.unit = unit; return e; } Event Event::UnitMorph(Unit* unit) { Event e; e.type = EventType::UnitMorph; e.unit = unit; return e; } Event Event::UnitRenegade(Unit* unit) { Event e; e.type = EventType::UnitRenegade; e.unit = unit; return e; } Event Event::SaveGame(std::string gameName) { Event e; e.type = EventType::SaveGame; e.text = gameName; return e; } } ================================================ FILE: SparCraft/bwapidata/include/ExplosionType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingExplosionType = true; std::string explosionTypeName[26]; std::map explosionTypeMap; std::set< ExplosionType > explosionTypeSet; namespace ExplosionTypes { const ExplosionType None(0); const ExplosionType Normal(1); const ExplosionType Radial_Splash(2); const ExplosionType Enemy_Splash(3); const ExplosionType Lockdown(4); const ExplosionType Nuclear_Missile(5); const ExplosionType Parasite(6); const ExplosionType Broodlings(7); const ExplosionType EMP_Shockwave(8); const ExplosionType Irradiate(9); const ExplosionType Ensnare(10); const ExplosionType Plague(11); const ExplosionType Stasis_Field(12); const ExplosionType Dark_Swarm(13); const ExplosionType Consume(14); const ExplosionType Yamato_Gun(15); const ExplosionType Restoration(16); const ExplosionType Disruption_Web(17); const ExplosionType Corrosive_Acid(18); const ExplosionType Mind_Control(19); const ExplosionType Feedback(20); const ExplosionType Optical_Flare(21); const ExplosionType Maelstrom(22); const ExplosionType Air_Splash(24); const ExplosionType Unknown(25); void init() { explosionTypeName[None.getID()] = "None"; explosionTypeName[Normal.getID()] = "Normal"; explosionTypeName[Radial_Splash.getID()] = "Radial Splash"; explosionTypeName[Enemy_Splash.getID()] = "Enemy Splash"; explosionTypeName[Lockdown.getID()] = "Lockdown"; explosionTypeName[Nuclear_Missile.getID()] = "Nuclear Missile"; explosionTypeName[Parasite.getID()] = "Parasite"; explosionTypeName[Broodlings.getID()] = "Broodlings"; explosionTypeName[EMP_Shockwave.getID()] = "EMP Shockwave"; explosionTypeName[Irradiate.getID()] = "Irradiate"; explosionTypeName[Ensnare.getID()] = "Ensnare"; explosionTypeName[Plague.getID()] = "Plague"; explosionTypeName[Stasis_Field.getID()] = "Stasis Field"; explosionTypeName[Dark_Swarm.getID()] = "Dark Swarm"; explosionTypeName[Consume.getID()] = "Consume"; explosionTypeName[Yamato_Gun.getID()] = "Yamato Gun"; explosionTypeName[Restoration.getID()] = "Restoration"; explosionTypeName[Disruption_Web.getID()] = "Disruption Web"; explosionTypeName[Corrosive_Acid.getID()] = "Corrosive Acid"; explosionTypeName[Mind_Control.getID()] = "Mind Control"; explosionTypeName[Feedback.getID()] = "Feedback"; explosionTypeName[Optical_Flare.getID()] = "Optical Flare"; explosionTypeName[Maelstrom.getID()] = "Maelstrom"; explosionTypeName[Air_Splash.getID()] = "Air Splash"; explosionTypeName[Unknown.getID()] = "Unknown"; explosionTypeSet.insert(None); explosionTypeSet.insert(Normal); explosionTypeSet.insert(Radial_Splash); explosionTypeSet.insert(Enemy_Splash); explosionTypeSet.insert(Lockdown); explosionTypeSet.insert(Nuclear_Missile); explosionTypeSet.insert(Parasite); explosionTypeSet.insert(Broodlings); explosionTypeSet.insert(EMP_Shockwave); explosionTypeSet.insert(Irradiate); explosionTypeSet.insert(Ensnare); explosionTypeSet.insert(Plague); explosionTypeSet.insert(Stasis_Field); explosionTypeSet.insert(Dark_Swarm); explosionTypeSet.insert(Consume); explosionTypeSet.insert(Yamato_Gun); explosionTypeSet.insert(Restoration); explosionTypeSet.insert(Disruption_Web); explosionTypeSet.insert(Corrosive_Acid); explosionTypeSet.insert(Mind_Control); explosionTypeSet.insert(Feedback); explosionTypeSet.insert(Optical_Flare); explosionTypeSet.insert(Maelstrom); explosionTypeSet.insert(Air_Splash); explosionTypeSet.insert(Unknown); foreach(ExplosionType i, explosionTypeSet) { std::string name = i.getName(); fixName(&name); explosionTypeMap.insert(std::make_pair(name, i)); } initializingExplosionType = false; } } ExplosionType::ExplosionType() { this->id = ExplosionTypes::None.id; } ExplosionType::ExplosionType(int id) { this->id = id; if (!initializingExplosionType && (id < 0 || id >= 26)) this->id = ExplosionTypes::Unknown.id; } ExplosionType::ExplosionType(const ExplosionType& other) { this->id = other.id; } ExplosionType& ExplosionType::operator=(const ExplosionType& other) { this->id = other.id; return *this; } bool ExplosionType::operator==(const ExplosionType& other) const { return this->id == other.id; } bool ExplosionType::operator!=(const ExplosionType& other) const { return this->id != other.id; } bool ExplosionType::operator<(const ExplosionType& other) const { return this->id < other.id; } int ExplosionType::getID() const { return this->id; } std::string ExplosionType::getName() const { return explosionTypeName[this->id]; } ExplosionType ExplosionTypes::getExplosionType(std::string name) { fixName(&name); std::map::iterator i = explosionTypeMap.find(name); if (i == explosionTypeMap.end()) return ExplosionTypes::Unknown; return (*i).second; } std::set& ExplosionTypes::allExplosionTypes() { return explosionTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/GameType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingGameType = true; std::string gameTypeName[35]; std::map gameTypeMap; std::set< GameType > gameTypeSet; namespace GameTypes { const GameType Melee(2); const GameType Free_For_All(3); const GameType One_on_One(4); const GameType Capture_The_Flag(5); const GameType Greed(6); const GameType Slaughter(7); const GameType Sudden_Death(8); const GameType Ladder(9); const GameType Use_Map_Settings(10); const GameType Team_Melee(11); const GameType Team_Free_For_All(12); const GameType Team_Capture_The_Flag(13); const GameType Top_vs_Bottom(15); const GameType Pro_Gamer_League(32); const GameType None(33); const GameType Unknown(34); void init() { gameTypeName[Melee.getID()] = "Melee"; gameTypeName[Free_For_All.getID()] = "Free For All"; gameTypeName[One_on_One.getID()] = "One on One"; gameTypeName[Capture_The_Flag.getID()] = "Capture The Flag"; gameTypeName[Greed.getID()] = "Greed"; gameTypeName[Slaughter.getID()] = "Slaughter"; gameTypeName[Sudden_Death.getID()] = "Sudden Death"; gameTypeName[Ladder.getID()] = "Ladder"; gameTypeName[Use_Map_Settings.getID()] = "Use Map Settings"; gameTypeName[Team_Melee.getID()] = "Team Melee"; gameTypeName[Team_Free_For_All.getID()] = "Team Free For All"; gameTypeName[Team_Capture_The_Flag.getID()] = "Team Capture The Flag"; gameTypeName[Top_vs_Bottom.getID()] = "Top vs Bottom"; gameTypeName[Pro_Gamer_League.getID()] = "Pro Gamer League"; gameTypeName[None.getID()] = "None"; gameTypeName[Unknown.getID()] = "Unknown"; gameTypeSet.insert(Melee); gameTypeSet.insert(Free_For_All); gameTypeSet.insert(One_on_One); gameTypeSet.insert(Capture_The_Flag); gameTypeSet.insert(Greed); gameTypeSet.insert(Slaughter); gameTypeSet.insert(Sudden_Death); gameTypeSet.insert(Ladder); gameTypeSet.insert(Use_Map_Settings); gameTypeSet.insert(Team_Melee); gameTypeSet.insert(Team_Free_For_All); gameTypeSet.insert(Team_Capture_The_Flag); gameTypeSet.insert(Top_vs_Bottom); gameTypeSet.insert(Pro_Gamer_League); gameTypeSet.insert(None); gameTypeSet.insert(Unknown); foreach(GameType i, gameTypeSet) { std::string name = i.getName(); fixName(&name); gameTypeMap.insert(std::make_pair(name, i)); } initializingGameType = false; } } GameType::GameType() { this->id = GameTypes::None.id; } GameType::GameType(int id) { this->id = id; if (!initializingGameType && (id < 0 || id >= 35 || gameTypeName[id].length() == 0)) this->id = GameTypes::Unknown.id; } GameType::GameType(const GameType& other) { this->id = other.id; } GameType& GameType::operator=(const GameType& other) { this->id = other.id; return *this; } bool GameType::operator==(const GameType& other) const { return this->id == other.id; } bool GameType::operator!=(const GameType& other) const { return this->id != other.id; } bool GameType::operator<(const GameType& other) const { return this->id < other.id; } int GameType::getID() const { return this->id; } std::string GameType::getName() const { return gameTypeName[this->id]; } GameType GameTypes::getGameType(std::string name) { fixName(&name); std::map::iterator i = gameTypeMap.find(name); if (i == gameTypeMap.end()) return GameTypes::Unknown; return (*i).second; } std::set& GameTypes::allGameTypes() { return gameTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/Order.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingOrder = true; std::string orderName[191]; std::map orderMap; std::set< Order > orderSet; namespace Orders { const Order Die(0); const Order Stop(1); const Order Guard(2); const Order PlayerGuard(3); const Order TurretGuard(4); const Order BunkerGuard(5); const Order Move(6); const Order AttackUnit(10); const Order AttackTile(12); const Order Hover(13); const Order AttackMove(14); const Order InfestedCommandCenter(15); const Order UnusedNothing(16); const Order UnusedPowerup(17); const Order TowerGuard(18); const Order VultureMine(20); const Order Nothing(23); const Order Nothing3(24); const Order CastInfestation(27); const Order InfestingCommandCenter(29); const Order PlaceBuilding(30); const Order BuildProtoss2(32); const Order ConstructingBuilding(33); const Order Repair(34); const Order PlaceAddon(36); const Order BuildAddon(37); const Order Train(38); const Order RallyPointUnit(39); const Order RallyPointTile(40); const Order ZergBirth(41); const Order ZergUnitMorph(42); const Order ZergBuildingMorph(43); const Order IncompleteBuilding(44); const Order BuildNydusExit(46); const Order EnterNydusCanal(47); const Order Follow(49); const Order Carrier(50); const Order ReaverCarrierMove(51); const Order CarrierIgnore2(55); const Order Reaver(58); const Order TrainFighter(63); const Order InterceptorAttack(64); const Order ScarabAttack(65); const Order RechargeShieldsUnit(66); const Order RechargeShieldsBattery(67); const Order ShieldBattery(68); const Order InterceptorReturn(69); const Order BuildingLand(71); const Order BuildingLiftOff(72); const Order DroneLiftOff(73); const Order LiftingOff(74); const Order ResearchTech(75); const Order Upgrade(76); const Order Larva(77); const Order SpawningLarva(78); const Order Harvest1(79); const Order Harvest2(80); const Order MoveToGas(81); const Order WaitForGas(82); const Order HarvestGas(83); const Order ReturnGas(84); const Order MoveToMinerals(85); const Order WaitForMinerals(86); const Order MiningMinerals(87); const Order Harvest3(88); const Order Harvest4(89); const Order ReturnMinerals(90); const Order Interrupted(91); const Order EnterTransport(92); const Order PickupIdle(93); const Order PickupTransport(94); const Order PickupBunker(95); const Order Pickup4(96); const Order PowerupIdle(97); const Order Sieging(98); const Order Unsieging(99); const Order InitCreepGrowth(101); const Order SpreadCreep(102); const Order StoppingCreepGrowth(103); const Order GuardianAspect(104); const Order ArchonWarp(105); const Order CompletingArchonsummon(106); const Order HoldPosition(107); const Order Cloak(109); const Order Decloak(110); const Order Unload(111); const Order MoveUnload(112); const Order FireYamatoGun(113); const Order CastLockdown(115); const Order Burrowing(116); const Order Burrowed(117); const Order Unburrowing(118); const Order CastDarkSwarm(119); const Order CastParasite(120); const Order CastSpawnBroodlings(121); const Order CastEMPShockwave(122); const Order NukeWait(123); const Order NukeTrain(124); const Order NukeLaunch(125); const Order NukeUnit(127); const Order CastNuclearStrike(128); const Order NukeTrack(129); const Order CloakNearbyUnits(131); const Order PlaceMine(132); const Order RightClickAction(133); const Order CastRecall(137); const Order TeleporttoLocation(138); const Order CastScannerSweep(139); const Order Scanner(140); const Order CastDefensiveMatrix(141); const Order CastPsionicStorm(142); const Order CastIrradiate(143); const Order CastPlague(144); const Order CastConsume(145); const Order CastEnsnare(146); const Order CastStasisField(147); const Order CastHallucination(148); const Order Hallucination2(149); const Order ResetCollision(150); const Order Patrol(152); const Order CTFCOPInit(153); const Order CTFCOP1(154); const Order CTFCOP2(155); const Order ComputerAI(156); const Order AtkMoveEP(157); const Order HarassMove(158); const Order AIPatrol(159); const Order GuardPost(160); const Order RescuePassive(161); const Order Neutral(162); const Order ComputerReturn(163); const Order SelfDestrucing(165); const Order Critter(166); const Order HiddenGun(167); const Order OpenDoor(168); const Order CloseDoor(169); const Order HideTrap(170); const Order RevealTrap(171); const Order Enabledoodad(172); const Order Disabledoodad(173); const Order Warpin(174); const Order Medic(175); const Order MedicHeal1(176); const Order HealMove(177); const Order MedicHeal2(179); const Order CastRestoration(180); const Order CastDisruptionWeb(181); const Order CastMindControl(182); const Order DarkArchonMeld(183); const Order CastFeedback(184); const Order CastOpticalFlare(185); const Order CastMaelstrom(186); const Order JunkYardDog(187); const Order Fatal(188); const Order None(189); const Order Unknown(190); void init() { orderName[Die.getID()] = "Die"; orderName[Stop.getID()] = "Stop"; orderName[Guard.getID()] = "Guard"; orderName[PlayerGuard.getID()] = "PlayerGuard"; orderName[TurretGuard.getID()] = "TurretGuard"; orderName[BunkerGuard.getID()] = "BunkerGuard"; orderName[Move.getID()] = "Move"; orderName[AttackUnit.getID()] = "AttackUnit"; orderName[AttackTile.getID()] = "AttackTile"; orderName[Hover.getID()] = "Hover"; orderName[AttackMove.getID()] = "AttackMove"; orderName[InfestedCommandCenter.getID()] = "InfestedCommandCenter"; orderName[UnusedNothing.getID()] = "UnusedNothing"; orderName[UnusedPowerup.getID()] = "UnusedPowerup"; orderName[TowerGuard.getID()] = "TowerGuard"; orderName[VultureMine.getID()] = "VultureMine"; orderName[Nothing.getID()] = "Nothing"; orderName[Nothing3.getID()] = "Nothing3"; orderName[CastInfestation.getID()] = "CastInfestation"; orderName[InfestingCommandCenter.getID()] = "InfestingCommandCenter"; orderName[PlaceBuilding.getID()] = "PlaceBuilding"; orderName[BuildProtoss2.getID()] = "BuildProtoss2"; orderName[ConstructingBuilding.getID()] = "ConstructingBuilding"; orderName[Repair.getID()] = "Repair"; orderName[PlaceAddon.getID()] = "PlaceAddon"; orderName[BuildAddon.getID()] = "BuildAddon"; orderName[Train.getID()] = "Train"; orderName[RallyPointUnit.getID()] = "RallyPointUnit"; orderName[RallyPointTile.getID()] = "RallyPointTile"; orderName[ZergBirth.getID()] = "ZergBirth"; orderName[ZergUnitMorph.getID()] = "ZergUnitMorph"; orderName[ZergBuildingMorph.getID()] = "ZergBuildingMorph"; orderName[IncompleteBuilding.getID()] = "IncompleteBuilding"; orderName[BuildNydusExit.getID()] = "BuildNydusExit"; orderName[EnterNydusCanal.getID()] = "EnterNydusCanal"; orderName[Follow.getID()] = "Follow"; orderName[Carrier.getID()] = "Carrier"; orderName[ReaverCarrierMove.getID()] = "ReaverCarrierMove"; orderName[CarrierIgnore2.getID()] = "CarrierIgnore2"; orderName[Reaver.getID()] = "Reaver"; orderName[TrainFighter.getID()] = "TrainFighter"; orderName[InterceptorAttack.getID()] = "InterceptorAttack"; orderName[ScarabAttack.getID()] = "ScarabAttack"; orderName[RechargeShieldsUnit.getID()] = "RechargeShieldsUnit"; orderName[RechargeShieldsBattery.getID()] = "RechargeShieldsBattery"; orderName[ShieldBattery.getID()] = "ShieldBattery"; orderName[InterceptorReturn.getID()] = "InterceptorReturn"; orderName[BuildingLand.getID()] = "BuildingLand"; orderName[BuildingLiftOff.getID()] = "BuildingLiftOff"; orderName[DroneLiftOff.getID()] = "DroneLiftOff"; orderName[LiftingOff.getID()] = "LiftingOff"; orderName[ResearchTech.getID()] = "ResearchTech"; orderName[Upgrade.getID()] = "Upgrade"; orderName[Larva.getID()] = "Larva"; orderName[SpawningLarva.getID()] = "SpawningLarva"; orderName[Harvest1.getID()] = "Harvest1"; orderName[Harvest2.getID()] = "Harvest2"; orderName[MoveToGas.getID()] = "MoveToGas"; orderName[WaitForGas.getID()] = "WaitForGas"; orderName[HarvestGas.getID()] = "HarvestGas"; orderName[ReturnGas.getID()] = "ReturnGas"; orderName[MoveToMinerals.getID()] = "MoveToMinerals"; orderName[WaitForMinerals.getID()] = "WaitForMinerals"; orderName[MiningMinerals.getID()] = "MiningMinerals"; orderName[Harvest3.getID()] = "Harvest3"; orderName[Harvest4.getID()] = "Harvest4"; orderName[ReturnMinerals.getID()] = "ReturnMinerals"; orderName[Interrupted.getID()] = "Interrupted"; orderName[EnterTransport.getID()] = "EnterTransport"; orderName[PickupIdle.getID()] = "PickupIdle"; orderName[PickupTransport.getID()] = "PickupTransport"; orderName[PickupBunker.getID()] = "PickupBunker"; orderName[Pickup4.getID()] = "Pickup4"; orderName[PowerupIdle.getID()] = "PowerupIdle"; orderName[Sieging.getID()] = "Sieging"; orderName[Unsieging.getID()] = "Unsieging"; orderName[InitCreepGrowth.getID()] = "InitCreepGrowth"; orderName[SpreadCreep.getID()] = "SpreadCreep"; orderName[StoppingCreepGrowth.getID()] = "StoppingCreepGrowth"; orderName[GuardianAspect.getID()] = "GuardianAspect"; orderName[ArchonWarp.getID()] = "ArchonWarp"; orderName[CompletingArchonsummon.getID()] = "CompletingArchonsummon"; orderName[HoldPosition.getID()] = "HoldPosition"; orderName[Cloak.getID()] = "Cloak"; orderName[Decloak.getID()] = "Decloak"; orderName[Unload.getID()] = "Unload"; orderName[MoveUnload.getID()] = "MoveUnload"; orderName[FireYamatoGun.getID()] = "FireYamatoGun"; orderName[CastLockdown.getID()] = "CastLockdown"; orderName[Burrowing.getID()] = "Burrowing"; orderName[Burrowed.getID()] = "Burrowed"; orderName[Unburrowing.getID()] = "Unburrowing"; orderName[CastDarkSwarm.getID()] = "CastDarkSwarm"; orderName[CastParasite.getID()] = "CastParasite"; orderName[CastSpawnBroodlings.getID()] = "CastSpawnBroodlings"; orderName[CastEMPShockwave.getID()] = "CastEMPShockwave"; orderName[NukeWait.getID()] = "NukeWait"; orderName[NukeTrain.getID()] = "NukeTrain"; orderName[NukeLaunch.getID()] = "NukeLaunch"; orderName[NukeUnit.getID()] = "NukeUnit"; orderName[CastNuclearStrike.getID()] = "CastNuclearStrike"; orderName[NukeTrack.getID()] = "NukeTrack"; orderName[CloakNearbyUnits.getID()] = "CloakNearbyUnits"; orderName[PlaceMine.getID()] = "PlaceMine"; orderName[RightClickAction.getID()] = "RightClickAction"; orderName[CastRecall.getID()] = "CastRecall"; orderName[TeleporttoLocation.getID()] = "TeleporttoLocation"; orderName[CastScannerSweep.getID()] = "CastScannerSweep"; orderName[Scanner.getID()] = "Scanner"; orderName[CastDefensiveMatrix.getID()] = "CastDefensiveMatrix"; orderName[CastPsionicStorm.getID()] = "CastPsionicStorm"; orderName[CastIrradiate.getID()] = "CastIrradiate"; orderName[CastPlague.getID()] = "CastPlague"; orderName[CastConsume.getID()] = "CastConsume"; orderName[CastEnsnare.getID()] = "CastEnsnare"; orderName[CastStasisField.getID()] = "CastStasisField"; orderName[CastHallucination.getID()] = "CastHallucination"; orderName[Hallucination2.getID()] = "Hallucination2"; orderName[ResetCollision.getID()] = "ResetCollision"; orderName[Patrol.getID()] = "Patrol"; orderName[CTFCOPInit.getID()] = "CTFCOPInit"; orderName[CTFCOP1.getID()] = "CTFCOP1"; orderName[CTFCOP2.getID()] = "CTFCOP2"; orderName[ComputerAI.getID()] = "ComputerAI"; orderName[AtkMoveEP.getID()] = "AtkMoveEP"; orderName[HarassMove.getID()] = "HarassMove"; orderName[AIPatrol.getID()] = "AIPatrol"; orderName[GuardPost.getID()] = "GuardPost"; orderName[RescuePassive.getID()] = "RescuePassive"; orderName[Neutral.getID()] = "Neutral"; orderName[ComputerReturn.getID()] = "ComputerReturn"; orderName[SelfDestrucing.getID()] = "SelfDestrucing"; orderName[Critter.getID()] = "Critter"; orderName[HiddenGun.getID()] = "HiddenGun"; orderName[OpenDoor.getID()] = "OpenDoor"; orderName[CloseDoor.getID()] = "CloseDoor"; orderName[HideTrap.getID()] = "HideTrap"; orderName[RevealTrap.getID()] = "RevealTrap"; orderName[Enabledoodad.getID()] = "Enabledoodad"; orderName[Disabledoodad.getID()] = "Disabledoodad"; orderName[Warpin.getID()] = "Warpin"; orderName[Medic.getID()] = "Medic"; orderName[MedicHeal1.getID()] = "MedicHeal1"; orderName[HealMove.getID()] = "HealMove"; orderName[MedicHeal2.getID()] = "MedicHeal2"; orderName[CastRestoration.getID()] = "CastRestoration"; orderName[CastDisruptionWeb.getID()] = "CastDisruptionWeb"; orderName[CastMindControl.getID()] = "CastMindControl"; orderName[DarkArchonMeld.getID()] = "DarkArchonMeld"; orderName[CastFeedback.getID()] = "CastFeedback"; orderName[CastOpticalFlare.getID()] = "CastOpticalFlare"; orderName[CastMaelstrom.getID()] = "CastMaelstrom"; orderName[JunkYardDog.getID()] = "JunkYardDog"; orderName[Fatal.getID()] = "Fatal"; orderName[None.getID()] = "None"; orderName[Unknown.getID()] = "Unknown"; orderSet.insert(Die); orderSet.insert(Stop); orderSet.insert(Guard); orderSet.insert(PlayerGuard); orderSet.insert(TurretGuard); orderSet.insert(BunkerGuard); orderSet.insert(Move); orderSet.insert(AttackUnit); orderSet.insert(AttackTile); orderSet.insert(Hover); orderSet.insert(AttackMove); orderSet.insert(InfestedCommandCenter); orderSet.insert(UnusedNothing); orderSet.insert(UnusedPowerup); orderSet.insert(TowerGuard); orderSet.insert(VultureMine); orderSet.insert(Nothing); orderSet.insert(Nothing3); orderSet.insert(CastInfestation); orderSet.insert(InfestingCommandCenter); orderSet.insert(PlaceBuilding); orderSet.insert(BuildProtoss2); orderSet.insert(ConstructingBuilding); orderSet.insert(Repair); orderSet.insert(PlaceAddon); orderSet.insert(BuildAddon); orderSet.insert(Train); orderSet.insert(RallyPointUnit); orderSet.insert(RallyPointTile); orderSet.insert(ZergBirth); orderSet.insert(ZergUnitMorph); orderSet.insert(ZergBuildingMorph); orderSet.insert(IncompleteBuilding); orderSet.insert(BuildNydusExit); orderSet.insert(EnterNydusCanal); orderSet.insert(Follow); orderSet.insert(Carrier); orderSet.insert(ReaverCarrierMove); orderSet.insert(CarrierIgnore2); orderSet.insert(Reaver); orderSet.insert(TrainFighter); orderSet.insert(InterceptorAttack); orderSet.insert(ScarabAttack); orderSet.insert(RechargeShieldsUnit); orderSet.insert(RechargeShieldsBattery); orderSet.insert(ShieldBattery); orderSet.insert(InterceptorReturn); orderSet.insert(BuildingLand); orderSet.insert(BuildingLiftOff); orderSet.insert(DroneLiftOff); orderSet.insert(LiftingOff); orderSet.insert(ResearchTech); orderSet.insert(Upgrade); orderSet.insert(Larva); orderSet.insert(SpawningLarva); orderSet.insert(Harvest1); orderSet.insert(Harvest2); orderSet.insert(MoveToGas); orderSet.insert(WaitForGas); orderSet.insert(HarvestGas); orderSet.insert(ReturnGas); orderSet.insert(MoveToMinerals); orderSet.insert(WaitForMinerals); orderSet.insert(MiningMinerals); orderSet.insert(Harvest3); orderSet.insert(Harvest4); orderSet.insert(ReturnMinerals); orderSet.insert(Interrupted); orderSet.insert(EnterTransport); orderSet.insert(PickupIdle); orderSet.insert(PickupTransport); orderSet.insert(PickupBunker); orderSet.insert(Pickup4); orderSet.insert(PowerupIdle); orderSet.insert(Sieging); orderSet.insert(Unsieging); orderSet.insert(InitCreepGrowth); orderSet.insert(SpreadCreep); orderSet.insert(StoppingCreepGrowth); orderSet.insert(GuardianAspect); orderSet.insert(ArchonWarp); orderSet.insert(CompletingArchonsummon); orderSet.insert(HoldPosition); orderSet.insert(Cloak); orderSet.insert(Decloak); orderSet.insert(Unload); orderSet.insert(MoveUnload); orderSet.insert(FireYamatoGun); orderSet.insert(CastLockdown); orderSet.insert(Burrowing); orderSet.insert(Burrowed); orderSet.insert(Unburrowing); orderSet.insert(CastDarkSwarm); orderSet.insert(CastParasite); orderSet.insert(CastSpawnBroodlings); orderSet.insert(CastEMPShockwave); orderSet.insert(NukeWait); orderSet.insert(NukeTrain); orderSet.insert(NukeLaunch); orderSet.insert(NukeUnit); orderSet.insert(CastNuclearStrike); orderSet.insert(NukeTrack); orderSet.insert(CloakNearbyUnits); orderSet.insert(PlaceMine); orderSet.insert(RightClickAction); orderSet.insert(CastRecall); orderSet.insert(TeleporttoLocation); orderSet.insert(CastScannerSweep); orderSet.insert(Scanner); orderSet.insert(CastDefensiveMatrix); orderSet.insert(CastPsionicStorm); orderSet.insert(CastIrradiate); orderSet.insert(CastPlague); orderSet.insert(CastConsume); orderSet.insert(CastEnsnare); orderSet.insert(CastStasisField); orderSet.insert(CastHallucination); orderSet.insert(Hallucination2); orderSet.insert(ResetCollision); orderSet.insert(Patrol); orderSet.insert(CTFCOPInit); orderSet.insert(CTFCOP1); orderSet.insert(CTFCOP2); orderSet.insert(ComputerAI); orderSet.insert(AtkMoveEP); orderSet.insert(HarassMove); orderSet.insert(AIPatrol); orderSet.insert(GuardPost); orderSet.insert(RescuePassive); orderSet.insert(Neutral); orderSet.insert(ComputerReturn); orderSet.insert(SelfDestrucing); orderSet.insert(Critter); orderSet.insert(HiddenGun); orderSet.insert(OpenDoor); orderSet.insert(CloseDoor); orderSet.insert(HideTrap); orderSet.insert(RevealTrap); orderSet.insert(Enabledoodad); orderSet.insert(Disabledoodad); orderSet.insert(Warpin); orderSet.insert(Medic); orderSet.insert(MedicHeal1); orderSet.insert(HealMove); orderSet.insert(MedicHeal2); orderSet.insert(CastRestoration); orderSet.insert(CastDisruptionWeb); orderSet.insert(CastMindControl); orderSet.insert(DarkArchonMeld); orderSet.insert(CastFeedback); orderSet.insert(CastOpticalFlare); orderSet.insert(CastMaelstrom); orderSet.insert(JunkYardDog); orderSet.insert(Fatal); orderSet.insert(None); orderSet.insert(Unknown); foreach(Order i, orderSet) { std::string name = i.getName(); fixName(&name); orderMap.insert(std::make_pair(name, i)); } initializingOrder = false; } } Order::Order() { this->id = Orders::None.id; } Order::Order(int id) { this->id = id; if (!initializingOrder && (id < 0 || id >= 191 || orderName[id].length() == 0)) this->id = Orders::Unknown.id; } Order::Order(const Order& other) { this->id = other.id; } Order& Order::operator=(const Order& other) { this->id = other.id; return *this; } bool Order::operator==(const Order& other) const { return this->id == other.id; } bool Order::operator!=(const Order& other) const { return this->id != other.id; } bool Order::operator<(const Order& other) const { return this->id < other.id; } int Order::getID() const { return this->id; } std::string Order::getName() const { return orderName[this->id]; } Order Orders::getOrder(std::string name) { fixName(&name); std::map::iterator i = orderMap.find(name); if (i == orderMap.end()) return Orders::Unknown; return (*i).second; } std::set& Orders::allOrders() { return orderSet; } } ================================================ FILE: SparCraft/bwapidata/include/PlayerType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingPlayerType = true; std::string playerTypeName[13]; std::map playerTypeMap; std::set< PlayerType > playerTypeSet; namespace PlayerTypes { const PlayerType None(0); const PlayerType Computer(1); const PlayerType Player(2); const PlayerType RescuePassive(3); const PlayerType EitherPreferComputer(5); const PlayerType EitherPreferHuman(6); const PlayerType Neutral(7); const PlayerType Closed(8); const PlayerType PlayerLeft(10); const PlayerType ComputerLeft(11); const PlayerType Unknown(12); void init() { playerTypeName[None.getID()] = "None"; playerTypeName[Computer.getID()] = "Computer"; playerTypeName[Player.getID()] = "Player"; playerTypeName[RescuePassive.getID()] = "RescuePassive"; playerTypeName[EitherPreferComputer.getID()] = "EitherPreferComputer"; playerTypeName[EitherPreferHuman.getID()] = "EitherPreferHuman"; playerTypeName[Neutral.getID()] = "Neutral"; playerTypeName[Closed.getID()] = "Closed"; playerTypeName[PlayerLeft.getID()] = "PlayerLeft"; playerTypeName[ComputerLeft.getID()] = "ComputerLeft"; playerTypeName[Unknown.getID()] = "Unknown"; playerTypeSet.insert(None); playerTypeSet.insert(Computer); playerTypeSet.insert(Player); playerTypeSet.insert(RescuePassive); playerTypeSet.insert(EitherPreferComputer); playerTypeSet.insert(EitherPreferHuman); playerTypeSet.insert(Neutral); playerTypeSet.insert(Closed); playerTypeSet.insert(PlayerLeft); playerTypeSet.insert(ComputerLeft); playerTypeSet.insert(Unknown); foreach(PlayerType i, playerTypeSet) { std::string name = i.getName(); fixName(&name); playerTypeMap.insert(std::make_pair(name, i)); } initializingPlayerType = false; } } PlayerType::PlayerType() { this->id = PlayerTypes::None.id; } PlayerType::PlayerType(int id) { this->id = id; if (!initializingPlayerType && (id < 0 || id >= 13 || playerTypeName[id].length() == 0) ) this->id = PlayerTypes::Unknown.id; } PlayerType::PlayerType(const PlayerType& other) { this->id = other.id; } PlayerType& PlayerType::operator=(const PlayerType& other) { this->id = other.id; return *this; } bool PlayerType::operator==(const PlayerType& other) const { return this->id == other.id; } bool PlayerType::operator!=(const PlayerType& other) const { return this->id != other.id; } bool PlayerType::operator<(const PlayerType& other) const { return this->id < other.id; } int PlayerType::getID() const { return this->id; } std::string PlayerType::getName() const { return playerTypeName[this->id]; } PlayerType PlayerTypes::getPlayerType(std::string name) { fixName(&name); std::map::iterator i = playerTypeMap.find(name); if (i == playerTypeMap.end()) return PlayerTypes::Unknown; return (*i).second; } std::set& PlayerTypes::allPlayerTypes() { return playerTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/Position.cpp ================================================ #include #include #include #include #include #include namespace BWAPI { namespace Positions { const Position Invalid(32000, 32000); const Position None(32000, 32032); const Position Unknown(32000, 32064); } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Position::Position() : _x(0) , _y(0) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Position::Position(const TilePosition& position) : _x(position.x()*TILE_SIZE) , _y(position.y()*TILE_SIZE) { } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- Position::Position(int x, int y) : _x(x) , _y(y) { } //---------------------------------------------- OPERATOR == ----------------------------------------------- bool Position::operator == (const Position& position) const { return this->x() == position.x() && this->y() == position.y(); } //---------------------------------------------- OPERATOR != ----------------------------------------------- bool Position::operator != (const Position& position) const { return this->x() != position.x() || this->y() != position.y(); } //---------------------------------------------- OPERATOR < ------------------------------------------------ bool Position::operator < (const Position& position) const { return this->x() < position.x() || (this->x() == position.x() && this->y() < position.y()); } //---------------------------------------------- IS VALID -------------------------------------------------- bool Position::isValid() const { return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth()*32 && _y < Broodwar->mapHeight()*32); } //---------------------------------------------------------------------------------------------------------- Position Position::operator+(const Position& position) const { return Position(this->x() + position.x(), this->y() + position.y()); } //---------------------------------------------------------------------------------------------------------- Position Position::operator-(const Position& position) const { return Position(this->x() - position.x(), this->y() - position.y()); } //-------------------------------------------- MAKE VALID -------------------------------------------------- Position& Position::makeValid() { if (_x > Broodwar->mapWidth()*32 - 1) _x = Broodwar->mapWidth()*32 - 1; if (_y > Broodwar->mapHeight()*32 - 1) _y = Broodwar->mapHeight()*32 - 1; if (_x < 0) _x = 0; if (_y < 0) _y = 0; return *this; } //---------------------------------------------------------------------------------------------------------- Position& Position::operator+=(const Position& position) { this->x() += position.x(); this->y() += position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- Position& Position::operator-=(const Position& position) { this->x() -= position.x(); this->y() -= position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- double Position::getDistance(const Position& position) const { return ((*this) - position).getLength(); } //---------------------------------------------------------------------------------------------------------- double Position::getApproxDistance(const Position& position) const { double min = abs(this->x() - position.x()); double max = abs(this->y() - position.y()); if (max < min) { double temp = min; min = max; max = temp; } if (min < max*0.25) return max; return min*0.4 + max*0.9; } //---------------------------------------------------------------------------------------------------------- double Position::getLength() const { double x = this->x(); double y = this->y(); return sqrt(x * x + y * y); } //---------------------------------------------------------------------------------------------------------- int& Position::x() { return this->_x; } //---------------------------------------------------------------------------------------------------------- int& Position::y() { return this->_y; } //---------------------------------------------------------------------------------------------------------- int Position::x() const { return this->_x; } //---------------------------------------------------------------------------------------------------------- int Position::y() const { return this->_y; } //---------------------------------------------------------------------------------------------------------- }; ================================================ FILE: SparCraft/bwapidata/include/Race.cpp ================================================ #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingRace = true; class RaceInternal { public: void set(const char* name, UnitType worker, UnitType center, UnitType refinery, UnitType transport, UnitType supplyProvider) { if (initializingRace) { this->name = name; this->worker = worker; this->center = center; this->refinery = refinery; this->transport = transport; this->supplyProvider = supplyProvider; } } std::string name; UnitType worker; UnitType center; UnitType refinery; UnitType transport; UnitType supplyProvider; }; RaceInternal raceData[7]; std::map raceMap; std::set< Race > raceSet; namespace Races { const Race Zerg(0); const Race Terran(1); const Race Protoss(2); const Race Random(3); const Race Other(4); const Race None(5); const Race Unknown(6); void init() { raceData[Zerg.getID()].set( "Zerg", UnitTypes::Zerg_Drone, UnitTypes::Zerg_Hatchery, UnitTypes::Zerg_Extractor, UnitTypes::Zerg_Overlord, UnitTypes::Zerg_Overlord); raceData[Terran.getID()].set( "Terran", UnitTypes::Terran_SCV, UnitTypes::Terran_Command_Center, UnitTypes::Terran_Refinery, UnitTypes::Terran_Dropship, UnitTypes::Terran_Supply_Depot); raceData[Protoss.getID()].set("Protoss", UnitTypes::Protoss_Probe, UnitTypes::Protoss_Nexus, UnitTypes::Protoss_Assimilator, UnitTypes::Protoss_Shuttle, UnitTypes::Protoss_Pylon); raceData[Random.getID()].set( "Random", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceData[Other.getID()].set( "Other", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceData[None.getID()].set( "None", UnitTypes::None, UnitTypes::None, UnitTypes::None, UnitTypes::None, UnitTypes::None); raceData[Unknown.getID()].set("Unknown", UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown, UnitTypes::Unknown); raceSet.insert(Zerg); raceSet.insert(Terran); raceSet.insert(Protoss); raceSet.insert(Other); raceSet.insert(None); raceSet.insert(Unknown); foreach(Race i, raceSet) { std::string name = i.getName(); fixName(&name); raceMap.insert(std::make_pair(name, i)); } initializingRace = false; } } Race::Race() { this->id = Races::None.id; } Race::Race(int id) { this->id = id; if (!initializingRace && (id < 0 || id >= 7) ) this->id = Races::Unknown.id; } Race::Race(const Race& other) { this->id = other.id; } Race& Race::operator=(const Race& other) { this->id = other.id; return *this; } bool Race::operator==(const Race& other) const { return this->id == other.id; } bool Race::operator!=(const Race& other) const { return this->id != other.id; } bool Race::operator<(const Race& other) const { return this->id < other.id; } int Race::getID() const { return this->id; } std::string Race::getName() const { return raceData[this->id].name; } UnitType Race::getWorker() const { return raceData[this->id].worker; } UnitType Race::getCenter() const { return raceData[this->id].center; } UnitType Race::getRefinery() const { return raceData[this->id].refinery; } UnitType Race::getTransport() const { return raceData[this->id].transport; } UnitType Race::getSupplyProvider() const { return raceData[this->id].supplyProvider; } Race Races::getRace(std::string name) { fixName(&name); std::map::iterator i = raceMap.find(name); if (i == raceMap.end()) return Races::Unknown; return (*i).second; } std::set& Races::allRaces() { return raceSet; } } ================================================ FILE: SparCraft/bwapidata/include/TechType.cpp ================================================ #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingTechType = true; class TechTypeInternal { public: TechTypeInternal() {valid = false;} void set(const char* name, int mineralPrice, int gasPrice, int researchTime, int energyUsed, UnitType whatResearches, Race race, WeaponType weapon, UnitType whatUses1, UnitType whatUses2=UnitTypes::None, UnitType whatUses3=UnitTypes::None, UnitType whatUses4=UnitTypes::None, UnitType whatUses5=UnitTypes::None, UnitType whatUses6=UnitTypes::None) { this->name = name; this->mineralPrice = mineralPrice; this->gasPrice = gasPrice; this->researchTime = researchTime; this->energyUsed = energyUsed; this->whatResearches = whatResearches; this->race = race; this->weapon = weapon; if (whatUses1 != UnitTypes::None) this->whatUses.insert(whatUses1); if (whatUses2 != UnitTypes::None) this->whatUses.insert(whatUses2); if (whatUses3 != UnitTypes::None) this->whatUses.insert(whatUses3); if (whatUses4 != UnitTypes::None) this->whatUses.insert(whatUses4); if (whatUses5 != UnitTypes::None) this->whatUses.insert(whatUses5); if (whatUses6 != UnitTypes::None) this->whatUses.insert(whatUses6); this->valid = true; } std::string name; int mineralPrice; int gasPrice; int researchTime; int energyUsed; UnitType whatResearches; Race race; WeaponType weapon; std::set whatUses; bool valid; }; TechTypeInternal techTypeData[47]; std::map techTypeMap; std::set< TechType > techTypeSet; namespace TechTypes { const TechType Stim_Packs(0); const TechType Lockdown(1); const TechType EMP_Shockwave(2); const TechType Spider_Mines(3); const TechType Scanner_Sweep(4); const TechType Tank_Siege_Mode(5); const TechType Defensive_Matrix(6); const TechType Irradiate(7); const TechType Yamato_Gun(8); const TechType Cloaking_Field(9); const TechType Personnel_Cloaking(10); const TechType Burrowing(11); const TechType Infestation(12); const TechType Spawn_Broodlings(13); const TechType Dark_Swarm(14); const TechType Plague(15); const TechType Consume(16); const TechType Ensnare(17); const TechType Parasite(18); const TechType Psionic_Storm(19); const TechType Hallucination(20); const TechType Recall(21); const TechType Stasis_Field(22); const TechType Archon_Warp(23); const TechType Restoration(24); const TechType Disruption_Web(25); const TechType Mind_Control(27); const TechType Dark_Archon_Meld(28); const TechType Feedback(29); const TechType Optical_Flare(30); const TechType Maelstrom(31); const TechType Lurker_Aspect(32); const TechType Healing(34); const TechType None(44); const TechType Unknown(45); const TechType Nuclear_Strike(46); void init() { techTypeData[Stim_Packs.getID()].set("Stim Packs" ,100,100,1200,0 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Marine, UnitTypes::Terran_Firebat, UnitTypes::Hero_Jim_Raynor_Marine, UnitTypes::Hero_Gui_Montag); techTypeData[Lockdown.getID()].set("Lockdown" ,200,200,1500,100,UnitTypes::Terran_Covert_Ops ,Races::Terran ,WeaponTypes::Lockdown ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan); techTypeData[EMP_Shockwave.getID()].set("EMP Shockwave" ,200,200,1800,100,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::EMP_Shockwave ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Spider_Mines.getID()].set("Spider Mines" ,100,100,1200,0 ,UnitTypes::Terran_Machine_Shop ,Races::Terran ,WeaponTypes::Spider_Mines ,UnitTypes::Terran_Vulture, UnitTypes::Hero_Jim_Raynor_Vulture); techTypeData[Scanner_Sweep.getID()].set("Scanner Sweep" ,0 ,0 ,0 ,50 ,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Comsat_Station); techTypeData[Tank_Siege_Mode.getID()].set("Tank Siege Mode" ,150,150,1200,0 ,UnitTypes::Terran_Machine_Shop ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Siege_Tank_Tank_Mode, UnitTypes::Terran_Siege_Tank_Siege_Mode, UnitTypes::Hero_Edmund_Duke_Tank_Mode, UnitTypes::Hero_Edmund_Duke_Siege_Mode); techTypeData[Defensive_Matrix.getID()].set("Defensive Matrix" ,0 ,0 ,0 ,100,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Irradiate.getID()].set("Irradiate" ,200,200,1200,75 ,UnitTypes::Terran_Science_Facility ,Races::Terran ,WeaponTypes::Irradiate ,UnitTypes::Terran_Science_Vessel, UnitTypes::Hero_Magellan); techTypeData[Yamato_Gun.getID()].set("Yamato Gun" ,100,100,1800,150,UnitTypes::Terran_Physics_Lab ,Races::Terran ,WeaponTypes::Yamato_Gun ,UnitTypes::Terran_Battlecruiser, UnitTypes::Hero_Gerard_DuGalle, UnitTypes::Hero_Hyperion, UnitTypes::Hero_Norad_II); techTypeData[Cloaking_Field.getID()].set("Cloaking Field" ,150,150,1500,25 ,UnitTypes::Terran_Control_Tower ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Wraith, UnitTypes::Hero_Tom_Kazansky); techTypeData[Personnel_Cloaking.getID()].set("Personnel Cloaking",100,100,1200,25 ,UnitTypes::Terran_Covert_Ops ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Ghost, UnitTypes::Hero_Alexei_Stukov, UnitTypes::Hero_Infested_Duran, UnitTypes::Hero_Samir_Duran, UnitTypes::Hero_Sarah_Kerrigan, UnitTypes::Hero_Infested_Kerrigan); techTypeData[Burrowing.getID()].set("Burrowing" ,100,100,1200,0 ,UnitTypes::Zerg_Hatchery ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Drone, UnitTypes::Zerg_Zergling, UnitTypes::Zerg_Hydralisk, UnitTypes::Zerg_Defiler, UnitTypes::Zerg_Infested_Terran, UnitTypes::Zerg_Lurker); techTypeData[Infestation.getID()].set("Infestation" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Spawn_Broodlings.getID()].set("Spawn Broodlings" ,100,100,1200,150,UnitTypes::Zerg_Queens_Nest ,Races::Zerg ,WeaponTypes::Spawn_Broodlings,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Dark_Swarm.getID()].set("Dark Swarm" ,0 ,0 ,0 ,100,UnitTypes::None ,Races::Zerg ,WeaponTypes::Dark_Swarm ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Plague.getID()].set("Plague" ,200,200,1500,150,UnitTypes::Zerg_Defiler_Mound ,Races::Zerg ,WeaponTypes::Plague ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Consume.getID()].set("Consume" ,100,100,1500,0 ,UnitTypes::Zerg_Defiler_Mound ,Races::Zerg ,WeaponTypes::Consume ,UnitTypes::Zerg_Defiler, UnitTypes::Hero_Unclean_One); techTypeData[Ensnare.getID()].set("Ensnare" ,100,100,1200,75 ,UnitTypes::Zerg_Queens_Nest ,Races::Zerg ,WeaponTypes::Ensnare ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Parasite.getID()].set("Parasite" ,0 ,0 ,0 ,75 ,UnitTypes::None ,Races::Zerg ,WeaponTypes::Parasite ,UnitTypes::Zerg_Queen, UnitTypes::Hero_Matriarch); techTypeData[Psionic_Storm.getID()].set("Psionic Storm" ,200,200,1800,75 ,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Psionic_Storm ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar); techTypeData[Hallucination.getID()].set("Hallucination" ,150,150,1200,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_High_Templar, UnitTypes::Hero_Tassadar); techTypeData[Recall.getID()].set("Recall" ,150,150,1800,150,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth); techTypeData[Stasis_Field.getID()].set("Stasis Field" ,150,150,1500,100,UnitTypes::Protoss_Arbiter_Tribunal,Races::Protoss,WeaponTypes::Stasis_Field ,UnitTypes::Protoss_Arbiter, UnitTypes::Hero_Danimoth); techTypeData[Archon_Warp.getID()].set("Archon Warp" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_High_Templar); techTypeData[Restoration.getID()].set("Restoration" ,100,100,1200,50 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::Restoration ,UnitTypes::Terran_Medic); techTypeData[Disruption_Web.getID()].set("Disruption Web" ,200,200,1200,125,UnitTypes::Protoss_Fleet_Beacon ,Races::Protoss,WeaponTypes::Disruption_Web ,UnitTypes::Protoss_Corsair, UnitTypes::Hero_Raszagal); techTypeData[Mind_Control.getID()].set("Mind Control" ,200,200,1800,150,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Mind_Control ,UnitTypes::Protoss_Dark_Archon); techTypeData[Dark_Archon_Meld.getID()].set("Dark Archon Meld" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Protoss,WeaponTypes::None ,UnitTypes::Protoss_Dark_Templar); techTypeData[Feedback.getID()].set("Feedback" ,0 ,0 ,0 ,50 ,UnitTypes::None ,Races::Protoss,WeaponTypes::Feedback ,UnitTypes::Protoss_Dark_Archon); techTypeData[Optical_Flare.getID()].set("Optical Flare" ,100,100,1800,75 ,UnitTypes::Terran_Academy ,Races::Terran ,WeaponTypes::Optical_Flare ,UnitTypes::Terran_Medic); techTypeData[Maelstrom.getID()].set("Maelstrom" ,100,100,1500,100,UnitTypes::Protoss_Templar_Archives,Races::Protoss,WeaponTypes::Maelstrom ,UnitTypes::Protoss_Dark_Archon); techTypeData[Lurker_Aspect.getID()].set("Lurker Aspect" ,200,200,1800,0 ,UnitTypes::Zerg_Hydralisk_Den ,Races::Zerg ,WeaponTypes::None ,UnitTypes::Zerg_Lurker); techTypeData[Healing.getID()].set("Healing" ,0 ,0 ,0 ,1 ,UnitTypes::None ,Races::Terran ,WeaponTypes::None ,UnitTypes::Terran_Medic); techTypeData[None.getID()].set("None" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::None ,WeaponTypes::None ,UnitTypes::None); techTypeData[Unknown.getID()].set("Unknown" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Unknown,WeaponTypes::None ,UnitTypes::None); techTypeData[Nuclear_Strike.getID()].set("Nuclear Strike" ,0 ,0 ,0 ,0 ,UnitTypes::None ,Races::Terran ,WeaponTypes::Nuclear_Strike ,UnitTypes::Terran_Ghost); techTypeSet.insert(Stim_Packs); techTypeSet.insert(Lockdown); techTypeSet.insert(EMP_Shockwave); techTypeSet.insert(Spider_Mines); techTypeSet.insert(Scanner_Sweep); techTypeSet.insert(Tank_Siege_Mode); techTypeSet.insert(Defensive_Matrix); techTypeSet.insert(Irradiate); techTypeSet.insert(Yamato_Gun); techTypeSet.insert(Cloaking_Field); techTypeSet.insert(Personnel_Cloaking); techTypeSet.insert(Burrowing); techTypeSet.insert(Infestation); techTypeSet.insert(Spawn_Broodlings); techTypeSet.insert(Dark_Swarm); techTypeSet.insert(Plague); techTypeSet.insert(Consume); techTypeSet.insert(Ensnare); techTypeSet.insert(Parasite); techTypeSet.insert(Psionic_Storm); techTypeSet.insert(Hallucination); techTypeSet.insert(Recall); techTypeSet.insert(Stasis_Field); techTypeSet.insert(Archon_Warp); techTypeSet.insert(Restoration); techTypeSet.insert(Disruption_Web); techTypeSet.insert(Mind_Control); techTypeSet.insert(Dark_Archon_Meld); techTypeSet.insert(Feedback); techTypeSet.insert(Optical_Flare); techTypeSet.insert(Maelstrom); techTypeSet.insert(Lurker_Aspect); techTypeSet.insert(Healing); techTypeSet.insert(None); techTypeSet.insert(Unknown); techTypeSet.insert(Nuclear_Strike); foreach(TechType i, techTypeSet) { std::string name = i.getName(); fixName(&name); techTypeMap.insert(std::make_pair(name, i)); } initializingTechType = false; } } TechType::TechType() { this->id = TechTypes::None.id; } TechType::TechType(int id) { this->id = id; if (!initializingTechType && (id < 0 || id >= 47 || techTypeData[id].name.length() == 0)) this->id = TechTypes::Unknown.id; } TechType::TechType(const TechType& other) { this->id = other.id; } TechType& TechType::operator=(const TechType& other) { this->id = other.id; return *this; } bool TechType::operator==(const TechType& other) const { return this->id == other.id; } bool TechType::operator!=(const TechType& other) const { return this->id != other.id; } bool TechType::operator<(const TechType& other) const { return this->id < other.id; } int TechType::getID() const { return this->id; } std::string TechType::getName() const { return techTypeData[this->id].name; } Race TechType::getRace() const { return techTypeData[this->id].race; } int TechType::mineralPrice() const { return techTypeData[this->id].mineralPrice; } int TechType::gasPrice() const { return techTypeData[this->id].gasPrice; } int TechType::researchTime() const { return techTypeData[this->id].researchTime; } int TechType::energyUsed() const { return techTypeData[this->id].energyUsed; } UnitType TechType::whatResearches() const { return techTypeData[this->id].whatResearches; } WeaponType TechType::getWeapon() const { return techTypeData[this->id].weapon; } const std::set& TechType::whatUses() const { return techTypeData[this->id].whatUses; } TechType TechTypes::getTechType(std::string name) { fixName(&name); std::map::iterator i = techTypeMap.find(name); if (i == techTypeMap.end()) return TechTypes::Unknown; return (*i).second; } std::set& TechTypes::allTechTypes() { return techTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/TilePosition.cpp ================================================ #include #include #include #include #include namespace BWAPI { namespace TilePositions { const TilePosition Invalid(1000, 1000); const TilePosition None(1000, 1001); const TilePosition Unknown(1000, 1002); } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition() : _x(0) , _y(0) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition(int x, int y) : _x(x) , _y(y) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- TilePosition::TilePosition(const Position& position) : _x(position.x() / TILE_SIZE) , _y(position.y() / TILE_SIZE) { } //---------------------------------------------- OPERATOR == ----------------------------------------------- bool TilePosition::operator == (const TilePosition& TilePosition) const { return this->x() == TilePosition.x() && this->y() == TilePosition.y(); } //---------------------------------------------- OPERATOR != ----------------------------------------------- bool TilePosition::operator != (const TilePosition& TilePosition) const { return this->x() != TilePosition.x() || this->y() != TilePosition.y(); } //---------------------------------------------- OPERATOR < ------------------------------------------------ bool TilePosition::operator < (const TilePosition& TilePosition) const { return this->x() < TilePosition.x() || (this->x() == TilePosition.x() && this->y() < TilePosition.y()); } //---------------------------------------------- IS VALID -------------------------------------------------- bool TilePosition::isValid() const { return (_x >= 0 && _y >= 0 && _x < Broodwar->mapWidth() && _y < Broodwar->mapHeight()); } //---------------------------------------------------------------------------------------------------------- TilePosition TilePosition::operator+(const TilePosition& position) const { return TilePosition(this->x() + position.x(), this->y() + position.y()); } //---------------------------------------------------------------------------------------------------------- TilePosition TilePosition::operator-(const TilePosition& position) const { return TilePosition(this->x() - position.x(), this->y() - position.y()); } //-------------------------------------------- MAKE VALID -------------------------------------------------- TilePosition& TilePosition::makeValid() { if (_x > Broodwar->mapWidth() - 1) _x = Broodwar->mapWidth() - 1; if (_y > Broodwar->mapHeight() - 1) _y = Broodwar->mapHeight() - 1; if (_x < 0) _x = 0; if (_y < 0) _y = 0; return *this; } //---------------------------------------------------------------------------------------------------------- TilePosition& TilePosition::operator+=(const TilePosition& position) { this->x() += position.x(); this->y() += position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- TilePosition& TilePosition::operator-=(const TilePosition& position) { this->x() -= position.x(); this->y() -= position.y(); return *this; } //---------------------------------------------------------------------------------------------------------- double TilePosition::getDistance(const TilePosition& position) const { return ((*this) - position).getLength(); } //---------------------------------------------------------------------------------------------------------- double TilePosition::getLength() const { double x = this->x(); double y = this->y(); return sqrt(x * x + y * y); } //---------------------------------------------------------------------------------------------------------- int& TilePosition::x() { return this->_x; } //---------------------------------------------------------------------------------------------------------- int& TilePosition::y() { return this->_y; } //---------------------------------------------------------------------------------------------------------- int TilePosition::x() const { return this->_x; } //---------------------------------------------------------------------------------------------------------- int TilePosition::y() const { return this->_y; } //---------------------------------------------------------------------------------------------------------- }; ================================================ FILE: SparCraft/bwapidata/include/UnitCommandType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitCommandType = true; std::string unitCommandTypeName[45]; std::map unitCommandTypeMap; std::set< UnitCommandType > unitCommandTypeSet; namespace UnitCommandTypes { const UnitCommandType Attack_Move(0); const UnitCommandType Attack_Unit(1); const UnitCommandType Build(2); const UnitCommandType Build_Addon(3); const UnitCommandType Train(4); const UnitCommandType Morph(5); const UnitCommandType Research(6); const UnitCommandType Upgrade(7); const UnitCommandType Set_Rally_Position(8); const UnitCommandType Set_Rally_Unit(9); const UnitCommandType Move(10); const UnitCommandType Patrol(11); const UnitCommandType Hold_Position(12); const UnitCommandType Stop(13); const UnitCommandType Follow(14); const UnitCommandType Gather(15); const UnitCommandType Return_Cargo(16); const UnitCommandType Repair(17); const UnitCommandType Burrow(18); const UnitCommandType Unburrow(19); const UnitCommandType Cloak(20); const UnitCommandType Decloak(21); const UnitCommandType Siege(22); const UnitCommandType Unsiege(23); const UnitCommandType Lift(24); const UnitCommandType Land(25); const UnitCommandType Load(26); const UnitCommandType Unload(27); const UnitCommandType Unload_All(28); const UnitCommandType Unload_All_Position(29); const UnitCommandType Right_Click_Position(30); const UnitCommandType Right_Click_Unit(31); const UnitCommandType Halt_Construction(32); const UnitCommandType Cancel_Construction(33); const UnitCommandType Cancel_Addon(34); const UnitCommandType Cancel_Train(35); const UnitCommandType Cancel_Train_Slot(36); const UnitCommandType Cancel_Morph(37); const UnitCommandType Cancel_Research(38); const UnitCommandType Cancel_Upgrade(39); const UnitCommandType Use_Tech(40); const UnitCommandType Use_Tech_Position(41); const UnitCommandType Use_Tech_Unit(42); const UnitCommandType None(43); const UnitCommandType Unknown(44); void init() { unitCommandTypeName[Attack_Move.getID()] = "Attack Move"; unitCommandTypeName[Attack_Unit.getID()] = "Attack Unit"; unitCommandTypeName[Build.getID()] = "Build"; unitCommandTypeName[Build_Addon.getID()] = "Build Addon"; unitCommandTypeName[Train.getID()] = "Train"; unitCommandTypeName[Morph.getID()] = "Morph"; unitCommandTypeName[Research.getID()] = "Research"; unitCommandTypeName[Upgrade.getID()] = "Upgrade"; unitCommandTypeName[Set_Rally_Position.getID()] = "Set Rally Position"; unitCommandTypeName[Set_Rally_Unit.getID()] = "Set Rally Unit"; unitCommandTypeName[Move.getID()] = "Move"; unitCommandTypeName[Patrol.getID()] = "Patrol"; unitCommandTypeName[Hold_Position.getID()] = "Hold Position"; unitCommandTypeName[Stop.getID()] = "Stop"; unitCommandTypeName[Follow.getID()] = "Follow"; unitCommandTypeName[Gather.getID()] = "Gather"; unitCommandTypeName[Return_Cargo.getID()] = "Return Cargo"; unitCommandTypeName[Repair.getID()] = "Repair"; unitCommandTypeName[Burrow.getID()] = "Burrow"; unitCommandTypeName[Unburrow.getID()] = "Unburrow"; unitCommandTypeName[Cloak.getID()] = "Cloak"; unitCommandTypeName[Decloak.getID()] = "Decloak"; unitCommandTypeName[Siege.getID()] = "Siege"; unitCommandTypeName[Unsiege.getID()] = "Unsiege"; unitCommandTypeName[Lift.getID()] = "Lift"; unitCommandTypeName[Land.getID()] = "Land"; unitCommandTypeName[Load.getID()] = "Load"; unitCommandTypeName[Unload.getID()] = "Unload"; unitCommandTypeName[Unload_All.getID()] = "Unload All"; unitCommandTypeName[Unload_All_Position.getID()] = "Unload All Position"; unitCommandTypeName[Right_Click_Position.getID()] = "Right Click Position"; unitCommandTypeName[Right_Click_Unit.getID()] = "Right Click Unit"; unitCommandTypeName[Halt_Construction.getID()] = "Halt Construction"; unitCommandTypeName[Cancel_Construction.getID()] = "Cancel Construction"; unitCommandTypeName[Cancel_Addon.getID()] = "Cancel Addon"; unitCommandTypeName[Cancel_Train.getID()] = "Cancel Train"; unitCommandTypeName[Cancel_Train_Slot.getID()] = "Cancel Train Slot"; unitCommandTypeName[Cancel_Morph.getID()] = "Cancel Morph"; unitCommandTypeName[Cancel_Research.getID()] = "Cancel Research"; unitCommandTypeName[Cancel_Upgrade.getID()] = "Cancel Upgrade"; unitCommandTypeName[Use_Tech.getID()] = "Use Tech"; unitCommandTypeName[Use_Tech_Position.getID()] = "Use Tech Position"; unitCommandTypeName[Use_Tech_Unit.getID()] = "Use Tech Unit"; unitCommandTypeName[None.getID()] = "None"; unitCommandTypeName[Unknown.getID()] = "Unknown"; unitCommandTypeSet.insert(Attack_Move); unitCommandTypeSet.insert(Attack_Unit); unitCommandTypeSet.insert(Build); unitCommandTypeSet.insert(Build_Addon); unitCommandTypeSet.insert(Train); unitCommandTypeSet.insert(Morph); unitCommandTypeSet.insert(Research); unitCommandTypeSet.insert(Upgrade); unitCommandTypeSet.insert(Set_Rally_Position); unitCommandTypeSet.insert(Set_Rally_Unit); unitCommandTypeSet.insert(Move); unitCommandTypeSet.insert(Patrol); unitCommandTypeSet.insert(Hold_Position); unitCommandTypeSet.insert(Stop); unitCommandTypeSet.insert(Follow); unitCommandTypeSet.insert(Gather); unitCommandTypeSet.insert(Return_Cargo); unitCommandTypeSet.insert(Repair); unitCommandTypeSet.insert(Burrow); unitCommandTypeSet.insert(Unburrow); unitCommandTypeSet.insert(Cloak); unitCommandTypeSet.insert(Decloak); unitCommandTypeSet.insert(Siege); unitCommandTypeSet.insert(Unsiege); unitCommandTypeSet.insert(Lift); unitCommandTypeSet.insert(Land); unitCommandTypeSet.insert(Load); unitCommandTypeSet.insert(Unload); unitCommandTypeSet.insert(Unload_All); unitCommandTypeSet.insert(Unload_All_Position); unitCommandTypeSet.insert(Right_Click_Position); unitCommandTypeSet.insert(Right_Click_Unit); unitCommandTypeSet.insert(Halt_Construction); unitCommandTypeSet.insert(Cancel_Construction); unitCommandTypeSet.insert(Cancel_Addon); unitCommandTypeSet.insert(Cancel_Train); unitCommandTypeSet.insert(Cancel_Train_Slot); unitCommandTypeSet.insert(Cancel_Morph); unitCommandTypeSet.insert(Cancel_Research); unitCommandTypeSet.insert(Cancel_Upgrade); unitCommandTypeSet.insert(Use_Tech); unitCommandTypeSet.insert(Use_Tech_Position); unitCommandTypeSet.insert(Use_Tech_Unit); unitCommandTypeSet.insert(None); unitCommandTypeSet.insert(Unknown); foreach(UnitCommandType i, unitCommandTypeSet) { std::string name = i.getName(); fixName(&name); unitCommandTypeMap.insert(std::make_pair(name, i)); } initializingUnitCommandType = false; } } UnitCommandType::UnitCommandType() { this->id = UnitCommandTypes::None.id; } UnitCommandType::UnitCommandType(int id) { this->id = id; if (!initializingUnitCommandType && (id < 0 || id >= 45)) this->id = UnitCommandTypes::Unknown.id; } UnitCommandType::UnitCommandType(const UnitCommandType& other) { this->id = other.id; } UnitCommandType& UnitCommandType::operator=(const UnitCommandType& other) { this->id = other.id; return *this; } bool UnitCommandType::operator==(const UnitCommandType& other) const { return this->id == other.id; } bool UnitCommandType::operator!=(const UnitCommandType& other) const { return this->id != other.id; } bool UnitCommandType::operator<(const UnitCommandType& other) const { return this->id < other.id; } int UnitCommandType::getID() const { return this->id; } std::string UnitCommandType::getName() const { return unitCommandTypeName[this->id]; } UnitCommandType UnitCommandTypes::getUnitCommandType(std::string name) { fixName(&name); std::map::iterator i = unitCommandTypeMap.find(name); if (i == unitCommandTypeMap.end()) return UnitCommandTypes::Unknown; return (*i).second; } std::set& UnitCommandTypes::allUnitCommandTypes() { return unitCommandTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/UnitSizeType.cpp ================================================ #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitSizeType = true; std::string unitSizeTypeName[6]; std::map unitSizeTypeMap; std::set< UnitSizeType > unitSizeTypeSet; namespace UnitSizeTypes { const UnitSizeType Independent(0); const UnitSizeType Small(1); const UnitSizeType Medium(2); const UnitSizeType Large(3); const UnitSizeType None(4); const UnitSizeType Unknown(5); void init() { unitSizeTypeName[Independent.getID()] = "Independent"; unitSizeTypeName[Small.getID()] = "Small"; unitSizeTypeName[Medium.getID()] = "Medium"; unitSizeTypeName[Large.getID()] = "Large"; unitSizeTypeName[None.getID()] = "None"; unitSizeTypeName[Unknown.getID()] = "Unknown"; unitSizeTypeSet.insert(Independent); unitSizeTypeSet.insert(Small); unitSizeTypeSet.insert(Medium); unitSizeTypeSet.insert(Large); unitSizeTypeSet.insert(None); unitSizeTypeSet.insert(Unknown); foreach(UnitSizeType i, unitSizeTypeSet) { std::string name = i.getName(); fixName(&name); unitSizeTypeMap.insert(std::make_pair(name, i)); } initializingUnitSizeType = false; } } UnitSizeType::UnitSizeType() { this->id = UnitSizeTypes::None.id; } UnitSizeType::UnitSizeType(int id) { this->id = id; if (!initializingUnitSizeType && (id < 0 || id >= 6)) this->id = UnitSizeTypes::Unknown.id; } UnitSizeType::UnitSizeType(const UnitSizeType& other) { this->id = other.id; } UnitSizeType& UnitSizeType::operator=(const UnitSizeType& other) { this->id = other.id; return *this; } bool UnitSizeType::operator==(const UnitSizeType& other) const { return this->id == other.id; } bool UnitSizeType::operator!=(const UnitSizeType& other) const { return this->id != other.id; } bool UnitSizeType::operator<(const UnitSizeType& other) const { return this->id < other.id; } int UnitSizeType::getID() const { return this->id; } std::string UnitSizeType::getName() const { return unitSizeTypeName[this->id]; } UnitSizeType UnitSizeTypes::getUnitSizeType(std::string name) { fixName(&name); std::map::iterator i = unitSizeTypeMap.find(name); if (i == unitSizeTypeMap.end()) return UnitSizeTypes::Unknown; return (*i).second; } std::set& UnitSizeTypes::allUnitSizeTypes() { return unitSizeTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/UnitType.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUnitType = true; class UnitTypeInternal { public: UnitTypeInternal() {valid = false;} void set(const char* name, Race race, bool isHero, UnitType whatBuilds, int whatBuildsAmt, UnitType requiredUnit1, UnitType requiredUnit2, TechType requiredTech, TechType ability1, TechType ability2, TechType ability3, TechType ability4, UpgradeType armorUpgrade, int maxHitPoints, int maxShields, int maxEnergy, int armor, int mineralPrice, int gasPrice, int buildTime, int supplyRequired, int supplyProvided, int spaceRequired, int spaceProvided, int buildScore, int destroyScore, UnitSizeType unitSizeType, int tileWidth, int tileHeight, int dimensionLeft, int dimensionUp, int dimensionRight, int dimensionDown, int seekRange, int sightRange, WeaponType groundWeapon, int maxGroundHits, WeaponType airWeapon, int maxAirHits, double topSpeed, int acceleration, int haltDistance, int turnRadius, bool canProduce, bool canMove, bool isFlyer, bool regeneratesHP, bool hasPermanentCloak, bool isInvincible, bool isOrganic, bool isMechanical, bool isRobotic, bool isDetector, bool isResourceContainer, bool isResourceDepot, bool isWorker, bool requiresPsi, bool requiresCreep, bool isTwoUnitsInOneEgg, bool isBurrowable, bool isCloakable, bool isBuilding, bool isAddon, bool isFlyingBuilding, bool isNeutral, bool isRefinery) { if (initializingUnitType) { this->name = name; this->race = race; this->isHero = isHero; this->whatBuilds = std::make_pair(whatBuilds, whatBuildsAmt); if ( whatBuilds != UnitTypes::None && whatBuildsAmt > 0 ) this->requiredUnits.insert(this->whatBuilds); if ( requiredUnit1 != UnitTypes::None ) this->requiredUnits.insert(std::make_pair(requiredUnit1, 1)); if ( requiredUnit2 != UnitTypes::None ) this->requiredUnits.insert(std::make_pair(requiredUnit2, 1)); this->requiredTech = requiredTech; if (ability1 != TechTypes::None) this->abilities.insert(ability1); if (ability2 != TechTypes::None) this->abilities.insert(ability2); if (ability3 != TechTypes::None) this->abilities.insert(ability3); if (ability4 != TechTypes::None) this->abilities.insert(ability4); this->cloakingTech = TechTypes::None; if ( this->abilities.find(TechTypes::Cloaking_Field) != this->abilities.end() ) cloakingTech = TechTypes::Cloaking_Field; if ( this->abilities.find(TechTypes::Personnel_Cloaking) != this->abilities.end() ) cloakingTech = TechTypes::Personnel_Cloaking; this->armorUpgrade = armorUpgrade; this->maxHitPoints = maxHitPoints; this->maxShields = maxShields; this->maxEnergy = maxEnergy; this->armor = armor; this->mineralPrice = mineralPrice; this->gasPrice = gasPrice; this->buildTime = buildTime; this->supplyRequired = supplyRequired; this->supplyProvided = supplyProvided; this->spaceRequired = spaceRequired; this->spaceProvided = spaceProvided; this->buildScore = buildScore; this->destroyScore = destroyScore; this->unitSizeType = unitSizeType; this->tileWidth = tileWidth; this->tileHeight = tileHeight; this->dimensionLeft = dimensionLeft; this->dimensionUp = dimensionUp; this->dimensionRight = dimensionRight; this->dimensionDown = dimensionDown; this->seekRange = seekRange; this->sightRange = sightRange; this->groundWeapon = groundWeapon; this->maxGroundHits = maxGroundHits; this->airWeapon = airWeapon; this->maxAirHits = maxAirHits; this->topSpeed = topSpeed; this->acceleration = acceleration; this->haltDistance = haltDistance; this->turnRadius = turnRadius; this->canProduce = canProduce; this->canAttack = groundWeapon != WeaponTypes::None || airWeapon != WeaponTypes::None; this->canMove = canMove; this->isFlyer = isFlyer; this->regeneratesHP = regeneratesHP; this->isSpellcaster = maxEnergy > 0; this->hasPermanentCloak = hasPermanentCloak; this->isInvincible = isInvincible; this->isOrganic = isOrganic; this->isMechanical = isMechanical; this->isRobotic = isRobotic; this->isDetector = isDetector; this->isResourceContainer = isResourceContainer; this->isResourceDepot = isResourceDepot; this->isWorker = isWorker; this->requiresPsi = requiresPsi; this->requiresCreep = requiresCreep; this->isTwoUnitsInOneEgg = isTwoUnitsInOneEgg; this->isBurrowable = isBurrowable; this->isCloakable = isCloakable; this->isBuilding = isBuilding; this->isAddon = isAddon; this->isFlyingBuilding = isFlyingBuilding; this->isNeutral = isNeutral; this->isRefinery = isRefinery; this->isSpecialBuilding = this->isBuilding && this->whatBuilds.second == 0; this->valid = true; } } std::string name; Race race; std::pair whatBuilds; std::map requiredUnits; TechType requiredTech; TechType cloakingTech; std::set abilities; std::set upgrades; UpgradeType armorUpgrade; int maxHitPoints; int maxShields; int maxEnergy; int armor; int mineralPrice; int gasPrice; int buildTime; int supplyRequired; int supplyProvided; int spaceRequired; int spaceProvided; int buildScore; int destroyScore; UnitSizeType unitSizeType; int tileWidth; int tileHeight; int dimensionLeft; int dimensionUp; int dimensionRight; int dimensionDown; int seekRange; int sightRange; WeaponType groundWeapon; int maxGroundHits; WeaponType airWeapon; int maxAirHits; double topSpeed; int acceleration; int haltDistance; int turnRadius; bool canProduce; bool canAttack; bool canMove; bool isFlyer; bool regeneratesHP; bool isSpellcaster; bool hasPermanentCloak; bool isInvincible; bool isOrganic; bool isMechanical; bool isRobotic; bool isDetector; bool isResourceContainer; bool isResourceDepot; bool isWorker; bool requiresPsi; bool requiresCreep; bool isTwoUnitsInOneEgg; bool isBurrowable; bool isCloakable; bool isBuilding; bool isAddon; bool isFlyingBuilding; bool isNeutral; bool isRefinery; bool isHero; bool isSpecialBuilding; bool valid; }; UnitTypeInternal unitTypeData[245]; std::map unitTypeMap; std::set< UnitType > unitTypeSet; namespace UnitTypes { const UnitType Terran_Marine(0); const UnitType Hero_Jim_Raynor_Marine(20); const UnitType Terran_Ghost(1); const UnitType Hero_Sarah_Kerrigan(16); const UnitType Hero_Samir_Duran(99); const UnitType Hero_Infested_Duran(104); const UnitType Hero_Alexei_Stukov(100); const UnitType Terran_Vulture(2); const UnitType Hero_Jim_Raynor_Vulture(19); const UnitType Terran_Goliath(3); const UnitType Hero_Alan_Schezar(17); const UnitType Terran_Siege_Tank_Tank_Mode(5); const UnitType Hero_Edmund_Duke_Tank_Mode(23); const UnitType Terran_SCV(7); const UnitType Terran_Wraith(8); const UnitType Hero_Tom_Kazansky(21); const UnitType Terran_Science_Vessel(9); const UnitType Hero_Magellan(22); const UnitType Terran_Dropship(11); const UnitType Terran_Battlecruiser(12); const UnitType Hero_Arcturus_Mengsk(27); const UnitType Hero_Hyperion(28); const UnitType Hero_Norad_II(29); const UnitType Hero_Gerard_DuGalle(102); const UnitType Terran_Vulture_Spider_Mine(13); const UnitType Terran_Nuclear_Missile(14); const UnitType Terran_Siege_Tank_Siege_Mode(30); const UnitType Hero_Edmund_Duke_Siege_Mode(25); const UnitType Terran_Firebat(32); const UnitType Hero_Gui_Montag(10); const UnitType Spell_Scanner_Sweep(33); const UnitType Terran_Medic(34); const UnitType Terran_Civilian(15); const UnitType Zerg_Larva(35); const UnitType Zerg_Egg(36); const UnitType Zerg_Zergling(37); const UnitType Hero_Devouring_One(54); const UnitType Hero_Infested_Kerrigan(51); const UnitType Zerg_Hydralisk(38); const UnitType Hero_Hunter_Killer(53); const UnitType Zerg_Ultralisk(39); const UnitType Hero_Torrasque(48); const UnitType Zerg_Broodling(40); const UnitType Zerg_Drone(41); const UnitType Zerg_Overlord(42); const UnitType Hero_Yggdrasill(57); const UnitType Zerg_Mutalisk(43); const UnitType Hero_Kukulza_Mutalisk(55); const UnitType Zerg_Guardian(44); const UnitType Hero_Kukulza_Guardian(56); const UnitType Zerg_Queen(45); const UnitType Hero_Matriarch(49); const UnitType Zerg_Defiler(46); const UnitType Hero_Unclean_One(52); const UnitType Zerg_Scourge(47); const UnitType Zerg_Infested_Terran(50); const UnitType Terran_Valkyrie(58); const UnitType Zerg_Cocoon(59); const UnitType Protoss_Corsair(60); const UnitType Hero_Raszagal(98); const UnitType Protoss_Dark_Templar(61); const UnitType Hero_Dark_Templar(74); const UnitType Hero_Zeratul(75); const UnitType Zerg_Devourer(62); const UnitType Protoss_Dark_Archon(63); const UnitType Protoss_Probe(64); const UnitType Protoss_Zealot(65); const UnitType Hero_Fenix_Zealot(77); const UnitType Protoss_Dragoon(66); const UnitType Hero_Fenix_Dragoon(78); const UnitType Protoss_High_Templar(67); const UnitType Hero_Tassadar(79); const UnitType Hero_Aldaris(87); const UnitType Protoss_Archon(68); const UnitType Hero_Tassadar_Zeratul_Archon(76); const UnitType Protoss_Shuttle(69); const UnitType Protoss_Scout(70); const UnitType Hero_Mojo(80); const UnitType Hero_Artanis(88); const UnitType Protoss_Arbiter(71); const UnitType Hero_Danimoth(86); const UnitType Protoss_Carrier(72); const UnitType Hero_Gantrithor(82); const UnitType Protoss_Interceptor(73); const UnitType Protoss_Reaver(83); const UnitType Hero_Warbringer(81); const UnitType Protoss_Observer(84); const UnitType Protoss_Scarab(85); const UnitType Critter_Rhynadon(89); const UnitType Critter_Bengalaas(90); const UnitType Critter_Scantid(93); const UnitType Critter_Kakaru(94); const UnitType Critter_Ragnasaur(95); const UnitType Critter_Ursadon(96); const UnitType Zerg_Lurker_Egg(97); const UnitType Zerg_Lurker(103); const UnitType Spell_Disruption_Web(105); const UnitType Terran_Command_Center(106); const UnitType Terran_Comsat_Station(107); const UnitType Terran_Nuclear_Silo(108); const UnitType Terran_Supply_Depot(109); const UnitType Terran_Refinery(110); const UnitType Terran_Barracks(111); const UnitType Terran_Academy(112); const UnitType Terran_Factory(113); const UnitType Terran_Starport(114); const UnitType Terran_Control_Tower(115); const UnitType Terran_Science_Facility(116); const UnitType Terran_Covert_Ops(117); const UnitType Terran_Physics_Lab(118); const UnitType Terran_Machine_Shop(120); const UnitType Terran_Engineering_Bay(122); const UnitType Terran_Armory(123); const UnitType Terran_Missile_Turret(124); const UnitType Terran_Bunker(125); const UnitType Special_Crashed_Norad_II(126); const UnitType Special_Ion_Cannon(127); const UnitType Zerg_Infested_Command_Center(130); const UnitType Zerg_Hatchery(131); const UnitType Zerg_Lair(132); const UnitType Zerg_Hive(133); const UnitType Zerg_Nydus_Canal(134); const UnitType Zerg_Hydralisk_Den(135); const UnitType Zerg_Defiler_Mound(136); const UnitType Zerg_Greater_Spire(137); const UnitType Zerg_Queens_Nest(138); const UnitType Zerg_Evolution_Chamber(139); const UnitType Zerg_Ultralisk_Cavern(140); const UnitType Zerg_Spire(141); const UnitType Zerg_Spawning_Pool(142); const UnitType Zerg_Creep_Colony(143); const UnitType Zerg_Spore_Colony(144); const UnitType Zerg_Sunken_Colony(146); const UnitType Special_Overmind_With_Shell(147); const UnitType Special_Overmind(148); const UnitType Zerg_Extractor(149); const UnitType Special_Mature_Chrysalis(150); const UnitType Special_Cerebrate(151); const UnitType Special_Cerebrate_Daggoth(152); const UnitType Protoss_Nexus(154); const UnitType Protoss_Robotics_Facility(155); const UnitType Protoss_Pylon(156); const UnitType Protoss_Assimilator(157); const UnitType Protoss_Observatory(159); const UnitType Protoss_Gateway(160); const UnitType Protoss_Photon_Cannon(162); const UnitType Protoss_Citadel_of_Adun(163); const UnitType Protoss_Cybernetics_Core(164); const UnitType Protoss_Templar_Archives(165); const UnitType Protoss_Forge(166); const UnitType Protoss_Stargate(167); const UnitType Special_Stasis_Cell_Prison(168); const UnitType Protoss_Fleet_Beacon(169); const UnitType Protoss_Arbiter_Tribunal(170); const UnitType Protoss_Robotics_Support_Bay(171); const UnitType Protoss_Shield_Battery(172); const UnitType Special_Khaydarin_Crystal_Form(173); const UnitType Special_Protoss_Temple(174); const UnitType Special_XelNaga_Temple(175); const UnitType Resource_Mineral_Field(176); const UnitType Resource_Vespene_Geyser(188); const UnitType Special_Warp_Gate(189); const UnitType Special_Psi_Disrupter(190); const UnitType Special_Power_Generator(200); const UnitType Special_Overmind_Cocoon(201); const UnitType Special_Zerg_Beacon(194); const UnitType Special_Terran_Beacon(195); const UnitType Special_Protoss_Beacon(196); const UnitType Special_Zerg_Flag_Beacon(197); const UnitType Special_Terran_Flag_Beacon(198); const UnitType Special_Protoss_Flag_Beacon(199); const UnitType Spell_Dark_Swarm(202); const UnitType Powerup_Uraj_Crystal(128); const UnitType Powerup_Khalis_Crystal(129); const UnitType Powerup_Flag(215); const UnitType Powerup_Young_Chrysalis(216); const UnitType Powerup_Psi_Emitter(217); const UnitType Powerup_Data_Disk(218); const UnitType Powerup_Khaydarin_Crystal(219); const UnitType None(228); const UnitType Unknown(229); void init() { unitTypeData[Terran_Marine.getID()].set("Terran Marine", Races::Terran, 0, Terran_Barracks, 1, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 50, 0, 360, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle, 1, WeaponTypes::Gauss_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Jim_Raynor_Marine.getID()].set("Hero Jim Raynor Marine", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 0, 3, 50, 0, 1, 0, 0, 1, 0, 0, 200, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 128, 224, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, WeaponTypes::Gauss_Rifle_Jim_Raynor, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Ghost.getID()].set("Terran Ghost", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, Terran_Covert_Ops, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Nuclear_Strike, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 45, 0, 200, 0, 25, 75, 750, 2, 0, 1, 0, 175, 350, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 288, WeaponTypes::C_10_Canister_Rifle, 1, WeaponTypes::C_10_Canister_Rifle, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Sarah_Kerrigan.getID()].set("Hero Sarah Kerrigan", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 50, 150, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, WeaponTypes::C_10_Canister_Rifle_Sarah_Kerrigan, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Samir_Duran.getID()].set("Hero Samir Duran", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 200, 0, 250, 2, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 320, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Samir_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Infested_Duran.getID()].set("Hero Infested Duran", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::Consume, TechTypes::None, UpgradeTypes::Zerg_Carapace, 300, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, WeaponTypes::C_10_Canister_Rifle_Infested_Duran, 1, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Alexei_Stukov.getID()].set("Hero Alexei Stukov", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Lockdown, TechTypes::Personnel_Cloaking, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 250, 0, 250, 3, 200, 75, 1500, 0, 0, 1, 0, 0, 700, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 224, 352, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, WeaponTypes::C_10_Canister_Rifle_Alexei_Stukov, 1, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Terran_Vulture.getID()].set("Terran Vulture", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 80, 0, 0, 0, 75, 0, 450, 4, 0, 2, 0, 75, 150, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Jim_Raynor_Vulture.getID()].set("Hero Jim Raynor Vulture", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Spider_Mines, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 150, 0, 900, 0, 0, 2, 0, 0, 300, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 160, 256, WeaponTypes::Fragmentation_Grenade_Jim_Raynor, 1, WeaponTypes::None, 0, 6.4, 100, 14569, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Goliath.getID()].set("Terran Goliath", Races::Terran, 0, Terran_Factory, 1, Terran_Armory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 125, 0, 0, 1, 100, 50, 600, 4, 0, 2, 0, 200, 400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons, 1, WeaponTypes::Hellfire_Missile_Pack, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Alan_Schezar.getID()].set("Hero Alan Schezar", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 300, 0, 0, 3, 200, 100, 1200, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 192, 256, WeaponTypes::Twin_Autocannons_Alan_Schezar, 1, WeaponTypes::Hellfire_Missile_Pack_Alan_Schezar, 1, 4.57, 1, 1, 17, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Siege_Tank_Tank_Mode.getID()].set("Terran Siege Tank Tank Mode", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 4, 0, 350, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Edmund_Duke_Tank_Mode.getID()].set("Hero Edmund Duke Tank Mode", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 4, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::Arclite_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 4, 1, 1, 13, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_SCV.getID()].set("Terran SCV", Races::Terran, 0, Terran_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Fusion_Cutter, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Wraith.getID()].set("Terran Wraith", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 120, 0, 200, 0, 150, 100, 900, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers, 1, WeaponTypes::Gemini_Missiles, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Hero_Tom_Kazansky.getID()].set("Hero Tom Kazansky", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Cloaking_Field, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 250, 4, 400, 200, 1800, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 19, 15, 18, 14, 160, 224, WeaponTypes::Burst_Lasers_Tom_Kazansky, 1, WeaponTypes::Gemini_Missiles_Tom_Kazansky, 1, 6.67, 67, 21745, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Terran_Science_Vessel.getID()].set("Terran Science Vessel", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Science_Facility, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 200, 1, 100, 225, 1200, 4, 0, 255, 0, 625, 1250, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Magellan.getID()].set("Hero Magellan", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::EMP_Shockwave, TechTypes::Defensive_Matrix, TechTypes::Irradiate, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 800, 0, 250, 4, 50, 600, 2400, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 2, 2, 32, 33, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 50, 5120, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Dropship.getID()].set("Terran Dropship", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 150, 0, 0, 1, 100, 100, 750, 4, 0, 255, 8, 300, 600, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 5.47, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Battlecruiser.getID()].set("Terran Battlecruiser", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Physics_Lab, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 500, 0, 200, 3, 400, 300, 2000, 12, 0, 255, 0, 1200, 2400, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery, 1, WeaponTypes::ATA_Laser_Battery, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Arcturus_Mengsk.getID()].set("Hero Arcturus Mengsk", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 1000, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 256, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Hyperion.getID()].set("Hero Hyperion", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 850, 0, 250, 4, 800, 600, 2400, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hyperion, 1, WeaponTypes::ATA_Laser_Battery_Hyperion, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Norad_II.getID()].set("Hero Norad II", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gerard_DuGalle.getID()].set("Hero Gerard DuGalle", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Yamato_Gun, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 700, 0, 250, 4, 800, 600, 4800, 0, 0, 255, 0, 0, 4800, UnitSizeTypes::Large, 2, 2, 37, 29, 37, 29, 192, 352, WeaponTypes::ATS_Laser_Battery_Hero, 1, WeaponTypes::ATA_Laser_Battery_Hero, 1, 2.5, 27, 7585, 20, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Vulture_Spider_Mine.getID()].set("Terran Vulture Spider Mine", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 20, 0, 0, 0, 1, 0, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 7, 7, 7, 7, 96, 96, WeaponTypes::Spider_Mines, 1, WeaponTypes::None, 0, 16, 1, 1, 127, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Nuclear_Missile.getID()].set("Terran Nuclear Missile", Races::Terran, 0, Terran_Nuclear_Silo, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 0, 0, 0, 200, 200, 1500, 16, 0, 255, 0, 800, 0, UnitSizeTypes::Independent, 1, 1, 7, 14, 7, 14, 0, 96, WeaponTypes::None, 0, WeaponTypes::None, 0, 33.33, 33, 1103213, 127, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Siege_Tank_Siege_Mode.getID()].set("Terran Siege Tank Siege Mode", Races::Terran, 0, Terran_Factory, 1, Terran_Machine_Shop, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 150, 0, 0, 1, 150, 100, 750, 4, 0, 255, 0, 0, 700, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Edmund_Duke_Siege_Mode.getID()].set("Hero Edmund Duke Siege Mode", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Tank_Siege_Mode, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Vehicle_Plating, 400, 0, 0, 3, 300, 200, 1500, 0, 0, 255, 0, 0, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 384, 320, WeaponTypes::Arclite_Shock_Cannon_Edmund_Duke, 1, WeaponTypes::None, 0, 0, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Firebat.getID()].set("Terran Firebat", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 50, 0, 0, 1, 50, 25, 360, 2, 0, 1, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gui_Montag.getID()].set("Hero Gui Montag", Races::Terran, 1, None, 0, None, None, TechTypes::None, TechTypes::Stim_Packs, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 160, 0, 0, 3, 100, 50, 720, 0, 0, 1, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 7, 11, 14, 96, 224, WeaponTypes::Flame_Thrower_Gui_Montag, 3, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Spell_Scanner_Sweep.getID()].set("Spell Scanner Sweep", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 13, 13, 13, 17, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Medic.getID()].set("Terran Medic", Races::Terran, 0, Terran_Barracks, 1, Terran_Academy, None, TechTypes::None, TechTypes::Restoration, TechTypes::Optical_Flare, TechTypes::Healing, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 60, 0, 200, 1, 50, 25, 450, 2, 0, 1, 0, 125, 250, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 288, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Civilian.getID()].set("Terran Civilian", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Infantry_Armor, 40, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Larva.getID()].set("Zerg Larva", Races::Zerg, 0, Zerg_Hatchery, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 25, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 1, 1, 20, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Egg.getID()].set("Zerg Egg", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 25, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Zergling.getID()].set("Zerg Zergling", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 35, 0, 0, 0, 50, 0, 420, 1, 0, 1, 0, 25, 50, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Devouring_One.getID()].set("Hero Devouring One", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 120, 0, 0, 3, 100, 0, 840, 0, 0, 1, 0, 0, 100, UnitSizeTypes::Small, 1, 1, 8, 4, 7, 11, 96, 160, WeaponTypes::Claws_Devouring_One, 1, WeaponTypes::None, 0, 5.49, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Infested_Kerrigan.getID()].set("Hero Infested Kerrigan", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Personnel_Cloaking, TechTypes::Ensnare, TechTypes::Psionic_Storm, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 400, 0, 250, 2, 200, 300, 1500, 0, 0, 1, 0, 0, 4000, UnitSizeTypes::Small, 1, 1, 7, 10, 7, 11, 96, 288, WeaponTypes::Claws_Infested_Kerrigan, 1, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); unitTypeData[Zerg_Hydralisk.getID()].set("Zerg Hydralisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Hydralisk_Den, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 80, 0, 0, 0, 75, 25, 420, 2, 0, 2, 0, 125, 350, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 192, WeaponTypes::Needle_Spines, 1, WeaponTypes::Needle_Spines, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Hunter_Killer.getID()].set("Hero Hunter Killer", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 160, 0, 0, 2, 150, 50, 780, 0, 0, 2, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 10, 10, 10, 12, 128, 256, WeaponTypes::Needle_Spines_Hunter_Killer, 1, WeaponTypes::Needle_Spines_Hunter_Killer, 1, 3.66, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Ultralisk.getID()].set("Zerg Ultralisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Ultralisk_Cavern, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 400, 0, 0, 1, 200, 200, 900, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Torrasque.getID()].set("Hero Torrasque", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 800, 0, 0, 4, 400, 400, 1800, 0, 0, 4, 0, 0, 2600, UnitSizeTypes::Large, 2, 2, 19, 16, 18, 15, 96, 224, WeaponTypes::Kaiser_Blades_Torrasque, 1, WeaponTypes::None, 0, 5.12, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Broodling.getID()].set("Zerg Broodling", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 30, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 25, UnitSizeTypes::Small, 1, 1, 9, 9, 9, 9, 96, 160, WeaponTypes::Toxic_Spores, 1, WeaponTypes::None, 0, 6, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Drone.getID()].set("Zerg Drone", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 40, 0, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 224, WeaponTypes::Spines, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Overlord.getID()].set("Zerg Overlord", Races::Zerg, 0, Zerg_Larva, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 200, 0, 0, 0, 100, 0, 600, 0, 16, 255, 8, 100, 200, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Yggdrasill.getID()].set("Hero Yggdrasill", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 1000, 0, 0, 4, 200, 0, 1200, 0, 60, 255, 8, 0, 400, UnitSizeTypes::Large, 2, 2, 25, 25, 24, 24, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0.83, 27, 840, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Mutalisk.getID()].set("Zerg Mutalisk", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 0, 0, 100, 100, 600, 4, 0, 255, 0, 300, 600, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm, 1, WeaponTypes::Glave_Wurm, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Kukulza_Mutalisk.getID()].set("Hero Kukulza Mutalisk", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 0, 3, 200, 200, 1200, 0, 0, 255, 0, 0, 1200, UnitSizeTypes::Small, 2, 2, 22, 22, 21, 21, 96, 224, WeaponTypes::Glave_Wurm_Kukulza, 1, WeaponTypes::Glave_Wurm_Kukulza, 1, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Guardian.getID()].set("Zerg Guardian", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 150, 0, 0, 2, 50, 100, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Kukulza_Guardian.getID()].set("Hero Kukulza Guardian", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 400, 0, 0, 4, 100, 200, 1200, 0, 0, 255, 0, 0, 2200, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 256, 352, WeaponTypes::Acid_Spore_Kukulza, 1, WeaponTypes::None, 0, 2.5, 27, 7585, 20, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Queen.getID()].set("Zerg Queen", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 120, 0, 200, 0, 100, 100, 750, 4, 0, 255, 0, 400, 800, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Matriarch.getID()].set("Hero Matriarch", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Infestation, TechTypes::Spawn_Broodlings, TechTypes::Ensnare, TechTypes::Parasite, UpgradeTypes::Zerg_Flyer_Carapace, 300, 0, 250, 3, 200, 300, 1500, 0, 0, 255, 0, 0, 1600, UnitSizeTypes::Medium, 2, 2, 24, 24, 23, 23, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 6.67, 67, 21745, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Defiler.getID()].set("Zerg Defiler", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Defiler_Mound, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 80, 0, 200, 1, 50, 150, 750, 4, 0, 2, 0, 225, 450, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Unclean_One.getID()].set("Hero Unclean One", Races::Zerg, 1, None, 0, None, None, TechTypes::None, TechTypes::Burrowing, TechTypes::Dark_Swarm, TechTypes::Plague, TechTypes::Consume, UpgradeTypes::Zerg_Carapace, 250, 0, 250, 3, 50, 200, 1500, 0, 0, 2, 0, 0, 900, UnitSizeTypes::Medium, 1, 1, 13, 12, 13, 12, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Scourge.getID()].set("Zerg Scourge", Races::Zerg, 0, Zerg_Larva, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 25, 0, 0, 0, 25, 75, 450, 1, 0, 255, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 12, 12, 11, 11, 96, 160, WeaponTypes::None, 0, WeaponTypes::Suicide_Scourge, 1, 6.67, 107, 13616, 40, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Infested_Terran.getID()].set("Zerg Infested Terran", Races::Zerg, 0, Zerg_Infested_Command_Center, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 60, 0, 0, 0, 100, 50, 600, 2, 0, 1, 0, 200, 400, UnitSizeTypes::Small, 1, 1, 8, 9, 8, 10, 96, 160, WeaponTypes::Suicide_Infested_Terran, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Terran_Valkyrie.getID()].set("Terran Valkyrie", Races::Terran, 0, Terran_Starport, 1, Terran_Control_Tower, Terran_Armory, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Terran_Ship_Plating, 200, 0, 0, 2, 250, 125, 750, 6, 0, 255, 0, 400, 800, UnitSizeTypes::Large, 2, 2, 24, 16, 24, 20, 192, 256, WeaponTypes::None, 0, WeaponTypes::Halo_Rockets, 4, 6.6, 65, 21901, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Cocoon.getID()].set("Zerg Cocoon", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 1100, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Corsair.getID()].set("Protoss Corsair", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 80, 200, 1, 150, 100, 600, 4, 0, 255, 0, 350, 700, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Raszagal.getID()].set("Hero Raszagal", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Disruption_Web, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 100, 60, 250, 0, 150, 100, 750, 0, 0, 255, 0, 0, 1300, UnitSizeTypes::Medium, 1, 1, 18, 16, 17, 15, 288, 288, WeaponTypes::None, 0, WeaponTypes::Neutron_Flare, 1, 6.67, 67, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dark_Templar.getID()].set("Protoss Dark Templar", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Dark_Archon_Meld, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 40, 0, 1, 125, 100, 750, 4, 0, 2, 0, 325, 650, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Dark_Templar.getID()].set("Hero Dark Templar", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 80, 0, 0, 150, 150, 750, 1, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Hero, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Zeratul.getID()].set("Hero Zeratul", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 60, 400, 0, 0, 100, 300, 1500, 0, 0, 2, 0, 0, 800, UnitSizeTypes::Small, 1, 1, 12, 6, 11, 19, 96, 224, WeaponTypes::Warp_Blades_Zeratul, 1, WeaponTypes::None, 0, 4.92, 27, 13474, 40, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Devourer.getID()].set("Zerg Devourer", Races::Zerg, 0, Zerg_Mutalisk, 1, Zerg_Greater_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Flyer_Carapace, 250, 0, 0, 2, 150, 50, 600, 4, 0, 255, 0, 550, 1100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 224, 320, WeaponTypes::None, 0, WeaponTypes::Corrosive_Acid, 1, 5, 48, 17067, 30, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dark_Archon.getID()].set("Protoss Dark Archon", Races::Protoss, 0, Protoss_Dark_Templar, 2, None, None, TechTypes::None, TechTypes::Mind_Control, TechTypes::Feedback, TechTypes::Maelstrom, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 25, 200, 200, 1, 0, 0, 300, 8, 0, 4, 0, 650, 1300, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 224, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Probe.getID()].set("Protoss Probe", Races::Protoss, 0, Protoss_Nexus, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 20, 0, 0, 50, 0, 300, 2, 0, 1, 0, 50, 100, UnitSizeTypes::Small, 1, 1, 11, 11, 11, 11, 32, 256, WeaponTypes::Particle_Beam, 1, WeaponTypes::None, 0, 4.92, 67, 12227, 40, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Zealot.getID()].set("Protoss Zealot", Races::Protoss, 0, Protoss_Gateway, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 60, 0, 1, 100, 0, 600, 4, 0, 2, 0, 100, 200, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Fenix_Zealot.getID()].set("Hero Fenix Zealot", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 2, 200, 0, 1200, 0, 0, 2, 0, 0, 400, UnitSizeTypes::Small, 1, 1, 11, 5, 11, 13, 96, 224, WeaponTypes::Psi_Blades_Fenix, 2, WeaponTypes::None, 0, 4, 1, 1, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Dragoon.getID()].set("Protoss Dragoon", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 1, 125, 50, 750, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor, 1, WeaponTypes::Phase_Disruptor, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Fenix_Dragoon.getID()].set("Hero Fenix Dragoon", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 240, 240, 0, 3, 300, 100, 1500, 0, 0, 4, 0, 0, 1000, UnitSizeTypes::Large, 1, 1, 15, 15, 16, 16, 128, 256, WeaponTypes::Phase_Disruptor_Fenix, 1, WeaponTypes::Phase_Disruptor_Fenix, 1, 5, 1, 1, 40, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_High_Templar.getID()].set("Protoss High Templar", Races::Protoss, 0, Protoss_Gateway, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::Archon_Warp, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 40, 40, 200, 0, 50, 150, 750, 4, 0, 2, 0, 350, 700, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Tassadar.getID()].set("Hero Tassadar", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Psionic_Storm, TechTypes::Hallucination, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Aldaris.getID()].set("Hero Aldaris", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 80, 300, 250, 2, 100, 300, 1500, 0, 0, 2, 0, 0, 1400, UnitSizeTypes::Small, 1, 1, 12, 10, 11, 13, 96, 224, WeaponTypes::Psi_Assault, 1, WeaponTypes::None, 0, 3.2, 27, 13474, 40, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Archon.getID()].set("Protoss Archon", Races::Protoss, 0, Protoss_High_Templar, 2, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 10, 350, 0, 0, 0, 0, 300, 8, 0, 4, 0, 700, 1400, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave, 1, WeaponTypes::Psionic_Shockwave, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Tassadar_Zeratul_Archon.getID()].set("Hero Tassadar Zeratul Archon", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 800, 0, 3, 0, 0, 600, 0, 0, 4, 0, 0, 2800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 96, 256, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, WeaponTypes::Psionic_Shockwave_TZ_Archon, 1, 4.92, 160, 5120, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Shuttle.getID()].set("Protoss Shuttle", Races::Protoss, 0, Protoss_Robotics_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 80, 60, 0, 1, 200, 0, 900, 4, 0, 255, 8, 200, 400, UnitSizeTypes::Large, 2, 1, 20, 16, 19, 15, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 4.43, 17, 37756, 20, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Scout.getID()].set("Protoss Scout", Races::Protoss, 0, Protoss_Stargate, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 150, 100, 0, 0, 275, 125, 1200, 6, 0, 255, 0, 650, 1300, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 256, WeaponTypes::Dual_Photon_Blasters, 1, WeaponTypes::Anti_Matter_Missiles, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Mojo.getID()].set("Hero Mojo", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 400, 400, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2600, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Mojo, 1, WeaponTypes::Anti_Matter_Missiles_Mojo, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Artanis.getID()].set("Hero Artanis", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 250, 250, 0, 3, 600, 300, 2400, 0, 0, 255, 0, 0, 2400, UnitSizeTypes::Large, 2, 1, 18, 16, 17, 15, 128, 320, WeaponTypes::Dual_Photon_Blasters_Artanis, 1, WeaponTypes::Anti_Matter_Missiles_Artanis, 1, 5, 48, 17067, 30, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Arbiter.getID()].set("Protoss Arbiter", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Arbiter_Tribunal, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 200, 150, 200, 1, 100, 350, 2400, 8, 0, 255, 0, 1025, 2050, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon, 1, WeaponTypes::Phase_Disruptor_Cannon, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Danimoth.getID()].set("Hero Danimoth", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::Recall, TechTypes::Stasis_Field, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 600, 500, 250, 3, 50, 1000, 4800, 0, 0, 255, 0, 0, 4100, UnitSizeTypes::Large, 2, 2, 22, 22, 21, 21, 160, 288, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, WeaponTypes::Phase_Disruptor_Cannon_Danimoth, 1, 5, 33, 24824, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Carrier.getID()].set("Protoss Carrier", Races::Protoss, 0, Protoss_Stargate, 1, Protoss_Fleet_Beacon, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 300, 150, 0, 4, 350, 250, 2100, 12, 0, 255, 0, 950, 1900, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Gantrithor.getID()].set("Hero Gantrithor", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 800, 500, 0, 4, 700, 600, 4200, 0, 0, 255, 0, 0, 3800, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 256, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Interceptor.getID()].set("Protoss Interceptor", Races::Protoss, 0, Protoss_Carrier, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 40, 0, 0, 25, 0, 300, 0, 0, 255, 0, 30, 60, UnitSizeTypes::Small, 1, 1, 8, 8, 7, 7, 128, 192, WeaponTypes::Pulse_Cannon, 1, WeaponTypes::Pulse_Cannon, 1, 13.33, 427, 13640, 40, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Reaver.getID()].set("Protoss Reaver", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Robotics_Support_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 100, 80, 0, 0, 200, 100, 1050, 8, 0, 4, 0, 400, 800, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Hero_Warbringer.getID()].set("Hero Warbringer", Races::Protoss, 1, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 200, 400, 0, 3, 400, 200, 1800, 0, 0, 4, 0, 0, 1600, UnitSizeTypes::Large, 1, 1, 16, 16, 15, 15, 256, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1.78, 1, 1, 20, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Observer.getID()].set("Protoss Observer", Races::Protoss, 0, Protoss_Robotics_Facility, 1, Protoss_Observatory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Air_Armor, 40, 20, 0, 0, 25, 75, 600, 2, 0, 255, 0, 225, 450, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 3.33, 27, 13474, 20, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Protoss_Scarab.getID()].set("Protoss Scarab", Races::Protoss, 0, Protoss_Reaver, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Protoss_Ground_Armor, 20, 10, 0, 0, 15, 0, 105, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Small, 1, 1, 2, 2, 2, 2, 128, 160, WeaponTypes::Scarab, 1, WeaponTypes::None, 0, 16, 1, 1, 27, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Critter_Rhynadon.getID()].set("Critter Rhynadon", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Bengalaas.getID()].set("Critter Bengalaas", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Scantid.getID()].set("Critter Scantid", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Kakaru.getID()].set("Critter Kakaru", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 5, 16, 51200, 14, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Ragnasaur.getID()].set("Critter Ragnasaur", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Critter_Ursadon.getID()].set("Critter Ursadon", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 60, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 10, UnitSizeTypes::Small, 1, 1, 16, 16, 15, 15, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 4, 1, 1, 27, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Zerg_Lurker_Egg.getID()].set("Zerg Lurker Egg", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 200, 0, 0, 10, 1, 1, 1, 0, 0, 255, 0, 0, 500, UnitSizeTypes::Medium, 1, 1, 16, 16, 15, 15, 0, 128, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Zerg_Lurker.getID()].set("Zerg Lurker", Races::Zerg, 0, Zerg_Hydralisk, 1, None, None, TechTypes::Lurker_Aspect, TechTypes::Lurker_Aspect, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::Zerg_Carapace, 125, 0, 0, 1, 50, 100, 600, 4, 0, 4, 0, 250, 500, UnitSizeTypes::Medium, 1, 1, 15, 15, 16, 16, 192, 256, WeaponTypes::Subterranean_Spines, 1, WeaponTypes::None, 0, 5.82, 1, 1, 40, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); unitTypeData[Spell_Disruption_Web.getID()].set("Spell Disruption Web", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 250, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 4, 3, 60, 40, 59, 39, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Terran_Command_Center.getID()].set("Terran Command Center", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 400, 0, 1800, 0, 20, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Comsat_Station.getID()].set("Terran Comsat Station", Races::Terran, 0, Terran_Command_Center, 1, Terran_Academy, None, TechTypes::None, TechTypes::Scanner_Sweep, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 200, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Nuclear_Silo.getID()].set("Terran Nuclear Silo", Races::Terran, 0, Terran_Command_Center, 1, Terran_Science_Facility, Terran_Covert_Ops, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 100, 100, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 37, 16, 31, 25, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Supply_Depot.getID()].set("Terran Supply Depot", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 100, 0, 600, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 38, 22, 38, 26, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Refinery.getID()].set("Terran Refinery", Races::Terran, 0, Terran_SCV, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 56, 32, 56, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Terran_Barracks.getID()].set("Terran Barracks", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 40, 56, 32, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Academy.getID()].set("Terran Academy", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 0, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 44, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Factory.getID()].set("Terran Factory", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 200, 100, 1200, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 56, 40, 56, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Starport.getID()].set("Terran Starport", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1300, 0, 0, 1, 150, 100, 1050, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Control_Tower.getID()].set("Terran Control Tower", Races::Terran, 0, Terran_Starport, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Science_Facility.getID()].set("Terran Science Facility", Races::Terran, 0, Terran_SCV, 1, Terran_Starport, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 150, 900, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 4, 3, 48, 38, 48, 38, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Covert_Ops.getID()].set("Terran Covert Ops", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Physics_Lab.getID()].set("Terran Physics Lab", Races::Terran, 0, Terran_Science_Facility, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 47, 24, 28, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Machine_Shop.getID()].set("Terran Machine Shop", Races::Terran, 0, Terran_Factory, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 50, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 39, 24, 31, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0); unitTypeData[Terran_Engineering_Bay.getID()].set("Terran Engineering Bay", Races::Terran, 0, Terran_SCV, 1, Terran_Command_Center, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 125, 0, 900, 0, 0, 255, 0, 65, 195, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Terran_Armory.getID()].set("Terran Armory", Races::Terran, 0, Terran_SCV, 1, Terran_Factory, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 100, 50, 1200, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 22, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Missile_Turret.getID()].set("Terran Missile Turret", Races::Terran, 0, Terran_SCV, 1, Terran_Engineering_Bay, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 0, 0, 0, 75, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 32, 16, 16, 224, 352, WeaponTypes::None, 0, WeaponTypes::Longbolt_Missile, 1, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Terran_Bunker.getID()].set("Terran Bunker", Races::Terran, 0, Terran_SCV, 1, Terran_Barracks, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 350, 0, 0, 1, 100, 0, 450, 0, 0, 255, 4, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 33, 2763, 27, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Crashed_Norad_II.getID()].set("Special Crashed Norad II", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 800, 600, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Ion_Cannon.getID()].set("Special Ion Cannon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 200, 0, 900, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Infested_Command_Center.getID()].set("Zerg Infested Command Center", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 1, 1, 1800, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 58, 41, 58, 41, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 1, 33, 2763, 27, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0); unitTypeData[Zerg_Hatchery.getID()].set("Zerg Hatchery", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1250, 0, 0, 1, 300, 0, 1800, 0, 2, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Lair.getID()].set("Zerg Lair", Races::Zerg, 0, Zerg_Hatchery, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1800, 0, 0, 1, 150, 100, 1500, 0, 2, 255, 0, 100, 1200, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Hive.getID()].set("Zerg Hive", Races::Zerg, 0, Zerg_Lair, 1, Zerg_Queens_Nest, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 200, 150, 1800, 0, 2, 255, 0, 100, 1500, UnitSizeTypes::Large, 4, 3, 49, 32, 49, 32, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Nydus_Canal.getID()].set("Zerg Nydus Canal", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 150, 0, 600, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Hydralisk_Den.getID()].set("Zerg Hydralisk Den", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Spawning_Pool, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 50, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 32, 40, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Defiler_Mound.getID()].set("Zerg Defiler Mound", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 100, 100, 900, 0, 0, 255, 0, 150, 450, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 4, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Greater_Spire.getID()].set("Zerg Greater Spire", Races::Zerg, 0, Zerg_Spire, 1, Zerg_Spire, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1000, 0, 0, 1, 100, 150, 1800, 0, 0, 255, 0, 200, 1350, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Queens_Nest.getID()].set("Zerg Queens Nest", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 850, 0, 0, 1, 150, 100, 900, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 38, 28, 32, 28, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Evolution_Chamber.getID()].set("Zerg Evolution Chamber", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 75, 0, 600, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 3, 2, 44, 32, 32, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Ultralisk_Cavern.getID()].set("Zerg Ultralisk Cavern", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hive, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 150, 200, 1200, 0, 0, 255, 0, 275, 825, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spire.getID()].set("Zerg Spire", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Lair, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 0, 0, 1, 200, 150, 1800, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 2, 2, 28, 32, 28, 24, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spawning_Pool.getID()].set("Zerg Spawning Pool", Races::Zerg, 0, Zerg_Drone, 1, Zerg_Hatchery, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 200, 0, 1200, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 3, 2, 36, 28, 40, 18, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Creep_Colony.getID()].set("Zerg Creep Colony", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 75, 0, 300, 0, 0, 255, 0, 40, 120, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Spore_Colony.getID()].set("Zerg Spore Colony", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 400, 0, 0, 0, 50, 0, 300, 0, 0, 255, 0, 25, 195, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::None, 0, WeaponTypes::Seeker_Spores, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Sunken_Colony.getID()].set("Zerg Sunken Colony", Races::Zerg, 0, Zerg_Creep_Colony, 1, Zerg_Creep_Colony, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 0, 0, 2, 50, 0, 300, 0, 0, 255, 0, 40, 240, UnitSizeTypes::Large, 2, 2, 24, 24, 23, 23, 224, 320, WeaponTypes::Subterranean_Tentacle, 1, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind_With_Shell.getID()].set("Special Overmind With Shell", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind.getID()].set("Special Overmind", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1, 1, 1, 0, 0, 255, 0, 0, 10000, UnitSizeTypes::Large, 5, 3, 80, 32, 79, 40, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Zerg_Extractor.getID()].set("Zerg Extractor", Races::Zerg, 0, Zerg_Drone, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 0, 0, 1, 50, 0, 600, 0, 0, 255, 0, 25, 75, UnitSizeTypes::Large, 4, 2, 64, 32, 63, 31, 0, 224, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Special_Mature_Chrysalis.getID()].set("Special Mature Chrysalis", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 2, 2, 32, 32, 31, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Cerebrate.getID()].set("Special Cerebrate", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Cerebrate_Daggoth.getID()].set("Special Cerebrate Daggoth", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 0, 0, 0, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 3, 2, 40, 32, 32, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Nexus.getID()].set("Protoss Nexus", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 750, 750, 0, 1, 400, 0, 1800, 0, 18, 255, 0, 400, 1200, UnitSizeTypes::Large, 4, 3, 56, 39, 56, 39, 0, 352, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Robotics_Facility.getID()].set("Protoss Robotics Facility", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 200, 1200, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 3, 2, 36, 16, 40, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Pylon.getID()].set("Protoss Pylon", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 300, 300, 0, 0, 100, 0, 450, 0, 16, 255, 0, 50, 150, UnitSizeTypes::Large, 2, 2, 16, 12, 16, 20, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Assimilator.getID()].set("Protoss Assimilator", Races::Protoss, 0, Protoss_Probe, 1, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 100, 0, 600, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 4, 2, 48, 32, 48, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1); unitTypeData[Protoss_Observatory.getID()].set("Protoss Observatory", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 250, 250, 0, 1, 50, 100, 450, 0, 0, 255, 0, 175, 525, UnitSizeTypes::Large, 3, 2, 44, 16, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Gateway.getID()].set("Protoss Gateway", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 0, 900, 0, 0, 255, 0, 75, 225, UnitSizeTypes::Large, 4, 3, 48, 32, 48, 40, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Photon_Cannon.getID()].set("Protoss Photon Cannon", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Forge, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100, 100, 0, 0, 150, 0, 750, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 2, 2, 20, 16, 20, 16, 224, 352, WeaponTypes::STS_Photon_Cannon, 1, WeaponTypes::STA_Photon_Cannon, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Citadel_of_Adun.getID()].set("Protoss Citadel of Adun", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 900, 0, 0, 255, 0, 200, 600, UnitSizeTypes::Large, 3, 2, 24, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Cybernetics_Core.getID()].set("Protoss Cybernetics Core", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 0, 900, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 40, 24, 40, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Templar_Archives.getID()].set("Protoss Templar Archives", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Citadel_of_Adun, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 150, 200, 900, 0, 0, 255, 0, 250, 750, UnitSizeTypes::Large, 3, 2, 32, 24, 32, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Forge.getID()].set("Protoss Forge", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Nexus, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 550, 550, 0, 1, 150, 0, 600, 0, 0, 255, 0, 100, 300, UnitSizeTypes::Large, 3, 2, 36, 24, 36, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Stargate.getID()].set("Protoss Stargate", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Cybernetics_Core, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 600, 600, 0, 1, 150, 150, 1050, 0, 0, 255, 0, 300, 900, UnitSizeTypes::Large, 4, 3, 48, 40, 48, 32, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Stasis_Cell_Prison.getID()].set("Special Stasis Cell Prison", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 150, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Fleet_Beacon.getID()].set("Protoss Fleet Beacon", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Stargate, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 300, 200, 900, 0, 0, 255, 0, 350, 1050, UnitSizeTypes::Large, 3, 2, 40, 32, 47, 24, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Arbiter_Tribunal.getID()].set("Protoss Arbiter Tribunal", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Templar_Archives, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 500, 500, 0, 1, 200, 150, 900, 0, 0, 255, 0, 450, 1350, UnitSizeTypes::Large, 3, 2, 44, 28, 44, 28, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Robotics_Support_Bay.getID()].set("Protoss Robotics Support Bay", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Robotics_Facility, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 450, 450, 0, 1, 150, 100, 450, 0, 0, 255, 0, 125, 375, UnitSizeTypes::Large, 3, 2, 32, 32, 32, 20, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Protoss_Shield_Battery.getID()].set("Protoss Shield Battery", Races::Protoss, 0, Protoss_Probe, 1, Protoss_Gateway, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 200, 200, 200, 1, 100, 0, 450, 0, 0, 255, 0, 50, 150, UnitSizeTypes::Large, 3, 2, 32, 16, 32, 16, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Khaydarin_Crystal_Form.getID()].set("Special Khaydarin Crystal Form", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 2500, UnitSizeTypes::Large, 4, 3, 64, 48, 63, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Temple.getID()].set("Special Protoss Temple", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 1500, 0, 0, 1, 250, 0, 1, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 7, 3, 112, 48, 111, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_XelNaga_Temple.getID()].set("Special XelNaga Temple", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 5000, 0, 0, 1, 1500, 500, 4800, 0, 0, 255, 0, 0, 5000, UnitSizeTypes::Large, 5, 4, 80, 34, 79, 63, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Resource_Mineral_Field.getID()].set("Resource Mineral Field", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 2, 1, 32, 16, 31, 15, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); unitTypeData[Resource_Vespene_Geyser.getID()].set("Resource Vespene Geyser", Races::Other, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 10, 10, UnitSizeTypes::Independent, 4, 2, 64, 32, 63, 31, 0, 288, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); unitTypeData[Special_Warp_Gate.getID()].set("Special Warp Gate", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 700, 0, 0, 1, 600, 200, 2400, 0, 0, 255, 0, 0, 2000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Psi_Disrupter.getID()].set("Special Psi Disrupter", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2000, 0, 0, 1, 1000, 400, 4800, 0, 0, 255, 0, 0, 3600, UnitSizeTypes::Large, 5, 3, 80, 38, 69, 47, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Power_Generator.getID()].set("Special Power Generator", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 1, 200, 50, 2400, 0, 0, 255, 0, 0, 600, UnitSizeTypes::Large, 4, 3, 56, 28, 63, 43, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Overmind_Cocoon.getID()].set("Special Overmind Cocoon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 2500, 0, 0, 1, 1000, 500, 2400, 0, 0, 255, 0, 0, 4000, UnitSizeTypes::Large, 3, 2, 48, 32, 47, 31, 0, 320, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Zerg_Beacon.getID()].set("Special Zerg Beacon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Terran_Beacon.getID()].set("Special Terran Beacon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Beacon.getID()].set("Special Protoss Beacon", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Zerg_Flag_Beacon.getID()].set("Special Zerg Flag Beacon", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 250, 0, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Terran_Flag_Beacon.getID()].set("Special Terran Flag Beacon", Races::Terran, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 50, 50, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Special_Protoss_Flag_Beacon.getID()].set("Special Protoss Flag Beacon", Races::Protoss, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 100000, 0, 0, 0, 100, 100, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 3, 2, 48, 32, 47, 31, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); unitTypeData[Spell_Dark_Swarm.getID()].set("Spell Dark Swarm", Races::Zerg, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 250, 200, 2400, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 5, 5, 80, 80, 79, 79, 0, 256, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); unitTypeData[Powerup_Uraj_Crystal.getID()].set("Powerup Uraj Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Khalis_Crystal.getID()].set("Powerup Khalis Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Flag.getID()].set("Powerup Flag", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 10000, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Young_Chrysalis.getID()].set("Powerup Young Chrysalis", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Psi_Emitter.getID()].set("Powerup Psi Emitter", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Data_Disk.getID()].set("Powerup Data Disk", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Powerup_Khaydarin_Crystal.getID()].set("Powerup Khaydarin Crystal", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 800, 0, 0, 0, 1, 1, 1, 0, 0, 255, 0, 0, 0, UnitSizeTypes::Independent, 1, 1, 16, 16, 15, 15, 0, 160, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[None.getID()].set("None", Races::None, 0, None, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); unitTypeData[Unknown.getID()].set("Unknown", Races::Unknown, 0, Unknown, 0, None, None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, TechTypes::None, UpgradeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, UnitSizeTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, WeaponTypes::None, 0, WeaponTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); foreach(UpgradeType i, UpgradeTypes::allUpgradeTypes()) { foreach (UnitType ut, i.whatUses()) unitTypeData[ut.getID()].upgrades.insert(i); } unitTypeSet.insert(Terran_Marine); unitTypeSet.insert(Hero_Jim_Raynor_Marine); unitTypeSet.insert(Terran_Ghost); unitTypeSet.insert(Hero_Sarah_Kerrigan); unitTypeSet.insert(Hero_Samir_Duran); unitTypeSet.insert(Hero_Infested_Duran); unitTypeSet.insert(Hero_Alexei_Stukov); unitTypeSet.insert(Terran_Vulture); unitTypeSet.insert(Hero_Jim_Raynor_Vulture); unitTypeSet.insert(Terran_Goliath); unitTypeSet.insert(Hero_Alan_Schezar); unitTypeSet.insert(Terran_Siege_Tank_Tank_Mode); unitTypeSet.insert(Hero_Edmund_Duke_Tank_Mode); unitTypeSet.insert(Terran_SCV); unitTypeSet.insert(Terran_Wraith); unitTypeSet.insert(Hero_Tom_Kazansky); unitTypeSet.insert(Terran_Science_Vessel); unitTypeSet.insert(Hero_Magellan); unitTypeSet.insert(Terran_Dropship); unitTypeSet.insert(Terran_Battlecruiser); unitTypeSet.insert(Hero_Arcturus_Mengsk); unitTypeSet.insert(Hero_Hyperion); unitTypeSet.insert(Hero_Norad_II); unitTypeSet.insert(Hero_Gerard_DuGalle); unitTypeSet.insert(Terran_Vulture_Spider_Mine); unitTypeSet.insert(Terran_Nuclear_Missile); unitTypeSet.insert(Terran_Siege_Tank_Siege_Mode); unitTypeSet.insert(Hero_Edmund_Duke_Siege_Mode); unitTypeSet.insert(Terran_Firebat); unitTypeSet.insert(Hero_Gui_Montag); unitTypeSet.insert(Spell_Scanner_Sweep); unitTypeSet.insert(Terran_Medic); unitTypeSet.insert(Terran_Civilian); unitTypeSet.insert(Zerg_Larva); unitTypeSet.insert(Zerg_Egg); unitTypeSet.insert(Zerg_Zergling); unitTypeSet.insert(Hero_Devouring_One); unitTypeSet.insert(Hero_Infested_Kerrigan); unitTypeSet.insert(Zerg_Hydralisk); unitTypeSet.insert(Hero_Hunter_Killer); unitTypeSet.insert(Zerg_Ultralisk); unitTypeSet.insert(Hero_Torrasque); unitTypeSet.insert(Zerg_Broodling); unitTypeSet.insert(Zerg_Drone); unitTypeSet.insert(Zerg_Overlord); unitTypeSet.insert(Hero_Yggdrasill); unitTypeSet.insert(Zerg_Mutalisk); unitTypeSet.insert(Hero_Kukulza_Mutalisk); unitTypeSet.insert(Zerg_Guardian); unitTypeSet.insert(Hero_Kukulza_Guardian); unitTypeSet.insert(Zerg_Queen); unitTypeSet.insert(Hero_Matriarch); unitTypeSet.insert(Zerg_Defiler); unitTypeSet.insert(Hero_Unclean_One); unitTypeSet.insert(Zerg_Scourge); unitTypeSet.insert(Zerg_Infested_Terran); unitTypeSet.insert(Terran_Valkyrie); unitTypeSet.insert(Zerg_Cocoon); unitTypeSet.insert(Protoss_Corsair); unitTypeSet.insert(Hero_Raszagal); unitTypeSet.insert(Protoss_Dark_Templar); unitTypeSet.insert(Hero_Dark_Templar); unitTypeSet.insert(Hero_Zeratul); unitTypeSet.insert(Zerg_Devourer); unitTypeSet.insert(Protoss_Dark_Archon); unitTypeSet.insert(Protoss_Probe); unitTypeSet.insert(Protoss_Zealot); unitTypeSet.insert(Hero_Fenix_Zealot); unitTypeSet.insert(Protoss_Dragoon); unitTypeSet.insert(Hero_Fenix_Dragoon); unitTypeSet.insert(Protoss_High_Templar); unitTypeSet.insert(Hero_Tassadar); unitTypeSet.insert(Hero_Aldaris); unitTypeSet.insert(Protoss_Archon); unitTypeSet.insert(Hero_Tassadar_Zeratul_Archon); unitTypeSet.insert(Protoss_Shuttle); unitTypeSet.insert(Protoss_Scout); unitTypeSet.insert(Hero_Mojo); unitTypeSet.insert(Hero_Artanis); unitTypeSet.insert(Protoss_Arbiter); unitTypeSet.insert(Hero_Danimoth); unitTypeSet.insert(Protoss_Carrier); unitTypeSet.insert(Hero_Gantrithor); unitTypeSet.insert(Protoss_Interceptor); unitTypeSet.insert(Protoss_Reaver); unitTypeSet.insert(Hero_Warbringer); unitTypeSet.insert(Protoss_Observer); unitTypeSet.insert(Protoss_Scarab); unitTypeSet.insert(Critter_Rhynadon); unitTypeSet.insert(Critter_Bengalaas); unitTypeSet.insert(Critter_Scantid); unitTypeSet.insert(Critter_Kakaru); unitTypeSet.insert(Critter_Ragnasaur); unitTypeSet.insert(Critter_Ursadon); unitTypeSet.insert(Zerg_Lurker_Egg); unitTypeSet.insert(Zerg_Lurker); unitTypeSet.insert(Spell_Disruption_Web); unitTypeSet.insert(Terran_Command_Center); unitTypeSet.insert(Terran_Comsat_Station); unitTypeSet.insert(Terran_Nuclear_Silo); unitTypeSet.insert(Terran_Supply_Depot); unitTypeSet.insert(Terran_Refinery); unitTypeSet.insert(Terran_Barracks); unitTypeSet.insert(Terran_Academy); unitTypeSet.insert(Terran_Factory); unitTypeSet.insert(Terran_Starport); unitTypeSet.insert(Terran_Control_Tower); unitTypeSet.insert(Terran_Science_Facility); unitTypeSet.insert(Terran_Covert_Ops); unitTypeSet.insert(Terran_Physics_Lab); unitTypeSet.insert(Terran_Machine_Shop); unitTypeSet.insert(Terran_Engineering_Bay); unitTypeSet.insert(Terran_Armory); unitTypeSet.insert(Terran_Missile_Turret); unitTypeSet.insert(Terran_Bunker); unitTypeSet.insert(Special_Crashed_Norad_II); unitTypeSet.insert(Special_Ion_Cannon); unitTypeSet.insert(Zerg_Infested_Command_Center); unitTypeSet.insert(Zerg_Hatchery); unitTypeSet.insert(Zerg_Lair); unitTypeSet.insert(Zerg_Hive); unitTypeSet.insert(Zerg_Nydus_Canal); unitTypeSet.insert(Zerg_Hydralisk_Den); unitTypeSet.insert(Zerg_Defiler_Mound); unitTypeSet.insert(Zerg_Greater_Spire); unitTypeSet.insert(Zerg_Queens_Nest); unitTypeSet.insert(Zerg_Evolution_Chamber); unitTypeSet.insert(Zerg_Ultralisk_Cavern); unitTypeSet.insert(Zerg_Spire); unitTypeSet.insert(Zerg_Spawning_Pool); unitTypeSet.insert(Zerg_Creep_Colony); unitTypeSet.insert(Zerg_Spore_Colony); unitTypeSet.insert(Zerg_Sunken_Colony); unitTypeSet.insert(Special_Overmind_With_Shell); unitTypeSet.insert(Special_Overmind); unitTypeSet.insert(Zerg_Extractor); unitTypeSet.insert(Special_Mature_Chrysalis); unitTypeSet.insert(Special_Cerebrate); unitTypeSet.insert(Special_Cerebrate_Daggoth); unitTypeSet.insert(Protoss_Nexus); unitTypeSet.insert(Protoss_Robotics_Facility); unitTypeSet.insert(Protoss_Pylon); unitTypeSet.insert(Protoss_Assimilator); unitTypeSet.insert(Protoss_Observatory); unitTypeSet.insert(Protoss_Gateway); unitTypeSet.insert(Protoss_Photon_Cannon); unitTypeSet.insert(Protoss_Citadel_of_Adun); unitTypeSet.insert(Protoss_Cybernetics_Core); unitTypeSet.insert(Protoss_Templar_Archives); unitTypeSet.insert(Protoss_Forge); unitTypeSet.insert(Protoss_Stargate); unitTypeSet.insert(Special_Stasis_Cell_Prison); unitTypeSet.insert(Protoss_Fleet_Beacon); unitTypeSet.insert(Protoss_Arbiter_Tribunal); unitTypeSet.insert(Protoss_Robotics_Support_Bay); unitTypeSet.insert(Protoss_Shield_Battery); unitTypeSet.insert(Special_Khaydarin_Crystal_Form); unitTypeSet.insert(Special_Protoss_Temple); unitTypeSet.insert(Special_XelNaga_Temple); unitTypeSet.insert(Resource_Mineral_Field); unitTypeSet.insert(Resource_Vespene_Geyser); unitTypeSet.insert(Special_Warp_Gate); unitTypeSet.insert(Special_Psi_Disrupter); unitTypeSet.insert(Special_Power_Generator); unitTypeSet.insert(Special_Overmind_Cocoon); unitTypeSet.insert(Special_Zerg_Beacon); unitTypeSet.insert(Special_Terran_Beacon); unitTypeSet.insert(Special_Protoss_Beacon); unitTypeSet.insert(Special_Zerg_Flag_Beacon); unitTypeSet.insert(Special_Terran_Flag_Beacon); unitTypeSet.insert(Special_Protoss_Flag_Beacon); unitTypeSet.insert(Spell_Dark_Swarm); unitTypeSet.insert(Powerup_Uraj_Crystal); unitTypeSet.insert(Powerup_Khalis_Crystal); unitTypeSet.insert(Powerup_Flag); unitTypeSet.insert(Powerup_Young_Chrysalis); unitTypeSet.insert(Powerup_Psi_Emitter); unitTypeSet.insert(Powerup_Data_Disk); unitTypeSet.insert(Powerup_Khaydarin_Crystal); unitTypeSet.insert(None); unitTypeSet.insert(Unknown); foreach(UnitType i, unitTypeSet) { std::string name = i.getName(); fixName(&name); unitTypeMap.insert(std::make_pair(name, i)); } initializingUnitType = false; } } UnitType::UnitType() { this->id = UnitTypes::None.id; } UnitType::UnitType(int id) { this->id = id; if (!initializingUnitType && (id < 0 || id >= 230 || !unitTypeData[id].valid)) this->id = UnitTypes::Unknown.id; } UnitType::UnitType(const UnitType& other) { this->id = other.id; } UnitType& UnitType::operator=(const UnitType& other) { this->id = other.id; return *this; } bool UnitType::operator==(const UnitType& other) const { return this->id == other.id; } bool UnitType::operator!=(const UnitType& other) const { return this->id != other.id; } bool UnitType::operator<(const UnitType& other) const { return this->id < other.id; } int UnitType::getID() const { return this->id; } std::string UnitType::getName() const { return unitTypeData[this->id].name; } Race UnitType::getRace() const { return unitTypeData[this->id].race; } const std::pair< UnitType, int> UnitType::whatBuilds() const { return unitTypeData[this->id].whatBuilds; } const std::map< UnitType, int >& UnitType::requiredUnits() const { return unitTypeData[this->id].requiredUnits; } TechType UnitType::requiredTech() const { return unitTypeData[this->id].requiredTech; } TechType UnitType::cloakingTech() const { return unitTypeData[this->id].cloakingTech; } const std::set< TechType >& UnitType::abilities() const { return unitTypeData[this->id].abilities; } const std::set< UpgradeType >& UnitType::upgrades() const { return unitTypeData[this->id].upgrades; } UpgradeType UnitType::armorUpgrade() const { return unitTypeData[this->id].armorUpgrade; } int UnitType::maxHitPoints() const { return unitTypeData[this->id].maxHitPoints; } int UnitType::maxShields() const { return unitTypeData[this->id].maxShields; } int UnitType::maxEnergy() const { return unitTypeData[this->id].maxEnergy; } int UnitType::armor() const { return unitTypeData[this->id].armor; } int UnitType::mineralPrice() const { return unitTypeData[this->id].mineralPrice; } int UnitType::gasPrice() const { return unitTypeData[this->id].gasPrice; } int UnitType::buildTime() const { return unitTypeData[this->id].buildTime; } int UnitType::supplyRequired() const { return unitTypeData[this->id].supplyRequired; } int UnitType::supplyProvided() const { return unitTypeData[this->id].supplyProvided; } int UnitType::spaceRequired() const { return unitTypeData[this->id].spaceRequired; } int UnitType::spaceProvided() const { return unitTypeData[this->id].spaceProvided; } int UnitType::buildScore() const { return unitTypeData[this->id].buildScore; } int UnitType::destroyScore() const { return unitTypeData[this->id].destroyScore; } UnitSizeType UnitType::size() const { return unitTypeData[this->id].unitSizeType; } int UnitType::tileWidth() const { return unitTypeData[this->id].tileWidth; } int UnitType::tileHeight() const { return unitTypeData[this->id].tileHeight; } int UnitType::dimensionLeft() const { return unitTypeData[this->id].dimensionLeft; } int UnitType::dimensionUp() const { return unitTypeData[this->id].dimensionUp; } int UnitType::dimensionRight() const { return unitTypeData[this->id].dimensionRight; } int UnitType::dimensionDown() const { return unitTypeData[this->id].dimensionDown; } int UnitType::seekRange() const { return unitTypeData[this->id].seekRange; } int UnitType::sightRange() const { return unitTypeData[this->id].sightRange; } WeaponType UnitType::groundWeapon() const { return unitTypeData[this->id].groundWeapon; } int UnitType::maxGroundHits() const { return unitTypeData[this->id].maxGroundHits; } WeaponType UnitType::airWeapon() const { return unitTypeData[this->id].airWeapon; } int UnitType::maxAirHits() const { return unitTypeData[this->id].maxAirHits; } double UnitType::topSpeed() const { return unitTypeData[this->id].topSpeed; } int UnitType::acceleration() const { return unitTypeData[this->id].acceleration; } int UnitType::haltDistance() const { return unitTypeData[this->id].haltDistance; } int UnitType::turnRadius() const { return unitTypeData[this->id].turnRadius; } bool UnitType::canProduce() const { return unitTypeData[this->id].canProduce; } bool UnitType::canAttack() const { return unitTypeData[this->id].canAttack; } bool UnitType::canMove() const { return unitTypeData[this->id].canMove; } bool UnitType::isFlyer() const { return unitTypeData[this->id].isFlyer; } bool UnitType::regeneratesHP() const { return unitTypeData[this->id].regeneratesHP; } bool UnitType::isSpellcaster() const { return unitTypeData[this->id].isSpellcaster; } bool UnitType::hasPermanentCloak() const { return unitTypeData[this->id].hasPermanentCloak; } bool UnitType::isInvincible() const { return unitTypeData[this->id].isInvincible; } bool UnitType::isOrganic() const { return unitTypeData[this->id].isOrganic; } bool UnitType::isMechanical() const { return unitTypeData[this->id].isMechanical; } bool UnitType::isRobotic() const { return unitTypeData[this->id].isRobotic; } bool UnitType::isDetector() const { return unitTypeData[this->id].isDetector; } bool UnitType::isResourceContainer() const { return unitTypeData[this->id].isResourceContainer; } bool UnitType::isResourceDepot() const { return unitTypeData[this->id].isResourceDepot; } bool UnitType::isRefinery() const { return unitTypeData[this->id].isRefinery; } bool UnitType::isWorker() const { return unitTypeData[this->id].isWorker; } bool UnitType::requiresPsi() const { return unitTypeData[this->id].requiresPsi; } bool UnitType::requiresCreep() const { return unitTypeData[this->id].requiresCreep; } bool UnitType::isTwoUnitsInOneEgg() const { return unitTypeData[this->id].isTwoUnitsInOneEgg; } bool UnitType::isBurrowable() const { return unitTypeData[this->id].isBurrowable; } bool UnitType::isCloakable() const { return unitTypeData[this->id].isCloakable; } bool UnitType::isBuilding() const { return unitTypeData[this->id].isBuilding; } bool UnitType::isAddon() const { return unitTypeData[this->id].isAddon; } bool UnitType::isFlyingBuilding() const { return unitTypeData[this->id].isFlyingBuilding; } bool UnitType::isNeutral() const { return unitTypeData[this->id].isNeutral; } bool UnitType::isHero() const { return unitTypeData[this->id].isHero || this->id == UnitTypes::Hero_Dark_Templar.id || this->id == UnitTypes::Terran_Civilian.id; } bool UnitType::isPowerup() const { return this->id == UnitTypes::Powerup_Uraj_Crystal.id || this->id == UnitTypes::Powerup_Khalis_Crystal.id || (this->id >= UnitTypes::Powerup_Flag.id && this->id < UnitTypes::None.id); } bool UnitType::isBeacon() const { return this->id == UnitTypes::Special_Zerg_Beacon.id || this->id == UnitTypes::Special_Terran_Beacon.id || this->id == UnitTypes::Special_Protoss_Beacon.id; } bool UnitType::isFlagBeacon() const { return this->id == UnitTypes::Special_Zerg_Flag_Beacon.id || this->id == UnitTypes::Special_Terran_Flag_Beacon.id || this->id == UnitTypes::Special_Protoss_Flag_Beacon.id; } bool UnitType::isSpecialBuilding() const { return unitTypeData[this->id].isSpecialBuilding && this->id != UnitTypes::Zerg_Infested_Command_Center.id; } bool UnitType::isSpell() const { return this->id == UnitTypes::Spell_Dark_Swarm.id || this->id == UnitTypes::Spell_Disruption_Web.id || this->id == UnitTypes::Spell_Scanner_Sweep.id; } bool UnitType::producesLarva() const { return this->id == UnitTypes::Zerg_Hatchery.id || this->id == UnitTypes::Zerg_Lair.id || this->id == UnitTypes::Zerg_Hive.id; } UnitType UnitTypes::getUnitType(std::string name) { fixName(&name); std::map::iterator i = unitTypeMap.find(name); if (i == unitTypeMap.end()) return UnitTypes::Unknown; return (*i).second; } std::set& UnitTypes::allUnitTypes() { return unitTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/UpgradeType.cpp ================================================ #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingUpgradeType = true; class UpgradeTypeInternal { public: UpgradeTypeInternal() {valid = false;} void set(const char* name, int mineralPriceBase, int mineralPriceFactor, int gasPriceBase, int gasPriceFactor, int upgradeTimeBase, int upgradeTimeFactor, BWAPI::UnitType whatUpgrades, Race race, BWAPI::UnitType whatUses, int maxRepeats) { if (initializingUpgradeType) { this->name = name; this->mineralPriceBase = mineralPriceBase; this->mineralPriceFactor = mineralPriceFactor; this->gasPriceBase = gasPriceBase; this->gasPriceFactor = gasPriceFactor; this->upgradeTimeBase = upgradeTimeBase; this->upgradeTimeFactor = upgradeTimeFactor; this->whatUpgrades = whatUpgrades; this->race = race; if (whatUses != UnitTypes::None) this->whatUses.insert(whatUses); this->maxRepeats = maxRepeats; this->valid = true; } } std::string name; int mineralPriceBase; int mineralPriceFactor; int gasPriceBase; int gasPriceFactor; int upgradeTimeBase; int upgradeTimeFactor; BWAPI::UnitType whatUpgrades; Race race; int maxRepeats; std::set whatUses; bool valid; }; UpgradeTypeInternal upgradeTypeData[63]; std::map upgradeTypeMap; std::set< UpgradeType > upgradeTypeSet; namespace UpgradeTypes { const UpgradeType Terran_Infantry_Armor(0); const UpgradeType Terran_Vehicle_Plating(1); const UpgradeType Terran_Ship_Plating(2); const UpgradeType Zerg_Carapace(3); const UpgradeType Zerg_Flyer_Carapace(4); const UpgradeType Protoss_Ground_Armor(5); const UpgradeType Protoss_Air_Armor(6); const UpgradeType Terran_Infantry_Weapons(7); const UpgradeType Terran_Vehicle_Weapons(8); const UpgradeType Terran_Ship_Weapons(9); const UpgradeType Zerg_Melee_Attacks(10); const UpgradeType Zerg_Missile_Attacks(11); const UpgradeType Zerg_Flyer_Attacks(12); const UpgradeType Protoss_Ground_Weapons(13); const UpgradeType Protoss_Air_Weapons(14); const UpgradeType Protoss_Plasma_Shields(15); const UpgradeType U_238_Shells(16); const UpgradeType Ion_Thrusters(17); const UpgradeType Titan_Reactor(19); const UpgradeType Ocular_Implants(20); const UpgradeType Moebius_Reactor(21); const UpgradeType Apollo_Reactor(22); const UpgradeType Colossus_Reactor(23); const UpgradeType Ventral_Sacs(24); const UpgradeType Antennae(25); const UpgradeType Pneumatized_Carapace(26); const UpgradeType Metabolic_Boost(27); const UpgradeType Adrenal_Glands(28); const UpgradeType Muscular_Augments(29); const UpgradeType Grooved_Spines(30); const UpgradeType Gamete_Meiosis(31); const UpgradeType Metasynaptic_Node(32); const UpgradeType Singularity_Charge(33); const UpgradeType Leg_Enhancements(34); const UpgradeType Scarab_Damage(35); const UpgradeType Reaver_Capacity(36); const UpgradeType Gravitic_Drive(37); const UpgradeType Sensor_Array(38); const UpgradeType Gravitic_Boosters(39); const UpgradeType Khaydarin_Amulet(40); const UpgradeType Apial_Sensors(41); const UpgradeType Gravitic_Thrusters(42); const UpgradeType Carrier_Capacity(43); const UpgradeType Khaydarin_Core(44); const UpgradeType Argus_Jewel(47); const UpgradeType Argus_Talisman(49); const UpgradeType Caduceus_Reactor(51); const UpgradeType Chitinous_Plating(52); const UpgradeType Anabolic_Synthesis(53); const UpgradeType Charon_Boosters(54); const UpgradeType None(61); const UpgradeType Unknown(62); void init() { upgradeTypeData[Terran_Infantry_Armor.getID()].set("Terran Infantry Armor" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Vehicle_Plating.getID()].set("Terran Vehicle Plating" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Ship_Plating.getID()].set("Terran Ship Plating" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Zerg_Carapace.getID()].set("Zerg Carapace" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Flyer_Carapace.getID()].set("Zerg Flyer Carapace" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Zerg_Spire , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Protoss_Ground_Armor.getID()].set("Protoss Ground Armor" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Air_Armor.getID()].set("Protoss Air Armor" , 150, 75 , 150, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Terran_Infantry_Weapons.getID()].set("Terran Infantry Weapons", 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Engineering_Bay , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Vehicle_Weapons.getID()].set("Terran Vehicle Weapons" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Terran_Ship_Weapons.getID()].set("Terran Ship Weapons" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Terran_Armory , Races::Terran , UnitTypes::None , 3); upgradeTypeData[Zerg_Melee_Attacks.getID()].set("Zerg Melee Attacks" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Missile_Attacks.getID()].set("Zerg Missile Attacks" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Zerg_Evolution_Chamber , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Zerg_Flyer_Attacks.getID()].set("Zerg Flyer Attacks" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Zerg_Spire , Races::Zerg , UnitTypes::None , 3); upgradeTypeData[Protoss_Ground_Weapons.getID()].set("Protoss Ground Weapons" , 100, 50 , 100, 50 , 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Air_Weapons.getID()].set("Protoss Air Weapons" , 100, 75 , 100, 75 , 4000, 480, UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[Protoss_Plasma_Shields.getID()].set("Protoss Plasma Shields" , 200, 100, 200, 100, 4000, 480, UnitTypes::Protoss_Forge , Races::Protoss, UnitTypes::None , 3); upgradeTypeData[U_238_Shells.getID()].set("U-238 Shells" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Terran_Academy , Races::Terran , UnitTypes::Terran_Marine , 1); upgradeTypeData[Ion_Thrusters.getID()].set("Ion Thrusters" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Terran_Machine_Shop , Races::Terran , UnitTypes::Terran_Vulture , 1); upgradeTypeData[Titan_Reactor.getID()].set("Titan Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Science_Facility , Races::Terran , UnitTypes::Terran_Science_Vessel, 1); upgradeTypeData[Ocular_Implants.getID()].set("Ocular Implants" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Terran_Covert_Ops , Races::Terran , UnitTypes::Terran_Ghost , 1); upgradeTypeData[Moebius_Reactor.getID()].set("Moebius Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Covert_Ops , Races::Terran , UnitTypes::Terran_Ghost , 1); upgradeTypeData[Apollo_Reactor.getID()].set("Apollo Reactor" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Terran_Control_Tower , Races::Terran , UnitTypes::Terran_Wraith , 1); upgradeTypeData[Colossus_Reactor.getID()].set("Colossus Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Physics_Lab , Races::Terran , UnitTypes::Terran_Battlecruiser , 1); upgradeTypeData[Ventral_Sacs.getID()].set("Ventral Sacs" , 200, 0 , 200, 0 , 2400, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Antennae.getID()].set("Antennae" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Pneumatized_Carapace.getID()].set("Pneumatized Carapace" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Lair , Races::Zerg , UnitTypes::Zerg_Overlord , 1); upgradeTypeData[Metabolic_Boost.getID()].set("Metabolic Boost" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Zerg_Spawning_Pool , Races::Zerg , UnitTypes::Zerg_Zergling , 1); upgradeTypeData[Adrenal_Glands.getID()].set("Adrenal Glands" , 200, 0 , 200, 0 , 1500, 0 , UnitTypes::Zerg_Spawning_Pool , Races::Zerg , UnitTypes::Zerg_Zergling , 1); upgradeTypeData[Muscular_Augments.getID()].set("Muscular Augments" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Zerg_Hydralisk_Den , Races::Zerg , UnitTypes::Zerg_Hydralisk , 1); upgradeTypeData[Grooved_Spines.getID()].set("Grooved Spines" , 150, 0 , 150, 0 , 1500, 0 , UnitTypes::Zerg_Hydralisk_Den , Races::Zerg , UnitTypes::Zerg_Hydralisk , 1); upgradeTypeData[Gamete_Meiosis.getID()].set("Gamete Meiosis" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Zerg_Queens_Nest , Races::Zerg , UnitTypes::Zerg_Queen , 1); upgradeTypeData[Metasynaptic_Node.getID()].set("Metasynaptic Node" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Zerg_Defiler_Mound , Races::Zerg , UnitTypes::Zerg_Defiler , 1); upgradeTypeData[Singularity_Charge.getID()].set("Singularity Charge" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Cybernetics_Core , Races::Protoss, UnitTypes::Protoss_Dragoon , 1); upgradeTypeData[Leg_Enhancements.getID()].set("Leg Enhancements" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Citadel_of_Adun , Races::Protoss, UnitTypes::Protoss_Zealot , 1); upgradeTypeData[Scarab_Damage.getID()].set("Scarab Damage" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Scarab , 1); upgradeTypeData[Reaver_Capacity.getID()].set("Reaver Capacity" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Reaver , 1); upgradeTypeData[Gravitic_Drive.getID()].set("Gravitic Drive" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Robotics_Support_Bay, Races::Protoss, UnitTypes::Protoss_Shuttle , 1); upgradeTypeData[Sensor_Array.getID()].set("Sensor Array" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Observatory , Races::Protoss, UnitTypes::Protoss_Observer , 1); upgradeTypeData[Gravitic_Boosters.getID()].set("Gravitic Boosters" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Protoss_Observatory , Races::Protoss, UnitTypes::Protoss_Observer , 1); upgradeTypeData[Khaydarin_Amulet.getID()].set("Khaydarin Amulet" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Templar_Archives , Races::Protoss, UnitTypes::Protoss_High_Templar , 1); upgradeTypeData[Apial_Sensors.getID()].set("Apial Sensors" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Scout , 1); upgradeTypeData[Gravitic_Thrusters.getID()].set("Gravitic Thrusters" , 200, 0 , 200, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Scout , 1); upgradeTypeData[Carrier_Capacity.getID()].set("Carrier Capacity" , 100, 0 , 100, 0 , 1500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Carrier , 1); upgradeTypeData[Khaydarin_Core.getID()].set("Khaydarin Core" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Arbiter_Tribunal , Races::Protoss, UnitTypes::Protoss_Arbiter , 1); upgradeTypeData[Argus_Jewel.getID()].set("Argus Jewel" , 100, 0 , 100, 0 , 2500, 0 , UnitTypes::Protoss_Fleet_Beacon , Races::Protoss, UnitTypes::Protoss_Corsair , 1); upgradeTypeData[Argus_Talisman.getID()].set("Argus Talisman" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Protoss_Templar_Archives , Races::Protoss, UnitTypes::Protoss_Dark_Archon , 1); upgradeTypeData[Caduceus_Reactor.getID()].set("Caduceus Reactor" , 150, 0 , 150, 0 , 2500, 0 , UnitTypes::Terran_Academy , Races::Terran , UnitTypes::Terran_Medic , 1); upgradeTypeData[Chitinous_Plating.getID()].set("Chitinous Plating" , 150, 0 , 150, 0 , 2000, 0 , UnitTypes::Zerg_Ultralisk_Cavern , Races::Zerg , UnitTypes::Zerg_Ultralisk , 1); upgradeTypeData[Anabolic_Synthesis.getID()].set("Anabolic Synthesis" , 200, 0 , 200, 0 , 2000, 0 , UnitTypes::Zerg_Ultralisk_Cavern , Races::Zerg , UnitTypes::Zerg_Ultralisk , 1); upgradeTypeData[Charon_Boosters.getID()].set("Charon Boosters" , 100, 0 , 100, 0 , 2000, 0 , UnitTypes::Terran_Machine_Shop , Races::Terran , UnitTypes::Terran_Goliath , 1); upgradeTypeData[None.getID()].set("None" , 0 , 0 , 0 , 0 , 0 , 0 , UnitTypes::None , Races::None , UnitTypes::None , 0); upgradeTypeData[Unknown.getID()].set("Unknown" , 0 , 0 , 0 , 0 , 0 , 0 , UnitTypes::None , Races::Unknown, UnitTypes::None , 0); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Firebat); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Ghost); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Marine); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_Medic); upgradeTypeData[Terran_Infantry_Armor.getID()].whatUses.insert(UnitTypes::Terran_SCV); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Goliath); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode); upgradeTypeData[Terran_Vehicle_Plating.getID()].whatUses.insert(UnitTypes::Terran_Vulture); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Dropship); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Science_Vessel); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie); upgradeTypeData[Terran_Ship_Plating.getID()].whatUses.insert(UnitTypes::Terran_Wraith); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Broodling); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Defiler); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Drone); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Infested_Terran); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Larva); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Lurker); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk); upgradeTypeData[Zerg_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Zergling); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Devourer); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Guardian); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Overlord); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Queen); upgradeTypeData[Zerg_Flyer_Carapace.getID()].whatUses.insert(UnitTypes::Zerg_Scourge); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Archon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Probe); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Reaver); upgradeTypeData[Protoss_Ground_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Carrier); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Observer); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Air_Armor.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Firebat); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Ghost); upgradeTypeData[Terran_Infantry_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Marine); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Goliath); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Siege_Mode); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Siege_Tank_Tank_Mode); upgradeTypeData[Terran_Vehicle_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Vulture); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Battlecruiser); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Valkyrie); upgradeTypeData[Terran_Ship_Weapons.getID()].whatUses.insert(UnitTypes::Terran_Wraith); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Broodling); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Ultralisk); upgradeTypeData[Zerg_Melee_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Zergling); upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Hydralisk); upgradeTypeData[Zerg_Missile_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Lurker); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Devourer); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Guardian); upgradeTypeData[Zerg_Flyer_Attacks.getID()].whatUses.insert(UnitTypes::Zerg_Mutalisk); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Ground_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Air_Weapons.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Arbiter_Tribunal); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Archon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Assimilator); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Carrier); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Citadel_of_Adun); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Corsair); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Cybernetics_Core); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Archon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dark_Templar); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Dragoon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Fleet_Beacon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Forge); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Gateway); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_High_Templar); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Interceptor); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Nexus); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observatory); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Observer); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Photon_Cannon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Probe); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Pylon); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Reaver); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Facility); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Robotics_Support_Bay); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scarab); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Scout); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shield_Battery); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Shuttle); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Stargate); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Templar_Archives); upgradeTypeData[Protoss_Plasma_Shields.getID()].whatUses.insert(UnitTypes::Protoss_Zealot); upgradeTypeSet.insert(Terran_Infantry_Armor); upgradeTypeSet.insert(Terran_Vehicle_Plating); upgradeTypeSet.insert(Terran_Ship_Plating); upgradeTypeSet.insert(Zerg_Carapace); upgradeTypeSet.insert(Zerg_Flyer_Carapace); upgradeTypeSet.insert(Protoss_Ground_Armor); upgradeTypeSet.insert(Protoss_Air_Armor); upgradeTypeSet.insert(Terran_Infantry_Weapons); upgradeTypeSet.insert(Terran_Vehicle_Weapons); upgradeTypeSet.insert(Terran_Ship_Weapons); upgradeTypeSet.insert(Zerg_Melee_Attacks); upgradeTypeSet.insert(Zerg_Missile_Attacks); upgradeTypeSet.insert(Zerg_Flyer_Attacks); upgradeTypeSet.insert(Protoss_Ground_Weapons); upgradeTypeSet.insert(Protoss_Air_Weapons); upgradeTypeSet.insert(Protoss_Plasma_Shields); upgradeTypeSet.insert(U_238_Shells); upgradeTypeSet.insert(Ion_Thrusters); upgradeTypeSet.insert(Titan_Reactor); upgradeTypeSet.insert(Ocular_Implants); upgradeTypeSet.insert(Moebius_Reactor); upgradeTypeSet.insert(Apollo_Reactor); upgradeTypeSet.insert(Colossus_Reactor); upgradeTypeSet.insert(Ventral_Sacs); upgradeTypeSet.insert(Antennae); upgradeTypeSet.insert(Pneumatized_Carapace); upgradeTypeSet.insert(Metabolic_Boost); upgradeTypeSet.insert(Adrenal_Glands); upgradeTypeSet.insert(Muscular_Augments); upgradeTypeSet.insert(Grooved_Spines); upgradeTypeSet.insert(Gamete_Meiosis); upgradeTypeSet.insert(Metasynaptic_Node); upgradeTypeSet.insert(Singularity_Charge); upgradeTypeSet.insert(Leg_Enhancements); upgradeTypeSet.insert(Scarab_Damage); upgradeTypeSet.insert(Reaver_Capacity); upgradeTypeSet.insert(Gravitic_Drive); upgradeTypeSet.insert(Sensor_Array); upgradeTypeSet.insert(Gravitic_Boosters); upgradeTypeSet.insert(Khaydarin_Amulet); upgradeTypeSet.insert(Apial_Sensors); upgradeTypeSet.insert(Gravitic_Thrusters); upgradeTypeSet.insert(Carrier_Capacity); upgradeTypeSet.insert(Khaydarin_Core); upgradeTypeSet.insert(Argus_Jewel); upgradeTypeSet.insert(Argus_Talisman); upgradeTypeSet.insert(Caduceus_Reactor); upgradeTypeSet.insert(Chitinous_Plating); upgradeTypeSet.insert(Anabolic_Synthesis); upgradeTypeSet.insert(Charon_Boosters); upgradeTypeSet.insert(None); upgradeTypeSet.insert(Unknown); foreach(UpgradeType i, upgradeTypeSet) { std::string name = i.getName(); fixName(&name); upgradeTypeMap.insert(std::make_pair(name, i)); } initializingUpgradeType = false; } } UpgradeType::UpgradeType() { this->id = UpgradeTypes::None.id; } UpgradeType::UpgradeType(int id) { this->id = id; if (!initializingUpgradeType && (id < 0 || id >= 63 || !upgradeTypeData[id].valid) ) this->id = UpgradeTypes::Unknown.id; } UpgradeType::UpgradeType(const UpgradeType& other) { this->id = other.id; } UpgradeType& UpgradeType::operator=(const UpgradeType& other) { this->id = other.id; return *this; } bool UpgradeType::operator==(const UpgradeType& other) const { return this->id == other.id; } bool UpgradeType::operator!=(const UpgradeType& other) const { return this->id != other.id; } bool UpgradeType::operator<(const UpgradeType& other) const { return this->id < other.id; } int UpgradeType::getID() const { return this->id; } std::string UpgradeType::getName() const { return upgradeTypeData[this->id].name; } Race UpgradeType::getRace() const { return upgradeTypeData[this->id].race; } int UpgradeType::mineralPrice() const { return upgradeTypeData[this->id].mineralPriceBase; } int UpgradeType::mineralPriceFactor() const { return upgradeTypeData[this->id].mineralPriceFactor; } int UpgradeType::gasPrice() const { return upgradeTypeData[this->id].gasPriceBase; } int UpgradeType::gasPriceFactor() const { return upgradeTypeData[this->id].gasPriceFactor; } int UpgradeType::upgradeTime() const { return upgradeTypeData[this->id].upgradeTimeBase; } int UpgradeType::upgradeTimeFactor() const { return upgradeTypeData[this->id].upgradeTimeFactor; } UnitType UpgradeType::whatUpgrades() const { return upgradeTypeData[this->id].whatUpgrades; } const std::set& UpgradeType::whatUses() const { return upgradeTypeData[this->id].whatUses; } int UpgradeType::maxRepeats() const { return upgradeTypeData[this->id].maxRepeats; } UpgradeType UpgradeTypes::getUpgradeType(std::string name) { fixName(&name); std::map::iterator i = upgradeTypeMap.find(name); if (i == upgradeTypeMap.end()) return UpgradeTypes::Unknown; return (*i).second; } std::set& UpgradeTypes::allUpgradeTypes() { return upgradeTypeSet; } } ================================================ FILE: SparCraft/bwapidata/include/Util/Bitmask.h ================================================ #pragma once /** Custom help classes not connected with the project */ namespace Util { /** * Representation of list of bool values using binary. * Size of the bitmask is always the same as Type (so it can be mapped in bw structurs) * This also means, that the bitmas has sizeof(Type)*8 values. */ template class BitMask { public : bool getBit(Type bit) const; void setBit(Type bit, bool val); Type value; }; //------------------------------------------------ GET BIT ------------------------------------------------- template bool BitMask::getBit(Type bit) const { return (value & bit) != 0; } //------------------------------------------------ SET BIT ------------------------------------------------- template void BitMask::setBit(Type bit, bool val) { if (val) value |= bit; else value &= ~bit; } } ================================================ FILE: SparCraft/bwapidata/include/Util/Exceptions.cpp ================================================ #include "Exceptions.h" //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ GeneralException::GeneralException(const std::string &message) :message(message) { } //----------------------------------------------- GET MESSAGE ------------------------------------------------ const std::string GeneralException::getMessage(void) { return this->message; } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ FileException::FileException(const std::string &message) : GeneralException(message) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ ConfigException::ConfigException(const std::string &message) : GeneralException(message) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ XmlException::XmlException(const std::string& message, const std::string& fileName, const long lineNumber) :GeneralException(message) ,fileName(fileName) ,lineNumber(lineNumber) { } //----------------------------------------------- CONSTRUCTOR ------------------------------------------------ ParseException::ParseException(const std::string& message) :GeneralException(message) { } //------------------------------------------------------------------------------------------------------------ ================================================ FILE: SparCraft/bwapidata/include/Util/Exceptions.h ================================================ #pragma once #include class MultiString; /** * Represents any exception that can be thrown during to program run, * it doesn't contain expressions that can be thrown by tinyXml */ class GeneralException { private : /** * Represents the property key of the exception message, but in some special * cases, the messageKey can contain the message itself */ std::string message; public: /** Creates exception with the specified message */ GeneralException(const std::string &messageKey); const std::string getMessage(void); }; /** * Can be thrown when the configuration files are invalid, or contain invalid * information. */ class ConfigException : public GeneralException { public : ConfigException(const std::string &message); }; /** Can be thrown when some required files are not found. */ class FileException : public GeneralException { public : FileException(const std::string &message); }; /** Can be thrown when the xml file structure is invalid. */ class XmlException : public GeneralException { std::string fileName; long lineNumber; public : XmlException(const std::string& message, const std::string& fileName = "", const long lineNumber = 0); }; /** Can be thrown during parsin (non integer paremters that should be numbers for example) */ class ParseException : public GeneralException { public : ParseException(const std::string& message); }; ================================================ FILE: SparCraft/bwapidata/include/Util/FileLogger.cpp ================================================ #include "FileLogger.h" #include namespace Util { //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- FileLogger::FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime) :Logger(logLevel) ,fileName(fileName + ".log") ,showTime(showTime) { } //------------------------------------------------- FLUSH -------------------------------------------------- bool FileLogger::flush(const char* data) { FILE *f = fopen(fileName.c_str(),"at"); if (!f) return false; if (showTime) { char time[9]; _strtime(time); fprintf(f, "%s ", time); } fprintf(f, "%s \n", data); fclose(f); return true; } } ================================================ FILE: SparCraft/bwapidata/include/Util/FileLogger.h ================================================ #pragma once #include "Logger.h" namespace Util { /** Mutation of logger that prints messages to file. */ class FileLogger : public Logger { public : FileLogger(const std::string& fileName, Util::LogLevel::Enum logLevel, bool showTime = true); protected : virtual bool flush(const char* data); private : std::string fileName; bool showTime; }; } ================================================ FILE: SparCraft/bwapidata/include/Util/Foreach.h ================================================ #pragma once #ifdef __GNUC__ #define foreach(element, collection) \ for(typeof((collection).begin()) _foreach_iter = (collection).begin(); _foreach_iter != (collection).end(); ++_foreach_iter) \ if(bool _foreach_loop = false) {} else \ for(element = *_foreach_iter; !_foreach_loop; _foreach_loop = true) #else #define foreach(element, collection) for each(element in collection) #endif ================================================ FILE: SparCraft/bwapidata/include/Util/Gnu.h ================================================ #pragma once #ifdef __GNUC__ #include #define fprintf_s fprintf #define sprintf_s snprintf #define vsnprintf_s(buf, s1, s2, fmt, ap) vsnprintf(buf, s1, fmt, ap) #define memcpy_s(dest, ds, src, ss) memcpy(dest, src, ss) inline void strcpy_s(char* dest, size_t size, char* src) { size_t s = strlen(src); if(s > size - 1) { s = size - 1; } memcpy(dest, src, s); dest[s] = 0; } #endif ================================================ FILE: SparCraft/bwapidata/include/Util/LogLevel.h ================================================ namespace Util { /** The level of detail of the log. */ namespace LogLevel { enum Enum { DontLog = 0, /**< No logs will be printed by logger with this logLevel specification. Shouldn't be used by the Logger#log for obvious reasons. */ Critical = 1, /**< Mostly errors, very important. */ Important = 2, /**< Bigger events. */ Normal = 2, /**< Normal events, like commands ordered etc. */ Commmon = 3, /**< Common things. */ Detailed = 4, /**< Detailed events mainly for investigation of problems. */ MicroDetailed = 5 /**< Super often occuring event's like calling common functions etc, used mainly for searching bugs. */ }; } } ================================================ FILE: SparCraft/bwapidata/include/Util/Logger.cpp ================================================ #include "Logger.h" #include #include #include "FileLogger.h" #include "Foreach.h" #include "Gnu.h" namespace Util { Logger* Logger::globalLog = new FileLogger("global", LogLevel::MicroDetailed); char Logger::buffer[BUFFER_SIZE]; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Logger::Logger(LogLevel::Enum levelToLog) :levelToLog(levelToLog) { } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- Logger::~Logger() { for (std::list::iterator i = this->connectedLoggers.begin(); i != this->connectedLoggers.end(); ++i) delete *i; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::log(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Normal, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logDetailed(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Detailed, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logCommon(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Commmon, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logImportant(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Important, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logCritical(const char* message, ...) { va_list ap; va_start(ap, message); logInternal(message, LogLevel::Critical, ap); va_end(ap); return true; } //-------------------------------------------------- LOG --------------------------------------------------- bool Logger::logInternal(const char* message, LogLevel::Enum logLevel, va_list ap) { if (logLevel > this->levelToLog) return true; vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, message, ap); this->flushInternal(buffer); if (globalLog != NULL && this != globalLog) globalLog->logInternal(message, logLevel, ap); return true; } //-------------------------------------------- REGISTER LOGGER --------------------------------------------- void Logger::registerLogger(Logger* logger) { this->connectedLoggers.push_back(logger); } //---------------------------------------------------------------------------------------------------------- bool Logger::flushInternal(const char* buffer) { foreach (Logger* i, this->connectedLoggers) i->flush(buffer); return this->flush(buffer); } //---------------------------------------------------------------------------------------------------------- } ================================================ FILE: SparCraft/bwapidata/include/Util/Logger.h ================================================ #pragma once #include #include #include #include #include "LogLevel.h" namespace Util { /** * Utility for logging debug output. * This class defines abstract logger interface, every descentant needs to define the flush function to be * instantiable. * Every kind of log should have it's own instance of this class, don't log different things to same log. * Different log instances can be later used to combine different logs with different detailLevels. */ class Logger { public : /** * Creates new logger. * @param levelToLog All log inputs with less importancy will be not * logged in this log */ Logger(LogLevel::Enum levelToLog); virtual ~Logger(); /** * Logs the message using printf formatting style. * This function use Normal Log level. * @param message message to be logged. * @param ... Parameters of the printf style format. */ bool log (const char* message, ...); bool logDetailed (const char* message, ...); bool logCommon (const char* message, ...); bool logImportant(const char* message, ...); bool logCritical (const char* message, ...); void registerLogger(Logger* logger); /** Every log message will be also posted to this global log. */ static Logger* globalLog; static bool deleteLogsAtStart; protected : virtual bool flush(const char* data) = 0; bool flushInternal(const char* data); private : bool logInternal(const char* message, LogLevel::Enum, va_list ap); LogLevel::Enum levelToLog; static const unsigned int BUFFER_SIZE = 2048; static char buffer[BUFFER_SIZE]; std::list connectedLoggers; }; }; ================================================ FILE: SparCraft/bwapidata/include/Util/RectangleArray.h ================================================ #pragma once #include #include #include "Exceptions.h" namespace Util { /** * Template used for work with dynamically initialized array with dimension 2. */ template class RectangleArray { public : /** * Creates the array with the specified proportions. * @param width Width of the new array. * @param height Height of the new array. */ RectangleArray(unsigned int width = 1, unsigned int height = 1, Type* data = NULL); /** Copy constructor */ RectangleArray(const RectangleArray& rectangleArray); /** Destorys the array and deletes all content of array. */ ~RectangleArray(void); /** * Gets the width of the array. * @return width of the array. */ unsigned int getWidth(void) const; /** * Gets the height of the array. * @return height of the array. */ unsigned int getHeight(void) const; /** * Gets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @return item on the specified position. */ Type* getItem(unsigned int x, unsigned int y); inline Type* operator[](int i) { return this->getColumn(i); } inline Type const * const operator[](int i) const {return this->getColumn(i); } /** * Sets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @param item new value of the field. */ void setItem(unsigned int x, unsigned int y, Type *item); void resize(unsigned int width, unsigned int height); void printToFile(FILE* f); void saveToFile(const std::string& fileName); /** Sets all fields of the array to the specified value */ void setTo(const Type& value); void setBorderTo(const Type& value); private : bool owner; /** width of array */ unsigned int width; /** height of array */ unsigned int height; /** Array data, stored as linear array of size width*height */ Type *data; /** Pointers to begins of lines*/ Type **columns; /** * Gets data item on the specified index * @param index index of the data to be returned. */ Type getData(unsigned int index); /** * Gets the pointer in data to the beginning of line with the specified * index. * @param index index of the line. */ Type *getColumn(unsigned int index); /** * Gets the pointer in data to the beginning of line with the specified * index. * @param index index of the line. */ const Type *getColumn(unsigned int index) const; /** * Sets the width of the array. * @param width New width of the array. */ void setWidth(unsigned int width); /** * Sets the height of the array. * @param height New height of the array. */ void setHeight(unsigned int height); }; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RectangleArray::RectangleArray(unsigned int width, unsigned int height, Type* data) { this->setWidth(width); this->setHeight(height); this->owner = (data == NULL); if (this->owner) this->data = new Type[this->getWidth()*this->getHeight()]; else this->data = data; columns = new Type*[this->getWidth()]; unsigned int i = 0; for (unsigned int position = 0;i < width; i ++,position += height) columns[i] = &this->data[position]; } //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RectangleArray::RectangleArray(const RectangleArray& rectangleArray) :owner(true) { this->setWidth(rectangleArray.getWidth()); this->setHeight(rectangleArray.getHeight()); this->data = new Type[this->getWidth()*this->getHeight()]; columns = new Type*[this->getWidth()]; unsigned int i = 0; for (unsigned int position = 0;i < width; i ++,position += height) columns[i] = &data[position]; memcpy(this->data, rectangleArray.data, sizeof(Type)*this->getWidth()*this->getHeight()); } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- template RectangleArray::~RectangleArray(void) { delete [] columns; if (this->owner) delete [] data; } //----------------------------------------------- GET WIDTH ------------------------------------------------ template unsigned int RectangleArray::getWidth(void) const { return this->width; } //----------------------------------------------- SET WIDTH ------------------------------------------------ template void RectangleArray::setWidth(unsigned int width) { this->width = width; } //----------------------------------------------- GET HEIGHT ----------------------------------------------- template unsigned int RectangleArray::getHeight(void) const { return this->height; } //----------------------------------------------- SET HEIGHT ----------------------------------------------- template void RectangleArray::setHeight(unsigned int height) { this->height = height; } //------------------------------------------------ GET ITEM ------------------------------------------------ template Type* RectangleArray::getItem(unsigned int x, unsigned int y) { return this->getColumn(x)[y]; } //------------------------------------------------ SET ITEM ------------------------------------------------ template void RectangleArray::setItem(unsigned int x, unsigned int y, Type* item) { this->getColumn(x)[y] = item; } //------------------------------------------------ GET LINE ------------------------------------------------ template Type* RectangleArray::getColumn(unsigned int index) { return columns[index]; } //------------------------------------------------ GET LINE ------------------------------------------------ template const Type* RectangleArray::getColumn(unsigned int index) const { return columns[index]; } //------------------------------------------------- RESIZE ------------------------------------------------- template void RectangleArray::resize(unsigned int width, unsigned int height) { if (!this->owner) throw GeneralException("Can't resize array that doesn't own the data"); if (this->getWidth() == width && this->getHeight() == height) return; delete [] this->columns; delete [] this->data; this->setWidth(width); this->setHeight(height); this->data = new Type[this->width * this->height]; this->columns = new Type*[this->width]; unsigned int i = 0; for (unsigned int position = 0;i < this->width; i ++,position += this->height) columns[i] = &data[position]; } //--------------------------------------------- PRINT TO FILE ---------------------------------------------- template void RectangleArray::printToFile(FILE* f) { for (unsigned int y = 0; y < this->getHeight(); y++) { for (unsigned int x = 0; x < this->getWidth(); x++) { char ch = this->getColumn(x)[y]; fprintf(f, "%c", ch); } fprintf(f, "\n"); } } //---------------------------------------------- SAVE TO FILE ---------------------------------------------- template void RectangleArray::saveToFile(const std::string& fileName) { FILE* f = fopen(fileName.c_str(), "wt"); if (!f) throw FileException("RectangleArray::saveToFile Couldn't open file " + fileName + "for writing"); this->printToFile(f); fclose(f); } //------------------------------------------------- SET TO ------------------------------------------------- template void RectangleArray::setTo(const Type& value) { for (unsigned int i = 0; i < this->getWidth()*this->getHeight(); i++) this->data[i] = value; } //--------------------------------------------- SET BORDER TO ---------------------------------------------- template void RectangleArray::setBorderTo(const Type& value) { for (unsigned int i = 0; i < this->width; i++) { this->getColumn(i)[0] = value; this->getColumn(i)[this->height - 1] = value; } for (unsigned int i = 0; i < this->height; i++) { this->getColumn(0)[i] = value; this->getColumn(this->width - 1)[i] = value; } } //---------------------------------------------------------------------------------------------------------- } ================================================ FILE: SparCraft/bwapidata/include/Util/RegionQuadTree.h ================================================ #pragma once #include namespace Util { /** * Structure representing 2D space containing objects of the specified type. This structure is optimised for * effective way of finding of objects in certain area. The top level of the structure contains single list * of all objects included, it divides into 2-4 partitions containing lists of units on respective quoters * of the space, and so on until sthe width/height size is reached. The structure works with list of * pointers of the type and doesn't act as owner, so removing items or deleting the whole quad tree will not * result in delatation of contained items. */ template class RegionQuadTree { public : /** * Creates the quad tree with the specified dimensions. * @param width Width of the highest detail level partition. * @param height Height of the highest detail level partition. */ RegionQuadTree(unsigned int width = 1, unsigned int height = 1); /** Destorys the array, but doesn't delete inserted objects. */ ~RegionQuadTree(void); /** * Gets the width of the array. * @return width of the array. */ unsigned int getWidth(void) const; /** * Gets the height of the array. * @return height of the array. */ unsigned int getHeight(void) const; /** * Gets list of items in the specified region. * @param x horizontal index of the region. * @param y vertical index of the region. * @return list of items on the specified region */ std::list* getItems(unsigned int x, unsigned int y, unsigned int level = 0); /** * Sets item of the array on the specified position. * @param x horizontal index of the array position. * @param y vertical index of the array position. * @param item new value of the field. */ void addItem(unsigned int x, unsigned int y, Type *item); void clear(unsigned int x, unsigned int y); private : /** width of array */ unsigned int width; /** height of array */ unsigned int height; /** array of rectangle arrays of lists of objects. * The 1. item of the array corresponds with the lowest (most detailed) level of the region resolution. * Every other level correspons to 4 times less detailed resolution. */ RectangleArray >* data; /** depth = log2(max(width,height)), but is here for optimalisation reasons. */ unsigned int depth; }; //---------------------------------------------- CONSTRUCTOR ----------------------------------------------- template RegionQuadTree::RegionQuadTree(unsigned int width, unsigned int height) :width(width) ,height(height) ,depth(ceil(log2(max(width,height))) { this->data = new RectangleArray >[depth]; unsigned int localWidth = width; unsigned int localHeight = height; for (unsigned int i = 0; i < this->depth; i++) { this->data[i].resize(localWidth, localHeight); localWidth = (localWidth >= 2) (localWidth+1)/2 : 1; localHeight = (localHeight >=2) (localHeight+1)/2 : 1; } } //----------------------------------------------- DESTRUCTOR ----------------------------------------------- template RectangleArray::~RectangleArray(void) { delete [] data; } //----------------------------------------------- GET WIDTH ------------------------------------------------ template unsigned int RectangleArray::getWidth(void) const { return this->width; } //----------------------------------------------- SET WIDTH ------------------------------------------------ template void RectangleArray::setWidth(unsigned int width) { this->width = width; } //----------------------------------------------- GET HEIGHT ----------------------------------------------- template unsigned int RectangleArray::getHeight(void) const { return this->height; } //------------------------------------------------ GET ITEM ------------------------------------------------ template std::list* getItems(unsigned int x, unsigned int y, unsigned int level = 0); { return this->data[level][x][y]; } //------------------------------------------------ ADD ITEM ------------------------------------------------ template void RectangleArray::addItem(unsigned int x, unsigned int y, Type* item) { for (unsigned int i = 0; i < this->depth; i++) this->data[i][x< void RectangleArray::clear(unsigned int x, unsigned int y) { for (unsigned int i = 0; i < this->depth; i++) this->data[i][x< #include #include "Exceptions.h" #include "Gnu.h" namespace Util { //--------------------------------------------- INT TO STRING ---------------------------------------------- std::string Strings::intToString(long value) { if (value == 0) return "0"; std::string returnValue; while (value != 0) { returnValue = (char) (48+(value % 10)) + returnValue; value/=10; } if (value >= 0) return returnValue; else return "-" + returnValue; } //--------------------------------------------- STRING TO INT ---------------------------------------------- unsigned long Strings::stringToInt(const std::string &input, const unsigned long begin, const int distance) { unsigned long returnValue = 0; for (unsigned long i = begin; i < distance + begin && i < input.size();i++) { if (!isdigit(input[i])) throw ParseException::ParseException("Strings::stringToInt - String " + input + " is not a number."); returnValue*=10; returnValue += (input[i] - '0'); } return returnValue; } //---------------------------------------- STRING TO VARIABLE NAME ----------------------------------------- std::string Strings::stringToVariableName(const std::string &input) { std::string variableName; for(unsigned int i=0;i= 1) return input[0]>='0' && input[0]<= '9'; return false; } //-------------------------------------------- ENDS WITH NUMBER -------------------------------------------- bool Strings::endsWithNumber(const std::string &input) { if (input.length() >= 1) return input[input.length() - 1]>='0' && input[input.length() - 1] <= '9'; return false; } //--------------------------------------------- LOAD FROM FILE --------------------------------------------- void Strings::loadFromFile(const std::string &fileName, std::string &target,const long bufferSize) { char* buffer = new char[bufferSize]; FILE* f = fopen(fileName.c_str(),"rt"); size_t fileSize; if (f) { fileSize = fread(buffer,1,bufferSize,f); fclose(f); buffer[fileSize] = 0; target = buffer; } else throw new FileException("Couldn't open file " + fileName); delete [] buffer; } //------------------------------------------------ TRIM ALL ------------------------------------------------ std::string Strings::trimAll(std::string input) { size_t length = input.size(); char* buffer = new char[length + 1]; long pos = 0; for (size_t i = 0;i < length;i++) { if (!isspace(input[i])) { buffer[pos] = input[i]; pos++; } } buffer[pos] = 0; std::string returnValue = buffer; delete [] buffer; return returnValue; } //------------------------------------------------ TRIM ALL ------------------------------------------------ std::string Strings::trim(std::string input) { size_t i, j; for (i = 0; i < input.length() && isspace(input[i]);i++); if (i == input.length()) return ""; for (j = input.length() - 1; j > 0 && isspace(input[j]);j--); if (i == 0 && j == input.length()) return input; else return input.substr(i,j - i + 1); } char Strings::buffer[STRING_UTIL_BUFFER_SIZE]; //----------------------------------------------- READ LINE ------------------------------------------------ std::string Strings::readLine(FILE* f) { std::string result; readNextBlock: int position = 0; fread(buffer, sizeof(char), 1, f); while (buffer[position] != 13 && buffer[position] != 10 && position < STRING_UTIL_BUFFER_SIZE - 1 && !feof(f)) { position++; fread(&buffer[position], 1, 1,f); } if (buffer[position] == 13 || buffer[position] == 10 || feof(f)) { buffer[position] = 0; result.append(buffer); return result; } else { buffer[position + 1] = 0; result.append(buffer); goto readNextBlock; } } //---------------------------------------------------------------------------------------------------------- const std::string& Strings::dereferenceString(const std::string* const input) { return *input; } //---------------------------------------------------------------------------------------------------------- RectangleArray Strings::makeBorder(const RectangleArray& input, bool coordinates) { int leftBorder = (int)log10((float)input.getHeight()) + 2; int topBorder = 3; RectangleArray returnValue = RectangleArray(input.getWidth() + leftBorder*2, input.getHeight() + topBorder*2); for (unsigned int x = 0; x < returnValue.getWidth(); x++) for (unsigned int y = 0; y < returnValue.getHeight(); y++) returnValue[x][y] = ' '; Strings::makeWindow(returnValue, leftBorder - 1, topBorder - 1, input.getWidth() + 2, input.getHeight() + 2); for (unsigned int x = 0; x < input.getWidth(); x++) for (unsigned int y = 0; y < input.getHeight(); y++) returnValue[x + leftBorder ][y + topBorder] = input[x][y]; for (unsigned int i = 0; i < input.getWidth(); i+=10) { Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, 0); Strings::printTo(returnValue, Strings::intToString(i), i + leftBorder, returnValue.getHeight() - 1); } for (unsigned int i = 0; i < input.getWidth(); i++) { Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, 1); Strings::printTo(returnValue, Strings::intToString(i%10), i + leftBorder, returnValue.getHeight() - 2); } for (unsigned int i = 0; i < input.getHeight(); i++) { Strings::printTo(returnValue, Strings::intToString(i), 0 , i + topBorder); Strings::printTo(returnValue, Strings::intToString(i), leftBorder + input.getWidth() + 1, i + topBorder); } return returnValue; } char Strings::FrameCharacters[2][6] = { { char(205), char(186), char(201), char(187), char(200), char(188) }, { char(196), char(179), char(218), char(191), char(192), char(217) } }; //---------------------------------------------------------------------------------------------------------- void Strings::makeWindow(RectangleArray& input, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int frameType) { for (unsigned int i = x + 1; i < x + width - 1 && x < input.getWidth(); i++) { input[i][y] = Strings::FrameCharacters[frameType][0]; input[i][y + height - 1] = Strings::FrameCharacters[frameType][0]; } for (unsigned int i = y + 1; i < y + height - 1 && y < input.getHeight(); i++) { input[x][i] = Strings::FrameCharacters[frameType][1]; input[x + width - 1][i] = Strings::FrameCharacters[frameType][1]; } input[x][y] = Strings::FrameCharacters[frameType][2]; input[x + width - 1][y] = Strings::FrameCharacters[frameType][3]; input[x][y + height - 1] = Strings::FrameCharacters[frameType][4]; input[x + width - 1][y + height- 1] = Strings::FrameCharacters[frameType][5]; } //------------------------------------------------ PRINT TO ------------------------------------------------ void Strings::printTo(RectangleArray& input, const std::string& text, unsigned int x, unsigned int y) { for (unsigned int i = 0; text[i] != 0; i++) input[x + i][y] = text[i]; } //---------------------------------------------- SPLIT STRING ---------------------------------------------- std::vector Strings::splitString(const std::string& input, const std::string& delimiters) { // Skip delims at beginning, find start of first token std::string::size_type lastPos = input.find_first_not_of(delimiters, 0); // Find next delimiter @ end of token std::string::size_type pos = input.find_first_of(delimiters, lastPos); // output vector std::vector tokens; while (std::string::npos != pos || std::string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(input.substr(lastPos, pos - lastPos)); // Skip delims. Note the "not_of". this is beginning of token lastPos = input.find_first_not_of(delimiters, pos); // Find next delimiter at end of token. pos = input.find_first_of(delimiters, lastPos); } return tokens; } //----------------------------------------------- GET BINARY ------------------------------------------------ template std::string Strings::getBinary(Type value) { std::string result; for (int i = 0; i < sizeof(Type)*8; i++) if (value & (1 << (sizeof(Type)*8-1-i))) result += "1"; else result += "0"; return result; } //----------------------------------------------- SKIP SPACE ------------------------------------------------ void Strings::skipSpace(const std::string& text, size_t& position) { while (isspace(text[position])) position ++; } //------------------------------------------------ READ WORD ------------------------------------------------ std::string Strings::readWord(const std::string& text, size_t& position) { std::string result; while (isalpha(text[position])) { result += text[position]; position++; } return result; } //------------------------------------------------ READ WORD ------------------------------------------------ std::string Strings::readNumber(const std::string& text, size_t& position) { std::string result; while (isdigit(text[position]) || text[position] == '.') { result += text[position]; position++; } return result; } const int BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; //----------------------------------------------------------------------------------------------------------- std::string Strings::ssprintf(const char* format, ...) { va_list ap; va_start(ap, format); vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE, format, ap); va_end(ap); return buffer; } //----------------------------------------------------------------------------------------------------------- } ================================================ FILE: SparCraft/bwapidata/include/Util/Strings.h ================================================ #pragma once #define STRING_UTIL_BUFFER_SIZE 100 #include #include #include "RectangleArray.h" namespace Util { /** Collection of std::string utilities */ class Strings { private : /** The class is abstract, so it has private constructor */ Strings(void); static char buffer[STRING_UTIL_BUFFER_SIZE]; public : /** * Gets textual representation of the specified number. * @param value Number to be converted to std::string. * @return Textual representation of the specified number. */ static std::string intToString(long value); /** * Converts textual representation of number to number. * @param input String containing number representation. * @param begin Position of the first caracter of the number in the input * std::string. * @param distance Maximum count of characters to read. * @return Returns textual representation of the specified std::string. * @throws ParseException if the text can't be converted to integer * (non-numerical characters) */ static unsigned long stringToInt(const std::string &input, const unsigned long begin = 0, const int distance = 9); static std::string stringToVariableName(const std::string &input); static void stringToFile(const std::string &input, FILE* f); static void saveToFile(const std::string &input, const std::string &fileName); static bool beginsWithNumber(const std::string &input); static bool endsWithNumber(const std::string &input); static std::string loadFromFile(FILE* f); static void loadFromFile(const std::string &fileName,std::string &Target,const long bufferSize); static std::string UTF8ToWindows1250(const std::string &input); static std::string Windows1250ToUTF8(const std::string &input); static std::string trimAll(std::string input); static std::string trim(std::string input); static std::string replace(const std::string &input, MultiString* values, const std::string &replacement); static RectangleArray makeBorder(const RectangleArray& input, bool coordinates = true); static char FrameCharacters[2][6]; static void makeWindow(RectangleArray& input, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int frameType = 0); static void printTo(RectangleArray& input, const std::string& text, unsigned int x, unsigned int y); /** * Reads one line from the input stream. * @param f Input stream. * @return Content of the line. */ static std::string readLine(FILE* f); static const std::string& dereferenceString(const std::string* const input); /** * convert input string into vector of string tokens. * * @note consecutive delimiters will be treated as single delimiter * @note delimiters are _not_ included in return data * * @param input string to be parsed * @param delimiters list of delimiters. * I was too lazy and took it from http://www.rosettacode.org/wiki/Tokenizing_A_String */ static std::vector splitString(const std::string& input, const std::string& delimiters = " \t"); template std::string getBinary(Type value); static void skipSpace(const std::string& text, size_t& position); /** Reads words consting of alphaNumeric characters */ static std::string readWord(const std::string& text, size_t& position); static std::string readNumber(const std::string& text, size_t& position); static std::string ssprintf(const char* format, ...); }; } ================================================ FILE: SparCraft/bwapidata/include/Util/Types.h ================================================ #pragma once typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned int u32; typedef signed int s32; typedef unsigned long long u64; typedef signed long long s64; typedef u8 _UNKNOWN; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef void* PVOID; typedef int BOOL; typedef void* HANDLE; #ifdef NULL #undef NULL #endif #define NULL 0 #define ever (;;) ================================================ FILE: SparCraft/bwapidata/include/Util/sha1.cpp ================================================ /* Copyright (c) 2009, Micael Hildenborg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Micael Hildenborg nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Contributors: Gustav Several members in the gamedev.se forum. */ #include "sha1.h" #include namespace sha1 { namespace // local { inline const unsigned int rol(const unsigned int num, const unsigned int cnt) { return((num << cnt) | (num >> (32-cnt))); } void innerHash(unsigned int *result, unsigned int *w) { unsigned int save[5]; save[0]=result[0]; save[1]=result[1]; save[2]=result[2]; save[3]=result[3]; save[4]=result[4]; #define a result[0] #define b result[1] #define c result[2] #define d result[3] #define e result[4] int j=0; #define sha1macro(func,val) \ {const unsigned int t = rol(a, 5)+(func)+e+val+w[j]; \ e = d; d = c; \ c = rol(b, 30); \ b = a; a = t;} while(j<16) { sha1macro((b&c)|(~b&d),0x5A827999) j++; } while(j<20) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro((b&c)|(~b&d),0x5A827999) j++; } while(j<40) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro(b^c^d,0x6ED9EBA1) j++; } while(j<60) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro((b&c)|(b&d)|(c&d),0x8F1BBCDC) j++; } while(j<80) { w[j] = rol((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]), 1); sha1macro(b^c^d,0xCA62C1D6) j++; } #undef sha1macro #undef a #undef b #undef c #undef d #undef e result[0]+=save[0]; result[1]+=save[1]; result[2]+=save[2]; result[3]+=save[3]; result[4]+=save[4]; } } void calc(const void *src, const int bytelength, unsigned char *hash) { // Init the result array, and create references to the five unsigned integers for better readabillity. unsigned int result[5]={0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0}; const unsigned char *sarray=(const unsigned char*)src; // The variables unsigned int w[80]; int j,i,i1; j=0; // Loop through all complete 64byte blocks. for(i=0,i1=64; i<=(bytelength-64); i=i1,i1+=64) { int k=0; for(j=i;j>2]|=(unsigned int)sarray[j+i]<<((3-(j&3))<<3); } w[j>>2]|=0x80<<((3-(j&3))<<3); if(i1>=56) { innerHash(result,w); memset(w,0,sizeof(unsigned int)*16); } w[15]=bytelength<<3; innerHash(result,w); // Store hash in result pointer, and make sure we get in in the correct order on both endian models. for(i=20;--i>=0;) { hash[i]=(result[i>>2]>>(((3-i)&0x3)<<3))&0xFF; } } void toHexString(const unsigned char *hash, char *hexstring) { const char tab[]={"0123456789abcdef"}; for(int i=20;--i>=0;) { hexstring[i<<1]=tab[(hash[i]>>4)&0xF]; hexstring[(i<<1)+1]=tab[hash[i]&0xF]; } hexstring[40]=0; } } ================================================ FILE: SparCraft/bwapidata/include/Util/sha1.h ================================================ // sha1.h and sha1.cpp are from code.google.com/p/smallsha1/ /* Copyright (c) 2009, Micael Hildenborg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Micael Hildenborg nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ACTIONS, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SHA1_DEFINED #define SHA1_DEFINED namespace sha1 { /** @param src points to any kind of data to be hashed. @param bytelength the number of bytes to hash from the src pointer. @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. */ void calc(const void *src, const int bytelength, unsigned char *hash); /** @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. */ void toHexString(const unsigned char *hash, char *hexstring); }; // namespace sha1 #endif // SHA1_DEFINED ================================================ FILE: SparCraft/bwapidata/include/WeaponType.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "Common.h" namespace BWAPI { bool initializingWeaponType = true; class WeaponTypeInternal { public: WeaponTypeInternal() {valid = false;} void set(const char* name, TechType techType, int damageAmount, int damageBonus, int damageCooldown, int damageFactor, UpgradeType upgradeType, DamageType damageType, ExplosionType explosionType, int minRange, int maxRange, int innerSplashRadius, int medianSplashRadius, int outerSplashRadius, bool targetsAir, bool targetsGround, bool targetsMechanical, bool targetsOrganic, bool targetsNonBuilding, bool targetsNonRobotic, bool targetsTerrain, bool targetsOrgOrMech, bool targetsOwn, UnitType whatUses) { if (initializingWeaponType) { this->name = name; this->techType = techType; this->damageAmount = damageAmount; this->damageBonus = damageBonus; this->damageCooldown = damageCooldown; this->damageFactor = damageFactor; this->upgradeType = upgradeType; this->damageType = damageType; this->explosionType = explosionType; this->minRange = minRange; this->maxRange = maxRange; this->innerSplashRadius = innerSplashRadius; this->medianSplashRadius = medianSplashRadius; this->outerSplashRadius = outerSplashRadius; this->targetsAir = targetsAir; this->targetsGround = targetsGround; this->targetsMechanical = targetsMechanical; this->targetsOrganic = targetsOrganic; this->targetsNonBuilding = targetsNonBuilding; this->targetsNonRobotic = targetsNonRobotic; this->targetsTerrain = targetsTerrain; this->targetsOrgOrMech = targetsOrgOrMech; this->targetsOwn = targetsOwn; this->whatUses = whatUses; this->valid = true; } } std::string name; TechType techType; UnitType whatUses; int damageAmount; int damageBonus; int damageCooldown; int damageFactor; UpgradeType upgradeType; DamageType damageType; ExplosionType explosionType; int minRange; int maxRange; int innerSplashRadius; int medianSplashRadius; int outerSplashRadius; bool targetsAir; bool targetsGround; bool targetsMechanical; bool targetsOrganic; bool targetsNonBuilding; bool targetsNonRobotic; bool targetsTerrain; bool targetsOrgOrMech; bool targetsOwn; bool valid; }; WeaponTypeInternal weaponTypeData[132]; std::map weaponTypeMap; std::set< WeaponType > weaponTypeSet; std::set< WeaponType > specialWeaponTypeSet; std::set< WeaponType > normalWeaponTypeSet; namespace WeaponTypes { const WeaponType Gauss_Rifle(0); const WeaponType Gauss_Rifle_Jim_Raynor(1); const WeaponType C_10_Canister_Rifle(2); const WeaponType C_10_Canister_Rifle_Sarah_Kerrigan(3); const WeaponType C_10_Canister_Rifle_Samir_Duran(112); const WeaponType C_10_Canister_Rifle_Infested_Duran(113); const WeaponType C_10_Canister_Rifle_Alexei_Stukov(116); const WeaponType Fragmentation_Grenade(4); const WeaponType Fragmentation_Grenade_Jim_Raynor(5); const WeaponType Spider_Mines(6); const WeaponType Twin_Autocannons(7); const WeaponType Twin_Autocannons_Alan_Schezar(9); const WeaponType Hellfire_Missile_Pack(8); const WeaponType Hellfire_Missile_Pack_Alan_Schezar(10); const WeaponType Arclite_Cannon(11); const WeaponType Arclite_Cannon_Edmund_Duke(12); const WeaponType Fusion_Cutter(13); const WeaponType Gemini_Missiles(15); const WeaponType Gemini_Missiles_Tom_Kazansky(17); const WeaponType Burst_Lasers(16); const WeaponType Burst_Lasers_Tom_Kazansky(18); const WeaponType ATS_Laser_Battery(19); const WeaponType ATS_Laser_Battery_Hero(21); const WeaponType ATS_Laser_Battery_Hyperion(23); const WeaponType ATA_Laser_Battery(20); const WeaponType ATA_Laser_Battery_Hero(22); const WeaponType ATA_Laser_Battery_Hyperion(24); const WeaponType Flame_Thrower(25); const WeaponType Flame_Thrower_Gui_Montag(26); const WeaponType Arclite_Shock_Cannon(27); const WeaponType Arclite_Shock_Cannon_Edmund_Duke(28); const WeaponType Longbolt_Missile(29); const WeaponType Claws(35); const WeaponType Claws_Devouring_One(36); const WeaponType Claws_Infested_Kerrigan(37); const WeaponType Needle_Spines(38); const WeaponType Needle_Spines_Hunter_Killer(39); const WeaponType Kaiser_Blades(40); const WeaponType Kaiser_Blades_Torrasque(41); const WeaponType Toxic_Spores(42); const WeaponType Spines(43); const WeaponType Acid_Spore(46); const WeaponType Acid_Spore_Kukulza(47); const WeaponType Glave_Wurm(48); const WeaponType Glave_Wurm_Kukulza(49); const WeaponType Seeker_Spores(52); const WeaponType Subterranean_Tentacle(53); const WeaponType Suicide_Infested_Terran(54); const WeaponType Suicide_Scourge(55); const WeaponType Particle_Beam(62); const WeaponType Psi_Blades(64); const WeaponType Psi_Blades_Fenix(65); const WeaponType Phase_Disruptor(66); const WeaponType Phase_Disruptor_Fenix(67); const WeaponType Psi_Assault(69); const WeaponType Psionic_Shockwave(70); const WeaponType Psionic_Shockwave_TZ_Archon(71); const WeaponType Dual_Photon_Blasters(73); const WeaponType Dual_Photon_Blasters_Mojo(75); const WeaponType Dual_Photon_Blasters_Artanis(114); const WeaponType Anti_Matter_Missiles(74); const WeaponType Anti_Matter_Missiles_Mojo(76); const WeaponType Anti_Matter_Missiles_Artanis(115); const WeaponType Phase_Disruptor_Cannon(77); const WeaponType Phase_Disruptor_Cannon_Danimoth(78); const WeaponType Pulse_Cannon(79); const WeaponType STS_Photon_Cannon(80); const WeaponType STA_Photon_Cannon(81); const WeaponType Scarab(82); const WeaponType Subterranean_Spines(109); const WeaponType Warp_Blades(111); const WeaponType Warp_Blades_Hero(86); const WeaponType Warp_Blades_Zeratul(85); const WeaponType Neutron_Flare(100); const WeaponType Halo_Rockets(103); const WeaponType Yamato_Gun(30); const WeaponType Nuclear_Strike(31); const WeaponType Lockdown(32); const WeaponType EMP_Shockwave(33); const WeaponType Irradiate(34); const WeaponType Parasite(56); const WeaponType Spawn_Broodlings(57); const WeaponType Ensnare(58); const WeaponType Dark_Swarm(59); const WeaponType Plague(60); const WeaponType Consume(61); const WeaponType Stasis_Field(83); const WeaponType Psionic_Storm(84); const WeaponType Disruption_Web(101); const WeaponType Restoration(102); const WeaponType Corrosive_Acid(104); const WeaponType Mind_Control(105); const WeaponType Feedback(106); const WeaponType Optical_Flare(107); const WeaponType Maelstrom(108); const WeaponType None(130); const WeaponType Unknown(131); void init() { weaponTypeData[Gauss_Rifle.getID()].set("Gauss Rifle", TechTypes::None, 6, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Marine); weaponTypeData[Gauss_Rifle_Jim_Raynor.getID()].set("Gauss Rifle (Jim Raynor)", TechTypes::None, 18, 1, 15, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Marine); weaponTypeData[C_10_Canister_Rifle.getID()].set("C-10 Canister Rifle", TechTypes::None, 10, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[C_10_Canister_Rifle_Sarah_Kerrigan.getID()].set("C-10 Canister Rifle (Sarah Kerrigan)", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Sarah_Kerrigan); weaponTypeData[C_10_Canister_Rifle_Samir_Duran.getID()].set("C-10 Canister Rifle (Samir Duran)", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Samir_Duran); weaponTypeData[C_10_Canister_Rifle_Infested_Duran.getID()].set("C-10 Canister Rifle (Infested Duran)", TechTypes::None, 25, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Duran); weaponTypeData[C_10_Canister_Rifle_Alexei_Stukov.getID()].set("C-10 Canister Rifle (Alexei Stukov)", TechTypes::None, 30, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alexei_Stukov); weaponTypeData[Fragmentation_Grenade.getID()].set("Fragmentation Grenade", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Vulture); weaponTypeData[Fragmentation_Grenade_Jim_Raynor.getID()].set("Fragmentation Grenade (Jim Raynor)", TechTypes::None, 30, 2, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Concussive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Jim_Raynor_Vulture); weaponTypeData[Spider_Mines.getID()].set("Spider Mines", TechTypes::Spider_Mines, 125, 0, 22, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 10, 50, 75, 100, 0, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Vulture_Spider_Mine); weaponTypeData[Twin_Autocannons.getID()].set("Twin Autocannons", TechTypes::None, 12, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath); weaponTypeData[Twin_Autocannons_Alan_Schezar.getID()].set("Twin Autocannons (Alan Schezar)", TechTypes::None, 24, 1, 22, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar); weaponTypeData[Hellfire_Missile_Pack.getID()].set("Hellfire Missile Pack", TechTypes::None, 10, 2, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Goliath); weaponTypeData[Hellfire_Missile_Pack_Alan_Schezar.getID()].set("Hellfire Missile Pack (Alan Schezar)", TechTypes::None, 20, 1, 22, 2, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Alan_Schezar); weaponTypeData[Arclite_Cannon.getID()].set("Arclite Cannon", TechTypes::None, 30, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Tank_Mode); weaponTypeData[Arclite_Cannon_Edmund_Duke.getID()].set("Arclite Cannon (Edmund Duke)", TechTypes::None, 70, 3, 37, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Tank_Mode); weaponTypeData[Fusion_Cutter.getID()].set("Fusion Cutter", TechTypes::None, 5, 1, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_SCV); weaponTypeData[Gemini_Missiles.getID()].set("Gemini Missiles", TechTypes::None, 20, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith); weaponTypeData[Gemini_Missiles_Tom_Kazansky.getID()].set("Gemini Missiles (Tom Kazansky)", TechTypes::None, 40, 2, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky); weaponTypeData[Burst_Lasers.getID()].set("Burst Lasers", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Wraith); weaponTypeData[Burst_Lasers_Tom_Kazansky.getID()].set("Burst Lasers (Tom Kazansky)", TechTypes::None, 16, 1, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tom_Kazansky); weaponTypeData[ATS_Laser_Battery.getID()].set("ATS Laser Battery", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[ATS_Laser_Battery_Hero.getID()].set("ATS Laser Battery (Hero)", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II); weaponTypeData[ATS_Laser_Battery_Hyperion.getID()].set("ATS Laser Battery (Hyperion)", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion); weaponTypeData[ATA_Laser_Battery.getID()].set("ATA Laser Battery", TechTypes::None, 25, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[ATA_Laser_Battery_Hero.getID()].set("ATA Laser Battery (Hero)", TechTypes::None, 50, 3, 30, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Norad_II); weaponTypeData[ATA_Laser_Battery_Hyperion.getID()].set("ATA Laser Battery (Hyperion)", TechTypes::None, 30, 3, 22, 1, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hyperion); weaponTypeData[Flame_Thrower.getID()].set("Flame Thrower", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat); weaponTypeData[Flame_Thrower_Gui_Montag.getID()].set("Flame Thrower (Gui Montag)", TechTypes::None, 16, 1, 22, 1, UpgradeTypes::Terran_Infantry_Weapons, DamageTypes::Concussive, ExplosionTypes::Enemy_Splash, 0, 32, 15, 20, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Firebat); weaponTypeData[Arclite_Shock_Cannon.getID()].set("Arclite Shock Cannon", TechTypes::None, 70, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Siege_Tank_Siege_Mode); weaponTypeData[Arclite_Shock_Cannon_Edmund_Duke.getID()].set("Arclite Shock Cannon (Edmund Duke)", TechTypes::None, 150, 5, 75, 1, UpgradeTypes::Terran_Vehicle_Weapons, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 64, 384, 10, 25, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Edmund_Duke_Siege_Mode); weaponTypeData[Longbolt_Missile.getID()].set("Longbolt Missile", TechTypes::None, 20, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Missile_Turret); weaponTypeData[Yamato_Gun.getID()].set("Yamato Gun", TechTypes::Yamato_Gun, 260, 0, 15, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Yamato_Gun, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Battlecruiser); weaponTypeData[Nuclear_Strike.getID()].set("Nuclear Strike", TechTypes::Nuclear_Strike, 600, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Nuclear_Missile, 0, 3, 128, 192, 256, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[Lockdown.getID()].set("Lockdown", TechTypes::Lockdown, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::Lockdown, 0, 256, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, UnitTypes::Terran_Ghost); weaponTypeData[EMP_Shockwave.getID()].set("EMP Shockwave", TechTypes::EMP_Shockwave, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Concussive, ExplosionTypes::EMP_Shockwave, 0, 256, 64, 64, 64, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel); weaponTypeData[Irradiate.getID()].set("Irradiate", TechTypes::Irradiate, 250, 0, 75, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Irradiate, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Science_Vessel); weaponTypeData[Claws.getID()].set("Claws", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Zergling); weaponTypeData[Claws_Devouring_One.getID()].set("Claws (Devouring One)", TechTypes::None, 10, 1, 8, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Devouring_One); weaponTypeData[Claws_Infested_Kerrigan.getID()].set("Claws (Infested Kerrigan)", TechTypes::None, 50, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Infested_Kerrigan); weaponTypeData[Needle_Spines.getID()].set("Needle Spines", TechTypes::None, 10, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Hydralisk); weaponTypeData[Needle_Spines_Hunter_Killer.getID()].set("Needle Spines (Hunter Killer)", TechTypes::None, 20, 1, 15, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Hunter_Killer); weaponTypeData[Kaiser_Blades.getID()].set("Kaiser Blades", TechTypes::None, 20, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Ultralisk); weaponTypeData[Kaiser_Blades_Torrasque.getID()].set("Kaiser Blades (Torrasque)", TechTypes::None, 50, 3, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 25, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Torrasque); weaponTypeData[Toxic_Spores.getID()].set("Toxic Spores", TechTypes::None, 4, 1, 15, 1, UpgradeTypes::Zerg_Melee_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Broodling); weaponTypeData[Spines.getID()].set("Spines", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Drone); weaponTypeData[Acid_Spore.getID()].set("Acid Spore", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Guardian); weaponTypeData[Acid_Spore_Kukulza.getID()].set("Acid Spore (Kukulza)", TechTypes::None, 40, 2, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 256, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Guardian); weaponTypeData[Glave_Wurm.getID()].set("Glave Wurm", TechTypes::None, 9, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Mutalisk); weaponTypeData[Glave_Wurm_Kukulza.getID()].set("Glave Wurm (Kukulza)", TechTypes::None, 18, 1, 30, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Kukulza_Mutalisk); weaponTypeData[Seeker_Spores.getID()].set("Seeker Spores", TechTypes::None, 15, 0, 15, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Spore_Colony); weaponTypeData[Subterranean_Tentacle.getID()].set("Subterranean Tentacle", TechTypes::None, 40, 0, 32, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Sunken_Colony); weaponTypeData[Suicide_Infested_Terran.getID()].set("Suicide Infested Terran", TechTypes::None, 500, 0, 1, 1, UpgradeTypes::None, DamageTypes::Explosive, ExplosionTypes::Radial_Splash, 0, 3, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Infested_Terran); weaponTypeData[Suicide_Scourge.getID()].set("Suicide Scourge", TechTypes::None, 110, 0, 1, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Scourge); weaponTypeData[Parasite.getID()].set("Parasite", TechTypes::Parasite, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Parasite, 0, 384, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, UnitTypes::Zerg_Queen); weaponTypeData[Spawn_Broodlings.getID()].set("Spawn Broodlings", TechTypes::Spawn_Broodlings, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Broodlings, 0, 288, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, UnitTypes::Zerg_Queen); weaponTypeData[Ensnare.getID()].set("Ensnare", TechTypes::Ensnare, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Ensnare, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Queen); weaponTypeData[Dark_Swarm.getID()].set("Dark Swarm", TechTypes::Dark_Swarm, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Dark_Swarm, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Defiler); weaponTypeData[Plague.getID()].set("Plague", TechTypes::Plague, 300, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Plague, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Zerg_Defiler); weaponTypeData[Consume.getID()].set("Consume", TechTypes::Consume, 0, 0, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Consume, 0, 16, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, UnitTypes::Zerg_Defiler); weaponTypeData[Particle_Beam.getID()].set("Particle Beam", TechTypes::None, 5, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Probe); weaponTypeData[Psi_Blades.getID()].set("Psi Blades", TechTypes::None, 8, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Zealot); weaponTypeData[Psi_Blades_Fenix.getID()].set("Psi Blades (Fenix)", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Zealot); weaponTypeData[Phase_Disruptor.getID()].set("Phase Disruptor", TechTypes::None, 20, 2, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dragoon); weaponTypeData[Phase_Disruptor_Fenix.getID()].set("Phase Disruptor (Fenix)", TechTypes::None, 45, 2, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Fenix_Dragoon); weaponTypeData[Psi_Assault.getID()].set("Psi Assault", TechTypes::None, 20, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 96, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar); weaponTypeData[Psionic_Shockwave.getID()].set("Psionic Shockwave", TechTypes::None, 30, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Archon); weaponTypeData[Psionic_Shockwave_TZ_Archon.getID()].set("Psionic Shockwave (Tassadar/Zeratul Archon)", TechTypes::None, 60, 3, 20, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 64, 3, 15, 30, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Tassadar_Zeratul_Archon); weaponTypeData[Dual_Photon_Blasters.getID()].set("Dual Photon Blasters", TechTypes::None, 8, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout); weaponTypeData[Dual_Photon_Blasters_Mojo.getID()].set("Dual Photon Blasters (Mojo)", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo); weaponTypeData[Dual_Photon_Blasters_Artanis.getID()].set("Dual Photon Blasters (Artanis)", TechTypes::None, 20, 1, 30, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis); weaponTypeData[Anti_Matter_Missiles.getID()].set("Anti-Matter Missiles", TechTypes::None, 14, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scout); weaponTypeData[Anti_Matter_Missiles_Mojo.getID()].set("Anti-Matter Missiles (Mojo)", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Mojo); weaponTypeData[Anti_Matter_Missiles_Artanis.getID()].set("Anti-Matter Missiles (Artanis)", TechTypes::None, 28, 1, 22, 2, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Artanis); weaponTypeData[Phase_Disruptor_Cannon.getID()].set("Phase Disruptor Cannon", TechTypes::None, 10, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Arbiter); weaponTypeData[Phase_Disruptor_Cannon_Danimoth.getID()].set("Phase Disruptor Cannon (Danimoth)", TechTypes::None, 20, 1, 45, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Normal, 0, 160, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Danimoth); weaponTypeData[Pulse_Cannon.getID()].set("Pulse Cannon", TechTypes::None, 6, 1, 1, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Interceptor); weaponTypeData[STS_Photon_Cannon.getID()].set("STS Photon Cannon", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon); weaponTypeData[STA_Photon_Cannon.getID()].set("STA Photon Cannon", TechTypes::None, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Normal, 0, 224, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Photon_Cannon); weaponTypeData[Scarab.getID()].set("Scarab", TechTypes::None, 100, 25, 1, 1, UpgradeTypes::Scarab_Damage, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 128, 20, 40, 60, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Scarab); weaponTypeData[Stasis_Field.getID()].set("Stasis Field", TechTypes::Stasis_Field, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Stasis_Field, 0, 288, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Arbiter); weaponTypeData[Psionic_Storm.getID()].set("Psionic Storm", TechTypes::Psionic_Storm, 14, 1, 45, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Radial_Splash, 0, 288, 48, 48, 48, 1, 1, 0, 0, 1, 0, 1, 0, 0, UnitTypes::Protoss_High_Templar); weaponTypeData[Neutron_Flare.getID()].set("Neutron Flare", TechTypes::None, 5, 1, 8, 1, UpgradeTypes::Protoss_Air_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 160, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair); weaponTypeData[Disruption_Web.getID()].set("Disruption Web", TechTypes::Disruption_Web, 0, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Disruption_Web, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Corsair); weaponTypeData[Restoration.getID()].set("Restoration", TechTypes::Restoration, 20, 0, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Restoration, 0, 192, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Terran_Medic); weaponTypeData[Halo_Rockets.getID()].set("Halo Rockets", TechTypes::None, 6, 1, 64, 2, UpgradeTypes::Terran_Ship_Weapons, DamageTypes::Explosive, ExplosionTypes::Air_Splash, 0, 192, 5, 50, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Valkyrie); weaponTypeData[Corrosive_Acid.getID()].set("Corrosive Acid", TechTypes::None, 25, 2, 100, 1, UpgradeTypes::Zerg_Flyer_Attacks, DamageTypes::Explosive, ExplosionTypes::Corrosive_Acid, 0, 192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Devourer); weaponTypeData[Mind_Control.getID()].set("Mind Control", TechTypes::Mind_Control, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Normal, ExplosionTypes::Mind_Control, 0, 256, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Feedback.getID()].set("Feedback", TechTypes::Feedback, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Ignore_Armor, ExplosionTypes::Feedback, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Optical_Flare.getID()].set("Optical Flare", TechTypes::Optical_Flare, 8, 1, 22, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Optical_Flare, 0, 288, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Terran_Medic); weaponTypeData[Maelstrom.getID()].set("Maelstrom", TechTypes::Maelstrom, 0, 1, 1, 1, UpgradeTypes::None, DamageTypes::Independent, ExplosionTypes::Maelstrom, 0, 320, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, UnitTypes::Protoss_Dark_Archon); weaponTypeData[Subterranean_Spines.getID()].set("Subterranean Spines", TechTypes::None, 20, 2, 37, 1, UpgradeTypes::Zerg_Missile_Attacks, DamageTypes::Normal, ExplosionTypes::Enemy_Splash, 0, 192, 20, 20, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Zerg_Lurker); weaponTypeData[Warp_Blades.getID()].set("Warp Blades", TechTypes::None, 40, 3, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Protoss_Dark_Templar); weaponTypeData[Warp_Blades_Hero.getID()].set("Warp Blades (Hero)", TechTypes::None, 45, 1, 30, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Dark_Templar); weaponTypeData[Warp_Blades_Zeratul.getID()].set("Warp Blades (Zeratul)", TechTypes::None, 100, 1, 22, 1, UpgradeTypes::Protoss_Ground_Weapons, DamageTypes::Normal, ExplosionTypes::Normal, 0, 15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, UnitTypes::Hero_Zeratul); weaponTypeData[None.getID()].set("None", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None); weaponTypeData[Unknown.getID()].set("Unknown", TechTypes::None, 0, 0, 0, 0, UpgradeTypes::None, DamageTypes::None, ExplosionTypes::None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UnitTypes::None); weaponTypeSet.insert(Gauss_Rifle); weaponTypeSet.insert(Gauss_Rifle_Jim_Raynor); weaponTypeSet.insert(C_10_Canister_Rifle); weaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan); weaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran); weaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran); weaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov); weaponTypeSet.insert(Fragmentation_Grenade); weaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor); weaponTypeSet.insert(Spider_Mines); weaponTypeSet.insert(Twin_Autocannons); weaponTypeSet.insert(Twin_Autocannons_Alan_Schezar); weaponTypeSet.insert(Hellfire_Missile_Pack); weaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar); weaponTypeSet.insert(Arclite_Cannon); weaponTypeSet.insert(Arclite_Cannon_Edmund_Duke); weaponTypeSet.insert(Fusion_Cutter); weaponTypeSet.insert(Gemini_Missiles); weaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky); weaponTypeSet.insert(Burst_Lasers); weaponTypeSet.insert(Burst_Lasers_Tom_Kazansky); weaponTypeSet.insert(ATS_Laser_Battery); weaponTypeSet.insert(ATS_Laser_Battery_Hero); weaponTypeSet.insert(ATS_Laser_Battery_Hyperion); weaponTypeSet.insert(ATA_Laser_Battery); weaponTypeSet.insert(ATA_Laser_Battery_Hero); weaponTypeSet.insert(ATA_Laser_Battery_Hyperion); weaponTypeSet.insert(Flame_Thrower); weaponTypeSet.insert(Flame_Thrower_Gui_Montag); weaponTypeSet.insert(Arclite_Shock_Cannon); weaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke); weaponTypeSet.insert(Longbolt_Missile); weaponTypeSet.insert(Claws); weaponTypeSet.insert(Claws_Devouring_One); weaponTypeSet.insert(Claws_Infested_Kerrigan); weaponTypeSet.insert(Needle_Spines); weaponTypeSet.insert(Needle_Spines_Hunter_Killer); weaponTypeSet.insert(Kaiser_Blades); weaponTypeSet.insert(Kaiser_Blades_Torrasque); weaponTypeSet.insert(Toxic_Spores); weaponTypeSet.insert(Spines); weaponTypeSet.insert(Acid_Spore); weaponTypeSet.insert(Acid_Spore_Kukulza); weaponTypeSet.insert(Glave_Wurm); weaponTypeSet.insert(Glave_Wurm_Kukulza); weaponTypeSet.insert(Seeker_Spores); weaponTypeSet.insert(Subterranean_Tentacle); weaponTypeSet.insert(Suicide_Infested_Terran); weaponTypeSet.insert(Suicide_Scourge); weaponTypeSet.insert(Particle_Beam); weaponTypeSet.insert(Psi_Blades); weaponTypeSet.insert(Psi_Blades_Fenix); weaponTypeSet.insert(Phase_Disruptor); weaponTypeSet.insert(Phase_Disruptor_Fenix); weaponTypeSet.insert(Psi_Assault); weaponTypeSet.insert(Psionic_Shockwave); weaponTypeSet.insert(Psionic_Shockwave_TZ_Archon); weaponTypeSet.insert(Dual_Photon_Blasters); weaponTypeSet.insert(Dual_Photon_Blasters_Mojo); weaponTypeSet.insert(Dual_Photon_Blasters_Artanis); weaponTypeSet.insert(Anti_Matter_Missiles); weaponTypeSet.insert(Anti_Matter_Missiles_Mojo); weaponTypeSet.insert(Anti_Matter_Missiles_Artanis); weaponTypeSet.insert(Phase_Disruptor_Cannon); weaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth); weaponTypeSet.insert(Pulse_Cannon); weaponTypeSet.insert(STS_Photon_Cannon); weaponTypeSet.insert(STA_Photon_Cannon); weaponTypeSet.insert(Scarab); weaponTypeSet.insert(Neutron_Flare); weaponTypeSet.insert(Halo_Rockets); weaponTypeSet.insert(Corrosive_Acid); weaponTypeSet.insert(Subterranean_Spines); weaponTypeSet.insert(Warp_Blades); weaponTypeSet.insert(Warp_Blades_Hero); weaponTypeSet.insert(Warp_Blades_Zeratul); normalWeaponTypeSet.insert(Gauss_Rifle); normalWeaponTypeSet.insert(Gauss_Rifle_Jim_Raynor); normalWeaponTypeSet.insert(C_10_Canister_Rifle); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Sarah_Kerrigan); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Samir_Duran); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Infested_Duran); normalWeaponTypeSet.insert(C_10_Canister_Rifle_Alexei_Stukov); normalWeaponTypeSet.insert(Fragmentation_Grenade); normalWeaponTypeSet.insert(Fragmentation_Grenade_Jim_Raynor); normalWeaponTypeSet.insert(Spider_Mines); normalWeaponTypeSet.insert(Twin_Autocannons); normalWeaponTypeSet.insert(Twin_Autocannons_Alan_Schezar); normalWeaponTypeSet.insert(Hellfire_Missile_Pack); normalWeaponTypeSet.insert(Hellfire_Missile_Pack_Alan_Schezar); normalWeaponTypeSet.insert(Arclite_Cannon); normalWeaponTypeSet.insert(Arclite_Cannon_Edmund_Duke); normalWeaponTypeSet.insert(Fusion_Cutter); normalWeaponTypeSet.insert(Gemini_Missiles); normalWeaponTypeSet.insert(Gemini_Missiles_Tom_Kazansky); normalWeaponTypeSet.insert(Burst_Lasers); normalWeaponTypeSet.insert(Burst_Lasers_Tom_Kazansky); normalWeaponTypeSet.insert(ATS_Laser_Battery); normalWeaponTypeSet.insert(ATS_Laser_Battery_Hero); normalWeaponTypeSet.insert(ATS_Laser_Battery_Hyperion); normalWeaponTypeSet.insert(ATA_Laser_Battery); normalWeaponTypeSet.insert(ATA_Laser_Battery_Hero); normalWeaponTypeSet.insert(ATA_Laser_Battery_Hyperion); normalWeaponTypeSet.insert(Flame_Thrower); normalWeaponTypeSet.insert(Flame_Thrower_Gui_Montag); normalWeaponTypeSet.insert(Arclite_Shock_Cannon); normalWeaponTypeSet.insert(Arclite_Shock_Cannon_Edmund_Duke); normalWeaponTypeSet.insert(Longbolt_Missile); normalWeaponTypeSet.insert(Claws); normalWeaponTypeSet.insert(Claws_Devouring_One); normalWeaponTypeSet.insert(Claws_Infested_Kerrigan); normalWeaponTypeSet.insert(Needle_Spines); normalWeaponTypeSet.insert(Needle_Spines_Hunter_Killer); normalWeaponTypeSet.insert(Kaiser_Blades); normalWeaponTypeSet.insert(Kaiser_Blades_Torrasque); normalWeaponTypeSet.insert(Toxic_Spores); normalWeaponTypeSet.insert(Spines); normalWeaponTypeSet.insert(Acid_Spore); normalWeaponTypeSet.insert(Acid_Spore_Kukulza); normalWeaponTypeSet.insert(Glave_Wurm); normalWeaponTypeSet.insert(Glave_Wurm_Kukulza); normalWeaponTypeSet.insert(Seeker_Spores); normalWeaponTypeSet.insert(Subterranean_Tentacle); normalWeaponTypeSet.insert(Suicide_Infested_Terran); normalWeaponTypeSet.insert(Suicide_Scourge); normalWeaponTypeSet.insert(Particle_Beam); normalWeaponTypeSet.insert(Psi_Blades); normalWeaponTypeSet.insert(Psi_Blades_Fenix); normalWeaponTypeSet.insert(Phase_Disruptor); normalWeaponTypeSet.insert(Phase_Disruptor_Fenix); normalWeaponTypeSet.insert(Psi_Assault); normalWeaponTypeSet.insert(Psionic_Shockwave); normalWeaponTypeSet.insert(Psionic_Shockwave_TZ_Archon); normalWeaponTypeSet.insert(Dual_Photon_Blasters); normalWeaponTypeSet.insert(Dual_Photon_Blasters_Mojo); normalWeaponTypeSet.insert(Dual_Photon_Blasters_Artanis); normalWeaponTypeSet.insert(Anti_Matter_Missiles); normalWeaponTypeSet.insert(Anti_Matter_Missiles_Mojo); normalWeaponTypeSet.insert(Anti_Matter_Missiles_Artanis); normalWeaponTypeSet.insert(Phase_Disruptor_Cannon); normalWeaponTypeSet.insert(Phase_Disruptor_Cannon_Danimoth); normalWeaponTypeSet.insert(Pulse_Cannon); normalWeaponTypeSet.insert(STS_Photon_Cannon); normalWeaponTypeSet.insert(STA_Photon_Cannon); normalWeaponTypeSet.insert(Scarab); normalWeaponTypeSet.insert(Neutron_Flare); normalWeaponTypeSet.insert(Halo_Rockets); normalWeaponTypeSet.insert(Corrosive_Acid); normalWeaponTypeSet.insert(Subterranean_Spines); normalWeaponTypeSet.insert(Warp_Blades); normalWeaponTypeSet.insert(Warp_Blades_Hero); normalWeaponTypeSet.insert(Warp_Blades_Zeratul); weaponTypeSet.insert(Yamato_Gun); weaponTypeSet.insert(Nuclear_Strike); weaponTypeSet.insert(Lockdown); weaponTypeSet.insert(EMP_Shockwave); weaponTypeSet.insert(Irradiate); weaponTypeSet.insert(Parasite); weaponTypeSet.insert(Spawn_Broodlings); weaponTypeSet.insert(Ensnare); weaponTypeSet.insert(Dark_Swarm); weaponTypeSet.insert(Plague); weaponTypeSet.insert(Consume); weaponTypeSet.insert(Stasis_Field); weaponTypeSet.insert(Psionic_Storm); weaponTypeSet.insert(Disruption_Web); weaponTypeSet.insert(Restoration); weaponTypeSet.insert(Mind_Control); weaponTypeSet.insert(Feedback); weaponTypeSet.insert(Optical_Flare); weaponTypeSet.insert(Maelstrom); specialWeaponTypeSet.insert(Yamato_Gun); specialWeaponTypeSet.insert(Nuclear_Strike); specialWeaponTypeSet.insert(Lockdown); specialWeaponTypeSet.insert(EMP_Shockwave); specialWeaponTypeSet.insert(Irradiate); specialWeaponTypeSet.insert(Parasite); specialWeaponTypeSet.insert(Spawn_Broodlings); specialWeaponTypeSet.insert(Ensnare); specialWeaponTypeSet.insert(Dark_Swarm); specialWeaponTypeSet.insert(Plague); specialWeaponTypeSet.insert(Consume); specialWeaponTypeSet.insert(Stasis_Field); specialWeaponTypeSet.insert(Psionic_Storm); specialWeaponTypeSet.insert(Disruption_Web); specialWeaponTypeSet.insert(Restoration); specialWeaponTypeSet.insert(Mind_Control); specialWeaponTypeSet.insert(Feedback); specialWeaponTypeSet.insert(Optical_Flare); specialWeaponTypeSet.insert(Maelstrom); weaponTypeSet.insert(None); weaponTypeSet.insert(Unknown); foreach(WeaponType i, weaponTypeSet) { std::string name = i.getName(); fixName(&name); weaponTypeMap.insert(std::make_pair(name, i)); } initializingWeaponType = false; } } WeaponType::WeaponType() { this->id = WeaponTypes::None.id; } WeaponType::WeaponType(int id) { this->id = id; if (!initializingWeaponType && (id < 0 || id >= 132 || !weaponTypeData[id].valid)) this->id = WeaponTypes::Unknown.id; } WeaponType::WeaponType(const WeaponType& other) { this->id = other.id; } WeaponType& WeaponType::operator=(const WeaponType& other) { this->id = other.id; return *this; } bool WeaponType::operator==(const WeaponType& other) const { return this->id == other.id; } bool WeaponType::operator!=(const WeaponType& other) const { return this->id != other.id; } bool WeaponType::operator<(const WeaponType& other) const { return this->id < other.id; } int WeaponType::getID() const { return this->id; } std::string WeaponType::getName() const { return weaponTypeData[this->id].name; } TechType WeaponType::getTech() const { return weaponTypeData[this->id].techType; } UnitType WeaponType::whatUses() const { return weaponTypeData[this->id].whatUses; } int WeaponType::damageAmount() const { return weaponTypeData[this->id].damageAmount; } int WeaponType::damageBonus() const { return weaponTypeData[this->id].damageBonus; } int WeaponType::damageCooldown() const { return weaponTypeData[this->id].damageCooldown; } int WeaponType::damageFactor() const { return weaponTypeData[this->id].damageFactor; } UpgradeType WeaponType::upgradeType() const { return weaponTypeData[this->id].upgradeType; } DamageType WeaponType::damageType() const { return weaponTypeData[this->id].damageType; } ExplosionType WeaponType::explosionType() const { return weaponTypeData[this->id].explosionType; } int WeaponType::minRange() const { return weaponTypeData[this->id].minRange; } int WeaponType::maxRange() const { return weaponTypeData[this->id].maxRange; } int WeaponType::innerSplashRadius() const { return weaponTypeData[this->id].innerSplashRadius; } int WeaponType::medianSplashRadius() const { return weaponTypeData[this->id].medianSplashRadius; } int WeaponType::outerSplashRadius() const { return weaponTypeData[this->id].outerSplashRadius; } bool WeaponType::targetsAir() const { return weaponTypeData[this->id].targetsAir; } bool WeaponType::targetsGround() const { return weaponTypeData[this->id].targetsGround; } bool WeaponType::targetsMechanical() const { return weaponTypeData[this->id].targetsMechanical; } bool WeaponType::targetsOrganic() const { return weaponTypeData[this->id].targetsOrganic; } bool WeaponType::targetsNonBuilding() const { return weaponTypeData[this->id].targetsNonBuilding; } bool WeaponType::targetsNonRobotic() const { return weaponTypeData[this->id].targetsNonRobotic; } bool WeaponType::targetsTerrain() const { return weaponTypeData[this->id].targetsTerrain; } bool WeaponType::targetsOrgOrMech() const { return weaponTypeData[this->id].targetsOrgOrMech; } bool WeaponType::targetsOwn() const { return weaponTypeData[this->id].targetsOwn; } WeaponType WeaponTypes::getWeaponType(std::string name) { fixName(&name); std::map::iterator i = weaponTypeMap.find(name); if (i == weaponTypeMap.end()) return WeaponTypes::Unknown; return (*i).second; } std::set& WeaponTypes::allWeaponTypes() { return weaponTypeSet; } std::set& WeaponTypes::normalWeaponTypes() { return weaponTypeSet; } std::set& WeaponTypes::specialWeaponTypes() { return weaponTypeSet; } } ================================================ FILE: SparCraft/sample_experiment/sample_exp.txt ================================================ #################################################################################################### # # SparCraft Experiment File Format # David Churchill - dave.churchill@gmail.com # # # denotes commented lines # # Specify the players in the experiment # # Format: # # PlayerNum PlayerType [Params]* # # ,---------------------------------------------------------, # | Scripted Player Syntax | # |---------------------------------------------------------| # | Player X ScriptName | # '---------------------------------------------------------' # # ,----------------------------------------------------------, # | Portfolio Greedy Search Player Syntax | # |----------------------------------------------------------| # | Player X PortfolioGreedySearch Seed Iterations Responses | # '----------------------------------------------------------' # # ,---------------------------------------------------------, # | Recursive Greedy Search Player Syntax | # |---------------------------------------------------------| # | Player X RecursiveGreedySearch Seed Iterations | # '---------------------------------------------------------' # # ,---------------------------------------------------------------------------------------------------------------------------------------------, # | AlphaBeta Player Syntax + Options (Scripts for Playouts) | # |---------------------------------------------------------------------------------------------------------------------------------------------| # | Player X AlphaBeta TimeLimitMS MaxChildren MoveOrdering EvalMethod P0Script P1Script PlayerToMoveMethod OpponentModelScript | # |---------------------------------------------------------------------------------------------------------------------------------------------| # | Integer Integer ScriptFirst Playout ScriptName ScriptName Alternate ScriptName | # | 0 = NoMax None LTD NotAlternate None | # | LTD2 Random | # '---------------------------------------------------------------------------------------------------------------------------------------------' # # ,--------------------------------------------------------------------------------------------------------------------------------------------------------------, # | UCT Player Syntax + Options (Scripts for Playouts) | # |--------------------------------------------------------------------------------------------------------------------------------------------------------------| # | Player X UCT TimeLimitMS CValue MaxTraversals MaxChildren MoveOrdering EvalMethod P0Script P1Script PlayerToMoveMethod OpponentModelScript | # |--------------------------------------------------------------------------------------------------------------------------------------------------------------| # | Integer Double Integer Integer ScriptFirst Playout ScriptName ScriptName Alternate ScriptName | # | None LTD NotAlternate None | # | LTD2 Random | # '--------------------------------------------------------------------------------------------------------------------------------------------------------------' # #################################################################################################### # Sample AlphaBeta Players Player 0 AlphaBeta 10 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None #Player 1 AlphaBeta 5 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS # Sample UCT Players Player 1 UCT 10 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None #Player 0 UCT 5 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS # Sample PortfolioGreedySearch Players #Player 0 PortfolioGreedySearch 0 NOKDPS 1 0 # Sample Scripted Players #Player 0 NOKDPS #Player 1 NOKDPS #################################################### # # Set player upgrade and tech levels # # Format: # PlayerUpgrade PlayerID UpgradeName UpgradeLevel # PlayerTech PlayerID TechName # #################################################### #PlayerUpgrade 0 Protoss_Ground_Weapons 1 #PlayerUpgrade 1 Protoss_Ground_Armor 3 #PlayerUpgrade 1 Singularity_Charge 1 #PlayerUpgrade 1 Zerg_Melee_Attacks 1 ################################################## # # Specify the states in the experiment # See map file description to specify legal unit positions # # State StateSymmetric NumStates MaxX MaxY [UnitType UnitNum]+ # State SeparatedState NumStates RandX RandY cx1 cy1 cx2 cy2 [UnitType UnitNum]+ # State StateDescriptionFile NumStates FileName # # For SeparatedState, NumStates / 2 mirrored copies will be created for fairness # ################################################## # Sample StateDescriptionFile States #State StateDescriptionFile 10 PATH_TO\sample_state.txt # Sample SeparatedState States State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 50 State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling 50 State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25 State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25 State SeparatedState 100 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25 # Sample Symmetric State States #State StateSymmetric 10 128 128 Protoss_Dragoon 8 #State StateSymmetric 10 128 128 Zerg_Zergling 8 #State StateSymmetric 10 128 128 Protoss_Dragoon 16 Protoss_Zealot 16 #State StateSymmetric 10 128 128 Protoss_Dragoon 16 Terran_Marine 16 #State StateSymmetric 10 128 128 Terran_Marine 16 Zerg_Zergling 16 ################################################## # # File where results will be stored # Boolean at the end indicates whether to append time stamp # .txt will be added to the end of the file automatically # # Format # ResultsFile FILENAME BOOL # ################################################## ResultsFile PATH_TO\sample_exp true ################################################## # # Map file to use for the simulation, all states will use this map. # Map file is used to define walkable boundaries for the simulation # Comment out line to use no map # No Map - Default map size is 1280*720 pixels all tiles walkable # If this map is specified, all units must be placed on walkable tiles within map boundaries or experiment will not run # ################################################## #MapFile PATH_TO\destination.txt ################################################## # # Show visualization? Only works if libraries enabled in Common.h # # Format # Display BOOL ImageDir # # This directory is included with SparCraft in folder SparCraft\starcraft_images\ # Be sure to use forward slash "\" and include the final "\" character # No spaces allowed! # ################################################## Display true PATH_TO\starcraft_images\ ================================================ FILE: SparCraft/sample_experiment/sample_exp_linux.txt ================================================ #################################################################################################### # # SparCraft Experiment File Format # David Churchill - dave.churchill@gmail.com # # # denotes commented lines # # Specify the players in the experiment # # Format: # # PlayerNum PlayerType [Params]* # # ,---------------------------------------------------------, # | Scripted Player Syntax | # |---------------------------------------------------------| # | Player X ScriptName | # '---------------------------------------------------------' # # ,----------------------------------------------------------, # | Portfolio Greedy Search Player Syntax | # |----------------------------------------------------------| # | Player X PortfolioGreedySearch Seed Iterations Responses | # '----------------------------------------------------------' # # ,---------------------------------------------------------, # | Recursive Greedy Search Player Syntax | # |---------------------------------------------------------| # | Player X RecursiveGreedySearch Seed Iterations | # '---------------------------------------------------------' # # ,---------------------------------------------------------------------------------------------------------------------------------------------, # | AlphaBeta Player Syntax + Options (Scripts for Playouts) | # |---------------------------------------------------------------------------------------------------------------------------------------------| # | Player X AlphaBeta TimeLimitMS MaxChildren MoveOrdering EvalMethod P0Script P1Script PlayerToMoveMethod OpponentModelScript | # |---------------------------------------------------------------------------------------------------------------------------------------------| # | Integer Integer ScriptFirst Playout ScriptName ScriptName Alternate ScriptName | # | 0 = NoMax None LTD NotAlternate None | # | LTD2 Random | # '---------------------------------------------------------------------------------------------------------------------------------------------' # # ,--------------------------------------------------------------------------------------------------------------------------------------------------------------, # | UCT Player Syntax + Options (Scripts for Playouts) | # |--------------------------------------------------------------------------------------------------------------------------------------------------------------| # | Player X UCT TimeLimitMS CValue MaxTraversals MaxChildren MoveOrdering EvalMethod P0Script P1Script PlayerToMoveMethod OpponentModelScript | # |--------------------------------------------------------------------------------------------------------------------------------------------------------------| # | Integer Double Integer Integer ScriptFirst Playout ScriptName ScriptName Alternate ScriptName | # | None LTD NotAlternate None | # | LTD2 Random | # '--------------------------------------------------------------------------------------------------------------------------------------------------------------' # #################################################################################################### # Sample AlphaBeta Players #Player 0 AlphaBeta 40 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None #Player 1 AlphaBeta 40 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS # Sample UCT Players #Player 0 UCT 40 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate None #Player 0 UCT 40 1.6 5000 20 ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS # Sample PortfolioGreedySearch Players Player 0 PortfolioGreedySearch 0 NOKDPS 1 0 # Sample Scripted Players Player 0 NOKDPS Player 1 NOKDPS #################################################### # # Set player upgrade and tech levels # # Format: # PlayerUpgrade PlayerID UpgradeName UpgradeLevel # PlayerTech PlayerID TechName # #################################################### #PlayerUpgrade 0 Protoss_Ground_Weapons 1 #PlayerUpgrade 1 Protoss_Ground_Armor 3 #PlayerUpgrade 1 Singularity_Charge 1 #PlayerUpgrade 1 Zerg_Melee_Attacks 1 ################################################## # # Specify the states in the experiment # See map file description to specify legal unit positions # # State StateSymmetric NumStates MaxX MaxY [UnitType UnitNum]+ # State SeparatedState NumStates RandX RandY cx1 cy1 cx2 cy2 [UnitType UnitNum]+ # State StateDescriptionFile NumStates FileName # # For SeparatedState, NumStates / 2 mirrored copies will be created for fairness # ################################################## # Sample StateDescriptionFile States #State StateDescriptionFile 10 PATH_TO\sample_state.txt # Sample SeparatedState States State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 50 State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling 50 State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25 State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25 State SeparatedState 100 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25 # Sample Symmetric State States #State StateSymmetric 10 128 128 Protoss_Dragoon 8 #State StateSymmetric 10 128 128 Zerg_Zergling 8 #State StateSymmetric 10 128 128 Protoss_Dragoon 16 Protoss_Zealot 16 #State StateSymmetric 10 128 128 Protoss_Dragoon 16 Terran_Marine 16 #State StateSymmetric 10 128 128 Terran_Marine 16 Zerg_Zergling 16 ################################################## # # File where results will be stored # Boolean at the end indicates whether to append time stamp # .txt will be added to the end of the file automatically # # Format # ResultsFile FILENAME BOOL # ################################################## ResultsFile PATH_TO\sample_exp true ################################################## # # Map file to use for the simulation, all states will use this map. # Map file is used to define walkable boundaries for the simulation # Comment out line to use no map # No Map - Default map size is 1280*720 pixels all tiles walkable # If this map is specified, all units must be placed on walkable tiles within map boundaries or experiment will not run # ################################################## #MapFile PATH_TO\destination.txt ################################################## # # Show visualization? Only works if libraries enabled in Common.h # # Format # Display BOOL ImageDir # # This directory is included with SparCraft in folder SparCraft\starcraft_images\ # Be sure to use forward slash "\" and include the final "\" character # No spaces allowed! # ################################################## Display true PATH_TO\starcraft_images\ ================================================ FILE: SparCraft/sample_experiment/sample_map_files/destination.txt ================================================ 384 512 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001101110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000001111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000001011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000011011100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000001111001100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000011111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001101110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000101110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000010000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000001100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111100001111111111111111111111111111000000011111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000011111111111111111111111110000000000111111000000000111111111111111111111111111111111111111111111111111111111111111111111000111111111111 000000000000000000000000000000110111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111000000001111111111111111111111110000000000111111000000000011111111111111111111111111111111111111111111111111111111111111111111000111111111111 000000000000000000000000000000110011000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000000011111111111111111111110000000000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000011111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111110000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111011111111111 000000000000000000000000000000111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111111110000000000000000000000000011000000000011111111111111111111111111111111111111111111111111111111111111111000111111111 000000000000000000000000000000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111100000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111000011111111 000000000000000000000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111100000000000000000000000011111111000000001111111111111111111111111111111111111111111111111111111111111111000011111111 000000000000000000000000000000010000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111100000000000000000000000001111111000000000111111111111111111111111111111111111111111111111111111111111111100000001111 000000000000000000000000000000010000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000011011100000000000000000000000000011110000000000011111111111111111111111111111111111111111111111111111111111111111000001111 000000000000000000000000000000110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000011011100000000000000000000000000001110000000000011111111111111111111111111111111111111111111111111111111111111111100000001 000000000000000000000000000011110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000001001100000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111100000001 000000000000000000000000000001111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111100000111111111111111111111111111111111111111111111111111111110000000 000000000000000000000000000001110111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000111100000000000000000000000000000000111000000001111111111111111111111111111111111111111111111111111111100000 000000000000000000000000000001110111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011111111111111100011000000000000111100000000000000000000000000111111000000000000000000000000000000111000000000000111111111111111111111111111111111111111111111111111110000 000000000000000000000000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111111111111110011110000000011111111000000000000000000000000111111110000000000000000000000000000110000000000000111111111111111111111111111111111111111111111111111110000 000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111101111111111111111111111111111111111111111 000000000000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111101111111111111111111111111111111111111111 000000000000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111111000111111111111111111111111111111111111111 000000000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111110000111111111111111111111111111111111111111 000000000000000000000000000000000000001111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011110000110000000111111111111111111111111111111111 000000000000000000000000000000000000001101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011000000001100000011111111111111111111111111111111 000000000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111000000000011000000001110000001111111111111111111111111111111 000000000000000000000000000000000000000000110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111000000000011000000001111000001111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111110000000000111000000001111000000001111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111100000000000111000000001111000000001111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000111000000001000000000111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111000000000000011111111111000000011111111111111111111111111111111 000000000000000000000000000000000000000000000001000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000001000011110000000011111111111111111111111111111111 000000000000000000000000000000000000000000000001000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000001000011000000000111111111111111111111111111111111 000000000000000000000000000000000000000000000011000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000011000010000000001111111111111111111111111111111111 000000000000000000000000000000000000000000001111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011110000000000001111111100000000111111111111111111111111111111111111 000000000000000000000000000000000000000011111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111 000000000000000000000000000000000000000001111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111 000000000000000000000000000000000000001101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111 000000000000000000000000000000000000001100110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111 000000000000000000000000000000001100001111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111111111 000000000000000000000000000000001100001111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111111111111111111111111111111111111111111 000000000000001100000000000000111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111 000000000000001100000000000000111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111 000000001111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000011111111111111111111111111111111111111111 000000001111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000011111111111111111111111111111111111111111 000000001111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000000000111111111111111111111111111111111111111111 000000001111111111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111100000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001101110111000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000101110111000000011111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000110011000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001100000011000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000111100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000100000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000000000000000001111110000000001111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000000000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000011111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111100000000000001000000000000000000000000000111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000001000000000000000000000000011111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000111100000000000000000000001111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111000000111111000000000000000000111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111100000000000111111111111111111111000000000011111111111100000000000011111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000001100000011100001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111110000000000000111111111111111111111000000000011111111111100000000001111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111100000000000000000000000000000111000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111110000000000000000000111111111111111100000000000001111111111100000000111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111100000000000000000000000000001111000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111100000000000000000000111111111111111100000000000001111111111100000011111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111000000000000000000000000111111000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111000000000000000000000000001111110000000000000000000111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111100001100000000000000000000011111100001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000001111000000000000000000000000000000011000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111100001100000000000000000000000111100001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111100000000000000000000000011110001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111000111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111000000011111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000011100000000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111000001111111111110000000001111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000011110000000000000000000000001111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111100000001111111111110000000000111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000111111111111000000000000000011111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111110000000000000011111110000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000011111111111111000000000000000011111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111000000000000000011111110000000000000000000000000000000000001110000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111110000000000001111111111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111100000000000000000011111110000000000000000000000000000000000001110000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000001111111111111111111100000000111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111110000000000000000000000011100000000000000000000000000000000000001110000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001100011111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000001100000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001000001111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011000000111111111111111111110000111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011000011111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000001000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000011110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000001111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000011111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000001111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111000001111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000001111100011111111000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000001111000000110111000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001110000000010111000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001100000000000011000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111110000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111100000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011110000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111 011111110000000000000011111111111111111111111111110000111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011100000000001111111111111111111111111111111111111111111111111111111111111111111 011111110000000000000011111111111111111111111111110000111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000000011111111111111111111111111111111111111111111111111111111111111111111 011111110000000000000000111111111111111111111111111111110000011111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000001111111111111111111111111111111111111111111111111111111111111111111111 011111110000000000000000111111111111111111111111111111110000000111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011100000111111111111111111111111111111111111111111111111111111111111111111111111 010000000000000000000000000000110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000011000000111111111111111111111111111111111111111111111111111111111111111111111111 010000000000000000000000000000110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000001111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000011111000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111100000000000011111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000011111000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111000000001111111111111111111100111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111000011111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111100000000111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001000000000000111110000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001000000000000011110000000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111100000000000000000000111111111111000011111000000111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011110000000000110000000000011111111100000001111000000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000001111000000000001111000000000000111110000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000111111110000000000111000000000000011111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111000000000000000000000000000111110000000011111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111100000000000000110000000000011110000000011111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000111111111111111111110000000000001111000000000001110000000011111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111100000000111111110000000000111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111100000000011111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111100001111111111111111111111111111111111110000000001111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111000000111111111111111111111111111111111111100000000001110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111000000111111111111111111111111111111111111111110000000000000001111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111000000111111111111111111111111111111111111111111000000000000111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111100000000001111111111111111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111000000001111111111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011 011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001000000000000000000001111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111000000000000000000000000011111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111110000000000011000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001 011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111100000000000111100110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111000000000011111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000001111110000000000111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001000000111000000000000011110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011110000010000000000000011110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111101111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100011111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100001111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100001111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111110000000111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111011111111111111111000000000011111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111011111111111111111110000000001111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111110001111111111111111111000000000111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111100001111111111111111111000000000011 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111100000001111111111111111100000000 011111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111000000111111111111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111000000 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111110000 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111110000000000000000000000000000000011111111111111111111111111111111111111111110000011111111111111111111111110000000001111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111000000011111111111111111111111110000000111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111000000000000000000000000111111111111111111111111111111111111111111100000000000001111111111111111111100000000111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111110000000000000000011111111111111110000000001111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111100000011110000001111111111111111111111111111111111111111111000000000000000000001111111111111100000000011111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111000011110000111111111111111111111111111111111111111111100000000000000000000001111111111110000000001111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111000000000000000000001111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111100000000000111111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001011110000000000100000011111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000011011100000000001111000001111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000001111001100000000111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000000111111111100001100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111000000000111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000011110000000000011111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001110000000000011111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001100000000000011111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111000000000111000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000001000000000000001111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000011000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000001000000000000011111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000011110000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000011000000000001111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111000000001111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111000110000001111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011110000000000011111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011100000000000111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011000000000011111111111111111111111111111111111111111111 011111111111111111111111111111110000011111111111111111111111000000000111110000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111110000001100000000000000001111000000000000111111111111111111111111111111111111111111111111 011111111111111111111111111111110000001111111111111111111111000000000111110000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111110000000100000000000000001110000000000001111111111111111111111111111111111111111111111111 011111111111111111111111111111111100000111111111111111110000000000000011000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111100000100000000000000111110000000000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111110000000000000001000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000011111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111100000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111110000000000011111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100011111111111100000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111110000000000011111000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000001110111110000000000111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110100000000000001111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001100100000000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111100000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111100000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111110000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111 010000111111111111111111111111111000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111 010000111111111111111111111111111110000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111000011111111111111100011000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111100000001111111111111110011110000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111110000000000000111111111111111111100000100000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111 000011111000000000000000111111111111111111000000100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110000000000111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000011111111111111100000000110000000000000000000000111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110000000000011111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000001111111111111100000000111100000000000000000011111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001100000000000011111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000111111111111111000000111111110000000000001111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011000000001100000000000111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000011111111111111110000111111110000000000111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001100000000001111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000111111111111111000111111110000000011111111111111111111111111111111111111111110000000000000000000000000011111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001100000000111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000000011111111111111111111111110000001111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111 000000000000111111000000000011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000000000111111110000000111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000011111000000111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011110000000011110000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111100000000001111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000000000111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000001111111100000000000000000001111100000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111100000000001100000000000011100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000000011110000000000011100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111000000001111111100000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111110000000000000011111111111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110000000000000000011111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000001111110000001111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000001111110000011111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111111000111111111111111111111111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111111111111111111110000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000001100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 011111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 011100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 011100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111 000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111 000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001111111111111110000111111111111111111111111111111111111111111111111111111111111111111 000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011111111111111100000001111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111000001 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111100000000000011111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000001111111111111111111110000000000000000111111110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111100000000000000000001111110000001 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000111111111111111100000000000000000000111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000011111110000000000000000000000000111111100000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111100000000000000000001111000000000000000000000000000011110000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111110000000000000000001110000000000000000000000000000011100000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000001110000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001100000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111100000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011100000000000000000000000000000111111100000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011100000000000000000000000000000111011110000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011000000000000000000000000000000111011110000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000110011110000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111100000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111100000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111100011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111100001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111100000001111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111000000111111111111100000000001111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111110000001111111111111100000000001111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111110000011111111111111100000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111110000000011111111100011000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111110000000011111111000000000001100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111100000000011110000000000011110000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000110000000000000000000000000000000000000000000111 011111111111111111111111111111111111111111111111111111111111111111111111000000011100000000001111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000110000000000000000000000000000000000000000000111 011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000111111000000000000000000000111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111000000000000000011111111 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111000000000000000000000111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111000000000000000011111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000001111111111111111111111111110000000011111111111111111111111111111111111000000000000011111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111100000011111111111111111111111111111111111000000000000011111111 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000001111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000011000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011100000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000111111111111111111111111111111111111111111111111111110000000000000000000110000000000000000011100000000000000000000000000000000000011111111111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111110000000000000000011110000000000000000001100000000000000000000000000000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111100000000000000111100000000000000000000111111111000000000000000000000000000111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111100000000000000000000000000000011000111111111111111111111111111111111111111111111111111111111111111111111111111111111111 010000011111111111111111111111111111111111111111111111111110000000000000011100000000000000000000000101111000000000000000000000000011111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111100000000001111111111111111111100000000000000000000000000000010000011111111111111111111111111111111111111111111111111111111111111111111111111111111111 011000011111111111111111111111111111111111111111111111111111100000000000011100000000000000000000000001111100000000000000000000001111111111111111111111111110000000000000000000011111111111111111111111111111111111111111111111111111111111100000000001111111111111111111110000000000000000000000000000110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111111111100000000001100000000000000000000000000111111000000000000000000111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111100000000000000000000000011111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000011111111111100000000000011111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111000000000000000001111111110000000011110000000000000000110000111110001111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000010000000000000000000000000000000000001111111111100000000001111111111111111111111111110000000000000000000000000000000111111111111111111111111111111111111111111111111110000000001100000000000111111100000000001110000000000000000110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000011000000000000000000000000000000000001111111111111100000111111111111111111111111111000000000000000000000000000000000011111111111111111111111111111111111111111111111100000000011110000000000011111100000000001111100000000000000110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111000000111110000000000000000000000000000000000111111111111100011111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111110000000001111111100000000001111100000000001111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111110000111000001111100000000000000000000000000000000000111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111100001100000011111111111111110000000011000000000000110000111111111111000111111111111000011111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001000001111100000000000000000000011100000000000111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111000000000000111111111111111111000000000000001100000000000011101111100000011101111100000001111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001000011100000000000000000000001111111100000000111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111000000000001111111111111111111100000000000011110000000000011101111000000011101000000000000111111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001111111100000000000000000000001111111100000011111111111111111111111111111111111110000000000000000000000000000000000000111111111111111111111111111111111111111111111000000000111111111111111111111111000000001111111100000000011100110000000011001000000000000011111111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001111000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000000000000000000011111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111110000001100000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001110000000000000000000000000001111111111111111111111111111111111111111111111110000000000000000000000000000000000001111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111000000000000001100000000000000110000000000011111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000001100000000000000000000000000001111111111111111111111111111111111111111111111110000000000000000000000000000000000111111111111111111111110000011111111111111110000000000111111111111111111111111111111111111111111111111111100000000000011110000000000001111000000000001111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111111100000000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111000000011111111111111110000000011111111111111111111111111111111111111111111111111111111000000001111111100000000111111110000000000111111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111100000000000000000111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000000000000000000000011111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111110000000000000000000001111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111000000000000000000000000111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111100000000000000000000000000110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111110000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111110000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111000000000000000000000000000000100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111000000001111111111111111111111100000000000000000000000000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111000000111111111111111111111110000000000000000000000000000000111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111100000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111110000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000110111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000110011000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111100000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111110000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000110000011100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000011111111000011110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000011111100000001110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111000000001110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111100000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111000000000011000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111111110000000011110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111 011111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111000011110000000000001111 011111111111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000001111111111111111000011110000000000001111 011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111000011110000000000000000 011111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111110000000000000000 011111111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111110000000000000000000000 011111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111110000000000000000000000 011111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111000000000000000000000000 011111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111000000000000000000000000 011111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111110000000000000000000000000000 011111111111111111111111111111111111111110000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001111111111000000000000000000000000000000 011111111111111111111111111111111111111111000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111110000000000000000000000000000000 011111111111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111110000000000000000000000000000000 011111111111111111111111111111111111111111100000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111110000000000000000000000000000000 011111111111111111111111111111111111111111100000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111110000000000000000000000000000000 011111111111111111111111111111111111111100000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111000000000000000000000000000000 011111111111111111111111111111111111111100000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111110000000000000000000000000000 011111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011111110000000000000000000000000000 011111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111000000000000000000000000000000 011111111111111111111111111111100000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001110000000000000000000000000000000 011111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000110000000000000000000000000000000 011111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000010000000000000000000000000000000 011111111111111111111111111111100000000000000000000000000000000001111000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000010000000000000000000000000000000 011111111111111111111111111111100000000000000011110000000000000001110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000011000000000000000000000000000000 011111111111111111111111111111110000000000001111110000000000000000110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011110000000000000000000000000000 011111111111111111111111111111111000000011000011111000000000111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111000000000000000000000000 011111111111111111111111111111111110000000000000111000000000011101110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000010111000000000000000000000000 011111111111111111111111111111111111100000000000110000000000011101110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000110000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111110000000000000000000000 011111111111111111111111111111111111110000000000100000000000001100110000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111100000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011110000000000000000000000 011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011110000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111100000000000000000000 011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011110000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001110110000000000000000000000 011111111111111111111111111111111111111100000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000010000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110100000000000000000000000 011111111111111111111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000010000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001100100000000000000000000000 011111111111111111111111111111111111111111111111111000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111101111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111101111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000 010000111111111111111111111111111111111111111111110000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111000111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000 000000011111111111111111111111111111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111110000111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000 000000001111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000 000000001111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000 000000000111111111111111111111111111111111111111110000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111110000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000 000000000011111111111111111111111111111111111111111100000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000 000000000001111111111111111111111111111111111111111111110000000000000000000000000000000100000000000011111111111011111111111111111111111111111110000011111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111000000000000000000000000000000000000000 000000000000111111111111111111111111111111111111111111110000000000000000000000000000000110000000000001111111100000011111111110000011111111111000000001111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000011101000000000000000000000000000000000000000 000000000000001111111111111111111111111111111111111111111100000000000011000000000000001111000000000001111000000000001111111100000001111110000000000001111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011101100000000000000000000000000000000000000 000000000000000111111111111111111111111111111111111111111111000000001111000000001111111111110000000001111000000000001111111100000000001110000000000000111000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000011001111000000000000000000000000000000000000 000000000000011111111111111111111111111111111111111111111111111111111111111000000000011111100000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000111111111100000000000000000000000000000000 010000000000111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111000000000000000000000000000000000 011100000001111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111011000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000110011000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000001111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000111111110000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000111111100000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000111011000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000110111111111000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111010000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000110011111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000110010000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000011111111111111110000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000001110000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111100000000011111111111111111110000000000000111000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001110000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111100000011111111111111111111111100000000111111110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111110000111111111100000011111111111111111111111111000000111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000001111110000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111110000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111011110000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001111111111111110000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011111111111111100000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000110000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000001000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000001000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001100000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111100000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000110000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000111100000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000011110000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000110000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000010000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111100000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000001110100000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001110110000000000000000000000000000000000000000000000 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001100111100000000000000000000000000000000000000000000 000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000001111111100000000000000000000000000000000000000000000 000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000001110110000000000000000000000000000000000000000000000 000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001110100000000000000000000000000000000000000000000000 000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001100100000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ================================================ FILE: SparCraft/sample_experiment/sample_map_files/map_file_format.txt ================================================ Map files are in ASCII format. First two lines specify WIDTH, HEIGHT in WalkTile resolution (8x8 pixel) Next HEIGHT lines (each with WIDTH columns) specify walkable tiles 0 = blocked, 1 = walkable SparCraft::Position p translates into map WalkTile position (p.x() / 8, p.y() / 8) Sample 20x10 map with all tiles walkable: 20 10 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 11111111111111111111 If no map is specified in experiment , default map has size: 40x22 BuildTile == 160x88 WalkTile == 1280x704 This size was chosen to best fit the Display's 1280*720 pixel size, and is also a decent sized arena If a GameState contains any initial unit whose Position is on a non-walkable tile, the experiment will not run ================================================ FILE: SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_config.txt ================================================ Player 0 NOKDPS Player 1 KiterDPS State SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 50 State SeparatedState 10 128 128 400 360 840 360 Zerg_Zergling 50 State SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 25 Protoss_Zealot 25 State SeparatedState 10 128 128 400 360 840 360 Protoss_Dragoon 25 Terran_Marine 25 State SeparatedState 10 128 128 400 360 840 360 Terran_Marine 25 Zerg_Zergling 25 ResultsFile c:\users\dave\desktop\results\sample_exp true Display true ================================================ FILE: SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_results_raw.txt ================================================ P1 P2 ST UNIT EVAL RND MS | UnitType PlayerID CurrentHP XPos YPos 0 0 0 50 100131 638 890.66 | Protoss_Dragoon 0 140 646 474 | Protoss_Dragoon 0 180 647 472 | Protoss_Dragoon 0 100 628 499 | Protoss_Dragoon 0 180 680 465 | Protoss_Dragoon 0 180 619 509 | Protoss_Dragoon 0 160 632 488 | Protoss_Dragoon 0 180 638 488 0 0 1 50 100244 523 701.88 | Protoss_Dragoon 0 180 574 312 | Protoss_Dragoon 0 180 585 275 | Protoss_Dragoon 0 180 616 276 | Protoss_Dragoon 0 20 502 282 | Protoss_Dragoon 0 100 637 283 | Protoss_Dragoon 0 120 513 274 | Protoss_Dragoon 0 140 613 303 | Protoss_Dragoon 0 160 576 303 | Protoss_Dragoon 0 160 556 294 | Protoss_Dragoon 0 160 589 305 | Protoss_Dragoon 0 100 586 276 | Protoss_Dragoon 0 160 609 280 | Protoss_Dragoon 0 180 602 289 | Protoss_Dragoon 0 160 618 264 0 0 2 50 100190 571 911.32 | Protoss_Dragoon 0 180 750 366 | Protoss_Dragoon 0 140 694 332 | Protoss_Dragoon 0 140 756 391 | Protoss_Dragoon 0 140 764 380 | Protoss_Dragoon 0 160 746 376 | Protoss_Dragoon 0 180 746 394 | Protoss_Dragoon 0 40 733 376 | Protoss_Dragoon 0 100 693 326 | Protoss_Dragoon 0 160 756 380 | Protoss_Dragoon 0 120 700 310 | Protoss_Dragoon 0 160 690 305 0 0 3 50 100186 562 890.04 | Protoss_Dragoon 0 100 530 401 | Protoss_Dragoon 0 140 492 319 | Protoss_Dragoon 0 160 515 377 | Protoss_Dragoon 0 140 479 362 | Protoss_Dragoon 0 180 492 373 | Protoss_Dragoon 0 180 542 379 | Protoss_Dragoon 0 160 502 335 | Protoss_Dragoon 0 180 537 421 | Protoss_Dragoon 0 160 526 408 | Protoss_Dragoon 0 180 521 389 0 0 4 50 100110 649 884.54 | Protoss_Dragoon 0 120 733 353 | Protoss_Dragoon 0 160 721 348 | Protoss_Dragoon 0 20 702 325 | Protoss_Dragoon 0 160 704 320 | Protoss_Dragoon 0 100 721 337 | Protoss_Dragoon 0 120 752 349 | Protoss_Dragoon 0 160 702 317 0 0 5 50 100099 639 790.77 | Protoss_Dragoon 0 60 506 448 | Protoss_Dragoon 0 100 545 467 | Protoss_Dragoon 0 120 506 355 | Protoss_Dragoon 0 160 466 238 | Protoss_Dragoon 0 140 503 282 | Protoss_Dragoon 0 180 500 384 0 0 6 50 100209 535 729.48 | Protoss_Dragoon 0 180 694 399 | Protoss_Dragoon 0 180 743 323 | Protoss_Dragoon 0 60 668 412 | Protoss_Dragoon 0 180 769 293 | Protoss_Dragoon 0 20 751 334 | Protoss_Dragoon 0 180 721 359 | Protoss_Dragoon 0 120 672 457 | Protoss_Dragoon 0 180 710 370 | Protoss_Dragoon 0 140 713 362 | Protoss_Dragoon 0 180 745 343 | Protoss_Dragoon 0 140 734 357 | Protoss_Dragoon 0 180 725 354 0 0 7 50 100220 512 699.67 | Protoss_Dragoon 0 80 471 480 | Protoss_Dragoon 0 140 519 271 | Protoss_Dragoon 0 160 472 263 | Protoss_Dragoon 0 180 514 327 | Protoss_Dragoon 0 160 501 379 | Protoss_Dragoon 0 180 487 295 | Protoss_Dragoon 0 80 543 270 | Protoss_Dragoon 0 180 519 448 | Protoss_Dragoon 0 180 536 390 | Protoss_Dragoon 0 180 538 394 | Protoss_Dragoon 0 160 482 446 | Protoss_Dragoon 0 180 498 366 0 0 8 50 100200 562 754.78 | Protoss_Dragoon 0 40 688 482 | Protoss_Dragoon 0 40 773 282 | Protoss_Dragoon 0 160 686 440 | Protoss_Dragoon 0 160 744 323 | Protoss_Dragoon 0 180 744 327 | Protoss_Dragoon 0 160 805 253 | Protoss_Dragoon 0 100 701 367 | Protoss_Dragoon 0 140 731 332 | Protoss_Dragoon 0 160 706 478 | Protoss_Dragoon 0 180 780 307 | Protoss_Dragoon 0 80 788 271 | Protoss_Dragoon 0 180 734 341 0 0 9 50 100139 588 859.14 | Protoss_Dragoon 0 20 480 381 | Protoss_Dragoon 0 80 519 253 | Protoss_Dragoon 0 40 493 372 | Protoss_Dragoon 0 100 493 363 | Protoss_Dragoon 0 140 467 403 | Protoss_Dragoon 0 180 487 377 | Protoss_Dragoon 0 140 503 368 | Protoss_Dragoon 0 180 498 370 | Protoss_Dragoon 0 180 512 353 0 0 10 50 100450 117 200.41 | Zerg_Zergling 0 20 640 383 | Zerg_Zergling 0 35 638 423 | Zerg_Zergling 0 35 642 374 | Zerg_Zergling 0 35 657 383 | Zerg_Zergling 0 35 662 365 | Zerg_Zergling 0 15 631 450 | Zerg_Zergling 0 20 653 387 | Zerg_Zergling 0 25 655 354 | Zerg_Zergling 0 25 668 396 | Zerg_Zergling 0 30 656 403 | Zerg_Zergling 0 35 643 404 | Zerg_Zergling 0 35 643 408 | Zerg_Zergling 0 35 644 418 | Zerg_Zergling 0 35 653 399 | Zerg_Zergling 0 35 671 414 | Zerg_Zergling 0 35 672 412 | Zerg_Zergling 0 35 674 405 | Zerg_Zergling 0 35 675 404 | Zerg_Zergling 0 35 676 410 | Zerg_Zergling 0 35 641 441 | Zerg_Zergling 0 35 643 500 | Zerg_Zergling 0 20 634 478 | Zerg_Zergling 0 35 640 430 | Zerg_Zergling 0 35 657 428 0 0 11 50 100388 125 202.70 | Zerg_Zergling 0 5 578 323 | Zerg_Zergling 0 35 568 320 | Zerg_Zergling 0 35 568 332 | Zerg_Zergling 0 35 572 267 | Zerg_Zergling 0 5 567 331 | Zerg_Zergling 0 10 570 279 | Zerg_Zergling 0 20 572 341 | Zerg_Zergling 0 25 569 270 | Zerg_Zergling 0 30 564 336 | Zerg_Zergling 0 35 565 332 | Zerg_Zergling 0 35 574 314 | Zerg_Zergling 0 35 567 329 | Zerg_Zergling 0 35 577 315 | Zerg_Zergling 0 35 571 329 | Zerg_Zergling 0 20 579 323 | Zerg_Zergling 0 35 566 334 | Zerg_Zergling 0 35 569 325 | Zerg_Zergling 0 30 569 326 | Zerg_Zergling 0 35 563 337 | Zerg_Zergling 0 35 565 325 | Zerg_Zergling 0 30 568 327 | Zerg_Zergling 0 35 565 268 0 0 12 50 100458 117 213.22 | Zerg_Zergling 0 5 670 334 | Zerg_Zergling 0 15 653 273 | Zerg_Zergling 0 35 668 313 | Zerg_Zergling 0 5 670 296 | Zerg_Zergling 0 10 663 309 | Zerg_Zergling 0 15 666 303 | Zerg_Zergling 0 20 643 316 | Zerg_Zergling 0 30 662 296 | Zerg_Zergling 0 30 664 296 | Zerg_Zergling 0 30 665 304 | Zerg_Zergling 0 30 666 304 | Zerg_Zergling 0 35 651 323 | Zerg_Zergling 0 35 651 324 | Zerg_Zergling 0 35 653 305 | Zerg_Zergling 0 35 657 302 | Zerg_Zergling 0 35 661 307 | Zerg_Zergling 0 35 671 298 | Zerg_Zergling 0 35 674 295 | Zerg_Zergling 0 35 676 292 | Zerg_Zergling 0 35 669 283 | Zerg_Zergling 0 35 671 290 | Zerg_Zergling 0 35 673 291 | Zerg_Zergling 0 15 669 271 | Zerg_Zergling 0 35 660 282 | Zerg_Zergling 0 5 670 300 | Zerg_Zergling 0 30 662 288 | Zerg_Zergling 0 30 673 288 0 0 13 50 100395 119 198.95 | Zerg_Zergling 0 15 575 345 | Zerg_Zergling 0 25 576 471 | Zerg_Zergling 0 25 586 386 | Zerg_Zergling 0 30 579 373 | Zerg_Zergling 0 35 569 366 | Zerg_Zergling 0 35 575 365 | Zerg_Zergling 0 35 587 447 | Zerg_Zergling 0 25 585 393 | Zerg_Zergling 0 35 562 397 | Zerg_Zergling 0 35 566 405 | Zerg_Zergling 0 35 568 391 | Zerg_Zergling 0 35 568 392 | Zerg_Zergling 0 35 579 401 | Zerg_Zergling 0 35 599 432 | Zerg_Zergling 0 20 596 438 | Zerg_Zergling 0 25 585 408 | Zerg_Zergling 0 30 571 396 | Zerg_Zergling 0 35 583 411 | Zerg_Zergling 0 35 577 387 | Zerg_Zergling 0 10 593 454 | Zerg_Zergling 0 15 578 392 | Zerg_Zergling 0 30 580 393 0 0 14 50 100425 117 198.66 | Zerg_Zergling 0 20 669 390 | Zerg_Zergling 0 25 661 393 | Zerg_Zergling 0 30 613 415 | Zerg_Zergling 0 30 651 391 | Zerg_Zergling 0 30 652 397 | Zerg_Zergling 0 35 653 400 | Zerg_Zergling 0 10 652 408 | Zerg_Zergling 0 35 655 430 | Zerg_Zergling 0 35 662 422 | Zerg_Zergling 0 35 656 399 | Zerg_Zergling 0 35 661 410 | Zerg_Zergling 0 30 605 423 | Zerg_Zergling 0 30 627 423 | Zerg_Zergling 0 35 637 412 | Zerg_Zergling 0 35 658 424 | Zerg_Zergling 0 35 667 431 | Zerg_Zergling 0 20 634 423 | Zerg_Zergling 0 25 657 420 | Zerg_Zergling 0 30 654 428 | Zerg_Zergling 0 35 627 414 | Zerg_Zergling 0 35 631 423 | Zerg_Zergling 0 35 632 420 | Zerg_Zergling 0 35 649 413 0 0 15 50 100371 127 270.19 | Zerg_Zergling 0 5 606 302 | Zerg_Zergling 0 15 588 293 | Zerg_Zergling 0 25 587 301 | Zerg_Zergling 0 25 592 298 | Zerg_Zergling 0 30 582 288 | Zerg_Zergling 0 35 587 284 | Zerg_Zergling 0 35 589 276 | Zerg_Zergling 0 35 589 286 | Zerg_Zergling 0 35 592 276 | Zerg_Zergling 0 35 597 294 | Zerg_Zergling 0 5 635 297 | Zerg_Zergling 0 30 600 305 | Zerg_Zergling 0 5 579 292 | Zerg_Zergling 0 35 576 283 | Zerg_Zergling 0 35 578 284 | Zerg_Zergling 0 35 584 290 | Zerg_Zergling 0 5 584 281 | Zerg_Zergling 0 30 588 291 | Zerg_Zergling 0 30 591 291 | Zerg_Zergling 0 35 577 279 | Zerg_Zergling 0 35 586 282 | Zerg_Zergling 0 35 586 282 0 0 16 50 100434 129 222.76 | Zerg_Zergling 0 10 652 471 | Zerg_Zergling 0 35 653 479 | Zerg_Zergling 0 35 657 459 | Zerg_Zergling 0 35 661 463 | Zerg_Zergling 0 35 628 461 | Zerg_Zergling 0 35 654 477 | Zerg_Zergling 0 35 656 471 | Zerg_Zergling 0 35 656 477 | Zerg_Zergling 0 35 662 462 | Zerg_Zergling 0 35 662 473 | Zerg_Zergling 0 35 667 460 | Zerg_Zergling 0 20 658 469 | Zerg_Zergling 0 30 652 469 | Zerg_Zergling 0 25 639 464 | Zerg_Zergling 0 20 667 477 | Zerg_Zergling 0 30 606 466 | Zerg_Zergling 0 35 644 463 | Zerg_Zergling 0 35 650 478 | Zerg_Zergling 0 35 651 473 | Zerg_Zergling 0 35 653 474 | Zerg_Zergling 0 35 654 478 | Zerg_Zergling 0 35 657 470 | Zerg_Zergling 0 35 652 480 0 0 17 50 100422 125 260.57 | Zerg_Zergling 0 35 576 280 | Zerg_Zergling 0 35 581 290 | Zerg_Zergling 0 35 581 295 | Zerg_Zergling 0 35 582 298 | Zerg_Zergling 0 35 588 281 | Zerg_Zergling 0 35 589 294 | Zerg_Zergling 0 35 600 258 | Zerg_Zergling 0 30 582 285 | Zerg_Zergling 0 30 586 269 | Zerg_Zergling 0 30 634 270 | Zerg_Zergling 0 35 595 262 | Zerg_Zergling 0 20 649 261 | Zerg_Zergling 0 30 596 257 | Zerg_Zergling 0 35 592 259 | Zerg_Zergling 0 35 599 262 | Zerg_Zergling 0 35 618 272 | Zerg_Zergling 0 15 602 268 | Zerg_Zergling 0 35 589 258 | Zerg_Zergling 0 35 599 255 | Zerg_Zergling 0 35 605 263 | Zerg_Zergling 0 35 606 262 | Zerg_Zergling 0 35 609 267 0 0 18 50 100404 123 219.80 | Zerg_Zergling 0 5 649 287 | Zerg_Zergling 0 20 613 234 | Zerg_Zergling 0 20 645 286 | Zerg_Zergling 0 35 621 287 | Zerg_Zergling 0 35 622 304 | Zerg_Zergling 0 35 639 294 | Zerg_Zergling 0 35 649 288 | Zerg_Zergling 0 35 626 280 | Zerg_Zergling 0 35 636 285 | Zerg_Zergling 0 35 631 285 | Zerg_Zergling 0 35 655 278 | Zerg_Zergling 0 30 627 294 | Zerg_Zergling 0 30 645 297 | Zerg_Zergling 0 35 616 288 | Zerg_Zergling 0 35 647 298 | Zerg_Zergling 0 30 645 288 | Zerg_Zergling 0 35 643 297 | Zerg_Zergling 0 35 646 296 | Zerg_Zergling 0 20 624 258 | Zerg_Zergling 0 30 625 252 | Zerg_Zergling 0 30 642 288 | Zerg_Zergling 0 30 653 290 0 0 19 50 100475 117 243.03 | Zerg_Zergling 0 5 602 432 | Zerg_Zergling 0 15 637 462 | Zerg_Zergling 0 25 606 424 | Zerg_Zergling 0 35 581 429 | Zerg_Zergling 0 35 594 419 | Zerg_Zergling 0 35 594 429 | Zerg_Zergling 0 35 601 423 | Zerg_Zergling 0 35 603 417 | Zerg_Zergling 0 10 630 449 | Zerg_Zergling 0 30 579 449 | Zerg_Zergling 0 30 596 444 | Zerg_Zergling 0 35 575 450 | Zerg_Zergling 0 35 582 456 | Zerg_Zergling 0 35 587 448 | Zerg_Zergling 0 35 588 451 | Zerg_Zergling 0 35 593 446 | Zerg_Zergling 0 35 595 456 | Zerg_Zergling 0 35 608 445 | Zerg_Zergling 0 35 616 471 | Zerg_Zergling 0 35 611 447 | Zerg_Zergling 0 35 641 475 | Zerg_Zergling 0 15 577 427 | Zerg_Zergling 0 15 601 421 | Zerg_Zergling 0 35 631 452 | Zerg_Zergling 0 10 600 440 | Zerg_Zergling 0 20 581 447 | Zerg_Zergling 0 30 578 446 0 0 20 50 100191 585 796.46 | Protoss_Dragoon 0 60 797 394 | Protoss_Dragoon 0 180 825 362 | Protoss_Dragoon 0 60 774 381 | Protoss_Dragoon 0 140 737 470 | Protoss_Dragoon 0 180 786 366 | Protoss_Dragoon 0 160 824 367 | Protoss_Dragoon 0 60 740 508 | Protoss_Dragoon 0 140 816 356 | Protoss_Dragoon 0 160 768 409 | Protoss_Dragoon 0 160 811 383 | Protoss_Dragoon 0 180 782 397 | Protoss_Dragoon 0 20 822 372 0 0 21 50 100226 585 826.56 | Protoss_Dragoon 0 60 431 374 | Protoss_Dragoon 0 180 402 364 | Protoss_Dragoon 0 160 414 364 | Protoss_Dragoon 0 160 411 364 | Protoss_Dragoon 0 180 441 238 | Protoss_Dragoon 0 180 444 242 | Protoss_Dragoon 0 180 452 239 | Protoss_Dragoon 0 180 394 364 | Protoss_Dragoon 0 140 453 245 | Protoss_Dragoon 0 80 413 353 | Protoss_Dragoon 0 80 438 223 | Protoss_Dragoon 0 140 368 381 | Protoss_Dragoon 0 140 400 369 0 0 22 50 100133 671 866.03 | Protoss_Dragoon 0 20 960 423 | Protoss_Dragoon 0 180 933 378 | Protoss_Dragoon 0 40 928 352 | Protoss_Dragoon 0 180 952 395 | Protoss_Dragoon 0 180 955 396 | Protoss_Dragoon 0 160 943 390 | Protoss_Dragoon 0 180 925 329 | Protoss_Dragoon 0 180 940 384 0 0 23 50 100065 772 1006.42 | Protoss_Dragoon 0 140 339 406 | Protoss_Dragoon 0 160 334 384 | Protoss_Dragoon 0 180 323 377 | Protoss_Dragoon 0 40 336 405 0 0 24 50 100151 628 822.37 | Protoss_Dragoon 0 180 884 409 | Protoss_Dragoon 0 20 881 397 | Protoss_Dragoon 0 180 868 318 | Protoss_Dragoon 0 60 896 406 | Protoss_Dragoon 0 180 896 396 | Protoss_Dragoon 0 140 884 367 | Protoss_Dragoon 0 160 885 407 | Protoss_Dragoon 0 140 882 388 | Protoss_Dragoon 0 180 880 242 0 0 25 50 100191 620 871.43 | Protoss_Dragoon 0 180 425 298 | Protoss_Dragoon 0 100 468 354 | Protoss_Dragoon 0 140 457 402 | Protoss_Dragoon 0 180 440 330 | Protoss_Dragoon 0 160 435 329 | Protoss_Dragoon 0 160 459 415 | Protoss_Dragoon 0 180 420 311 | Protoss_Dragoon 0 180 428 307 | Protoss_Dragoon 0 40 473 368 | Protoss_Dragoon 0 160 424 308 | Protoss_Dragoon 0 100 436 337 0 0 26 50 100121 662 857.16 | Protoss_Dragoon 0 180 861 390 | Protoss_Dragoon 0 60 849 393 | Protoss_Dragoon 0 100 833 401 | Protoss_Dragoon 0 180 853 388 | Protoss_Dragoon 0 120 894 386 | Protoss_Dragoon 0 180 874 381 | Protoss_Dragoon 0 180 885 378 0 0 27 50 100146 619 867.06 | Protoss_Dragoon 0 160 387 316 | Protoss_Dragoon 0 140 409 283 | Protoss_Dragoon 0 180 419 287 | Protoss_Dragoon 0 40 362 318 | Protoss_Dragoon 0 100 413 287 | Protoss_Dragoon 0 180 407 292 | Protoss_Dragoon 0 180 391 311 | Protoss_Dragoon 0 140 395 314 | Protoss_Dragoon 0 40 387 310 0 0 28 50 100227 617 826.62 | Protoss_Dragoon 0 20 863 388 | Protoss_Dragoon 0 140 736 459 | Protoss_Dragoon 0 160 866 460 | Protoss_Dragoon 0 180 883 420 | Protoss_Dragoon 0 180 891 411 | Protoss_Dragoon 0 120 887 371 | Protoss_Dragoon 0 160 881 390 | Protoss_Dragoon 0 100 889 370 | Protoss_Dragoon 0 140 872 348 | Protoss_Dragoon 0 180 742 470 | Protoss_Dragoon 0 180 863 431 | Protoss_Dragoon 0 180 866 377 | Protoss_Dragoon 0 160 884 325 0 0 29 50 100265 544 828.52 | Protoss_Dragoon 0 84 409 476 | Protoss_Dragoon 0 120 376 282 | Protoss_Dragoon 0 180 392 261 | Protoss_Dragoon 0 180 407 285 | Protoss_Dragoon 0 180 416 420 | Protoss_Dragoon 0 180 417 407 | Protoss_Dragoon 0 164 399 281 | Protoss_Dragoon 0 180 372 264 | Protoss_Dragoon 0 180 383 280 | Protoss_Dragoon 0 180 388 283 | Protoss_Dragoon 0 160 432 425 | Protoss_Dragoon 0 180 438 420 | Protoss_Dragoon 0 180 423 420 | Protoss_Dragoon 0 180 425 406 0 0 30 50 100297 446 552.35 | Protoss_Dragoon 0 100 680 400 | Protoss_Dragoon 0 140 738 326 | Protoss_Dragoon 0 140 765 330 | Protoss_Dragoon 0 180 697 379 | Protoss_Dragoon 0 140 692 382 | Protoss_Dragoon 0 60 744 331 | Protoss_Dragoon 0 100 691 377 | Protoss_Dragoon 0 160 685 386 | Protoss_Dragoon 0 120 695 380 | Protoss_Dragoon 0 180 691 385 | Protoss_Dragoon 0 180 685 384 0 0 31 50 100292 462 617.72 | Protoss_Dragoon 0 22 491 352 | Protoss_Dragoon 0 160 522 338 | Protoss_Dragoon 0 60 561 247 | Protoss_Dragoon 0 120 540 344 | Protoss_Dragoon 0 160 523 350 | Protoss_Dragoon 0 160 528 320 | Protoss_Dragoon 0 160 511 362 | Protoss_Dragoon 0 180 517 351 | Protoss_Dragoon 0 20 502 362 | Protoss_Dragoon 0 160 485 375 | Protoss_Dragoon 0 160 496 357 | Protoss_Dragoon 0 60 491 368 0 0 32 50 100110 615 666.12 | Protoss_Dragoon 0 100 717 408 | Protoss_Dragoon 0 140 689 447 | Protoss_Dragoon 0 160 665 442 | Protoss_Dragoon 0 160 687 441 0 0 33 50 100213 525 646.77 | Protoss_Dragoon 0 40 590 307 | Protoss_Dragoon 0 160 537 340 | Protoss_Dragoon 0 180 562 326 | Protoss_Dragoon 0 140 598 302 | Protoss_Dragoon 0 140 553 343 | Protoss_Dragoon 0 160 539 328 | Protoss_Dragoon 0 80 551 337 | Protoss_Dragoon 0 180 575 326 0 0 34 50 100203 518 680.20 | Protoss_Dragoon 0 160 718 348 | Protoss_Dragoon 0 180 734 324 | Protoss_Dragoon 0 140 722 339 | Protoss_Dragoon 0 100 729 332 | Protoss_Dragoon 0 54 730 351 | Protoss_Dragoon 0 80 741 343 | Protoss_Dragoon 0 140 741 343 | Protoss_Dragoon 0 120 719 361 0 0 35 50 100199 528 616.97 | Protoss_Dragoon 0 180 527 329 | Protoss_Dragoon 0 60 537 337 | Protoss_Dragoon 0 140 545 315 | Protoss_Dragoon 0 180 522 340 | Protoss_Dragoon 0 160 515 345 | Protoss_Dragoon 0 180 511 340 | Protoss_Dragoon 0 160 506 364 0 0 36 50 100247 490 636.46 | Protoss_Dragoon 0 180 703 392 | Protoss_Dragoon 0 160 688 408 | Protoss_Dragoon 0 160 717 388 | Protoss_Dragoon 0 60 732 384 | Protoss_Dragoon 0 180 720 404 | Protoss_Dragoon 0 180 719 384 | Protoss_Dragoon 0 160 664 457 | Protoss_Dragoon 0 180 706 405 | Protoss_Dragoon 0 40 698 413 0 0 37 50 100201 527 685.14 | Protoss_Dragoon 0 120 523 337 | Protoss_Dragoon 0 180 505 336 | Protoss_Dragoon 0 20 560 262 | Protoss_Dragoon 0 100 478 368 | Protoss_Dragoon 0 140 488 348 | Protoss_Dragoon 0 120 520 328 | Protoss_Dragoon 0 120 519 325 | Protoss_Dragoon 0 180 521 328 0 0 38 50 100178 536 670.64 | Protoss_Dragoon 0 60 749 425 | Protoss_Dragoon 0 140 722 347 | Protoss_Dragoon 0 180 700 327 | Protoss_Dragoon 0 180 730 324 | Protoss_Dragoon 0 20 731 345 | Protoss_Dragoon 0 180 757 367 | Protoss_Dragoon 0 140 740 342 0 0 39 50 100146 565 648.46 | Protoss_Dragoon 0 180 594 407 | Protoss_Dragoon 0 20 500 330 | Protoss_Dragoon 0 80 578 396 | Protoss_Dragoon 0 120 466 339 | Protoss_Dragoon 0 134 554 375 | Protoss_Dragoon 0 180 566 405 0 0 40 50 100186 270 364.42 | Terran_Marine 0 40 675 353 | Terran_Marine 0 40 682 364 | Terran_Marine 0 28 694 361 | Terran_Marine 0 40 675 320 | Terran_Marine 0 40 680 365 | Terran_Marine 0 40 697 334 | Terran_Marine 0 34 662 398 | Terran_Marine 0 34 690 351 | Terran_Marine 0 40 681 366 | Terran_Marine 0 28 671 418 | Terran_Marine 0 16 654 409 | Terran_Marine 0 40 654 409 0 0 41 50 100187 269 381.94 | Terran_Marine 0 4 522 359 | Terran_Marine 0 34 531 365 | Terran_Marine 0 40 532 372 | Terran_Marine 0 40 533 372 | Terran_Marine 0 40 534 355 | Terran_Marine 0 40 534 359 | Terran_Marine 0 40 533 362 | Terran_Marine 0 40 527 353 | Terran_Marine 0 40 534 350 | Terran_Marine 0 40 535 368 | Terran_Marine 0 34 546 381 | Terran_Marine 0 40 537 370 0 0 42 50 100226 250 394.14 | Terran_Marine 0 4 713 484 | Terran_Marine 0 40 680 469 | Terran_Marine 0 40 698 280 | Terran_Marine 0 40 690 464 | Terran_Marine 0 40 683 374 | Terran_Marine 0 40 702 413 | Terran_Marine 0 40 678 430 | Terran_Marine 0 40 690 338 | Terran_Marine 0 40 694 335 | Terran_Marine 0 40 697 307 | Terran_Marine 0 16 706 311 | Terran_Marine 0 34 690 289 | Terran_Marine 0 34 694 313 | Terran_Marine 0 22 694 427 | Terran_Marine 0 40 695 323 0 0 43 50 100180 276 417.00 | Terran_Marine 0 4 561 365 | Terran_Marine 0 40 549 346 | Terran_Marine 0 40 547 284 | Terran_Marine 0 40 566 361 | Terran_Marine 0 10 558 292 | Terran_Marine 0 40 540 307 | Terran_Marine 0 40 554 350 | Terran_Marine 0 40 563 382 | Terran_Marine 0 34 578 385 | Terran_Marine 0 40 546 341 | Terran_Marine 0 40 526 339 | Terran_Marine 0 40 527 341 0 0 44 50 100213 256 394.30 | Terran_Marine 0 40 717 346 | Terran_Marine 0 40 721 349 | Terran_Marine 0 40 723 350 | Terran_Marine 0 34 728 367 | Terran_Marine 0 40 726 364 | Terran_Marine 0 40 734 371 | Terran_Marine 0 28 738 355 | Terran_Marine 0 40 727 346 | Terran_Marine 0 40 729 358 | Terran_Marine 0 34 729 354 | Terran_Marine 0 4 727 350 | Terran_Marine 0 40 721 366 | Terran_Marine 0 34 723 358 | Terran_Marine 0 28 722 348 0 0 45 50 100169 275 419.11 | Terran_Marine 0 40 513 318 | Terran_Marine 0 10 575 395 | Terran_Marine 0 34 517 330 | Terran_Marine 0 40 535 350 | Terran_Marine 0 22 542 349 | Terran_Marine 0 40 551 358 | Terran_Marine 0 40 541 355 | Terran_Marine 0 40 547 354 | Terran_Marine 0 34 551 362 | Terran_Marine 0 40 524 337 | Terran_Marine 0 40 529 342 0 0 46 50 100223 256 413.34 | Terran_Marine 0 40 693 381 | Terran_Marine 0 40 697 387 | Terran_Marine 0 40 698 388 | Terran_Marine 0 22 690 379 | Terran_Marine 0 22 694 389 | Terran_Marine 0 40 677 364 | Terran_Marine 0 40 685 384 | Terran_Marine 0 40 693 374 | Terran_Marine 0 34 696 381 | Terran_Marine 0 34 682 382 | Terran_Marine 0 40 660 365 | Terran_Marine 0 40 695 380 | Terran_Marine 0 40 682 373 | Terran_Marine 0 40 696 382 0 0 47 50 100237 250 414.02 | Terran_Marine 0 10 576 347 | Terran_Marine 0 34 587 356 | Terran_Marine 0 40 577 364 | Terran_Marine 0 40 580 367 | Terran_Marine 0 40 583 371 | Terran_Marine 0 40 574 338 | Terran_Marine 0 40 576 346 | Terran_Marine 0 40 541 328 | Terran_Marine 0 40 567 340 | Terran_Marine 0 40 579 351 | Terran_Marine 0 40 582 347 | Terran_Marine 0 40 575 349 | Terran_Marine 0 22 570 348 | Terran_Marine 0 40 586 359 | Terran_Marine 0 40 583 358 0 0 48 50 100204 262 404.37 | Terran_Marine 0 40 647 338 | Terran_Marine 0 40 681 380 | Terran_Marine 0 40 695 386 | Terran_Marine 0 40 681 374 | Terran_Marine 0 40 701 390 | Terran_Marine 0 16 701 383 | Terran_Marine 0 40 655 357 | Terran_Marine 0 40 687 385 | Terran_Marine 0 16 659 353 | Terran_Marine 0 40 692 373 | Terran_Marine 0 40 695 376 | Terran_Marine 0 40 680 369 | Terran_Marine 0 34 663 355 0 0 49 50 100176 266 418.56 | Terran_Marine 0 34 516 335 | Terran_Marine 0 34 553 363 | Terran_Marine 0 40 499 322 | Terran_Marine 0 40 509 324 | Terran_Marine 0 40 549 365 | Terran_Marine 0 22 507 324 | Terran_Marine 0 34 556 378 | Terran_Marine 0 40 502 322 | Terran_Marine 0 40 511 345 | Terran_Marine 0 40 517 351 | Terran_Marine 0 40 544 367 ================================================ FILE: SparCraft/sample_experiment/sample_results/sample_exp_2013-03-22_17-49-13_results_summary.txt ================================================ 1.0000000 ================================================ FILE: SparCraft/sample_experiment/sample_state.txt ================================================ Protoss_Dragoon 0 300 300 Protoss_Dragoon 0 300 320 Protoss_Dragoon 0 300 340 Protoss_Dragoon 0 300 360 Protoss_Dragoon 1 600 300 Protoss_Dragoon 1 600 320 Protoss_Dragoon 1 600 340 Protoss_Dragoon 1 600 360 ================================================ FILE: SparCraft/source/Action.cpp ================================================ #include "Action.h" using namespace SparCraft; Action::Action() : _unit(255) , _player(255) , _moveType(ActionTypes::NONE) , _moveIndex(255) { } Action::Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex, const Position & dest) : _unit(unitIndex) , _player(player) , _moveType(type) , _moveIndex(moveIndex) , _p(dest) { } Action::Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex) : _unit(unitIndex) , _player(player) , _moveType(type) , _moveIndex(moveIndex) { } const bool Action::operator == (const Action & rhs) { return _unit == rhs._unit && _player == rhs._player && _moveType == rhs._moveType && _moveIndex == rhs._moveIndex && _p == rhs._p; } const size_t & Action::unit() const { return _unit; } const size_t & Action::player() const { return _player; } const size_t & Action::type() const { return _moveType; } const size_t & Action::index() const { return _moveIndex; } const Position & Action::pos() const { return _p; } const std::string Action::moveString() const { if (_moveType == ActionTypes::ATTACK) { return "ATTACK"; } else if (_moveType == ActionTypes::MOVE) { return "MOVE"; } else if (_moveType == ActionTypes::RELOAD) { return "RELOAD"; } else if (_moveType == ActionTypes::PASS) { return "PASS"; } else if (_moveType == ActionTypes::HEAL) { return "HEAL"; } return "NONE"; } const Position Action::getDir() const { return Position(Constants::Move_Dir[_moveIndex][0], Constants::Move_Dir[_moveIndex][1]); } const std::string Action::debugString() const { std::stringstream ss; ss << moveString() << ": (" << (int)unit() << "," << (int)player() << "," << (int)type() << "," << (int)index() << ") " << "(" << pos().x() << "," << pos().y() << ")"; return ss.str(); } ================================================ FILE: SparCraft/source/Action.h ================================================ #pragma once #include "Common.h" #include "Position.hpp" namespace SparCraft { namespace ActionTypes { enum {NONE, ATTACK, RELOAD, MOVE, PASS, HEAL}; }; class Action { size_t _unit; size_t _player; size_t _moveType; size_t _moveIndex; Position _p; public: Action(); Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex, const Position & dest); Action( const size_t & unitIndex, const size_t & player, const size_t & type, const size_t & moveIndex); const bool operator == (const Action & rhs); const size_t & unit() const; const size_t & player() const; const size_t & type() const; const size_t & index() const; const Position & pos() const; const std::string moveString() const; const Position getDir() const; const std::string debugString() const; }; } ================================================ FILE: SparCraft/source/AllPlayers.cpp ================================================ #include "AllPlayers.h" using namespace SparCraft; Player * AllPlayers::getPlayer(const size_t & playerID, const size_t & type) { if (type == PlayerModels::AttackClosest) { return new Player_AttackClosest(playerID); } else if (type == PlayerModels::AttackDPS) { return new Player_AttackDPS(playerID); } else if (type == PlayerModels::AttackWeakest) { return new Player_AttackWeakest(playerID); } else if (type == PlayerModels::Kiter) { return new Player_Kiter(playerID); } else if (type == PlayerModels::KiterDPS) { return new Player_KiterDPS(playerID); } else if (type == PlayerModels::Kiter_NOKDPS) { return new Player_Kiter_NOKDPS(playerID); } else if (type == PlayerModels::Cluster) { return new Player_Cluster(playerID); } else if (type == PlayerModels::NOKDPS) { return new Player_NOKDPS(playerID); } else if (type == PlayerModels::Random) { return new Player_Random(playerID); } else { return NULL; } } PlayerPtr AllPlayers::getPlayerPtr(const size_t & playerID, const size_t & type) { if (type == PlayerModels::AttackClosest) { return PlayerPtr(new Player_AttackClosest(playerID)); } else if (type == PlayerModels::AttackDPS) { return PlayerPtr(new Player_AttackDPS(playerID)); } else if (type == PlayerModels::AttackWeakest) { return PlayerPtr(new Player_AttackWeakest(playerID)); } else if (type == PlayerModels::Kiter) { return PlayerPtr(new Player_Kiter(playerID)); } else if (type == PlayerModels::KiterDPS) { return PlayerPtr(new Player_KiterDPS(playerID)); } else if (type == PlayerModels::Kiter_NOKDPS) { return PlayerPtr(new Player_Kiter_NOKDPS(playerID)); } else if (type == PlayerModels::Cluster) { return PlayerPtr(new Player_Cluster(playerID)); } else if (type == PlayerModels::NOKDPS) { return PlayerPtr(new Player_NOKDPS(playerID)); } else if (type == PlayerModels::Random) { return PlayerPtr(new Player_Random(playerID)); } else { return PlayerPtr(new Player_NOKDPS(playerID)); } } ================================================ FILE: SparCraft/source/AllPlayers.h ================================================ #pragma once #include "Common.h" #include "Player.h" #include // search-based players #include "Player_AlphaBeta.h" #include "Player_PortfolioGreedySearch.h" #include "Player_UCT.h" // script-based players #include "Player_AttackClosest.h" #include "Player_AttackDPS.h" #include "Player_AttackWeakest.h" #include "Player_Kiter.h" #include "Player_KiterDPS.h" #include "Player_NOKDPS.h" #include "Player_Kiter_NOKDPS.h" #include "Player_Cluster.h" #include "Player_Random.h" namespace SparCraft { typedef std::shared_ptr PlayerPtr; namespace AllPlayers { Player * getPlayer(const size_t & playerID, const size_t & type); PlayerPtr getPlayerPtr(const size_t & playerID, const size_t & type); } } ================================================ FILE: SparCraft/source/AlphaBetaMove.cpp ================================================ #include "AlphaBetaMove.h" using namespace SparCraft; AlphaBetaMove::AlphaBetaMove() : _isValid(false) { } AlphaBetaMove::AlphaBetaMove(const std::vector & move,const bool & isValid) : _move(move) ,_isValid(isValid) { } const bool AlphaBetaMove::isValid() const { return _isValid; } const std::vector & AlphaBetaMove::moveVec() const { return _move; } TTBestMove::TTBestMove() { } TTBestMove::TTBestMove(const AlphaBetaMove & first,const AlphaBetaMove & second) : _firstMove(first) ,_secondMove(second) { } const AlphaBetaMove & TTBestMove::firstMove() const { return _firstMove; } const AlphaBetaMove & TTBestMove::secondMove() const { return _secondMove; } AlphaBetaValue::AlphaBetaValue() { } AlphaBetaValue::AlphaBetaValue(const StateEvalScore & score,const AlphaBetaMove & abMove) : _score(score) ,_move(abMove) { } const StateEvalScore & AlphaBetaValue::score() const { return _score; } const AlphaBetaMove & AlphaBetaValue::abMove() const { return _move; } ================================================ FILE: SparCraft/source/AlphaBetaMove.h ================================================ #pragma once #include "Common.h" #include "Position.hpp" #include "Action.h" namespace SparCraft { class AlphaBetaMove { std::vector _move; bool _isValid; public: AlphaBetaMove(); AlphaBetaMove(const std::vector & move, const bool & isValid); const bool isValid() const; const std::vector & moveVec() const; }; class TTBestMove { AlphaBetaMove _firstMove; AlphaBetaMove _secondMove; public: TTBestMove(); TTBestMove(const AlphaBetaMove & first, const AlphaBetaMove & second); const AlphaBetaMove & firstMove() const; const AlphaBetaMove & secondMove() const; }; class AlphaBetaValue { StateEvalScore _score; AlphaBetaMove _move; public: AlphaBetaValue(); AlphaBetaValue(const StateEvalScore & score, const AlphaBetaMove & abMove); const StateEvalScore & score() const; const AlphaBetaMove & abMove() const; }; } ================================================ FILE: SparCraft/source/AlphaBetaSearch.cpp ================================================ #include "AlphaBetaSearch.h" using namespace SparCraft; AlphaBetaSearch::AlphaBetaSearch(const AlphaBetaSearchParameters & params, TTPtr TT) : _params(params) , _currentRootDepth(0) , _TT(TT ? TT : TTPtr(new TranspositionTable())) { for (size_t p(0); pgetMoves(initialState, moves, _results.bestMoves); } break; } long long unsigned nodes = _results.nodesExpanded; double ms = _searchTimer.getElapsedTimeInMilliSec(); //printTTResults(); //fprintf(stdout, "%s %8d %9d %9d %13.4lf %14llu %12d %12llu %15.2lf\n", "IDA", d, val.score().val(), (int)val.abMove().moveTuple(), ms, nodes, (int)_TT->numFound(), getResults().ttcuts, 1000*nodes/ms); } return val; } // Transposition Table save void AlphaBetaSearch::TTsave( GameState & state, const StateEvalScore & value, const StateEvalScore & alpha, const StateEvalScore & beta, const size_t & depth, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) { // IF THE DEPTH OF THE ENTRY IS BIGGER THAN CURRENT DEPTH, DO NOTHING TTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1)); bool valid = entry && entry->isValid(); size_t edepth = entry ? entry->getDepth() : 0; _results.ttSaveAttempts++; if (valid && (edepth > depth)) { return; } int type(TTEntry::NONE); if (value <= alpha) type = TTEntry::UPPER; else if (value >= beta) type = TTEntry::LOWER; else type = TTEntry::ACCURATE; // SAVE A NEW ENTRY IN THE TRANSPOSITION TABLE _TT->save(state.calculateHash(0), state.calculateHash(1), value, depth, type, firstPlayer, bestFirstMove, bestSecondMove); } // Transposition Table look up + alpha/beta update TTLookupValue AlphaBetaSearch::TTlookup(const GameState & state, StateEvalScore & alpha, StateEvalScore & beta, const size_t & depth) { TTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1)); if (entry && (entry->getDepth() == depth)) { // get the value and type of the entry StateEvalScore TTvalue = entry->getScore(); // set alpha and beta depending on the type of entry in the TT if (entry->getType() == TTEntry::LOWER) { if (TTvalue > alpha) { alpha = TTvalue; } } else if (entry->getType() == TTEntry::UPPER) { if (TTvalue < beta) { beta = TTvalue; } } else { printf("LOL\n"); alpha = TTvalue; beta = TTvalue; } if (alpha >= beta) { // this will be a cut _results.ttcuts++; return TTLookupValue(true, true, entry); } else { // found but no cut _results.ttFoundNoCut++; return TTLookupValue(true, false, entry); } } else if (entry) { _results.ttFoundLessDepth++; return TTLookupValue(true, false, entry); } return TTLookupValue(false, false, entry); } const bool AlphaBetaSearch::searchTimeOut() { return (_params.timeLimit() && (_results.nodesExpanded % 50 == 0) && (_searchTimer.getElapsedTimeInMilliSec() >= _params.timeLimit())); } const bool AlphaBetaSearch::terminalState(GameState & state, const size_t & depth) const { return (depth <= 0 || state.isTerminal()); } const AlphaBetaMove & AlphaBetaSearch::getAlphaBetaMove(const TTLookupValue & TTval, const size_t & playerToMove) const { const size_t enemyPlayer(getEnemy(playerToMove)); // if we have a valid first move for this player, use it if (TTval.entry()->getBestMove(playerToMove).firstMove().isValid()) { return TTval.entry()->getBestMove(playerToMove).firstMove(); } // otherwise return the response to an opponent move, if it doesn't exist it will just be invalid else { return TTval.entry()->getBestMove(enemyPlayer).secondMove(); } } void AlphaBetaSearch::generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth) { // get the array where we will store the moves and clear it Array, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); orderedMoves.clear(); // if we are using opponent modeling, get the move and then return, we don't want to put any more moves in if (_params.playerModel(playerToMove) != PlayerModels::None) { // put the vector into the ordered moves array orderedMoves.add(std::vector()); // generate the moves into that vector _playerModels[playerToMove]->getMoves(state, moves, orderedMoves[0]); return; } // if there is a transposition table entry for this state /*if (TTval.found()) { // get the abMove we stored for this player const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); _results.ttFoundCheck++; // Two checks: // 1) Is the move 'valid' ie: was it actually set inside the TT // TODO:: Possibly validate this move a second time somehow // Was previously done with move tuple numbers if (abMove.isValid()) { orderedMoves.add(abMove.moveVec()); _results.ttMoveOrders++; return; } else { _results.ttFoundButNoMove++; } }*/ if (depth == 2) { int a = 6; } // if we are using script move ordering, insert the script moves we want if (_params.moveOrderingMethod() == MoveOrderMethod::ScriptFirst) { for (size_t s(0); s<_params.getOrderedMoveScripts().size(); s++) { std::vector moveVec; _allScripts[playerToMove][s]->getMoves(state, moves, moveVec); orderedMoves.add(moveVec); } if (orderedMoves.size() < 2) { int a = 6; } } } bool AlphaBetaSearch::getNextMoveVec(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector & moveVec) const { if (_params.maxChildren() && (moveNumber >= _params.maxChildren())) { return false; } // if this move is beyond the first, check to see if we are only using a single move if (moveNumber == 1) { // if we are player modeling, we should have only generated the first move if (_params.playerModel(playerToMove) != PlayerModels::None) { // so return false return false; } // if there is a transposition table entry for this state if (TTval.found()) { // if there was a valid move found with higher depth, just do that one const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); if ((TTval.entry()->getDepth() >= depth) && abMove.isValid()) { // so return false return false; } } } const Array, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); moveVec.clear(); // if this move should be from the ordered list, return it from the list if (moveNumber < orderedMoves.size()) { moveVec.assign(orderedMoves[moveNumber].begin(), orderedMoves[moveNumber].end()); return true; } // otherwise return the next move vector starting from the beginning else { if (moves.hasMoreMoves()) { moves.getNextMoveVec(moveVec); return true; } else { return false; } } } const size_t AlphaBetaSearch::getPlayerToMove(GameState & state, const size_t & depth, const size_t & lastPlayerToMove, const bool isFirstSimMove) const { const size_t whoCanMove(state.whoCanMove()); // if both players can move if (whoCanMove == Players::Player_Both) { // no matter what happens, the 2nd player to move is always the enemy of the first if (!isFirstSimMove) { return getEnemy(lastPlayerToMove); } // pick the first move based on our policy const size_t policy(_params.playerToMoveMethod()); const size_t maxPlayer(_params.maxPlayer()); if (policy == SparCraft::PlayerToMove::Alternate) { return isRoot(depth) ? maxPlayer : getEnemy(lastPlayerToMove); } else if (policy == SparCraft::PlayerToMove::Not_Alternate) { return isRoot(depth) ? maxPlayer : lastPlayerToMove; } else if (policy == SparCraft::PlayerToMove::Random) { // srand(state.calculateHash(0)); return isRoot(depth) ? maxPlayer : rand() % 2; } // we should never get to this state System::FatalError("AlphaBeta Error: Nobody can move for some reason"); return Players::Player_None; } else { return whoCanMove; } } const bool AlphaBetaSearch::isTranspositionLookupState(GameState & state, const std::vector * firstSimMove) const { return !state.bothCanMove() || (state.bothCanMove() && !firstSimMove); } AlphaBetaValue AlphaBetaSearch::alphaBeta(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector * prevSimMove, StateEvalScore alpha, StateEvalScore beta) { // update statistics _results.nodesExpanded++; if (searchTimeOut()) { throw 1; } if (terminalState(state, depth)) { // return the value, but the move will not be valid since none was performed StateEvalScore evalScore = state.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two)); return AlphaBetaValue(StateEvalScore(evalScore.val(), state.getNumMovements(_params.maxPlayer()) + evalScore.numMoves() ), AlphaBetaMove()); } // figure out which player is to move const size_t playerToMove(getPlayerToMove(state, depth, lastPlayerToMove, !prevSimMove)); // is the player to move the max player? bool maxPlayer = (playerToMove == _params.maxPlayer()); // Transposition Table Logic TTLookupValue TTval; if (isTranspositionLookupState(state, prevSimMove)) { TTval = TTlookup(state, alpha, beta, depth); // if this is a TT cut, return the proper value if (TTval.cut()) { return AlphaBetaValue(TTval.entry()->getScore(), getAlphaBetaMove(TTval, playerToMove)); } } bool bestMoveSet(false); // move generation MoveArray & moves = _allMoves[depth]; state.generateMoves(moves, playerToMove); moves.shuffleMoveActions(); generateOrderedMoves(state, moves, TTval, playerToMove, depth); // while we have more simultaneous moves AlphaBetaMove bestMove, bestSimResponse; size_t moveNumber(0); std::vector moveVec; // for each child while (getNextMoveVec(playerToMove, moves, moveNumber, TTval, depth, moveVec)) { // the value of the recursive AB we will call AlphaBetaValue val; // generate the child state GameState child(state); bool firstMove = true; // if this is the first player in a simultaneous move state if (state.bothCanMove() && !prevSimMove && (depth != 1)) { firstMove = true; // don't generate a child yet, just pass on the move we are investigating val = alphaBeta(state, depth-1, playerToMove, &moveVec, alpha, beta); } else { firstMove = false; // if this is the 2nd move of a simultaneous move state if (prevSimMove) { // do the previous move selected by the first player to move during this state child.makeMoves(*prevSimMove); } // do the moves of the current player child.makeMoves(moveVec); child.finishedMoving(); // get the alpha beta value val = alphaBeta(child, depth-1, playerToMove, NULL, alpha, beta); } // set alpha or beta based on maxplayer if (maxPlayer && (val.score() > alpha)) { alpha = val.score(); bestMove = AlphaBetaMove(moveVec, true); bestMoveSet = true; if (state.bothCanMove() && !prevSimMove) { bestSimResponse = val.abMove(); } // if this is depth 1 of the first try at depth 1, store the best in results } else if (!maxPlayer && (val.score() < beta)) { beta = val.score(); bestMove = AlphaBetaMove(moveVec, true); bestMoveSet = true; if (state.bothCanMove() && prevSimMove) { bestSimResponse = val.abMove(); } } if (alpha.val() == -10000000 && beta.val() == 10000000) { fprintf(stderr, "\n\nALPHA BETA ERROR, NO VALUE SET\n\n"); } // alpha-beta cut if (alpha >= beta) { break; } moveNumber++; } if (isTranspositionLookupState(state, prevSimMove)) { TTsave(state, maxPlayer ? alpha : beta, alpha, beta, depth, playerToMove, bestMove, bestSimResponse); } return maxPlayer ? AlphaBetaValue(alpha, bestMove) : AlphaBetaValue(beta, bestMove); } AlphaBetaSearchResults & AlphaBetaSearch::getResults() { return _results; } const size_t AlphaBetaSearch::getEnemy(const size_t & player) const { return (player + 1) % 2; } const bool AlphaBetaSearch::isRoot(const size_t & depth) const { return depth == _currentRootDepth; } void AlphaBetaSearch::printTTResults() const { printf("\n"); printf("Total Usage %9d\n", (int)_TT->getUsage()); printf("Save Attempt %9d\n", (int)_results.ttSaveAttempts); printf(" Save Succeed %9d\n", (int)_TT->numSaves()); printf(" Save Empty %9d\n", (int)_TT->saveEmpty); printf(" Save Self %9d\n", (int)_TT->saveOverwriteSelf); printf(" Save Other %9d\n", (int)_TT->saveOverwriteOther); printf("Look-Up %9d\n", (int)_TT->numLookups()); printf(" Not Found %9d\n", (int)_TT->numNotFound()); printf(" Collisions %9d\n", (int)_TT->numCollisions()); printf(" Found %9d\n", (int)_TT->numFound()); printf(" Less Depth %9d\n", (int)_results.ttFoundLessDepth); printf(" More Depth %9d\n", ((int)_results.ttFoundCheck + (int)_results.ttcuts)); printf(" Cut %9d\n", (int)_results.ttcuts); printf(" Move %9d\n", (int)_results.ttMoveOrders); printf(" No Move %9d\n", (int)_results.ttFoundButNoMove); printf("\n"); } ================================================ FILE: SparCraft/source/AlphaBetaSearch.h ================================================ #pragma once #include #include "AllPlayers.h" #include "Timer.h" #include "GameState.h" #include "Action.h" #include "Array.hpp" #include "MoveArray.h" #include "TranspositionTable.h" #include "Player.h" #include "AlphaBetaSearchResults.hpp" #include "AlphaBetaSearchParameters.hpp" #include "GraphViz.hpp" namespace SparCraft { class Game; class AlphaBetaSearchParameters; class Player; class AlphaBetaSearch { AlphaBetaSearchParameters _params; AlphaBetaSearchResults _results; SparCraft::Timer _searchTimer; size_t _currentRootDepth; Array _allMoves; Array2D, Constants::Max_Search_Depth, Constants::Max_Ordered_Moves> _orderedMoves; std::vector _allScripts[Constants::Num_Players]; PlayerPtr _playerModels[Constants::Num_Players]; TTPtr _TT; public: AlphaBetaSearch(const AlphaBetaSearchParameters & params, TTPtr TT = TTPtr((TranspositionTable *)NULL)); void doSearch(GameState & initialState); // search functions AlphaBetaValue IDAlphaBeta(GameState & initialState, const size_t & maxDepth); AlphaBetaValue alphaBeta(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector * firstSimMove, StateEvalScore alpha, StateEvalScore beta); // Transposition Table TTLookupValue TTlookup(const GameState & state, StateEvalScore & alpha, StateEvalScore & beta, const size_t & depth); void TTsave(GameState & state, const StateEvalScore & value, const StateEvalScore & alpha, const StateEvalScore & beta, const size_t & depth, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove); // Transposition Table look up + alpha/beta update // get the results from the search AlphaBetaSearchResults & getResults(); void generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth); const size_t getEnemy(const size_t & player) const; const size_t getPlayerToMove(GameState & state, const size_t & depth, const size_t & lastPlayerToMove, const bool isFirstSimMove) const; bool getNextMoveVec(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector & moveVec) const; const size_t getNumMoves(MoveArray & moves, const TTLookupValue & TTval, const size_t & playerToMove, const size_t & depth) const; const AlphaBetaMove & getAlphaBetaMove(const TTLookupValue & TTval, const size_t & playerToMove) const; const bool searchTimeOut(); const bool isRoot(const size_t & depth) const; const bool terminalState(GameState & state, const size_t & depth) const; const bool isTranspositionLookupState(GameState & state, const std::vector * firstSimMove) const; void printTTResults() const; }; } ================================================ FILE: SparCraft/source/AlphaBetaSearchParameters.hpp ================================================ #pragma once #include "Common.h" namespace SparCraft { class AlphaBetaSearchParameters; } class SparCraft::AlphaBetaSearchParameters { // DEFAULT DESCRIPTION size_t _searchMethod; // ID-AB The Method to use for AB Search size_t _maxPlayer; // Player_One The player who will make maximizing moves size_t _maxDepth; // Max_Depth Maximum depth of AB search to allow size_t _timeLimit; // 0 Search time limit. 0 means no time limit size_t _maxChildren; // 10 Max children at each node size_t _moveOrdering; // ScriptFirst Move ordering method for child generation size_t _evalMethod; // LTD Evaluation function type size_t _simScripts[2]; // NOKDPS Policy to use for playouts size_t _playerToMoveMethod; // Alternate The player to move policy size_t _playerModel[2]; // None Player model to use for each player std::string _graphVizFilename; // "" File name to output graph viz file std::vector _orderedMoveScripts; std::vector > _desc; // 2-column description vector public: // default constructor AlphaBetaSearchParameters() : _searchMethod (SearchMethods::IDAlphaBeta) , _maxPlayer (Players::Player_One) , _maxDepth (Constants::Max_Search_Depth) , _timeLimit (0) , _maxChildren (10) , _moveOrdering (MoveOrderMethod::ScriptFirst) , _evalMethod (SparCraft::EvaluationMethods::Playout) , _playerToMoveMethod (SparCraft::PlayerToMove::Alternate) { setPlayerModel(Players::Player_One, PlayerModels::None); setPlayerModel(Players::Player_Two, PlayerModels::None); setSimScripts(PlayerModels::NOKDPS, PlayerModels::NOKDPS); } const size_t & searchMethod() const { return _searchMethod; } const size_t & maxPlayer() const { return _maxPlayer; } const size_t & maxDepth() const { return _maxDepth; } const size_t & timeLimit() const { return _timeLimit; } const size_t & maxChildren() const { return _maxChildren; } const size_t & moveOrderingMethod() const { return _moveOrdering; } const size_t & evalMethod() const { return _evalMethod; } const size_t & simScript(const size_t & player) const { return _simScripts[player]; } const size_t & playerToMoveMethod() const { return _playerToMoveMethod; } const size_t & playerModel(const size_t & player) const { return _playerModel[player]; } const std::string & graphVizFilename() const { return _graphVizFilename; } const std::vector & getOrderedMoveScripts() const { return _orderedMoveScripts; } void setSearchMethod(const size_t & method) { _searchMethod = method; } void setMaxPlayer(const size_t & player) { _maxPlayer = player; } void setMaxDepth(const size_t & depth) { _maxDepth = depth; } void setTimeLimit(const size_t & timeLimit) { _timeLimit = timeLimit; } void setMaxChildren(const size_t & children) { _maxChildren = children; } void setMoveOrderingMethod(const size_t & method) { _moveOrdering = method; } void setEvalMethod(const size_t & eval) { _evalMethod = eval; } void setSimScripts(const size_t & p1, const size_t & p2) { _simScripts[0] = p1; _simScripts[1] = p2; } void setPlayerToMoveMethod(const size_t & method) { _playerToMoveMethod = method; } void setGraphVizFilename(const std::string & filename) { _graphVizFilename = filename; } void addOrderedMoveScript(const size_t & script) { _orderedMoveScripts.push_back(script); } void setPlayerModel(const size_t & player, const size_t & model) { _playerModel[player] = model; } std::vector > & getDescription() { if (_desc.size() == 0) { _desc.push_back(std::vector()); _desc.push_back(std::vector()); std::stringstream ss; _desc[0].push_back("Player Type:"); _desc[0].push_back("Time Limit:"); _desc[0].push_back("Max Children:"); _desc[0].push_back("Move Ordering:"); _desc[0].push_back("Player To Move:"); _desc[0].push_back("Opponent Model:"); ss << "AlphaBeta"; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << timeLimit() << "ms"; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << maxChildren(); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << MoveOrderMethod::getName(moveOrderingMethod()); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << PlayerToMove::getName(playerToMoveMethod()); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << PlayerModels::getName(playerModel((maxPlayer()+1)%2)); _desc[1].push_back(ss.str()); ss.str(std::string()); } return _desc; } }; ================================================ FILE: SparCraft/source/AlphaBetaSearchResults.hpp ================================================ #pragma once #include #include "Action.h" namespace SparCraft { class AlphaBetaSearchResults { public: bool solved, // whether ot not a solution was found timedOut; // did the search time-out? unsigned long long nodesExpanded; // number of nodes expanded in the search double timeElapsed, // time elapsed in milliseconds avgBranch; // avg branching factor std::vector bestMoves; ScoreType abValue; unsigned long long ttcuts; size_t maxDepthReached; size_t ttMoveOrders; size_t ttFoundButNoMove; size_t ttFoundNoCut; size_t ttFoundCheck; size_t ttFoundLessDepth; size_t ttSaveAttempts; std::vector > _desc; // 2-column description vector AlphaBetaSearchResults() : solved(false) , timedOut(false) , nodesExpanded(0) , timeElapsed(0) , avgBranch(0) , abValue(0) , ttcuts(0) , maxDepthReached(0) , ttMoveOrders(0) , ttFoundButNoMove(0) , ttFoundNoCut(0) , ttFoundCheck(0) , ttFoundLessDepth(0) , ttSaveAttempts(0) { } std::vector > & getDescription() { _desc.clear(); _desc.push_back(std::vector()); _desc.push_back(std::vector()); std::stringstream ss; _desc[0].push_back("Nodes Searched: "); _desc[0].push_back("AB Value: "); _desc[0].push_back("Max Depth: "); ss << nodesExpanded; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << abValue; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << maxDepthReached; _desc[1].push_back(ss.str()); ss.str(std::string()); return _desc; } }; } ================================================ FILE: SparCraft/source/AnimationFrameData.cpp ================================================ #include "AnimationFrameData.h" using namespace SparCraft; std::vector AnimationFrameData::attackFrameData; void AnimationFrameData::init() { // allocate the vector according to UnitType size attackFrameData = std::vector(BWAPI::UnitTypes::allUnitTypes().size(), AttackFrameData(0,0)); // Protoss Units attackFrameData[BWAPI::UnitTypes::Protoss_Probe.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Protoss_Zealot.getID()] = AttackFrameData(8, 7); attackFrameData[BWAPI::UnitTypes::Protoss_Dragoon.getID()] = AttackFrameData(7, 3); attackFrameData[BWAPI::UnitTypes::Protoss_Dark_Templar.getID()] = AttackFrameData(9, 9); attackFrameData[BWAPI::UnitTypes::Protoss_Scout.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Protoss_Corsair.getID()] = AttackFrameData(8, 8); attackFrameData[BWAPI::UnitTypes::Protoss_Arbiter.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Protoss_Archon.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Protoss_Photon_Cannon.getID()] = AttackFrameData(1, 1); // Terran Units attackFrameData[BWAPI::UnitTypes::Terran_SCV.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Terran_Marine.getID()] = AttackFrameData(8, 6); attackFrameData[BWAPI::UnitTypes::Terran_Firebat.getID()] = AttackFrameData(8, 8); attackFrameData[BWAPI::UnitTypes::Terran_Ghost.getID()] = AttackFrameData(3, 2); attackFrameData[BWAPI::UnitTypes::Terran_Vulture.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Terran_Goliath.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Terran_Wraith.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Terran_Battlecruiser.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Terran_Valkyrie.getID()] = AttackFrameData(40, 40); attackFrameData[BWAPI::UnitTypes::Terran_Missile_Turret.getID()] = AttackFrameData(1, 1); // Zerg Units attackFrameData[BWAPI::UnitTypes::Zerg_Drone.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Zerg_Zergling.getID()] = AttackFrameData(5, 5); attackFrameData[BWAPI::UnitTypes::Zerg_Hydralisk.getID()] = AttackFrameData(3, 2); attackFrameData[BWAPI::UnitTypes::Zerg_Lurker.getID()] = AttackFrameData(2, 2); attackFrameData[BWAPI::UnitTypes::Zerg_Ultralisk.getID()] = AttackFrameData(14, 14); attackFrameData[BWAPI::UnitTypes::Zerg_Mutalisk.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Zerg_Devourer.getID()] = AttackFrameData(9, 9); attackFrameData[BWAPI::UnitTypes::Zerg_Sunken_Colony.getID()] = AttackFrameData(1, 1); attackFrameData[BWAPI::UnitTypes::Zerg_Spore_Colony.getID()] = AttackFrameData(1, 1); } const AttackFrameData & AnimationFrameData::getAttackFrames(const BWAPI::UnitType & type) { return attackFrameData[type.getID()]; } ================================================ FILE: SparCraft/source/AnimationFrameData.h ================================================ #pragma once #include "Common.h" namespace SparCraft { typedef std::pair AttackFrameData; class AnimationFrameData { static std::vector attackFrameData; public: static void init(); static const AttackFrameData & getAttackFrames(const BWAPI::UnitType & type); }; } ================================================ FILE: SparCraft/source/Array.hpp ================================================ #pragma once namespace SparCraft { template class Array { size_t _size; size_t _capacity; T _arr[elem]; public: Array () : _size(0) , _capacity(elem) { } Array (const T & fill) : _size(0) , _capacity(elem) { std::fill(_arr, _arr + elem, fill); } T & get(const size_t & index) { return _arr[index]; } const T & get(const size_t & index) const { return _arr[index]; } T & operator [] (const size_t & index) { return get(index); } const T & operator [] (const size_t & index) const { return get(index); } const bool contains(const T & e) const { for (size_t i(0); i 0); return get(_size); } void clear() { _size = 0; } const size_t & size() const { return _size; } void fill(const T & e) { std::fill(_arr, _arr + elem, e); } }; template class Array2D { size_t _rows; size_t _cols; Array< Array, rows> _arr; public: Array2D() : _rows(rows) , _cols(cols) { } Array2D & operator = (const Array2D & rhs) { if (this == &rhs) { return *this; } for (size_t r(0); r<_rows; ++r) { _arr[r] = rhs._arr[r]; } return *this; } Array2D (const Array2D & rhs) : _rows(rhs._rows) , _cols(rhs._cols) , _arr(rhs._arr) { } const size_t getRows() const { return _arr.capacity(); } Array & operator [] (const size_t & index) { assert(index < _rows); return _arr[index]; } const Array & operator [] (const size_t & index) const { assert(index < _rows); return _arr[index]; } void fill(const T & e) { for (size_t i(0); i<_rows; ++i) { _arr[i].fill(e); } } }; } ================================================ FILE: SparCraft/source/BaseTypes.hpp ================================================ #pragma once #include "Common.h" namespace SparCraft { // type definitions for storing data typedef int PositionType; typedef int TimeType; typedef short HealthType; typedef int ScoreType; typedef unsigned int HashType; typedef int UCTValue; class StateEvalScore { ScoreType _val; int _numMoves; public: StateEvalScore() : _val(0) ,_numMoves(0) { } StateEvalScore(const ScoreType & val,const int & numMoves) : _val(val) ,_numMoves(numMoves) { } const bool operator < (const StateEvalScore & rhs) const { if (_val < rhs._val) { return true; } else if (_val == rhs._val) { return _numMoves > rhs._numMoves; } else { return false; } } const bool operator > (const StateEvalScore & rhs) const { if (_val > rhs._val) { return true; } else if (_val == rhs._val) { return _numMoves < rhs._numMoves; } else { return false; } } const bool operator <= (const StateEvalScore & rhs) const { if (_val > rhs._val) { return true; } else if (_val == rhs._val) { return _numMoves >= rhs._numMoves; } else { return false; } } const bool operator >= (const StateEvalScore & rhs) const { if (_val > rhs._val) { return true; } else if (_val == rhs._val) { return _numMoves <= rhs._numMoves; } else { return false; } } const bool operator == (const StateEvalScore & rhs) const { return (_val == rhs._val) && (_numMoves == rhs._numMoves); } const ScoreType & val() const { return _val; } const TimeType & numMoves() const { return _numMoves; } }; } ================================================ FILE: SparCraft/source/Common.cpp ================================================ #include "Common.h" // SEARCH PARAMETERS char SPARCRAFT_LOGFILE[100] { "sparcraft_error_log.txt" }; namespace SparCraft { namespace System { void FatalError(const std::string & errorMessage) { std::cerr << "\n\n\nSparCraft Fatal Error: \n\n\n " << errorMessage << "\n\n"; /*std::ofstream logStream; logStream.open(SPARCRAFT_LOGFILE, std::ofstream::app); logStream << "\n\n\nSparCraft Fatal Error: \n\n\n " << errorMessage << "\n\n"; logStream.flush(); logStream.close();*/ throw(SPARCRAFT_FATAL_ERROR); } void checkSupportedUnitType(const BWAPI::UnitType & type) { if (type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown) { System::FatalError("Unknown unit type in experiment file, not supported"); } if (type == BWAPI::UnitTypes::Protoss_Corsair || type == BWAPI::UnitTypes::Zerg_Devourer || type == BWAPI::UnitTypes::Zerg_Scourge || type == BWAPI::UnitTypes::Terran_Valkyrie) { System::FatalError("Units with just air weapons currently not supported correctly: " + type.getName()); } if (type.isBuilding() && !(type == BWAPI::UnitTypes::Protoss_Photon_Cannon || type == BWAPI::UnitTypes::Zerg_Sunken_Colony || type == BWAPI::UnitTypes::Terran_Missile_Turret)) { System::FatalError("Non-attacking buildings not currently supported: " + type.getName()); } if (type.isSpellcaster()) { System::FatalError("Spell casting units not currently supported: " + type.getName()); } // Don't support units loading other units yet if (type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine || type == BWAPI::UnitTypes::Protoss_Carrier || type == BWAPI::UnitTypes::Protoss_Interceptor || type == BWAPI::UnitTypes::Protoss_Reaver || type == BWAPI::UnitTypes::Protoss_Scarab || type == BWAPI::UnitTypes::Zerg_Broodling) { System::FatalError("Units which have unit projectiles not supported: " + type.getName()); } } bool isSupportedUnitType(const BWAPI::UnitType & type) { if (type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown) { return false; } if (type == BWAPI::UnitTypes::Protoss_Corsair || type == BWAPI::UnitTypes::Zerg_Devourer || type == BWAPI::UnitTypes::Zerg_Scourge || type == BWAPI::UnitTypes::Terran_Valkyrie) { return false; } if (type.isBuilding() && !(type == BWAPI::UnitTypes::Protoss_Photon_Cannon || type == BWAPI::UnitTypes::Zerg_Sunken_Colony || type == BWAPI::UnitTypes::Terran_Missile_Turret)) { return false; } if (type.isSpellcaster()) { return false; } // Don't support units loading other units yet if (type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine || type == BWAPI::UnitTypes::Protoss_Carrier || type == BWAPI::UnitTypes::Protoss_Interceptor || type == BWAPI::UnitTypes::Protoss_Reaver || type == BWAPI::UnitTypes::Protoss_Scarab || type == BWAPI::UnitTypes::Zerg_Broodling) { return false; } return true; } } }; ================================================ FILE: SparCraft/source/Common.h ================================================ #pragma once #include "BWAPI.h" #include "BaseTypes.hpp" #include #include #include #include #include #include #include #include #include #include #include "Logger.h" #include "SparCraftAssert.h" extern char SPARCRAFT_LOGFILE[100]; namespace SparCraft { // constants for search namespace Constants { // number of players in the game const size_t Num_Players = 2; // maximum number of units a player can have const size_t Max_Units = 100; // max depth the search can ever handle const size_t Max_Search_Depth = 50; // number of directions that units can move const size_t Num_Directions = 4; // max number of ordered moves in a search depth const size_t Max_Ordered_Moves = 10; // distance moved for a 'move' command const size_t Move_Distance = 16; // add between a move and attack as penalty const TimeType Move_Penalty = 4; // add range to units because of bounding boxes const PositionType Range_Addition = 32; // maximum number of moves possible for any unit const size_t Max_Moves = Max_Units + Num_Directions + 1; const bool Use_Unit_Bounding = false; const size_t Pass_Move_Duration = 20; const float Min_Unit_DPF = 0.1f; const HealthType Starting_Energy = 50; // whether to use transposition table in search const bool Use_Transposition_Table = true; const size_t Transposition_Table_Size = 100000; const size_t Transposition_Table_Scan = 10; const size_t Num_Hashes = 2; // UCT options const size_t Max_UCT_Children = 10; // rng seeding options const bool Seed_Hash_Time = false; const bool Seed_Player_Random_Time = true; // directions of movement const int Move_Dir[4][2] = {{-1,0}, {1,0}, {0,1}, {0,-1} }; } namespace System { const int SPARCRAFT_FATAL_ERROR = -1; void FatalError(const std::string & errorMessage); void checkSupportedUnitType(const BWAPI::UnitType & type); bool isSupportedUnitType(const BWAPI::UnitType & type); } }; #include "EnumData.h" ================================================ FILE: SparCraft/source/ConfigFileGenerator.h ================================================ #pragma once #include "Common.h" #include "SearchExperiment.h" #include "UCTSearch.h" #include "PlayerProperties.h" #include "UnitProperties.h" // you shouldn't run this, I used it for my paper void generateExperimentFile(int searchTimer, int maxChildren, int numStates, int numUnits, bool sep) { std::string display("Display true C:\\Users\\Dave\\Desktop\\sc2010\\StarCraft_Bot\\Visual_Studio_Projects\\SparCraft\\starcraft_images\\"); std::string stat = (sep ? "sep" : "sym"); std::stringstream folder; folder << "exp\\exp_" << numUnits << "_" << stat; std::stringstream command; command << "mkdir " << folder.str(); // Creates the directory system("mkdir exp"); system(command.str().c_str()); std::stringstream states; if (sep) { states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << (numUnits/2) << " Protoss_Zealot " << (numUnits/2) << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << (numUnits/2) << " Terran_Marine " << (numUnits/2) << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Terran_Marine " << (numUnits/2) << " Zerg_Zergling " << (numUnits/2) << "\n"; } else { states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Zerg_Zergling " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << (numUnits/2) << " Protoss_Zealot " << (numUnits/2) << "\n"; states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << (numUnits/2) << " Terran_Marine " << (numUnits/2) << "\n"; states << "State StateSymmetric 100 128 128 Terran_Marine " << (numUnits/2) << " Zerg_Zergling " << (numUnits/2) << "\n"; } std::stringstream exp1; exp1 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp1 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp1 << "Player 1 PortfolioGreedySearch 40 NOKDPS 1 0\n"; exp1 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_ab_vs_portfolio_" << stat << " true\n"; std::stringstream exp2; exp2 << "Player 0 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp2 << "Player 0 UCT " << searchTimer << " 1.5 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp2 << "Player 1 PortfolioGreedySearch 40 NOKDPS 1 0\n"; exp2 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_uct_vs_portfolio_" << stat << " true\n"; std::stringstream exp3; exp3 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp3 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp3 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp3 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_ab_vs_uct_nok_" << stat << " true\n"; std::stringstream exp4; exp4 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp4 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp4 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp4 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_ab_vs_uct_none_" << stat << " true\n"; std::stringstream exp5; exp5 << "Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\n"; exp5 << "Player 1 PortfolioGreedySearch 0 NOKDPS 2 0\n"; exp5 << "Player 1 PortfolioGreedySearch 0 NOKDPS 3 0\n"; exp5 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_p_vs_p_iter_" << stat << " true\n"; std::stringstream exp6; exp6 << "Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\n"; exp6 << "Player 1 PortfolioGreedySearch 0 NOKDPS 1 1\n"; exp6 << "Player 1 PortfolioGreedySearch 0 NOKDPS 1 2\n"; exp6 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_p_vs_p_resp_" << stat << " true\n"; std::stringstream exp7; exp7 << "Player 0 PortfolioGreedySearch 0 NOKDPS 1 0\n"; exp7 << "Player 1 PortfolioGreedySearch 0 NOKDPS 1 1\n"; exp7 << "Player 1 PortfolioGreedySearch 0 NOKDPS 1 2\n"; exp7 << "ResultsFile c:\\users\\dave\\desktop\\results\\exp\\exp_" << numUnits << "_" << stat << "\\results_" << numUnits << "_p_vs_p_resp_" << stat << " true\n"; std::stringstream f1; f1 << folder.str() << "\\exp_" << numUnits << "_ab_vs_portfolio_" << stat << ".txt"; std::stringstream f2; f2 << folder.str() << "\\exp_" << numUnits << "_uct_vs_portfolio_" << stat << ".txt"; std::stringstream f3; f3 << folder.str() << "\\exp_" << numUnits << "_ab_vs_uct_nok_" << stat << ".txt"; std::stringstream f4; f4 << folder.str() << "\\exp_" << numUnits << "_ab_vs_uct_none_" << stat << ".txt"; std::stringstream f5; f5 << folder.str() << "\\exp_" << numUnits << "_p_vs_p_iter_" << stat << ".txt"; std::stringstream f6; f6 << folder.str() << "\\exp_" << numUnits << "_p_vs_p_resp_" << stat << ".txt"; std::ofstream fout1(f1.str().c_str()); fout1 << exp1.str(); fout1 << states.str(); fout1 << display; fout1.close(); std::ofstream fout2(f2.str().c_str()); fout2 << exp2.str(); fout2 << states.str(); fout2 << display; fout2.close(); std::ofstream fout3(f3.str().c_str()); fout3 << exp3.str(); fout3 << states.str(); fout3 << display; fout3.close(); std::ofstream fout4(f4.str().c_str()); fout4 << exp4.str(); fout4 << states.str(); fout4 << display; fout4.close(); std::ofstream fout5(f5.str().c_str()); fout5 << exp5.str(); fout5 << states.str(); fout5 << display; fout5.close(); std::ofstream fout6(f6.str().c_str()); fout6 << exp6.str(); fout6 << states.str(); fout6 << display; fout6.close(); std::stringstream batName; batName << folder.str() << "\\runall_" << numUnits << "_" << stat << ".bat"; std::ofstream bat(batName.str().c_str()); bat << "@echo off\n"; bat << "cd C:\\Users\\Dave\\Desktop\\sc2010\\StarCraft_Bot\\Visual_Studio_Projects\\SparCraft\\VisualStudio\\Release\n"; bat << "copy SparCraft.exe exp_" << numUnits << "_" << stat << ".exe\n"; bat << "TIMEOUT 3\n"; bat << "start exp_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f1.str() << "\n"; bat << "start exp_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f2.str() << "\n"; bat << "start exp_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f3.str() << "\n"; bat << "start exp_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f4.str() << "\n"; bat.close(); std::stringstream batName2; batName2 << folder.str() << "\\runall_p_" << numUnits << "_" << stat << ".bat"; std::ofstream bat2(batName2.str().c_str()); bat2 << "@echo off\n"; bat2 << "cd C:\\Users\\Dave\\Desktop\\sc2010\\StarCraft_Bot\\Visual_Studio_Projects\\SparCraft\\VisualStudio\\Release\n"; bat2 << "copy SparCraft.exe exp_p_" << numUnits << "_" << stat << ".exe\n"; bat2 << "TIMEOUT 3\n"; bat2 << "start exp_p_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f5.str() << "\n"; bat2 << "start exp_p_" << numUnits << "_" << stat << ".exe c:\\users\\dave\\desktop\\results\\" << f6.str() << "\n"; bat.close(); } void generateStateConfig(int numUnits, bool sep) { std::stringstream states; if (sep) { states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Zealot " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Terran_Marine " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Terran_Vulture " << numUnits << "\n"; } else { states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Zerg_Zergling " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Protoss_Zealot " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Terran_Marine " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Terran_Vulture " << numUnits << "\n"; } std::cout << states.str(); } // you shouldn't run this, I used it for my paper void generateExperimentFileLinux(int searchTimer, int maxChildren, int numStates, int numUnits, bool sep) { std::string display("Display false ."); std::string stat = (sep ? "sep" : "sym"); std::stringstream folder; folder << "exp_linux_" << numUnits << "_" << stat; std::stringstream command; command << "mkdir exp\\" << folder.str(); // Creates the directory system("mkdir exp"); system(command.str().c_str()); std::stringstream states; if (sep) { states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Zerg_Zergling " << numUnits << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << (numUnits/2) << " Protoss_Zealot " << (numUnits/2) << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Protoss_Dragoon " << (numUnits/2) << " Terran_Marine " << (numUnits/2) << "\n"; states << "State SeparatedState 100 128 128 400 360 840 360 Terran_Marine " << (numUnits/2) << " Zerg_Zergling " << (numUnits/2) << "\n"; } else { states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Zerg_Zergling " << numUnits << "\n"; states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << (numUnits/2) << " Protoss_Zealot " << (numUnits/2) << "\n"; states << "State StateSymmetric 100 128 128 Protoss_Dragoon " << (numUnits/2) << " Terran_Marine " << (numUnits/2) << "\n"; states << "State StateSymmetric 100 128 128 Terran_Marine " << (numUnits/2) << " Zerg_Zergling " << (numUnits/2) << "\n"; } std::stringstream exp1; exp1 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp1 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp1 << "Player 1 PortfolioGreedySearch NOKDPS 1 0\n"; exp1 << "ResultsFile /home/cdavid/SparCraft/linux/exp/" << folder.str() << "/results_" << numUnits << "_ab_vs_portfolio_" << stat << " true\n"; std::stringstream exp2; exp2 << "Player 0 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp2 << "Player 0 UCT " << searchTimer << " 1.5 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp2 << "Player 1 PortfolioGreedySearch NOKDPS 1 0\n"; exp2 << "ResultsFile /home/cdavid/SparCraft/linux/exp/" << folder.str() << "/results_" << numUnits << "_uct_vs_portfolio_" << stat << " true\n"; std::stringstream exp3; exp3 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp3 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp3 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp3 << "ResultsFile /home/cdavid/SparCraft/linux/exp/" << folder.str() << "/results_" << numUnits << "_ab_vs_uct_nok_" << stat << " true\n"; std::stringstream exp4; exp4 << "Player 0 AlphaBeta " << searchTimer << " " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp4 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate None\n"; exp4 << "Player 1 UCT " << searchTimer << " 1.6 5000 " << maxChildren << " ScriptFirst Playout NOKDPS NOKDPS Alternate NOKDPS\n"; exp4 << "ResultsFile /home/cdavid/SparCraft/linux/exp/" << folder.str() << "/results_" << numUnits << "_ab_vs_uct_none_" << stat << " true\n"; std::stringstream f1; f1 << "exp/" << folder.str() << "/exp_linux_" << numUnits << "_ab_vs_portfolio_" << stat << ".txt"; std::stringstream f2; f2 << "exp/" << folder.str() << "/exp_linux_" << numUnits << "_uct_vs_portfolio_" << stat << ".txt"; std::stringstream f3; f3 << "exp/" << folder.str() << "/exp_linux_" << numUnits << "_ab_vs_uct_nok_" << stat << ".txt"; std::stringstream f4; f4 << "exp/" << folder.str() << "/exp_linux_" << numUnits << "_ab_vs_uct_none_" << stat << ".txt"; std::ofstream fout1(f1.str().c_str()); fout1 << exp1.str(); fout1 << states.str(); fout1 << display; fout1.close(); std::ofstream fout2(f2.str().c_str()); fout2 << exp2.str(); fout2 << states.str(); fout2 << display; fout2.close(); std::ofstream fout3(f3.str().c_str()); fout3 << exp3.str(); fout3 << states.str(); fout3 << display; fout3.close(); std::ofstream fout4(f4.str().c_str()); fout4 << exp4.str(); fout4 << states.str(); fout4 << display; fout4.close(); std::stringstream batName; batName << "exp\\" << folder.str() << "\\ssh_linuxbox_runall_" << numUnits << "_" << stat << ".bat"; std::ofstream bat(batName.str().c_str()); bat << "start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/" << f1.str() << "\n"; bat << "start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/" << f2.str() << "\n"; bat << "start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/" << f3.str() << "\n"; bat << "start cmd /K plink cdavid@linuxbox /home/cdavid/SparCraft/linux/SparCraft /home/cdavid/SparCraft/linux/" << f4.str() << "\n"; bat.close(); } void generate() { generateExperimentFileLinux(40, 20, 100, 8, true); generateExperimentFileLinux(40, 20, 100, 16, true); generateExperimentFileLinux(40, 20, 100, 32, true); generateExperimentFileLinux(40, 20, 100, 50, true); generateExperimentFileLinux(40, 20, 100, 8, false); generateExperimentFileLinux(40, 20, 100, 16, false); generateExperimentFileLinux(40, 20, 100, 32, false); generateExperimentFileLinux(40, 20, 100, 50, false); generateExperimentFile(40, 20, 100, 8, true); generateExperimentFile(40, 20, 100, 16, true); generateExperimentFile(40, 20, 100, 32, true); generateExperimentFile(40, 20, 100, 50, true); generateExperimentFile(40, 20, 100, 8, false); generateExperimentFile(40, 20, 100, 16, false); generateExperimentFile(40, 20, 100, 32, false); generateExperimentFile(40, 20, 100, 50, false); //for (int i=1; i<51; ++i) //{ // generateStateConfig(i, false); //} } ================================================ FILE: SparCraft/source/EnumData.cpp ================================================ #include "EnumData.h" using namespace SparCraft; void SparCraft::EnumDataInit() { Players::init(); SearchMethods::init(); PlayerModels::init(); EvaluationMethods::init(); SearchNodeType::init(); MoveOrderMethod::init(); PlayerToMove::init(); } ================================================ FILE: SparCraft/source/EnumData.h ================================================ #pragma once #include "Common.h" namespace SparCraft { template class EnumData { protected: static std::string name; static std::vector names; static std::map nameMap; public: static const int size() { return T::Size; } static void setType(const std::string & s) { name = s; } static const std::string & getType() { return name; } static void setData(const int & ID, const std::string & s) { if (ID > size()) { std::stringstream ss; ss << ID; System::FatalError("Unknown " + getType() + " ID: " + ss.str()); } names[ID] = s; nameMap[s] = ID; } static const size_t getID(const std::string & s) { const std::map::const_iterator it(nameMap.find(s)); if (it == nameMap.end()) { System::FatalError("Unknown " + getType() + " String: " + s); } return it->second; } static const std::string & getName(const size_t & ID) { if (ID > (size_t)size()) { std::stringstream ss; ss << ID; System::FatalError("Unknown " + getType() + " ID: " + ss.str()); } return names[ID]; } }; template std::string EnumData::name; template std::vector EnumData::names; template std::map EnumData::nameMap; class Players : public EnumData { public: enum { Player_One = 0, Player_Two = 1, Player_None = 2, Player_Both = 3, Size}; static void init() { setType("Players"); names.resize(Size); setData(Player_One, "Player One"); setData(Player_Two, "Player Two"); setData(Player_None, "Player None"); setData(Player_Both, "Player Both"); } }; class SearchMethods : public EnumData { public: enum { AlphaBeta, IDAlphaBeta, MiniMax, Size }; static void init() { setType("SearchMethod"); names.resize(Size); setData(AlphaBeta, "AlphaBeta"); setData(IDAlphaBeta, "IDAlphaBeta"); setData(MiniMax, "MiniMax"); } }; class PlayerModels : public EnumData { public: enum { AlphaBeta, AttackClosest, Kiter, Random, AttackWeakest, AttackDPS, KiterDPS, NOKDPS, Kiter_NOKDPS, Cluster, PortfolioGreedySearch, UCT, None, Size }; static void init() { setType("PlayerModels"); names.resize(Size); setData(AlphaBeta, "AlphaBeta"); setData(AttackClosest, "AttackClosest"); setData(Kiter, "Kiter"); setData(Random, "Random"); setData(AttackWeakest, "AttackWeakest"); setData(AttackDPS, "AttackDPS"); setData(KiterDPS, "KiterDPS"); setData(NOKDPS, "NOKDPS"); setData(Kiter_NOKDPS, "Kiter_NOKDPS"); setData(Cluster, "Cluster"); setData(PortfolioGreedySearch, "PortfolioGreedySearch"); setData(UCT, "UCT"); setData(None, "None"); } }; class EvaluationMethods : public EnumData { public: enum { LTD, LTD2, Playout, Size }; static void init() { setType("EvaluationMethods"); names.resize(Size); setData(LTD, "LTD"); setData(LTD2, "LTD2"); setData(Playout, "Playout"); } }; class SearchNodeType : public EnumData { public: enum { Default, RootNode, SoloNode, FirstSimNode, SecondSimNode, Size }; static void init() { setType("SearchNodeType"); names.resize(Size); setData(Default, "Default"); setData(RootNode, "RootNode"); setData(SoloNode, "SoloNode"); setData(FirstSimNode, "FirstSimNode"); setData(SecondSimNode, "SecondSimNode"); } }; class MoveOrderMethod : public EnumData { public: enum { ScriptFirst, None, Size }; static void init() { setType("MoveOrderMethod"); names.resize(Size); setData(ScriptFirst, "ScriptFirst"); setData(None, "None"); } }; class PlayerToMove : public EnumData { public: enum { Random, Alternate, Not_Alternate, Size }; static void init() { setType("PlayerToMove"); names.resize(Size); setData(Random, "Random"); setData(Alternate, "Alternate"); setData(Not_Alternate, "Not_Alternate"); } }; extern void EnumDataInit(); } ================================================ FILE: SparCraft/source/Game.cpp ================================================ #include "Game.h" using namespace SparCraft; Game::Game(const GameState & initialState, const size_t & limit) : _numPlayers(0) , state(initialState) , _playerToMoveMethod(SparCraft::PlayerToMove::Alternate) , rounds(0) , moveLimit(limit) { } Game::Game(const GameState & initialState, PlayerPtr & p1, PlayerPtr & p2, const size_t & limit) : _numPlayers(0) , state(initialState) , _playerToMoveMethod(SparCraft::PlayerToMove::Alternate) , rounds(0) , moveLimit(limit) { // add the players _players[Players::Player_One] = p1; _players[Players::Player_Two] = p2; } // play the game until there is a winner void Game::play() { scriptMoves[Players::Player_One] = std::vector(state.numUnits(Players::Player_One)); scriptMoves[Players::Player_Two] = std::vector(state.numUnits(Players::Player_Two)); t.start(); // play until there is no winner while (!gameOver()) { if (moveLimit && rounds >= moveLimit) { break; } playNextTurn(); } gameTimeMS = t.getElapsedTimeInMilliSec(); } void Game::playNextTurn() { Timer frameTimer; frameTimer.start(); scriptMoves[0].clear(); scriptMoves[1].clear(); // the player that will move next const size_t playerToMove(getPlayerToMove()); PlayerPtr & toMove = _players[playerToMove]; PlayerPtr & enemy = _players[state.getEnemy(playerToMove)]; // generate the moves possible from this state state.generateMoves(moves[toMove->ID()], toMove->ID()); // the tuple of moves he wishes to make toMove->getMoves(state, moves[playerToMove], scriptMoves[playerToMove]); // if both players can move, generate the other player's moves if (state.bothCanMove()) { state.generateMoves(moves[enemy->ID()], enemy->ID()); enemy->getMoves(state, moves[enemy->ID()], scriptMoves[enemy->ID()]); state.makeMoves(scriptMoves[enemy->ID()]); } // make the moves state.makeMoves(scriptMoves[toMove->ID()]); state.finishedMoving(); rounds++; } // play the game until there is a winner void Game::playIndividualScripts(UnitScriptData & scriptData) { // array which will hold all the script moves for players Array2D, Constants::Num_Players, PlayerModels::Size> allScriptMoves; scriptMoves[Players::Player_One] = std::vector(state.numUnits(Players::Player_One)); scriptMoves[Players::Player_Two] = std::vector(state.numUnits(Players::Player_Two)); t.start(); // play until there is no winner while (!gameOver()) { if (moveLimit && rounds > moveLimit) { break; } Timer frameTimer; frameTimer.start(); // clear all script moves for both players for (size_t p(0); p #include "Timer.h" namespace SparCraft { typedef std::shared_ptr PlayerPtr; class UnitScriptData; class Game { protected: PlayerPtr _players[2]; size_t _numPlayers; size_t _playerToMoveMethod; size_t rounds; Timer t; double gameTimeMS; size_t moveLimit; GameState state; // moves array to store moves in MoveArray moves[2]; std::vector scriptMoves[2]; public: // game constructor Game(const GameState & initialState, PlayerPtr & p1, PlayerPtr & p2, const size_t & limit); Game(const GameState & initialState, const size_t & limit); void play(); void playNextTurn(); void playIndividualScripts(UnitScriptData & scriptsChosen); void storeHistory(const bool & store); bool gameOver() const; ScoreType eval(const size_t & evalMethod) const; GameState & getState(); const GameState & getState() const; int getRounds(); double getTime(); const size_t getPlayerToMove(); PlayerPtr getPlayer(const size_t & player); }; } ================================================ FILE: SparCraft/source/GameState.cpp ================================================ #include "GameState.h" #include "Player.h" #include "Game.h" using namespace SparCraft; #define TABS(N) for (int i(0); i(Constants::Max_Units, Unit()); _units[1] = std::vector(Constants::Max_Units, Unit()); _unitIndex[0] = std::vector(Constants::Max_Units, 0); _unitIndex[1] = std::vector(Constants::Max_Units, 0); for (size_t u(0); u<_maxUnits; ++u) { _unitIndex[0][u] = u; _unitIndex[1][u] = u; } } // construct state from a save file GameState::GameState(const std::string & filename) { read(filename); } // call this whenever we are done with moves void GameState::finishedMoving() { // sort the unit vector based on time left to move sortUnits(); // update the current time of the state updateGameTime(); // calculate the hp sum of each player int hpSum[2]; for (size_t p(0); p & moves) { if (moves.size() > 0) { const size_t canMove(whoCanMove()); const size_t playerToMove(moves[0].player()); if (canMove == getEnemy(playerToMove)) { System::FatalError("GameState Error - Called makeMove() for a player that cannot currently move"); } } for (size_t m(0); misWalkable(pos); } // if there is no map, then return true return true; } const bool GameState::isFlyable(const Position & pos) const { if (_map) { return _map->isFlyable(pos); } // if there is no map, then return true return true; } const size_t GameState::getEnemy(const size_t & player) const { return (player + 1) % 2; } const Unit & GameState::getClosestOurUnit(const size_t & player, const size_t & unitIndex) { const Unit & myUnit(getUnit(player,unitIndex)); size_t minDist(1000000); size_t minUnitInd(0); Position currentPos = myUnit.currentPosition(_currentTime); for (size_t u(0); u<_numUnits[player]; ++u) { if (u == unitIndex || getUnit(player, u).canHeal()) { continue; } //size_t distSq(myUnit.distSq(getUnit(enemyPlayer,u))); size_t distSq(currentPos.getDistanceSq(getUnit(player, u).currentPosition(_currentTime))); if (distSq < minDist) { minDist = distSq; minUnitInd = u; } } return getUnit(player, minUnitInd); } const Unit & GameState::getClosestEnemyUnit(const size_t & player, const size_t & unitIndex, bool checkCloaked) { const size_t enemyPlayer(getEnemy(player)); const Unit & myUnit(getUnit(player,unitIndex)); PositionType minDist(1000000); size_t minUnitInd(0); size_t minUnitID(255); Position currentPos = myUnit.currentPosition(_currentTime); for (size_t u(0); u<_numUnits[enemyPlayer]; ++u) { Unit & enemyUnit(getUnit(enemyPlayer, u)); if (checkCloaked&& enemyUnit.type().hasPermanentCloak()) { bool invisible = true; for (size_t detectorIndex(0); detectorIndex < _numUnits[player]; ++detectorIndex) { // unit reference const Unit & detector(getUnit(player, detectorIndex)); if (detector.type().isDetector() && detector.canSeeTarget(enemyUnit, _currentTime)) { invisible = false; break; } } if (invisible) { continue; } } PositionType distSq = myUnit.getDistanceSqToUnit(enemyUnit, _currentTime); if ((distSq < minDist))// || ((distSq == minDist) && (enemyUnit.ID() < minUnitID))) { minDist = distSq; minUnitInd = u; minUnitID = enemyUnit.ID(); } else if ((distSq == minDist) && (enemyUnit.ID() < minUnitID)) { minDist = distSq; minUnitInd = u; minUnitID = enemyUnit.ID(); } } return getUnit(enemyPlayer, minUnitInd); } const bool GameState::checkFull(const size_t & player) const { if (numUnits(player) >= Constants::Max_Units) { std::stringstream ss; ss << "GameState has too many units. Constants::Max_Units = " << Constants::Max_Units; System::FatalError(ss.str()); return false; } return false; } // Add a given unit to the state // This function will give the unit a unique unitID void GameState::addUnit(const Unit & u) { checkFull(u.player()); System::checkSupportedUnitType(u.type()); // Calculate the unitID for this unit // This will just be the current total number of units in the state size_t unitID = _numUnits[Players::Player_One] + _numUnits[Players::Player_Two]; // Set the unit and it's unitID getUnit(u.player(), _numUnits[u.player()]) = u; getUnit(u.player(), _numUnits[u.player()]).setUnitID(unitID); // Increment the number of units this player has _numUnits[u.player()]++; _prevNumUnits[u.player()]++; // And do the clean-up finishedMoving(); calculateStartingHealth(); if (!checkUniqueUnitIDs()) { System::FatalError("GameState has non-unique Unit ID values"); } } // Add a unit with given parameters to the state // This function will give the unit a unique unitID void GameState::addUnit(const BWAPI::UnitType type, const size_t playerID, const Position & pos) { checkFull(playerID); System::checkSupportedUnitType(type); // Calculate the unitID for this unit // This will just be the current total number of units in the state size_t unitID = _numUnits[Players::Player_One] + _numUnits[Players::Player_Two]; // Set the unit and it's unitID getUnit(playerID, _numUnits[playerID]) = Unit(type, playerID, pos); getUnit(playerID, _numUnits[playerID]).setUnitID(unitID); // Increment the number of units this player has _numUnits[playerID]++; _prevNumUnits[playerID]++; // And do the clean-up finishedMoving(); calculateStartingHealth(); if (!checkUniqueUnitIDs()) { System::FatalError("GameState has non-unique Unit ID values"); } } // Add a given unit to the state // This function will keep the unit ID assigned by player. Only use this for advanced / BWAPI states void GameState::addUnitWithID(const Unit & u) { checkFull(u.player()); System::checkSupportedUnitType(u.type()); // Simply add the unit to the array getUnit(u.player(), _numUnits[u.player()]) = u; // Increment the number of units this player has _numUnits[u.player()]++; _prevNumUnits[u.player()]++; // And do the clean-up finishedMoving(); calculateStartingHealth(); if (!checkUniqueUnitIDs()) { System::FatalError("GameState has non-unique Unit ID values"); } } void GameState::sortUnits() { // sort the units based on time free for (size_t p(0); p 0) && (*item < *(_unitPtrs[p][iHole - 1]))) while ((iHole > 0) && (itemUnit < getUnit(p, iHole-1))) { // move hole to next smaller index //_unitPtrs[p][iHole] = _unitPtrs[p][iHole - 1]; _unitIndex[p][iHole] = _unitIndex[p][iHole - 1]; iHole = iHole - 1; } // put item in the hole _unitIndex[p][iHole] = itemIndex; //_unitPtrs[p][iHole] = item; }*/ //_unitPtrs[p].sort(_prevNumUnits[p], UnitPtrCompare()); std::sort(&_unitIndex[p][0], &_unitIndex[p][0] + _prevNumUnits[p], UnitIndexCompare(*this, p)); _prevNumUnits[p] = _numUnits[p]; } } } Unit & GameState::getUnit(const size_t & player, const size_t & unitIndex) { return _units[player][_unitIndex[player][unitIndex]]; } const Unit & GameState::getUnit(const size_t & player, const size_t & unitIndex) const { return _units[player][_unitIndex[player][unitIndex]]; } const size_t GameState::closestEnemyUnitDistance(const Unit & unit) const { size_t enemyPlayer(getEnemy(unit.player())); size_t closestDist(0); for (size_t u(0); u closestDist) { closestDist = dist; } } return closestDist; } const bool GameState::playerDead(const size_t & player) const { if (numUnits(player) <= 0) { return true; } for (size_t u(0); u 0) { return false; } } return true; } const size_t GameState::whoCanMove() const { TimeType p1Time(getUnit(0,0).firstTimeFree()); TimeType p2Time(getUnit(1,0).firstTimeFree()); // if player one is to move first if (p1Time < p2Time) { return Players::Player_One; } // if player two is to move first else if (p1Time > p2Time) { return Players::Player_Two; } else { return Players::Player_Both; } } const bool GameState::checkUniqueUnitIDs() const { std::set unitIDs; for (size_t p(0); p 200) { return true; } for (size_t p(0); p typeCount; for (size_t u(0); u<_numUnits[p]; ++u) { const Unit & unit(getUnit(p, u)); if (typeCount.find(unit.type()) != std::end(typeCount)) { typeCount[unit.type()]++; } else { typeCount[unit.type()] = 1; } } for (auto & kv : typeCount) { const BWAPI::UnitType & type = kv.first; const size_t count = kv.second; ss << "P" << (int)p << " " << count << " " << type.getName() << "\n"; } } return ss.str(); } void GameState::write(const std::string & filename) const { std::ofstream fout (filename.c_str(), std::ios::out | std::ios::binary); fout.write((char *)this, sizeof(*this)); fout.close(); } void GameState::read(const std::string & filename) { std::ifstream fin (filename.c_str(), std::ios::in | std::ios::binary); fin.read((char *)this, sizeof(*this)); fin.close(); } ================================================ FILE: SparCraft/source/GameState.h ================================================ #pragma once #include "Common.h" #include #include "MoveArray.h" #include "Hash.h" #include "Map.hpp" #include "Unit.h" #include "GraphViz.hpp" #include "Array.hpp" #include "Logger.h" #include typedef std::shared_ptr MapPtr; namespace SparCraft { class GameState { Map * _map; std::vector _units[Constants::Num_Players]; std::vector _unitIndex[Constants::Num_Players]; Array2D _units2; Array2D _unitIndex2; Array _neutralUnits; Array _numUnits; Array _prevNumUnits; Array _totalLTD; Array _totalSumSQRT; Array _numMovements; Array _prevHPSum; TimeType _currentTime; size_t _maxUnits; TimeType _sameHPFrames; // checks to see if the unit array is full before adding a unit to the state const bool checkFull(const size_t & player) const; const bool checkUniqueUnitIDs() const; void performAction(const Action & theMove); public: GameState(); GameState(const std::string & filename); // misc functions void finishedMoving(); void updateGameTime(); const bool playerDead(const size_t & player) const; const bool isTerminal() const; // unit data functions const size_t numUnits(const size_t & player) const; const size_t prevNumUnits(const size_t & player) const; const size_t numNeutralUnits() const; const size_t closestEnemyUnitDistance(const Unit & unit) const; // Unit functions void sortUnits(); void addUnit(const Unit & u); void addUnit(const BWAPI::UnitType unitType, const size_t playerID, const Position & pos); void addUnitWithID(const Unit & u); void addNeutralUnit(const Unit & unit); const Unit & getUnit(const size_t & player, const size_t & unitIndex) const; const Unit & getUnitByID(const size_t & unitID) const; Unit & getUnit(const size_t & player, const size_t & unitIndex); const Unit & getUnitByID(const size_t & player, const size_t & unitID) const; Unit & getUnitByID(const size_t & player, const size_t & unitID); const Unit & getClosestEnemyUnit(const size_t & player, const size_t & unitIndex, bool checkCloaked=false); const Unit & getClosestOurUnit(const size_t & player, const size_t & unitIndex); const Unit & getUnitDirect(const size_t & player, const size_t & unit) const; const Unit & getNeutralUnit(const size_t & u) const; // game time functions void setTime(const TimeType & time); const TimeType getTime() const; // evaluation functions const StateEvalScore eval( const size_t & player, const size_t & evalMethod, const size_t p1Script = PlayerModels::NOKDPS, const size_t p2Script = PlayerModels::NOKDPS) const; const ScoreType evalLTD(const size_t & player) const; const ScoreType evalLTD2(const size_t & player) const; const ScoreType LTD(const size_t & player) const; const ScoreType LTD2(const size_t & player) const; const StateEvalScore evalSim(const size_t & player, const size_t & p1, const size_t & p2) const; const size_t getEnemy(const size_t & player) const; // unit hitpoint calculations, needed for LTD2 evaluation void calculateStartingHealth(); void setTotalLTD(const float & p1, const float & p2); void setTotalLTD2(const float & p1, const float & p2); const float & getTotalLTD(const size_t & player) const; const float & getTotalLTD2(const size_t & player) const; // move related functions void generateMoves(MoveArray & moves, const size_t & playerIndex) const; void makeMoves(const std::vector & moves); const int & getNumMovements(const size_t & player) const; const size_t whoCanMove() const; const bool bothCanMove() const; // map-related functions void setMap(Map * map); Map * getMap() const; const bool isWalkable(const Position & pos) const; const bool isFlyable(const Position & pos) const; // hashing functions const HashType calculateHash(const size_t & hashNum) const; // state i/o functions void print(int indent = 0) const; std::string toString() const; std::string toStringCompact() const; void write(const std::string & filename) const; void read(const std::string & filename); }; } ================================================ FILE: SparCraft/source/GraphViz.hpp ================================================ #pragma once #include namespace SparCraft { namespace GraphViz { class Property { public: std::string prop; std::string value; Property(std::string p, std::string val) : prop(p), value(val) { } void print(std::ofstream & out) { out << prop << "=\"" << value << "\", "; } }; class Node { public: std::vector props; std::string name; Node(std::string n) : name(n) {} Node() {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void print(std::ofstream & out) { out << name << " ["; for (size_t p(0); p nodes; std::vector props; Edge(std::string n1, std::string n2) : nodes(n1, n2) {} Edge(Node & n1, Node & n2) : nodes(n1.name, n2.name) {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void print(std::ofstream & out) { out << nodes.first << " -> " << nodes.second << " ["; for (size_t p(0); p nodes; std::vector edges; std::vector props; std::string name; public: Graph(std::string n) : name(n) {} void set(std::string p, std::string v) { props.push_back(Property(p,v)); } void addNode(Node & n) { nodes.push_back(n); } void addEdge(Edge & e) { edges.push_back(e); } void print(std::ofstream & out) { out << "digraph " << name << " {\n"; for (size_t p(0); p test.png }*/ } } ================================================ FILE: SparCraft/source/Hash.cpp ================================================ #include "Hash.h" using namespace SparCraft; namespace SparCraft { namespace Hash { HashType unitIndexHash[Constants::Num_Players][Constants::Max_Units]; HashValues values[Constants::Num_Hashes]; } } const HashType Hash::HashValues::positionHash(const size_t & player, const PositionType & x, const PositionType & y) const { // return hash32shift(unitPositionHash[player] ^ ((x << 16) + y)) return hash32shift(hash32shift(unitPositionHash[player] ^ x) ^ y); } Hash::HashValues::HashValues(int seed) { RandomInt rand(std::numeric_limits::min(), std::numeric_limits::max(), Constants::Seed_Hash_Time ? 0 : seed); for (size_t p(0); p>19); a = (a+0x165667b1) + (a<<5); a = (a+0xd3a2646c) ^ (a<<9); a = (a+0xfd7046c5) + (a<<3); a = (a^0xb55a4f09) ^ (a>>16); return a; } void Hash::initHash() { values[0] = HashValues(0); values[1] = HashValues(1); } int Hash::hash32shift(int key) { key = ~key + (key << 15); // key = (key << 15) - key - 1; key = key ^ (key >> 12); key = key + (key << 2); key = key ^ (key >> 4); key = key * 2057; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 16); return key; } const int Hash::jenkinsHashCombine(const HashType & hash, const int val) { return hash32shift(hash ^ (HashType)val); } const size_t Hash::magicHash(const HashType & hash, const size_t & player, const size_t & index) { return hash32shift(hash ^ unitIndexHash[player][index]); } ================================================ FILE: SparCraft/source/Hash.h ================================================ #pragma once #include "Common.h" #include #include "Random.hpp" namespace SparCraft { namespace Hash { typedef std::vector HashVec; class HashValues { HashType unitPositionHash[Constants::Num_Players]; HashType timeCanAttackHash[Constants::Num_Players]; HashType timeCanMoveHash[Constants::Num_Players]; HashType unitTypeHash[Constants::Num_Players]; HashType currentHPHash[Constants::Num_Players]; public: HashValues(int seed = 0); const HashType getAttackHash (const size_t & player, const size_t & value) const; const HashType getMoveHash (const size_t & player, const size_t & value) const; const HashType getUnitTypeHash (const size_t & player, const size_t & value) const; const HashType getCurrentHPHash (const size_t & player, const size_t & value) const; const HashType positionHash (const size_t & player, const PositionType & x, const PositionType & y) const; }; // some data storage extern HashType unitIndexHash[Constants::Num_Players][Constants::Max_Units]; extern HashValues values[Constants::Num_Hashes]; // good hashing functions void initHash(); int hash32shift(int key); const size_t jenkinsHash( size_t a); const size_t magicHash(const HashType & hash, const size_t & player, const size_t & index); const int jenkinsHashCombine(const HashType & hash, const int val); }; } ================================================ FILE: SparCraft/source/Logger.cpp ================================================ #include "Logger.h" using namespace SparCraft; Logger::Logger() : totalCharsLogged(0) { } Logger & Logger::Instance() { static Logger instance; return instance; } void Logger::clearLogFile(const std::string & logFile) { } void Logger::log(const std::string & logFile, std::string & msg) { std::ofstream logStream; logStream.open(logFile.c_str(), std::ofstream::app); logStream << msg; logStream.flush(); logStream.close(); } ================================================ FILE: SparCraft/source/Logger.h ================================================ #pragma once #include #include #include namespace SparCraft { class Logger { size_t totalCharsLogged; Logger(); public: static Logger & Instance(); void log(const std::string & logFile, std::string & msg); void clearLogFile(const std::string & logFile); }; } ================================================ FILE: SparCraft/source/Map.hpp ================================================ #pragma once #include "Common.h" #include "Array.hpp" #include "Unit.h" namespace SparCraft { typedef std::vector< std::vector > bvv; class Map { size_t _walkTileWidth; size_t _walkTileHeight; size_t _buildTileWidth; size_t _buildTileHeight; bvv _mapData; // true if walk tile [x][y] is walkable bvv _unitData; // true if unit on build tile [x][y] bvv _buildingData; // true if building on build tile [x][y] const Position getWalkPosition(const Position & pixelPosition) const { return Position(pixelPosition.x() / 8, pixelPosition.y() / 8); } void resetVectors() { _mapData = bvv(_walkTileWidth, std::vector(_walkTileHeight, true)); _unitData = bvv(_buildTileWidth, std::vector(_buildTileHeight, false)); _buildingData = bvv(_buildTileWidth, std::vector(_buildTileHeight, false)); } public: Map() : _walkTileWidth(0) , _walkTileHeight(0) , _buildTileWidth(0) , _buildTileHeight(0) { } // constructor which sets a completely walkable map Map(const size_t & bottomRightBuildTileX, const size_t & bottomRightBuildTileY) : _walkTileWidth(bottomRightBuildTileX * 4) , _walkTileHeight(bottomRightBuildTileY * 4) , _buildTileWidth(bottomRightBuildTileX) , _buildTileHeight(bottomRightBuildTileY) { resetVectors(); } Map(BWAPI::GameWrapper & game) : _walkTileWidth(game->mapWidth() * 4) , _walkTileHeight(game->mapHeight() * 4) , _buildTileWidth(game->mapWidth()) , _buildTileHeight(game->mapHeight()) { resetVectors(); for (size_t x(0); x<_walkTileWidth; ++x) { for (size_t y(0); y<_walkTileHeight; ++y) { setMapData(x, y, game->isWalkable(x, y)); } } } const size_t getPixelWidth() const { return getWalkTileWidth() * 4; } const size_t getPixelHeight() const { return getWalkTileHeight() * 4; } const size_t & getWalkTileWidth() const { return _walkTileWidth; } const size_t & getWalkTileHeight() const { return _walkTileHeight; } const size_t & getBuildTileWidth() const { return _buildTileWidth; } const size_t & getBuildTileHeight() const { return _buildTileHeight; } const bool isWalkable(const SparCraft::Position & pixelPosition) const { const Position & wp(getWalkPosition(pixelPosition)); return isWalkable(wp.x(), wp.y()); } const bool isFlyable(const SparCraft::Position & pixelPosition) const { const Position & wp(getWalkPosition(pixelPosition)); return isFlyable(wp.x(), wp.y()); } const bool isWalkable(const size_t & walkTileX, const size_t & walkTileY) const { return walkTileX >= 0 && walkTileX < (PositionType)getWalkTileWidth() && walkTileY >= 0 && walkTileY < (PositionType)getWalkTileHeight() && getMapData(walkTileX, walkTileY); } const bool isFlyable(const size_t & walkTileX, const size_t & walkTileY) const { return walkTileX >= 0 && walkTileX < (PositionType)getWalkTileWidth() && walkTileY >= 0 && walkTileY < (PositionType)getWalkTileHeight(); } const bool getMapData(const size_t & walkTileX, const size_t & walkTileY) const { return _mapData[walkTileX][walkTileY]; } const bool getUnitData(const size_t & buildTileX, const size_t & buildTileY) const { return _unitData[buildTileX][buildTileY]; } void setMapData(const size_t & walkTileX, const size_t & walkTileY, const bool val) { _mapData[walkTileX][walkTileY] = val; } void setUnitData(BWAPI::GameWrapper & game) { _unitData = bvv(getBuildTileWidth(), std::vector(getBuildTileHeight(), true)); for (BWAPI::UnitInterface * unit : game->getAllUnits()) { if (!unit->getType().isBuilding()) { addUnit(unit); } } } const bool canBuildHere(BWAPI::TilePosition pos) { return _unitData[pos.x][pos.y] && _buildingData[pos.x][pos.y]; } void setBuildingData(BWAPI::GameWrapper & game) { _buildingData = bvv(getBuildTileWidth(), std::vector(getBuildTileHeight(), true)); for (BWAPI::UnitInterface * unit : game->getAllUnits()) { if (unit->getType().isBuilding()) { addUnit(unit); } } } void addUnit(BWAPI::Unit & unit) { if (unit->getType().isBuilding()) { int tx = unit->getPosition().x / TILE_SIZE; int ty = unit->getPosition().y / TILE_SIZE; int sx = unit->getType().tileWidth(); int sy = unit->getType().tileHeight(); for(int x = tx; x < tx + sx && x < (int)getBuildTileWidth(); ++x) { for(int y = ty; y < ty + sy && y < (int)getBuildTileHeight(); ++y) { _buildingData[x][y] = true; } } } else { int startX = (unit->getPosition().x - unit->getType().dimensionLeft()) / TILE_SIZE; int endX = (unit->getPosition().x + unit->getType().dimensionRight() + TILE_SIZE - 1) / TILE_SIZE; // Division - round up int startY = (unit->getPosition().y - unit->getType().dimensionUp()) / TILE_SIZE; int endY = (unit->getPosition().y + unit->getType().dimensionDown() + TILE_SIZE - 1) / TILE_SIZE; for (int x = startX; x < endX && x < (int)getBuildTileWidth(); ++x) { for (int y = startY; y < endY && y < (int)getBuildTileHeight(); ++y) { _unitData[x][y] = true; } } } } unsigned int * getRGBATexture() { unsigned int * data = new unsigned int[getWalkTileWidth() * getWalkTileHeight()]; for (size_t x(0); x= 0; --a) { size_t moveType(getMove(u, a).type()); // mark the end of the move actions if (moveEnd == -1 && (moveType == ActionTypes::MOVE)) { moveEnd = a; } // mark the beginning of the MOVE unit actions else if ((moveEnd != -1) && (moveBegin == -1) && (moveType != ActionTypes::MOVE)) { moveBegin = a; } else if (moveBegin != -1) { break; } } // if we found the end but didn't find the beginning if (moveEnd != -1 && moveBegin == -1) { // then the move actions begin at the beginning of the array moveBegin = 0; } // shuffle the movement actions for this unit if (moveEnd != -1 && moveBegin != -1 && moveEnd != moveBegin) { std::random_shuffle(&_moves[u][moveBegin], &_moves[u][moveEnd]); resetMoveIterator(); } } } // returns a given move from a unit const Action & MoveArray::getMove(const size_t & unit, const size_t & move) const { assert(_moves[unit][(size_t)move].unit() != 255); return _moves[unit][(size_t)move]; } void MoveArray::printCurrentMoveIndex() { for (size_t u(0); u<_numUnits; ++u) { std::cout << _currentMovesIndex[u] << " "; } std::cout << std::endl; } void MoveArray::incrementMove(const size_t & unit) { // increment the index for this unit _currentMovesIndex[unit] = (_currentMovesIndex[unit] + 1) % _numMoves[unit]; // if the value rolled over, we need to do the carry calculation if (_currentMovesIndex[unit] == 0) { // the next unit index size_t nextUnit = unit + 1; // if we have space left to increment, do it if (nextUnit < _numUnits) { incrementMove(nextUnit); } // otherwise we have no more moves else { // stop _hasMoreMoves = false; } } _currentMoves[unit] = _moves[unit][_currentMovesIndex[unit]]; //_currentMovesVec[unit] = _moves[unit][_currentMovesIndex[unit]]; } const bool MoveArray::hasMoreMoves() const { return _hasMoreMoves; } void MoveArray::resetMoveIterator() { _hasMoreMoves = true; _currentMovesIndex.fill(0); for (size_t u(0); u & moves) { moves.assign(&_currentMoves[0], &_currentMoves[_numUnits]); //moves = _currentMovesVec; incrementMove(0); } const size_t MoveArray::maxUnits() const { return _moves.getRows(); } // adds a Move to the unit specified void MoveArray::add(const Action & move) { _moves[move.unit()][_numMoves[move.unit()]] = move; _numMoves[move.unit()]++; _currentMovesIndex[_numUnits-1] = 0; _currentMoves[_numUnits-1] = _moves[move.unit()][0]; //_currentMovesVec.push_back(_moves[move.unit()][0]); //resetMoveIterator(); } bool MoveArray::validateMoves() { for (size_t u(0); u 200) { printf("Unit Move Incorrect! Something will be wrong\n"); return false; } } } return true; } const size_t MoveArray::getUnitID(const size_t & unit) const { return getMove(unit, 0).unit(); } const size_t MoveArray::getPlayerID(const size_t & unit) const { return getMove(unit, 0).player(); } void MoveArray::addUnit() { _numUnits++; } const size_t & MoveArray::numUnits() const { return _numUnits; } const size_t & MoveArray::numUnitsInTuple() const { return numUnits(); } const size_t & MoveArray::numMoves(const size_t & unit) const { return _numMoves[unit]; } ================================================ FILE: SparCraft/source/MoveArray.h ================================================ #pragma once #include "Common.h" #include "Array.hpp" #include "Unit.h" #include "Action.h" namespace SparCraft { class MoveArray { // the array which contains all the moves Array2D _moves; // how many moves each unit has Array _numMoves; // the current move array, used for the 'iterator' //std::vector _currentMoves; //std::vector _currentMovesVec; Array _currentMoves; Array _currentMovesIndex; // the number of units that have moves; size_t _numUnits; size_t _maxUnits; bool _hasMoreMoves; public: MoveArray(const size_t maxUnits = 0); void clear(); // returns a given move from a unit const Action & getMove(const size_t & unit, const size_t & move) const; void printCurrentMoveIndex(); void incrementMove(const size_t & unit); const bool hasMoreMoves() const; void resetMoveIterator(); void getNextMoveVec(std::vector & moves); const size_t maxUnits() const; // adds a Move to the unit specified void add(const Action & move); bool validateMoves(); const size_t getUnitID(const size_t & unit) const; const size_t getPlayerID(const size_t & unit) const; void addUnit(); void shuffleMoveActions(); const size_t & numUnits() const; const size_t & numUnitsInTuple() const; const size_t & numMoves(const size_t & unit) const; }; } ================================================ FILE: SparCraft/source/MoveSet.hpp ================================================ #pragma once #include #include "Common.h" /////////////////////////////////////////////////////////////////////////////// // // BitSet // /////////////////////////////////////////////////////////////////////////////// #ifdef WIN32 #include #pragma intrinsic(__ll_lshift) #pragma intrinsic(__ll_rshift) #define __lz(a) countLeadingZeros(a) #define __tz(a) countTrailingZeros(a) #define __ONE 1ull #define __ZERO 0ull #define __LSHIFT64(VAL, N) __ll_lshift(VAL, N) #define __RSHIFT64(VAL, N) __ll_rshift(VAL, N) #else #define __lz(a) __builtin_clzll(a) #define __tz(a) __builtin_ctzll(a) #define __ONE 1LLU #define __ZERO 0LLU #define __LSHIFT64(VAL, N) VAL << N #define __RSHIFT64(VAL, N) VAL >> N #endif #define LBIT(N) (__LSHIFT64(__ONE, (63-N))) #define RBIT(N) (__LSHIFT64(__ONE, N)) #define SINGLE_BIT(N) RBIT(N) //#define REVERSE_ACTION_ITERATOR class BitSet { unsigned long long set; // 64 bit unsigned int to represent set public: BitSet() : set(0) {} // default constructor sets to zero BitSet(long long unsigned s) : set(s) {} // constructor which takes a uint64 // pops the next action (bit from the right) int popAction() { #ifdef REVERSE_ACTION_ITERATOR // get the number of trailing zeros int nextAction = 63 - __lz(set); #else // get the number of trailing zeros int nextAction = __tz(set); #endif // set that bit to a zero subtract(nextAction); return (Action)nextAction; } // peeks at the next action int nextAction() { #ifdef REVERSE_ACTION_ITERATOR // get the number of trailing zeros int nextAction = 63 - __lz(set); #else // get the number of trailing zeros int nextAction = __tz(set); #endif return nextAction; } int operator [] (const int bit) const { return set & SINGLE_BIT(bit) ? 1 : 0; } // get the bit at i BitSet operator + (const int bit) const { return BitSet(set | SINGLE_BIT(bit)); } // member addition BitSet operator - (const int bit) const { return BitSet(set & ~SINGLE_BIT(bit)); } // member subtraction BitSet operator | (const BitSet & a) const { return BitSet(set | a.set); } // set union BitSet operator + (const BitSet & a) const { return BitSet(set | a.set); } // set union BitSet operator - (const BitSet & a) const { return BitSet(set & ~a.set); } // set subtraction BitSet operator & (const BitSet & a) const { return BitSet(set & a.set); } // set intersection BitSet operator ~ () const { return BitSet(~set); } // set negation bool isEmpty () const { return set == __ZERO; } // the set is all zeros bool contains (const BitSet a) const { return (set & a.set) == a.set; } // completely contain another set bool contains (const int bit) const { return (set & SINGLE_BIT(bit)) != __ZERO;}// contains a bit set to 1 bool containsAny (const BitSet a) const { return (set & ~a.set) != set; } // does set contain any of bool containsNone (const BitSet a) const { return (set & ~a.set) == set; } // does set contain none of bool isSubsetOf (const BitSet a) const { return (a.set & set) == set; } // is a subset of another set int getBit (const int bit) const { return (set & SINGLE_BIT(bit)) ? 1 : 0; } // identical to contains void add (const int bit) { set |= SINGLE_BIT(bit); } // sets a bit to 1 void add (const BitSet a) { set |= a.set; } // sets all of input set to 1 void subtract (const int bit) { set &= ~SINGLE_BIT(bit); } // set bit to zero void subtract (const BitSet a) { set &= ~a.set; } // sets all of input set to 0 int countTrailingZeros(unsigned long long s) const { int zeros = 0; while (!(s & __ONE)) { s = __RSHIFT64(s,1); ++zeros; } return zeros; } int countLeadingZeros(unsigned long long s) const { int zeros = 0; unsigned long long __L_ONE = __LSHIFT64(__ONE, 63); while (!(s & __L_ONE)) { s = __LSHIFT64(s,1); ++zeros; } return zeros; } int numActions() const { BitSet t(set); int count(0); while (!t.isEmpty()) { t.popAction(); ++count; } return count; } int randomAction() const { BitSet s(set); int num = s.numActions(); if (num == 1) { return s.popAction(); } int r = (rand() % (s.numActions() - 1)); Action a = s.popAction(); for (int i=0; i & moveVec) { // not implemented } const size_t Player::ID() { return _playerID; } void Player::setID(const size_t & playerID) { _playerID = playerID; } ================================================ FILE: SparCraft/source/Player.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "MoveArray.h" #include "Unit.h" #include namespace SparCraft { class GameState; class Player { protected: size_t _playerID; public: virtual void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); const size_t ID(); void setID(const size_t & playerid); virtual size_t getType() { return PlayerModels::None; } }; class CompareUnitDPSThreat { const bool operator() (Unit * u1, Unit * u2) const { double u1Threat = ((double)u1->damage()/(double)u1->attackCooldown()) / u1->currentHP(); double u2Threat = ((double)u2->damage()/(double)u2->attackCooldown()) / u2->currentHP(); return u1Threat > u2Threat; } }; typedef std::shared_ptr PlayerPtr; } ================================================ FILE: SparCraft/source/PlayerProperties.cpp ================================================ #include "PlayerProperties.h" #include "WeaponProperties.h" using namespace SparCraft; PlayerProperties PlayerProperties::props[2]; PlayerProperties::PlayerProperties() { Reset(); } PlayerProperties::PlayerProperties(const BWAPI::Player & player) { Capture(player); } PlayerProperties & PlayerProperties::Get(const size_t & playerID) { return props[playerID]; } void PlayerProperties::Reset() { for(int i(0); i= 0 && level <= upgrade.maxRepeats()); upgradeLevel[upgrade.getID()] = level; } void PlayerProperties::SetResearched(BWAPI::TechType tech, bool researched) { assert(tech != BWAPI::TechTypes::None); assert(tech != BWAPI::TechTypes::Unknown); hasResearched[tech.getID()] = researched; } void PlayerProperties::Capture(const BWAPI::Player & player) { for(int i(0); igetUpgradeLevel(i); } for(int i(0); ihasResearched(i); } } int PlayerProperties::GetUpgradeLevel(BWAPI::UpgradeType upgrade) const { return upgradeLevel[upgrade.getID()]; } bool PlayerProperties::HasUpgrade(BWAPI::UpgradeType upgrade) const { return upgradeLevel[upgrade.getID()] > 0; } bool PlayerProperties::HasResearched(BWAPI::TechType tech) const { return hasResearched[tech.getID()]; } PlayerWeapon::PlayerWeapon(const PlayerProperties * player, BWAPI::WeaponType type) : player(player) , type(type) { } int PlayerWeapon::GetDamageBase() const { return SparCraft::WeaponProperties::Get(type).GetDamageBase(*player); } float PlayerWeapon::GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const { return SparCraft::WeaponProperties::Get(type).GetDamageMultiplier(targetSize); } int PlayerWeapon::GetCooldown() const { return SparCraft::WeaponProperties::Get(type).GetCooldown(*player); } int PlayerWeapon::GetMaxRange() const { return SparCraft::WeaponProperties::Get(type).GetMaxRange(*player); } ================================================ FILE: SparCraft/source/PlayerProperties.h ================================================ #pragma once #include "Common.h" namespace SparCraft { class PlayerProperties { enum { NUM_UPGRADES = 63, NUM_TECHS = 47 }; int upgradeLevel[NUM_UPGRADES]; bool hasResearched[NUM_TECHS]; static PlayerProperties props[2]; public: PlayerProperties(); PlayerProperties(const BWAPI::Player & player); int GetUpgradeLevel(BWAPI::UpgradeType upgrade) const; bool HasUpgrade(BWAPI::UpgradeType upgrade) const; bool HasResearched(BWAPI::TechType tech) const; void Reset(); void SetUpgradeLevel(BWAPI::UpgradeType upgrade, int level); void SetResearched(BWAPI::TechType tech, bool researched); void Capture(const BWAPI::Player & player); static PlayerProperties & Get(const size_t & playerID); }; class PlayerWeapon { const PlayerProperties * player; BWAPI::WeaponType type; public: PlayerWeapon(const PlayerProperties * player, BWAPI::WeaponType type); int GetDamageBase() const; float GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const; int GetCooldown() const; int GetMaxRange() const; }; } ================================================ FILE: SparCraft/source/Player_AlphaBeta.cpp ================================================ #include "Player_AlphaBeta.h" using namespace SparCraft; Player_AlphaBeta::Player_AlphaBeta (const size_t & playerID) { _playerID = playerID; } Player_AlphaBeta::Player_AlphaBeta (const size_t & playerID, const AlphaBetaSearchParameters & params, TTPtr table) { _playerID = playerID; _params = params; TT = table; alphaBeta = new AlphaBetaSearch(_params, TT); } Player_AlphaBeta::~Player_AlphaBeta() { delete alphaBeta; } AlphaBetaSearchResults & Player_AlphaBeta::results() { return alphaBeta->getResults(); } AlphaBetaSearchParameters & Player_AlphaBeta::getParams() { return _params; } void Player_AlphaBeta::setParameters(AlphaBetaSearchParameters & p) { _params = p; } void Player_AlphaBeta::setTranspositionTable(TTPtr table) { TT = table; } void Player_AlphaBeta::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); alphaBeta->doSearch(state); moveVec.assign(alphaBeta->getResults().bestMoves.begin(), alphaBeta->getResults().bestMoves.end()); } ================================================ FILE: SparCraft/source/Player_AlphaBeta.h ================================================ #pragma once #include "Common.h" #include "Player.h" #include "TranspositionTable.h" #include "AlphaBetaSearch.h" #include "AlphaBetaSearchParameters.hpp" #include "AlphaBetaSearchResults.hpp" namespace SparCraft { class AlphaBetaSearch; /*---------------------------------------------------------------------- | Alpha Beta Player |---------------------------------------------------------------------- | Runs Alpha Beta search given a set of search parameters `----------------------------------------------------------------------*/ class Player_AlphaBeta : public Player { AlphaBetaSearch * alphaBeta; TTPtr TT; AlphaBetaSearchParameters _params; public: Player_AlphaBeta (const size_t & playerID); Player_AlphaBeta (const size_t & playerID, const AlphaBetaSearchParameters & params, TTPtr table); virtual ~Player_AlphaBeta(); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); void setParameters(AlphaBetaSearchParameters & p); AlphaBetaSearchParameters & getParams(); void setTranspositionTable(TTPtr table); AlphaBetaSearchResults & results(); size_t getType() { return PlayerModels::AlphaBeta; } }; } ================================================ FILE: SparCraft/source/Player_AttackClosest.cpp ================================================ #include "Player_AttackClosest.h" using namespace SparCraft; Player_AttackClosest::Player_AttackClosest(const size_t & playerID) { _playerID = playerID; } void Player_AttackClosest::getMoves(GameState & state,const MoveArray & moves,std::vector & moveVec) { moveVec.clear(); for (size_t u(0); u::max()); unsigned long long closestMoveDist(std::numeric_limits::max()); const Unit & ourUnit(state.getUnit(_playerID,u)); const Unit & closestUnit(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID,u) : state.getClosestEnemyUnit(_playerID,u)); for (size_t m(0); m & moveVec); size_t getType() { return PlayerModels::AttackClosest; } }; ================================================ FILE: SparCraft/source/Player_AttackDPS.cpp ================================================ #include "Player_AttackDPS.h" using namespace SparCraft; Player_AttackDPS::Player_AttackDPS (const size_t & playerID) { _playerID = playerID; } void Player_AttackDPS::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } if (move.type() == ActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move.index())); double dpsHPValue = (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == ActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move.index()][0], ourUnit.y() + Constants::Move_Dir[move.index()][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex); moveVec.push_back(moves.getMove(u, bestMoveIndex)); } } ================================================ FILE: SparCraft/source/Player_AttackDPS.h ================================================ #pragma once #include "Common.h" #include "Player.h" namespace SparCraft { /*---------------------------------------------------------------------- | Attack HighestDPS Player |---------------------------------------------------------------------- | Chooses an action with following priority: | 1) If it can attack, ATTACK highest DPS/HP enemy unit in range | 2) If it cannot attack: | a) If it is in range to attack an enemy, WAIT until attack | b) If it is not in range of enemy, MOVE towards closest `----------------------------------------------------------------------*/ class Player_AttackDPS : public Player { public: Player_AttackDPS (const size_t & playerID); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::AttackDPS; } }; } ================================================ FILE: SparCraft/source/Player_AttackWeakest.cpp ================================================ #include "Player_AttackWeakest.h" using namespace SparCraft; Player_AttackWeakest::Player_AttackWeakest (const size_t & playerID) { _playerID = playerID; } void Player_AttackWeakest::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m & moveVec); size_t getType() { return PlayerModels::AttackWeakest; } }; } ================================================ FILE: SparCraft/source/Player_Cluster.cpp ================================================ #include "Player_Cluster.h" using namespace SparCraft; Player_Cluster::Player_Cluster (const size_t & playerID) { _playerID = playerID; } void Player_Cluster::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); size_t enemy(state.getEnemy(_playerID)); // compute the centroid of our unit cluster Position avgPos(0,0); for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); for (size_t m(0); m & moveVec); size_t getType() { return PlayerModels::Cluster; } }; } ================================================ FILE: SparCraft/source/Player_Kiter.cpp ================================================ #include "Player_Kiter.h" using namespace SparCraft; Player_Kiter::Player_Kiter (const size_t & playerID) { _playerID = playerID; } void Player_Kiter::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); for (size_t u(0); u::max()); unsigned long long closestMoveDist (std::numeric_limits::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } // the move we will be returning size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } } ================================================ FILE: SparCraft/source/Player_Kiter.h ================================================ #pragma once #include "Common.h" #include "Player.h" namespace SparCraft { /*---------------------------------------------------------------------- | Kiter Player |---------------------------------------------------------------------- | Chooses an action with following priority: | 1) If it can attack, ATTACK closest enemy unit | 2) If it cannot attack: | a) If it is in range to attack an enemy, move away from closest | b) If it is not in range of enemy, MOVE towards closest `----------------------------------------------------------------------*/ class Player_Kiter : public Player { public: Player_Kiter (const size_t & playerID); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::Kiter; } }; } ================================================ FILE: SparCraft/source/Player_KiterDPS.cpp ================================================ #include "Player_KiterDPS.h" using namespace SparCraft; Player_KiterDPS::Player_KiterDPS (const size_t & playerID) { _playerID = playerID; } void Player_KiterDPS::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move.index())); double dpsHPValue (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move.index()][0], ourUnit.y() + Constants::Move_Dir[move.index()][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist > furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } // the move we will be returning size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } } ================================================ FILE: SparCraft/source/Player_KiterDPS.h ================================================ #pragma once #include "Common.h" #include "Player.h" namespace SparCraft { /*---------------------------------------------------------------------- | Kiter DPS Player |---------------------------------------------------------------------- | Chooses an action with following priority: | 1) If it can attack, ATTACK highest DPS/HP enemy unit in range | 2) If it cannot attack: | a) If it is in range to attack an enemy, move away from closest one | b) If it is not in range of enemy, MOVE towards closest one `----------------------------------------------------------------------*/ class Player_KiterDPS : public Player { public: Player_KiterDPS (const size_t & playerID); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::KiterDPS; } }; } ================================================ FILE: SparCraft/source/Player_Kiter_NOKDPS.cpp ================================================ #include "Player_Kiter_NOKDPS.h" using namespace SparCraft; Player_Kiter_NOKDPS::Player_Kiter_NOKDPS (const size_t & playerID) { _playerID = playerID; } void Player_Kiter_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); size_t enemy(state.getEnemy(_playerID)); Array hpRemaining; for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m 0)) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } if (move.index() >= state.numUnits(enemy)) { int e = enemy; int pl = _playerID; printf("wtf\n"); } } else if (move.type() == ActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == ActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move.index()][0], ourUnit.y() + Constants::Move_Dir[move.index()][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist > furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } Action theMove(moves.getMove(u, actionMoveIndex)); if (theMove.type() == ActionTypes::ATTACK) { hpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage(); } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } } ================================================ FILE: SparCraft/source/Player_Kiter_NOKDPS.h ================================================ #pragma once #include "Common.h" #include "Player.h" namespace SparCraft { /*---------------------------------------------------------------------- | Attack HighestDPS Player No Overkill |---------------------------------------------------------------------- | Chooses an action with following priority: | 1) If it can attack, ATTACK highest DPS/HP enemy unit to overkill | 2) If it cannot attack: | a) If it is in range to attack an enemy, WAIT until attack | b) If it is not in range of enemy, MOVE towards closest `----------------------------------------------------------------------*/ class Player_Kiter_NOKDPS : public Player { public: Player_Kiter_NOKDPS (const size_t & playerID); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::Kiter_NOKDPS; } }; } ================================================ FILE: SparCraft/source/Player_NOKDPS.cpp ================================================ #include "Player_NOKDPS.h" using namespace SparCraft; Player_NOKDPS::Player_NOKDPS (const size_t & playerID) { _playerID = playerID; } void Player_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); size_t enemy(state.getEnemy(_playerID)); Array hpRemaining; for (size_t u(0); u::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : ourUnit.type().isDetector() ? state.getClosestEnemyUnit(_playerID, u, false):state.getClosestEnemyUnit(_playerID, u, true)); for (size_t m(0); m 0)) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } if (move.index() >= state.numUnits(enemy)) { int e = enemy; int pl = _playerID; printf("wtf\n"); } } else if (move.type() == ActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == ActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move.index()][0], ourUnit.y() + Constants::Move_Dir[move.index()][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex); Action theMove(moves.getMove(u, actionMoveIndex)); if (theMove.type() == ActionTypes::ATTACK) { hpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage(); } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } } ================================================ FILE: SparCraft/source/Player_NOKDPS.h ================================================ #pragma once #include "Common.h" #include "Player.h" namespace SparCraft { /*---------------------------------------------------------------------- | Attack HighestDPS Player No Overkill |---------------------------------------------------------------------- | Chooses an action with following priority: | 1) If it can attack, ATTACK highest DPS/HP enemy unit to overkill | 2) If it cannot attack: | a) If it is in range to attack an enemy, WAIT until attack | b) If it is not in range of enemy, MOVE towards closest `----------------------------------------------------------------------*/ class Player_NOKDPS : public Player { public: Player_NOKDPS (const size_t & playerID); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::NOKDPS; } }; } ================================================ FILE: SparCraft/source/Player_PortfolioGreedySearch.cpp ================================================ #include "Player_PortfolioGreedySearch.h" using namespace SparCraft; Player_PortfolioGreedySearch::Player_PortfolioGreedySearch (const size_t & playerID) { _playerID = playerID; _iterations = 1; _responses = 0; _seed = PlayerModels::NOKDPS; } Player_PortfolioGreedySearch::Player_PortfolioGreedySearch (const size_t & playerID, const size_t & seed, const size_t & iter, const size_t & responses, const size_t & timeLimit) { _playerID = playerID; _iterations = iter; _responses = responses; _seed = seed; _timeLimit = timeLimit; } void Player_PortfolioGreedySearch::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); PortfolioGreedySearch pgs(_playerID, _seed, _iterations, _responses, _timeLimit); moveVec = pgs.search(_playerID, state); } ================================================ FILE: SparCraft/source/Player_PortfolioGreedySearch.h ================================================ #pragma once #include "Common.h" #include "Player.h" #include "PortfolioGreedySearch.h" namespace SparCraft { class Player_PortfolioGreedySearch : public Player { size_t _seed; size_t _iterations; size_t _responses; size_t _timeLimit; public: Player_PortfolioGreedySearch (const size_t & playerID); Player_PortfolioGreedySearch (const size_t & playerID, const size_t & seed, const size_t & iter, const size_t & responses, const size_t & timeLimit); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::PortfolioGreedySearch; } }; } ================================================ FILE: SparCraft/source/Player_Random.cpp ================================================ #include "Player_Random.h" using namespace SparCraft; Player_Random::Player_Random (const size_t & playerID) : rand(0, std::numeric_limits::max(), Constants::Seed_Player_Random_Time ? static_cast(std::time(0)) : 0) { _playerID = playerID; } void Player_Random::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { for (size_t u(0); u & moveVec); size_t getType() { return PlayerModels::Random; } }; } ================================================ FILE: SparCraft/source/Player_UCT.cpp ================================================ #include "Player_UCT.h" using namespace SparCraft; Player_UCT::Player_UCT (const size_t & playerID, const UCTSearchParameters & params) { _playerID = playerID; _params = params; } void Player_UCT::getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec) { moveVec.clear(); UCTSearch uct(_params); uct.doSearch(state, moveVec); _prevResults = uct.getResults(); } UCTSearchParameters & Player_UCT::getParams() { return _params; } UCTSearchResults & Player_UCT::getResults() { return _prevResults; } ================================================ FILE: SparCraft/source/Player_UCT.h ================================================ #pragma once #include "Common.h" #include "Player.h" #include "AllPlayers.h" #include "UCTSearch.h" #include "UCTMemoryPool.hpp" namespace SparCraft { class Player_UCT : public Player { UCTSearchParameters _params; UCTSearchResults _prevResults; public: Player_UCT (const size_t & playerID, const UCTSearchParameters & params); void getMoves(GameState & state, const MoveArray & moves, std::vector & moveVec); size_t getType() { return PlayerModels::UCT; } UCTSearchParameters & getParams(); UCTSearchResults & getResults(); }; } ================================================ FILE: SparCraft/source/PortfolioGreedySearch.cpp ================================================ #include "PortfolioGreedySearch.h" using namespace SparCraft; PortfolioGreedySearch::PortfolioGreedySearch(const size_t & player, const size_t & enemyScript, const size_t & iter, const size_t & responses, const size_t & timeLimit) : _player(player) , _enemyScript(enemyScript) , _iterations(iter) , _responses(responses) , _totalEvals(0) , _timeLimit(timeLimit) { _playerScriptPortfolio.push_back(PlayerModels::NOKDPS); _playerScriptPortfolio.push_back(PlayerModels::KiterDPS); } std::vector PortfolioGreedySearch::search(const size_t & player, const GameState & state) { Timer t; t.start(); const size_t enemyPlayer(state.getEnemy(player)); // calculate the seed scripts for each player // they will be used to seed the initial root search size_t seedScript = calculateInitialSeed(player, state); size_t enemySeedScript = calculateInitialSeed(enemyPlayer, state); // set up the root script data UnitScriptData originalScriptData; setAllScripts(player, state, originalScriptData, seedScript); setAllScripts(enemyPlayer, state, originalScriptData, enemySeedScript); double ms = t.getElapsedTimeInMilliSec(); //printf("\nFirst Part %lf ms\n", ms); // do the initial root portfolio search for our player UnitScriptData currentScriptData(originalScriptData); doPortfolioSearch(player, state, currentScriptData); // iterate as many times as required for (size_t i(0); i<_responses; ++i) { // do the portfolio search to improve the enemy's scripts doPortfolioSearch(enemyPlayer, state, currentScriptData); // then do portfolio search again for us to improve vs. enemy's update doPortfolioSearch(player, state, currentScriptData); } // convert the script vector into a move vector and return it MoveArray moves; state.generateMoves(moves, player); std::vector moveVec; GameState copy(state); currentScriptData.calculateMoves(player, moves, copy, moveVec); _totalEvals = 0; return moveVec; } void PortfolioGreedySearch::doPortfolioSearch(const size_t & player, const GameState & state, UnitScriptData & currentScriptData) { Timer t; t.start(); // the enemy of this player const size_t enemyPlayer(state.getEnemy(player)); for (size_t i(0); i<_iterations; ++i) { // set up data for best scripts size_t bestScriptVec[Constants::Max_Units]; StateEvalScore bestScoreVec[Constants::Max_Units]; // for each unit that can move for (size_t unitIndex(0); unitIndex 0 && t.getElapsedTimeInMilliSec() > _timeLimit) { break; } const Unit & unit(state.getUnit(player, unitIndex)); // iterate over each script move that it can execute for (size_t sIndex(0); sIndex<_playerScriptPortfolio.size(); ++sIndex) { // set the current script for this unit currentScriptData.setUnitScript(unit, _playerScriptPortfolio[sIndex]); // evaluate the current state given a playout with these unit scripts StateEvalScore score = eval(player, state, currentScriptData); // if we have a better score, set it if (sIndex == 0 || score > bestScoreVec[unitIndex]) { bestScriptVec[unitIndex] = _playerScriptPortfolio[sIndex]; bestScoreVec[unitIndex] = score; } } // set the current vector to the best move for use in future simulations currentScriptData.setUnitScript(unit, bestScriptVec[unitIndex]); } } } size_t PortfolioGreedySearch::calculateInitialSeed(const size_t & player, const GameState & state) { size_t bestScript; StateEvalScore bestScriptScore; const size_t enemyPlayer(state.getEnemy(player)); // try each script in the portfolio for each unit as an initial seed for (size_t sIndex(0); sIndex<_playerScriptPortfolio.size(); ++sIndex) { UnitScriptData currentScriptData; // set the player's chosen script initially to the seed choice for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex) { currentScriptData.setUnitScript(state.getUnit(player, unitIndex), _playerScriptPortfolio[sIndex]); } // set the enemy units script choice to NOKDPS for (size_t unitIndex(0); unitIndex < state.numUnits(enemyPlayer); ++unitIndex) { currentScriptData.setUnitScript(state.getUnit(enemyPlayer, unitIndex), _enemyScript); } // evaluate the current state given a playout with these unit scripts StateEvalScore score = eval(player, state, currentScriptData); if (sIndex == 0 || score > bestScriptScore) { bestScriptScore = score; bestScript = _playerScriptPortfolio[sIndex]; } } return bestScript; } StateEvalScore PortfolioGreedySearch::eval(const size_t & player, const GameState & state, UnitScriptData & playerScriptsChosen) { const size_t enemyPlayer(state.getEnemy(player)); Game g(state, 100); g.playIndividualScripts(playerScriptsChosen); _totalEvals++; return g.getState().eval(player, SparCraft::EvaluationMethods::LTD2); } void PortfolioGreedySearch::setAllScripts(const size_t & player, const GameState & state, UnitScriptData & data, const size_t & script) { for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex) { data.setUnitScript(state.getUnit(player, unitIndex), script); } } /* std::vector PortfolioGreedySparCraft::search(const size_t & player, const GameState & state) { const size_t enemyPlayer(state.getEnemy(player)); GameState initialState(state); MoveArray moves; state.generateMoves(moves, player); size_t seedScript = calculateInitialSeed(player, state); UnitScriptData currentScriptData; // set the player's chosen script initially to the seed choice for (size_t unitIndex(0); unitIndex < state.numUnits(player); ++unitIndex) { currentScriptData.setUnitScript(state.getUnit(player, unitIndex), seedScript); } // set the enemy units script choice to the seed as well for (size_t unitIndex(0); unitIndex < state.numUnits(enemyPlayer); ++unitIndex) { currentScriptData.setUnitScript(state.getUnit(enemyPlayer, unitIndex), _enemyScript); } std::vector bestScriptVec(moves.numUnits(), seedScript); std::vector bestScoreVec(moves.numUnits()); // the current script vector we will be working with std::vector currentScriptVec(moves.numUnits(), seedScript); // for each unit that can move for (size_t unitIndex(0); unitIndex bestScoreVec[unitIndex]) { bestScriptVec[unitIndex] = _playerScriptPortfolio[sIndex]; bestScoreVec[unitIndex] = score; } } // set the current vector to the best move for use in future simulations currentScriptData.setUnitScript(unit, bestScriptVec[unitIndex]); } std::vector moveVec; currentScriptData.calculateMoves(player, moves, GameState(state), moveVec); return moveVec; }*/ ================================================ FILE: SparCraft/source/PortfolioGreedySearch.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "Player.h" #include "Game.h" #include "Action.h" #include "UnitScriptData.h" #include namespace SparCraft { typedef std::shared_ptr PlayerPtr; class PortfolioGreedySearch { protected: const size_t _player; const size_t _enemyScript; const size_t _iterations; const size_t _responses; std::vector _playerScriptPortfolio; size_t _totalEvals; size_t _timeLimit; void doPortfolioSearch(const size_t & player,const GameState & state,UnitScriptData & currentData); std::vector getMoveVec(const size_t & player,const GameState & state,const std::vector & playerScripts); StateEvalScore eval(const size_t & player,const GameState & state,UnitScriptData & playerScriptsChosen); size_t calculateInitialSeed(const size_t & player,const GameState & state); void setAllScripts(const size_t & player,const GameState & state,UnitScriptData & data,const size_t & script); public: PortfolioGreedySearch(const size_t & player, const size_t & enemyScript, const size_t & iter, const size_t & responses, const size_t & timeLimit); std::vector search(const size_t & player, const GameState & state); }; } ================================================ FILE: SparCraft/source/Position.hpp ================================================ #pragma once #include "Common.h" #include #include namespace SparCraft { class Position { // x,y location will be used for Units in a 'grid' PositionType _x, _y; public: Position() : _x(0) , _y(0) { } Position(const PositionType & x, const PositionType & y) : _x(x) , _y(y) { } Position(const BWAPI::Position & p) : _x(p.x) , _y(p.y) { } const bool operator < (const Position & rhs) const { return (x() < rhs.x()) || ((x() == rhs.x()) && y() < rhs.y()); } const bool operator == (const Position & rhs) const { return x() == rhs.x() && y() == rhs.y(); } const Position operator + (const Position & rhs) const { return Position(x() + rhs.x(), y() + rhs.y()); } const Position operator - (const Position & rhs) const { return Position(x() - rhs.x(), y() - rhs.y()); } const Position scale(const float & f) const { return Position((PositionType)(f * x()), (PositionType)(f * y())); } void scalePosition(const float & f) { _x = (PositionType)(f * _x); _y = (PositionType)(f * _y); } void addPosition(const Position & rhs) { _x += rhs.x(); _y += rhs.y(); } void subtractPosition(const Position & rhs) { _x -= rhs.x(); _y -= rhs.y(); } void moveTo(const Position & pos) { _x = pos.x(); _y = pos.y(); } void addPosition(const PositionType & x, const PositionType & y) { _x += x; _y += y; } void moveTo(const PositionType & x, const PositionType & y) { _x = x; _y = y; } const PositionType x() const { return _x; } const PositionType y() const { return _y; } const Position flipX() const { return Position(-_x,_y); } const Position flipY() const { return Position(_y,_x); } const float Q_rsqrt( float number ) const { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = * ( long * ) &y; // evil floating point bit level hacking i = 0x5f3759df - ( i >> 1 ); y = * ( float * ) &i; y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed return y; } const Position flip() const { return Position(-_x, -_y); } inline const PositionType getDistance(const Position & p) const { PositionType dX = x() - p.x(); PositionType dY = y() - p.y(); if (dX == 0) { return abs(dY); } else if (dY == 0) { return abs(dX); } else { return (PositionType)sqrt((float)(dX*dX - dY*dY)); } } inline const PositionType getDistanceSq(const Position & p) const { return (x()-p.x())*(x()-p.x()) + (y()-p.y())*(y()-p.y()); } void print() const { printf("Position = (%d, %d)\n", _x, _y); } const std::string getString() const { std::stringstream ss; ss << "(" << x() << ", " << y() << ")"; return ss.str(); } }; } ================================================ FILE: SparCraft/source/Random.hpp ================================================ #pragma once #include #include namespace SparCraft { class RandomInt; } class SparCraft::RandomInt { int _seed; int _min; int _max; public: RandomInt(int min, int max, int seed) : _seed(seed) , _min(min) , _max(max) { srand(seed); } int nextInt() { return ( rand() % (_max-_min) ) + _min; } }; ================================================ FILE: SparCraft/source/SparCraft.cpp ================================================ #include "SparCraft.h" namespace SparCraft { void init() { // Initialize Data for Attack Frame Animations SparCraft::AnimationFrameData::init(); // Initialize Random Data for State Hashing SparCraft::Hash::initHash(); // Initialize Weapon and Unit Property Data SparCraft::WeaponProperties::Init(); SparCraft::UnitProperties::Init(); // Initialize EnumData Class Types SparCraft::EnumDataInit(); } } ================================================ FILE: SparCraft/source/SparCraft.h ================================================ #pragma once #ifndef WIN32 #define APIENTRY #define APIENTRYP #endif #include "Common.h" #include "PlayerProperties.h" #include "UnitProperties.h" #include "Player.h" #include "AllPlayers.h" #include "Game.h" #include "GameState.h" #include "AnimationFrameData.h" namespace SparCraft { void init(); } ================================================ FILE: SparCraft/source/SparCraftAssert.cpp ================================================ #include "SparCraftAssert.h" #include "SparCraftException.h" #include using namespace SparCraft; namespace SparCraft { namespace Assert { const std::string currentDateTime() { time_t now = time(0); struct tm tstruct; char buf[80]; tstruct = *localtime(&now); strftime(buf, sizeof(buf), "%Y-%m-%d_%X", &tstruct); for (size_t i(0); i < strlen(buf); ++i) { if (buf[i] == ':') { buf[i] = '-'; } } return buf; } void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...) { std::cerr << "Assertion thrown!\n"; char messageBuffer[4096] = ""; if (msg != NULL) { va_list args; va_start(args, msg); vsprintf(messageBuffer, msg, args); va_end(args); } std::stringstream ss; ss << std::endl; ss << "!Assert: " << condition << std::endl; ss << "File: " << file << std::endl; ss << "Message: " << messageBuffer << std::endl; ss << "Line: " << line << std::endl; #if !defined(EMSCRIPTEN) std::cerr << ss.str(); throw SparCraftException(ss.str(), state); #else printf("C++ AI: AI Exception Thrown:\n %s\n", ss.str().c_str()); throw SparCraftException(ss.str()); #endif } } } ================================================ FILE: SparCraft/source/SparCraftAssert.h ================================================ #pragma once #include "Common.h" #include #include namespace SparCraft { class GameState; namespace Assert { const std::string currentDateTime(); void ReportFailure(const GameState * state, const char * condition, const char * file, int line, const char * msg, ...); } } #define SPARCRAFT_ASSERT_ENABLE #ifdef SPARCRAFT_ASSERT_ENABLE #define SPARCRAFT_ASSERT(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ SparCraft::Assert::ReportFailure(nullptr, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ } \ } while(0) #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) \ do \ { \ if (!(cond)) \ { \ SparCraft::Assert::ReportFailure(&state, #cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ } \ } while(0) #else #define SPARCRAFT_ASSERT(cond, msg, ...) #define SPARCRAFT_ASSERT_STATE(cond, state, filename, msg, ...) #endif ================================================ FILE: SparCraft/source/SparCraftException.cpp ================================================ #include "SparCraftException.h" using namespace SparCraft; SparCraftException::SparCraftException(std::string ss) : _s(ss) , _hasState(false) { } SparCraftException::SparCraftException(std::string ss, const GameState * state) : _s(ss) , _hasState(false) { if (state != nullptr) { _state = *state; _hasState = true; } } SparCraftException::~SparCraftException() throw () { } const char* SparCraftException::what() const throw() { return _s.c_str(); } bool SparCraftException::hasState() const { return _hasState; } const GameState & SparCraftException::getState() const { return _state; } ================================================ FILE: SparCraft/source/SparCraftException.h ================================================ #pragma once #include "Common.h" #include "GameState.h" namespace SparCraft { class SparCraftException : public std::exception { std::string _s; GameState _state; bool _hasState; public : SparCraftException(std::string ss, const GameState * state); SparCraftException(std::string ss); ~SparCraftException() throw (); const char* what() const throw(); bool hasState() const; const GameState & getState() const; }; } ================================================ FILE: SparCraft/source/Timer.cpp ================================================ #include "Timer.h" using namespace SparCraft; Timer::Timer() { #ifdef WIN32 QueryPerformanceFrequency(&frequency); startCount.QuadPart = 0; endCount.QuadPart = 0; #else startCount.tv_sec = startCount.tv_usec = 0; endCount.tv_sec = endCount.tv_usec = 0; #endif stopped = 0; startTimeInMicroSec = 0; endTimeInMicroSec = 0; start(); } Timer::~Timer() {} // default destructor void Timer::start() { stopped = 0; // reset stop flag #ifdef WIN32 QueryPerformanceCounter(&startCount); #else gettimeofday(&startCount, NULL); #endif } void Timer::stop() { stopped = 1; // set timer stopped flag #ifdef WIN32 QueryPerformanceCounter(&endCount); #else gettimeofday(&endCount, NULL); #endif } double Timer::getElapsedTimeInMicroSec() { #ifdef WIN32 if(!stopped) QueryPerformanceCounter(&endCount); startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart); endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart); #else if(!stopped) gettimeofday(&endCount, NULL); startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec; endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec; #endif return endTimeInMicroSec - startTimeInMicroSec; } double Timer::getElapsedTimeInMilliSec() { return this->getElapsedTimeInMicroSec() * 0.001; } double Timer::getElapsedTimeInSec() { return this->getElapsedTimeInMicroSec() * 0.000001; } double Timer::getElapsedTime() { return this->getElapsedTimeInSec(); } ================================================ FILE: SparCraft/source/Timer.h ================================================ ////////////////////////////////////////////////////////////////////////////// // Timer.h // ======= // High Resolution Timer. // This timer is able to measure the elapsed time with 1 micro-second accuracy // in both Windows, Linux and Unix system // // AUTHOR: Song Ho Ahn (song.ahn@gmail.com) // CREATED: 2003-01-13 // UPDATED: 2006-01-13 // // Copyright (c) 2003 Song Ho Ahn ////////////////////////////////////////////////////////////////////////////// // Modified by: David Churchill (dave.churchill@gmail.com) // For academic use (2011) ////////////////////////////////////////////////////////////////////////////// #pragma once #ifdef WIN32 // Windows system specific #include #else // Unix based system specific #include #endif #include "Common.h" namespace SparCraft { class Timer { double startTimeInMicroSec; // starting time in micro-second double endTimeInMicroSec; // ending time in micro-second int stopped; // stop flag #ifdef WIN32 LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER startCount; // LARGE_INTEGER endCount; // #else timeval startCount; // timeval endCount; // #endif public: Timer(); ~Timer(); void start(); void stop(); double getElapsedTimeInMicroSec(); double getElapsedTimeInMilliSec(); double getElapsedTimeInSec(); double getElapsedTime(); }; } ================================================ FILE: SparCraft/source/TranspositionTable.cpp ================================================ #include "TranspositionTable.h" using namespace SparCraft; TTEntry::TTEntry() : _hash2(0) , _depth(0) , _type(TTEntry::NONE) { } TTEntry::TTEntry(const HashType & hash2, const StateEvalScore & score, const size_t & depth, const int & type, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) : _hash2(hash2) , _score(score) , _depth(depth) , _type(type) { _bestMoves[firstPlayer] = TTBestMove(bestFirstMove, bestSecondMove); } const bool TTEntry::hashMatches(const HashType & hash2) const { return hash2 == _hash2; } const bool TTEntry::isValid() const { return _type != TTEntry::NONE; } const HashType & TTEntry::getHash() const { return _hash2; } const StateEvalScore & TTEntry::getScore() const { return _score; } const size_t & TTEntry::getDepth() const { return _depth; } const int & TTEntry::getType() const { return _type; } const TTBestMove & TTEntry::getBestMove(const size_t & player) const { return _bestMoves[player]; } void TTEntry::setBestMove(const size_t &firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) { _bestMoves[firstPlayer] = TTBestMove(bestFirstMove, bestSecondMove); } TranspositionTable::TranspositionTable () : TT(Constants::Transposition_Table_Size, TTEntry()) , size(Constants::Transposition_Table_Size) , collisions(0) , lookups(0) , found(0) , notFound(0) , saves(0) , minIndex(0) , maxIndex(0) , saveOverwriteSelf(0) , saveOverwriteOther(0) , saveEmpty(0) { } const TTEntry & TranspositionTable::operator [] (const size_t & hash) const { return TT[getIndex(hash)]; } const TTEntry & TranspositionTable::get(const size_t & hash) const { return TT[getIndex(hash)]; } const size_t TranspositionTable::getSaveIndex(const size_t & index, const HashType & hash2, const size_t & depth) const { size_t worstDepth(1000); size_t worstDepthIndex(index); // scan ahead to find the best spot to store this entryw for (size_t i(index); (i<(index+Constants::Transposition_Table_Scan)) && (i depth) { printf("We shouldn't get here\n"); } // otherwise if this entry is empty, use it else if (!TT[i].isValid()) { return i; } // otherwise if the hashes don't match, check to see how old the data is else if (TT[i].getHash() != hash2) { if (TT[i].getDepth() < worstDepth) { worstDepth = TT[i].getDepth(); worstDepthIndex = i; } } } return worstDepthIndex; } void TranspositionTable::save( const HashType & hash1, const HashType & hash2, const StateEvalScore & value, const size_t & depth, const int & type, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) { size_t indexToSave = getSaveIndex(getIndex(hash1), hash2, depth); TTEntry existing = TT[indexToSave]; if (existing.isValid()) { if (existing.getHash() == hash2) { saveOverwriteSelf++; } else { saveOverwriteOther++; } } else { saveEmpty++; } saves++; TT[indexToSave] = TTEntry(hash2, value, depth, type, firstPlayer, bestFirstMove, bestSecondMove); } TTEntry * TranspositionTable::lookupScan(const HashType & hash1, const HashType & hash2) { lookups++; size_t index = getIndex(hash1); // scan to see if this exists anywhere in the next few entries for (size_t i(index); (i<(index+Constants::Transposition_Table_Scan)) && (i maxIndex) maxIndex = index; TTEntry tte = TT[index]; // if there is a valid entry at that location if (TT[index].isValid()) { // test for matching secondary hash if (TT[index].hashMatches(hash2)) { found++; return &TT[index]; } // if no match it is a collision else { //collisions++; return NULL; } } else { //notFound++; return NULL; } } const size_t & TranspositionTable::getSize() const { return size; } const size_t & TranspositionTable::numFound() const { return found; } const size_t & TranspositionTable::numNotFound() const { return notFound; } const size_t & TranspositionTable::numCollisions() const { return collisions; } const size_t & TranspositionTable::numSaves() const { return saves; } const size_t & TranspositionTable::numLookups() const { return lookups; } const size_t TranspositionTable::getUsage() const { size_t sum(0); for (size_t i(0); i #include "Common.h" #include "GameState.h" #include "Action.h" #include "AlphaBetaMove.h" #include namespace SparCraft { class TTEntry { public: enum { NONE, UPPER, LOWER, ACCURATE }; private: HashType _hash2; StateEvalScore _score; size_t _depth; TTBestMove _bestMoves[2]; int _type; public: TTEntry(); TTEntry(const HashType & hash2, const StateEvalScore & score, const size_t & depth, const int & type, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove); const bool hashMatches(const HashType & hash2) const; const bool isValid() const; const HashType & getHash() const; const StateEvalScore & getScore() const; const size_t & getDepth() const; const int & getType() const; const TTBestMove & getBestMove(const size_t & player) const; void setBestMove(const size_t &firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove); void print() const { printf ("%d, %d, %d, %d\n", (int) _hash2, (int) _score.val(), (int) _depth, (int) _type); } }; class TTLookupValue { bool _found; // did we find a value? bool _cut; // should we produce a cut? TTEntry * _entry; // the entry we found public: TTLookupValue() : _found(false) , _cut(false) , _entry(NULL) { } TTLookupValue(const bool found, const bool cut, TTEntry * entry) : _found(found) , _cut(cut) , _entry(entry) { } const bool found() const { return _found; } const bool cut() const { return _cut; } TTEntry * entry() const { return _entry; } }; class TranspositionTable { //Array TT; //TTEntry TT[Constants::Transposition_Table_Size]; std::vector TT; size_t size; size_t minIndex, maxIndex; const size_t getIndex(const HashType & hash1) const { return hash1 % size; } public: size_t collisions, lookups, found, notFound, saves, saveOverwriteSelf, saveOverwriteOther, saveEmpty; TranspositionTable (); const TTEntry & operator [] (const size_t & hash) const; const TTEntry & get(const size_t & hash) const; void save(const HashType & hash1, const TTEntry & entry) ; void save( const HashType & hash1, const HashType & hash2, const StateEvalScore & value, const size_t & depth, const int & type, const size_t & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove); TTEntry * lookup(const size_t & index, const HashType & hash2); TTEntry * lookupScan(const HashType & hash1, const HashType & hash2); const size_t & getSize() const; const size_t & numFound() const; const size_t & numNotFound() const; const size_t & numCollisions() const; const size_t & numSaves() const; const size_t & numLookups() const; const size_t getUsage() const; const size_t getSaveIndex(const size_t & index, const HashType & hash2, const size_t & depth) const; void print(); }; typedef std::shared_ptr TTPtr; } ================================================ FILE: SparCraft/source/TutorialCode.cpp ================================================ #include "SparCraft.h" using namespace SparCraft; // IMPORTANT: // Consult BaseTypes.hpp for all important variable typedefs // Consult Common.h for all important constant and enum values Unit getSampleUnit() { // Unit has several constructors // You will typically only be using this one to construct a 'starting' unit // Unit(const BWAPI::UnitType unitType, const IDType & playerID, const Position & pos) // The BWAPI::UnitType of the unit to be added BWAPI::UnitType marine = BWAPI::UnitTypes::Terran_Marine; // The player to add this unit to, specified by an IDType IDType player = Players::Player_One; // A Position, measured in Pixel coordinates Position p(0,0); // Simple unit constructor Unit marineAtOrigin(marine, player, p); return marineAtOrigin; } GameState getSampleState() { // GameState only has a default constructor, you must add units to it manually GameState state; // The recommended way of adding a unit to a state is to just construct a unit and add it with: state.addUnit(getSampleUnit()); // Or it can be added to the state via unit construction parameters state.addUnit(BWAPI::UnitTypes::Terran_Marine, Players::Player_One, Position(10,10)); state.addUnit(BWAPI::UnitTypes::Protoss_Dragoon, Players::Player_Two, Position(40,40)); // Units added with those 2 functions will be given a unique unitID inside GameState // If you require setting your own unique unitID for a unit, for example when translating a BWAPI::Broodwar state to GameState // Construct the unit Unit u(BWAPI::UnitTypes::Terran_Marine, Players::Player_One, Position(0,0)); // Set the unitID u.setUnitID(5); // Add it to the state and tell it not to change the unitID. // If a state contains two units with the same ID, an error will occur state.addUnitWithID(u); return state; } Map getSampleMap() { // Maps are used to constrain the movement of Units on a battlefield // There are 3 resolution scales at which positions operate in StarCraft maps // Pixel Resolution = 1x1 pixel = StarCraft smallest movement resolution // WalkTile Resolution = 8x8 pixels = StarCraft 'walkable' resolution // BuildTile Resolution = 32x32 pixels, or 4x4 WalkTiles = StarCraft "map size" resolution // Example: A Map of size 32*32 BuildTiles has size 128*128 WalkTiles or 1024*1024 pixels // The Map object constructor takes in size coordinates in BWAPI BuildTile resolution Map smallMap(32, 32); // We can set the walkable values of WalkTile resolution via // void setMapData(const size_t & buildTileX, const size_t & buildTileY, const bool val) smallMap.setMapData(21, 98, false); // The default map sets all tiles to walkable, with an upper-left boundary of (0,0) and a lower-right boundary of (x,y) // We can query whether or not a unit can walk at a given position bool canWalkHere = smallMap.isWalkable(Position(100, 30)); // You can also construct a Map from a BWAPI::Game object, if you are using this code from within a bot // Map gameMap(BWAPI::BroodWar) // Once constructed, maps can be saved or loaded to files // A sample map (Destination) is provided under the sample_experiment directory // smallMap.load("mapname.txt"); // We can set the Map of a GameState via a pointer to the map, as Map objects can be quite large: GameState state(getSampleState()); state.setMap(&smallMap); return smallMap; } // When dealing with players, use a shared pointer, it's safer // PlayerPtr is a boost::shared_pointer wrapper for Player * PlayerPtr getSamplePlayer(const IDType playerID) { // Player is the base class for all Player objects // // Scripted players all have the same constructor which is just the player ID which will be using this script // It is imoprtant to set that player ID correctly, as that player will only be generating and returning moves for that player PlayerPtr attackClosest(new Player_AttackClosest(playerID)); return attackClosest; } std::vector getSamplePlayerActionsFromState() { // get our sample player IDType currentPlayerID = Players::Player_One; PlayerPtr myPlayer = getSamplePlayer(currentPlayerID); // Construct a blank vector of Actions, which are individual unit moves std::vector move; // Get a state GameState state = getSampleState(); // Construct a MoveArray. This structure will hold all the legal moves for each unit possible for this state MoveArray moveArray; // Generate the moves possible by currentPlayer from state into moveArray state.generateMoves(moveArray, currentPlayerID); // Call getMoves with these arguments myPlayer->getMoves(state, moveArray, move); return move; } void runSampleGame() { // running a game is quite simple, you just need 2 players and an initial state GameState initialState = getSampleState(); // get the players PlayerPtr p1 = getSamplePlayer(Players::Player_One); PlayerPtr p2 = getSamplePlayer(Players::Player_Two); // enter a maximum move limit for the game to go on for int moveLimit = 1000; // contruct the game Game g(initialState, p1, p2, moveLimit); // play the game g.play(); // you can access the resulting game state after g has been played via getState GameState finalState = g.getState(); // you can now evaluate the state however you wish. let's use an LTD2 evaluation from the point of view of player one StateEvalScore score = finalState.eval(Players::Player_One, EvaluationMethods::LTD2); // StateEvalScore has two components, a numerical score and a number of Movement actions performed by each player // with this evaluation, positive val means win, negative means loss, 0 means tie if (score.val() > 0) { std::cout << "Player One Wins!\n"; } else if (score.val() < 0) { std::cout << "Player Two Wins!\n"; } else { std::cout << "Game is a draw!\n"; } } ================================================ FILE: SparCraft/source/UCTMemoryPool.hpp ================================================ #pragma once #include "Common.h" #include "UCTNode.h" namespace SparCraft { class UCTMemoryPool; } class SparCraft::UCTMemoryPool { std::vector< std::vector > _pool; const size_t _poolSize; const size_t _maxChildren; size_t _currentIndex; public: UCTMemoryPool(const size_t & poolSize, const size_t & maxChildren) : _pool (poolSize, std::vector()) , _poolSize (poolSize) , _maxChildren (maxChildren) , _currentIndex (0) { for (size_t s(0); s * alloc() { std::vector & ret(_pool[_currentIndex]); if (ret.size() > 0) { ret.clear(); } _currentIndex = (_currentIndex + 1) % _poolSize; return &ret; } void clearPool() { for (size_t i(0); i<_poolSize; ++i) { _pool[i].clear(); } _currentIndex = 0; } }; ================================================ FILE: SparCraft/source/UCTNode.h ================================================ #pragma once #include "Common.h" #include "Action.h" namespace SparCraft { class UCTNode { // uct stat counting variables size_t _numVisits; // total visits to this node double _numWins; // wins from this node double _uctVal; // previous computed UCT value // game specific variables size_t _player; // the player who made a move to generate this node size_t _nodeType; std::vector _move; // the ove that generated this node // holds children std::vector _children; // nodes for traversing the tree UCTNode * _parent; public: UCTNode () : _numVisits (0) , _numWins (0) , _uctVal (0) , _player (Players::Player_None) , _nodeType (SearchNodeType::Default) , _parent (NULL) { } UCTNode (UCTNode * parent, const size_t player, const size_t nodeType, const std::vector & move, const size_t & maxChildren, std::vector * fromPool = NULL) : _numVisits (0) , _numWins (0) , _uctVal (0) , _player (player) , _nodeType (nodeType) , _move (move) , _parent (parent) { _children.reserve(maxChildren); } const size_t numVisits() const { return _numVisits; } const double numWins() const { return _numWins; } const size_t numChildren() const { return _children.size(); } const double getUCTVal() const { return _uctVal; } const bool hasChildren() const { return numChildren() > 0; } const size_t getNodeType() const { return _nodeType; } const size_t getPlayer() const { return _player; } UCTNode * getParent() const { return _parent; } UCTNode & getChild(const size_t & c) { return _children[c]; } void setUCTVal(double val) { _uctVal = val; } void incVisits() { _numVisits++; } void addWins(double val) { _numWins += val; } std::vector & getChildren() { return _children; } const std::vector & getMove() const { return _move; } void setMove(const std::vector & move) { _move = move; } void addChild(UCTNode * parent, const size_t player, const size_t nodeType, const std::vector & move, const size_t & maxChildren, std::vector * fromPool = NULL) { _children.push_back(UCTNode(parent, player, nodeType, move, maxChildren)); } UCTNode & mostVisitedChild() { UCTNode * mostVisitedChild = NULL; size_t mostVisits = 0; for (size_t c(0); c < numChildren(); ++c) { UCTNode & child = getChild(c); if (!mostVisitedChild || (child.numVisits() > mostVisits)) { mostVisitedChild = &child; mostVisits = child.numVisits(); } } return *mostVisitedChild; } UCTNode & bestUCTValueChild(const bool maxPlayer, const UCTSearchParameters & params) { UCTNode * bestChild = NULL; double bestVal = maxPlayer ? std::numeric_limits::min() : std::numeric_limits::max(); for (size_t c(0); c < numChildren(); ++c) { UCTNode & child = getChild(c); double winRate = (double)child.numWins() / (double)child.numVisits(); double uctVal = params.cValue() * sqrt( log( (double)numVisits() ) / ( child.numVisits() ) ); double currentVal = maxPlayer ? (winRate + uctVal) : (winRate - uctVal); if (maxPlayer) { if (currentVal > bestVal) { bestVal = currentVal; bestChild = &child; } } else if (currentVal < bestVal) { bestVal = currentVal; bestChild = &child; } } return *bestChild; } }; } ================================================ FILE: SparCraft/source/UCTSearch.cpp ================================================ #include "UCTSearch.h" using namespace SparCraft; UCTSearch::UCTSearch(const UCTSearchParameters & params) : _params(params) , _memoryPool(NULL) { for (size_t p(0); p & move) { Timer t; t.start(); _rootNode = UCTNode(NULL, Players::Player_None, SearchNodeType::RootNode, _actionVec, _params.maxChildren(), _memoryPool ? _memoryPool->alloc() : NULL); // do the required number of traversals for (size_t traversals(0); traversals < _params.maxTraversals(); ++traversals) { GameState state(initialState); traverse(_rootNode, state); if (traversals && (traversals % 5 == 0)) { if (_params.timeLimit() && (t.getElapsedTimeInMilliSec() >= _params.timeLimit())) { break; } } _results.traversals++; //printSubTree(_rootNode, initialState, "__uct.txt"); //system("\"C:\\Program Files (x86)\\Graphviz2.30\\bin\\dot.exe\" < __uct.txt -Tpng > uct.png"); } // choose the move to return if (_params.rootMoveSelectionMethod() == UCTMoveSelect::HighestValue) { move = _rootNode.bestUCTValueChild(true, _params).getMove(); } else if (_params.rootMoveSelectionMethod() == UCTMoveSelect::MostVisited) { move = _rootNode.mostVisitedChild().getMove(); } if (_params.graphVizFilename().length() > 0) { //printSubTree(_rootNode, initialState, _params.graphVizFilename()); //system("\"C:\\Program Files (x86)\\Graphviz2.30\\bin\\dot.exe\" < __uct.txt -Tpng > uct.png"); } double ms = t.getElapsedTimeInMilliSec(); _results.timeElapsed = ms; //printf("Search took %lf ms\n", ms); //printf("Hello\n"); } const bool UCTSearch::searchTimeOut() { return (_params.timeLimit() && (_searchTimer.getElapsedTimeInMilliSec() >= _params.timeLimit())); } const bool UCTSearch::terminalState(GameState & state, const size_t & depth) const { return (depth <= 0 || state.isTerminal()); } void UCTSearch::generateOrderedMoves(GameState & state, MoveArray & moves, const size_t & playerToMove) { _orderedMoves.clear(); // if we are using opponent modeling, get the move and then return, we don't want to put any more moves in if (_params.playerModel(playerToMove) != PlayerModels::None) { // put the vector into the ordered moves array _orderedMoves.add(std::vector()); // generate the moves into that vector _playerModels[playerToMove]->getMoves(state, moves, _orderedMoves[0]); return; } // if we are using script move ordering, insert the script moves we want if (_params.moveOrderingMethod() == MoveOrderMethod::ScriptFirst) { for (size_t s(0); s<_params.getOrderedMoveScripts().size(); s++) { std::vector moveVec; _allScripts[playerToMove][s]->getMoves(state, moves, moveVec); _orderedMoves.add(moveVec); } } } const size_t UCTSearch::getChildNodeType(UCTNode & parent, const GameState & prevState) const { if (!prevState.bothCanMove()) { return SearchNodeType::SoloNode; } else { if (parent.getNodeType() == SearchNodeType::RootNode) { return SearchNodeType::FirstSimNode; } else if (parent.getNodeType() == SearchNodeType::SoloNode) { return SearchNodeType::FirstSimNode; } else if (parent.getNodeType() == SearchNodeType::SecondSimNode) { return SearchNodeType::FirstSimNode; } else if (parent.getNodeType() == SearchNodeType::FirstSimNode) { return SearchNodeType::SecondSimNode; } } return SearchNodeType::Default; } const bool UCTSearch::getNextMove(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, std::vector & actionVec) { if (moveNumber > _params.maxChildren()) { return false; } // if this move is beyond the first, check to see if we are only using a single move if (moveNumber == 1) { // if we are player modeling, we should have only generated the first move if (_params.playerModel(playerToMove) != PlayerModels::None) { // so return false return false; } } actionVec.clear(); // if this move should be from the ordered list, return it from the list if (moveNumber < _orderedMoves.size()) { actionVec.assign(_orderedMoves[moveNumber].begin(), _orderedMoves[moveNumber].end()); return true; } // otherwise return the next move vector starting from the beginning else { if (moves.hasMoreMoves()) { moves.getNextMoveVec(actionVec); return true; } else { return false; } } } const size_t UCTSearch::getPlayerToMove(UCTNode & node, const GameState & state) const { const size_t whoCanMove(state.whoCanMove()); // if both players can move if (whoCanMove == Players::Player_Both) { // pick the first move based on our policy const size_t policy(_params.playerToMoveMethod()); const size_t maxPlayer(_params.maxPlayer()); // the max player always chooses at the root if (isRoot(node)) { return maxPlayer; } // the type of node this is const size_t nodeType = node.getNodeType(); // the 2nd player in a sim move is always the enemy of the first if (nodeType == SearchNodeType::FirstSimNode) { return state.getEnemy(node.getPlayer()); } // otherwise use our policy to see who goes first in a sim move state else { if (policy == SparCraft::PlayerToMove::Alternate) { return state.getEnemy(node.getPlayer()); } else if (policy == SparCraft::PlayerToMove::Not_Alternate) { return node.getPlayer(); } else if (policy == SparCraft::PlayerToMove::Random) { return rand() % 2; } // we should never get to this state System::FatalError("UCT Error: Nobody can move for some reason"); return Players::Player_None; } } else { return whoCanMove; } } UCTNode & UCTSearch::UCTNodeSelect(UCTNode & parent) { UCTNode * bestNode = NULL; bool maxPlayer = isRoot(parent) || (parent.getChild(0).getPlayer() == _params.maxPlayer()); double bestVal = maxPlayer ? std::numeric_limits::min() : std::numeric_limits::max(); // loop through each child to find the best node for (size_t c(0); c < parent.numChildren(); ++c) { UCTNode & child = parent.getChild(c); double currentVal(0); // if we have visited this node already, get its UCT value if (child.numVisits() > 0) { double winRate = (double)child.numWins() / (double)child.numVisits(); double uctVal = _params.cValue() * sqrt( log( (double)parent.numVisits() ) / ( child.numVisits() ) ); currentVal = maxPlayer ? (winRate + uctVal) : (winRate - uctVal); child.setUCTVal(currentVal); } else { // if we haven't visited it yet, return it and visit immediately return child; } // choose the best node depending on max or min player if (maxPlayer) { if (currentVal > bestVal) { bestVal = currentVal; bestNode = &child; } } else if (currentVal < bestVal) { bestVal = currentVal; bestNode = &child; } } return *bestNode; } void UCTSearch::updateState(UCTNode & node, GameState & state, bool isLeaf) { // if it's the first sim move with children, or the root node if ((node.getNodeType() != SearchNodeType::FirstSimNode) || isLeaf) { // if this is a second sim node if (node.getNodeType() == SearchNodeType::SecondSimNode) { // make the parent's moves on the state because they haven't been done yet state.makeMoves(node.getParent()->getMove()); } // do the current node moves and call finished moving state.makeMoves(node.getMove()); state.finishedMoving(); } } StateEvalScore UCTSearch::traverse(UCTNode & node, GameState & currentState) { StateEvalScore playoutVal; _results.totalVisits++; // if we haven't visited this node yet, do a playout if (node.numVisits() == 0) { // update the status of the current state with this node's moves //updateState(node, currentState, !node.hasChildren()); updateState(node, currentState, true); // do the playout playoutVal = currentState.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two)); _results.nodesVisited++; } // otherwise we have seen this node before else { // update the state for a non-leaf node updateState(node, currentState, false); if (currentState.isTerminal()) { playoutVal = currentState.eval(_params.maxPlayer(), EvaluationMethods::LTD2); } else { // if the children haven't been generated yet if (!node.hasChildren()) { generateChildren(node, currentState); } UCTNode & next = UCTNodeSelect(node); playoutVal = traverse(next, currentState); } } node.incVisits(); if (playoutVal.val() > 0) { node.addWins(1); } else if (playoutVal.val() == 0) { node.addWins(0.5); } return playoutVal; } // generate the children of state 'node' // state is the GameState after node's moves have been performed void UCTSearch::generateChildren(UCTNode & node, GameState & state) { // figure out who is next to move in the game const size_t playerToMove(getPlayerToMove(node, state)); // generate all the moves possible from this state state.generateMoves(_moveArray, playerToMove); _moveArray.shuffleMoveActions(); // generate the 'ordered moves' for move ordering generateOrderedMoves(state, _moveArray, playerToMove); // for each child of this state, add a child to the current node for (size_t child(0); (child < _params.maxChildren()) && getNextMove(playerToMove, _moveArray, child, _actionVec); ++child) { // add the child to the tree node.addChild(&node, playerToMove, getChildNodeType(node, state), _actionVec, _params.maxChildren(), _memoryPool ? _memoryPool->alloc() : NULL); _results.nodesCreated++; } } StateEvalScore UCTSearch::performPlayout(GameState & state) { GameState copy(state); copy.finishedMoving(); return copy.eval(_params.maxPlayer(), _params.evalMethod(), _params.simScript(Players::Player_One), _params.simScript(Players::Player_Two)); } const bool UCTSearch::isRoot(UCTNode & node) const { return &node == &_rootNode; } void UCTSearch::printSubTree(UCTNode & node, GameState s, std::string filename) { std::ofstream out(filename.c_str()); GraphViz::Graph G("g"); G.set("bgcolor", "#ffffff"); printSubTreeGraphViz(node, G, s); G.print(out); } void UCTSearch::printSubTreeGraphViz(UCTNode & node, GraphViz::Graph & g, GameState state) { if (node.getNodeType() == SearchNodeType::FirstSimNode && node.hasChildren()) { // don't make any moves if it is a first simnode } else { if (node.getNodeType() == SearchNodeType::SecondSimNode) { state.makeMoves(node.getParent()->getMove()); } state.makeMoves(node.getMove()); state.finishedMoving(); } std::stringstream label; std::stringstream move; for (size_t a(0); a 0) { GraphViz::Edge edge(getNodeIDString(node), getNodeIDString(child)); g.addEdge(edge); printSubTreeGraphViz(child, g, state); } } } std::string UCTSearch::getNodeIDString(UCTNode & node) { std::stringstream ss; ss << (unsigned long long)&node; return ss.str(); } UCTSearchResults & UCTSearch::getResults() { return _results; } ================================================ FILE: SparCraft/source/UCTSearch.h ================================================ #pragma once #include #include "Timer.h" #include "GameState.h" #include "Action.h" #include "GraphViz.hpp" #include "Array.hpp" #include "MoveArray.h" #include "UCTSearchParameters.hpp" #include "UCTSearchResults.hpp" #include "Player.h" #include "AllPlayers.h" #include "UCTNode.h" #include "GraphViz.hpp" #include "UCTMemoryPool.hpp" #include namespace SparCraft { class Game; class Player; class UCTSearch { UCTSearchParameters _params; UCTSearchResults _results; Timer _searchTimer; UCTNode _rootNode; UCTMemoryPool * _memoryPool; GameState _currentState; // we will use these as variables to save stack allocation every time std::vector _actionVec; MoveArray _moveArray; Array, Constants::Max_Ordered_Moves> _orderedMoves; std::vector _allScripts[Constants::Num_Players]; PlayerPtr _playerModels[Constants::Num_Players]; public: UCTSearch(const UCTSearchParameters & params); // UCT-specific functions UCTNode & UCTNodeSelect(UCTNode & parent); StateEvalScore traverse(UCTNode & node, GameState & currentState); void uct(GameState & state, size_t depth, const size_t lastPlayerToMove, std::vector * firstSimMove); void doSearch(GameState & initialState, std::vector & move); // Move and Child generation functions void generateChildren(UCTNode & node, GameState & state); void generateOrderedMoves(GameState & state, MoveArray & moves, const size_t & playerToMove); void makeMove(UCTNode & node, GameState & state); const bool getNextMove(size_t playerToMove, MoveArray & moves, const size_t & moveNumber, std::vector & actionVec); // Utility functions const size_t getPlayerToMove(UCTNode & node, const GameState & state) const; const size_t getChildNodeType(UCTNode & parent, const GameState & prevState) const; const bool searchTimeOut(); const bool isRoot(UCTNode & node) const; const bool terminalState(GameState & state, const size_t & depth) const; const bool isFirstSimMove(UCTNode & node, GameState & state); const bool isSecondSimMove(UCTNode & node, GameState & state); StateEvalScore performPlayout(GameState & state); void updateState(UCTNode & node, GameState & state, bool isLeaf); void setMemoryPool(UCTMemoryPool * pool); UCTSearchResults & getResults(); // graph printing functions void printSubTree(UCTNode & node, GameState state, std::string filename); void printSubTreeGraphViz(UCTNode & node, GraphViz::Graph & g, GameState state); std::string getNodeIDString(UCTNode & node); }; } ================================================ FILE: SparCraft/source/UCTSearchParameters.hpp ================================================ #pragma once #include "Common.h" namespace SparCraft { class UCTSearchParameters; namespace UCTMoveSelect { enum { HighestValue, MostVisited }; } } class SparCraft::UCTSearchParameters { // DEFAULT DESCRIPTION size_t _maxPlayer; // Player_One The player who will make maximizing moves size_t _rootMoveSelection; // MostVisited Which node to pick from the root size_t _timeLimit; // 0 Search time limit. 0 means no time limit double _cValue; // 1 C constant for UCT formula size_t _maxTraversals; // 100 Max number of UCT traversals to make size_t _maxChildren; // 10 Max children at each node size_t _moveOrdering; // ScriptFirst Move ordering method for child generation size_t _evalMethod; // LTD Evaluation function type size_t _simScripts[2]; // NOKDPS Policy to use for playouts size_t _playerToMoveMethod; // Alternate The player to move policy size_t _playerModel[2]; // None Player model to use for each player std::string _graphVizFilename; // "" File name to output graph viz file std::vector _orderedMoveScripts; std::vector > _desc; // 2-column description vector public: // default constructor UCTSearchParameters() : _maxPlayer (Players::Player_One) , _rootMoveSelection (UCTMoveSelect::MostVisited) , _timeLimit (0) , _cValue (1) , _maxTraversals (100) , _maxChildren (10) , _moveOrdering (MoveOrderMethod::ScriptFirst) , _evalMethod (SparCraft::EvaluationMethods::Playout) , _playerToMoveMethod (SparCraft::PlayerToMove::Alternate) { setPlayerModel(Players::Player_One, PlayerModels::None); setPlayerModel(Players::Player_Two, PlayerModels::None); setSimScripts(PlayerModels::NOKDPS, PlayerModels::NOKDPS); } const size_t & maxPlayer() const { return _maxPlayer; } const size_t & timeLimit() const { return _timeLimit; } const double & cValue() const { return _cValue; } const size_t & maxTraversals() const { return _maxTraversals; } const size_t & maxChildren() const { return _maxChildren; } const size_t & moveOrderingMethod() const { return _moveOrdering; } const size_t & evalMethod() const { return _evalMethod; } const size_t & simScript(const size_t & player) const { return _simScripts[player]; } const size_t & playerToMoveMethod() const { return _playerToMoveMethod; } const size_t & playerModel(const size_t & player) const { return _playerModel[player]; } const size_t & rootMoveSelectionMethod() const { return _rootMoveSelection; } const std::string & graphVizFilename() const { return _graphVizFilename; } const std::vector & getOrderedMoveScripts() const { return _orderedMoveScripts; } void setMaxPlayer(const size_t & player) { _maxPlayer = player; } void setTimeLimit(const size_t & timeLimit) { _timeLimit = timeLimit; } void setCValue(const double & c) { _cValue = c; } void setMaxTraversals(const size_t & traversals) { _maxTraversals = traversals; } void setMaxChildren(const size_t & children) { _maxChildren = children; } void setMoveOrderingMethod(const size_t & method) { _moveOrdering = method; } void setEvalMethod(const size_t & eval) { _evalMethod = eval; } void setPlayerToMoveMethod(const size_t & method) { _playerToMoveMethod = method; } void setSimScripts(const size_t & p1, const size_t & p2) { _simScripts[0] = p1; _simScripts[1] = p2; } void setRootMoveSelectionMethod(const size_t & method) { _rootMoveSelection = method; } void setGraphVizFilename(const std::string & filename) { _graphVizFilename = filename; } void addOrderedMoveScript(const size_t & script) { _orderedMoveScripts.push_back(script); } void setPlayerModel(const size_t & player, const size_t & model) { _playerModel[player] = model; } std::vector > & getDescription() { if (_desc.size() == 0) { _desc.push_back(std::vector()); _desc.push_back(std::vector()); std::stringstream ss; _desc[0].push_back("Player Type:"); _desc[0].push_back("Time Limit:"); _desc[0].push_back("C Value:"); _desc[0].push_back("Max Traversals:"); _desc[0].push_back("Max Children:"); _desc[0].push_back("Move Ordering:"); _desc[0].push_back("Player To Move:"); _desc[0].push_back("Opponent Model:"); ss << "UCT"; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << timeLimit() << "ms"; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << cValue(); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << maxTraversals(); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << maxChildren(); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << MoveOrderMethod::getName(moveOrderingMethod()); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << PlayerToMove::getName(playerToMoveMethod()); _desc[1].push_back(ss.str()); ss.str(std::string()); ss << PlayerModels::getName(playerModel((maxPlayer()+1)%2)); _desc[1].push_back(ss.str()); ss.str(std::string()); } return _desc; } }; ================================================ FILE: SparCraft/source/UCTSearchResults.hpp ================================================ #pragma once #include #include "Action.h" namespace SparCraft { class UCTSearchResults { public: unsigned long long nodesExpanded; // number of nodes expanded in the search double timeElapsed; // time elapsed in milliseconds int traversals; int traverseCalls; int nodesVisited; int totalVisits; int nodesCreated; std::vector bestMoves; ScoreType abValue; std::vector > _desc; // 2-column description vector UCTSearchResults() : nodesExpanded (0) , timeElapsed (0) , traversals (0) , traverseCalls (0) , nodesVisited (0) , totalVisits (0) , nodesCreated (0) , abValue (0) { } std::vector > & getDescription() { _desc.clear(); _desc.push_back(std::vector()); _desc.push_back(std::vector()); std::stringstream ss; _desc[0].push_back("Traversals: "); _desc[0].push_back("Nodes Visited: "); _desc[0].push_back("Total Visits: "); _desc[0].push_back("Nodes Created: "); ss << traversals; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << nodesVisited; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << totalVisits; _desc[1].push_back(ss.str()); ss.str(std::string()); ss << nodesCreated; _desc[1].push_back(ss.str()); ss.str(std::string()); return _desc; } }; } ================================================ FILE: SparCraft/source/Unit.cpp ================================================ #include "Unit.h" using namespace SparCraft; Unit::Unit() : _unitType (BWAPI::UnitTypes::None) , _range (0) , _unitID (255) , _playerID (255) , _currentHP (0) , _currentEnergy (0) , _timeCanMove (0) , _timeCanAttack (0) , _previousActionTime (0) , _prevCurrentPosTime (0) { } // test constructor for setting all variables of a unit Unit::Unit(const BWAPI::UnitType unitType, const Position & pos, const size_t & unitID, const size_t & playerID, const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta) : _unitType (unitType) , _range (PlayerWeapon(&PlayerProperties::Get(playerID), unitType.groundWeapon()).GetMaxRange() + Constants::Range_Addition) , _position (pos) , _unitID (unitID) , _playerID (playerID) , _currentHP (hp) , _currentEnergy (energy) , _timeCanMove (tm) , _timeCanAttack (ta) , _previousActionTime (0) , _prevCurrentPosTime (0) , _previousPosition (pos) , _prevCurrentPos (pos) { System::checkSupportedUnitType(unitType); } // constructor for units to construct basic units, sets some things automatically Unit::Unit(const BWAPI::UnitType unitType, const size_t & playerID, const Position & pos) : _unitType (unitType) , _range (PlayerWeapon(&PlayerProperties::Get(playerID), unitType.groundWeapon()).GetMaxRange() + Constants::Range_Addition) , _position (pos) , _unitID (0) , _playerID (playerID) , _currentHP (maxHP()) , _currentEnergy (unitType == BWAPI::UnitTypes::Terran_Medic ? Constants::Starting_Energy : 0) , _timeCanMove (0) , _timeCanAttack (0) , _previousActionTime (0) , _prevCurrentPosTime (0) , _previousPosition (pos) , _prevCurrentPos (pos) { System::checkSupportedUnitType(unitType); } // Less than operator, used for sorting the GameState unit array. // Units are sorted in this order: // 1) alive < dead // 2) firstTimeFree() // 3) currentHP() // 4) pos() const bool Unit::operator < (const Unit & rhs) const { if (!isAlive()) { return false; } else if (!rhs.isAlive()) { return true; } if (firstTimeFree() == rhs.firstTimeFree()) { return ID() < rhs.ID(); } else { return firstTimeFree() < rhs.firstTimeFree(); } /*if (firstTimeFree() == rhs.firstTimeFree()) { if (currentHP() == rhs.currentHP()) { return pos() < rhs.pos(); } else { return currentHP() < rhs.currentHP(); } } else { return firstTimeFree() < rhs.firstTimeFree(); }*/ } // compares a unit based on unit id const bool Unit::equalsID(const Unit & rhs) const { return _unitID == rhs._unitID; } // returns whether or not this unit can see a given unit at a given time bool Unit::canSeeTarget(const Unit & unit, const TimeType & gameTime) const { // range of this unit attacking PositionType r = type().sightRange(); // return whether the target unit is in range return (r * r) >= getDistanceSqToUnit(unit, gameTime); } // returns whether or not this unit can attack a given unit at a given time const bool Unit::canAttackTarget(const Unit & unit, const TimeType & gameTime) const { BWAPI::WeaponType weapon = unit.type().isFlyer() ? type().airWeapon() : type().groundWeapon(); if (weapon.damageAmount() == 0) { return false; } // range of this unit attacking PositionType r = range(); // return whether the target unit is in range return (r * r) >= getDistanceSqToUnit(unit, gameTime); } const bool Unit::canHealTarget(const Unit & unit, const TimeType & gameTime) const { // if the unit can't heal or the target unit is not on the same team if (!canHeal() || !unit.isOrganic() || !(unit.player() == player()) || (unit.currentHP() == unit.maxHP())) { // then it can't heal the target return false; } // range of this unit attacking PositionType r = healRange(); // return whether the target unit is in range return (r * r) >= getDistanceSqToUnit(unit, gameTime); } const Position & Unit::position() const { return _position; } // take an attack, subtract the hp void Unit::takeAttack(const Unit & attacker) { PlayerWeapon weapon(attacker.getWeapon(*this)); HealthType damage(weapon.GetDamageBase()); // calculate the damage based on armor and damage types damage = std::max((int)((damage-getArmor()) * weapon.GetDamageMultiplier(getSize())), 2); // special case where units attack multiple times if (attacker.type() == BWAPI::UnitTypes::Protoss_Zealot || attacker.type() == BWAPI::UnitTypes::Terran_Firebat) { damage *= 2; } //std::cout << type().getName() << " took " << (int)attacker.player() << " " << damage << "\n"; updateCurrentHP(_currentHP - damage); } void Unit::takeHeal(const Unit & healer) { updateCurrentHP(_currentHP + healer.healAmount()); } // returns whether or not this unit is alive const bool Unit::isAlive() const { return _currentHP > 0; } // attack a unit, set the times accordingly void Unit::attack(const Action & move, const Unit & target, const TimeType & gameTime) { // if this is a repeat attack if (_previousAction.type() == ActionTypes::ATTACK || _previousAction.type() == ActionTypes::RELOAD) { // add the repeat attack animation duration // can't attack again until attack cooldown is up updateMoveActionTime (gameTime + attackRepeatFrameTime()); updateAttackActionTime (gameTime + attackCooldown()); } // if there previous action was a MOVE action, add the move penalty else if (_previousAction.type() == ActionTypes::MOVE) { updateMoveActionTime (gameTime + attackInitFrameTime() + 2); updateAttackActionTime (gameTime + attackCooldown() + Constants::Move_Penalty); } else { // add the initial attack animation duration updateMoveActionTime (gameTime + attackInitFrameTime() + 2); updateAttackActionTime (gameTime + attackCooldown()); } // if the unit is not mobile, set its next move time to its next attack time if (!isMobile()) { updateMoveActionTime(_timeCanAttack); } setPreviousAction(move, gameTime); } // attack a unit, set the times accordingly void Unit::heal(const Action & move, const Unit & target, const TimeType & gameTime) { _currentEnergy -= healCost(); // can't attack again until attack cooldown is up updateAttackActionTime (gameTime + healCooldown()); updateMoveActionTime (gameTime + healCooldown()); if (currentEnergy() < healCost()) { updateAttackActionTime(1000000); } setPreviousAction(move, gameTime); } // unit update for moving based on a given Move void Unit::move(const Action & move, const TimeType & gameTime) { _previousPosition = pos(); // get the distance to the move action destination PositionType dist = move.pos().getDistance(pos()); // how long will this move take? TimeType moveDuration = (TimeType)((double)dist / speed()); // update the next time we can move, make sure a move always takes 1 time step updateMoveActionTime(gameTime + std::max(moveDuration, 1)); // assume we need 4 frames to turn around after moving updateAttackActionTime(std::max(nextAttackActionTime(), nextMoveActionTime())); // update the position //_position.addPosition(dist * dir.x(), dist * dir.y()); _position.moveTo(move.pos()); setPreviousAction(move, gameTime); } // unit is commanded to wait until his attack cooldown is up void Unit::waitUntilAttack(const Action & move, const TimeType & gameTime) { // do nothing until we can attack again updateMoveActionTime(_timeCanAttack); setPreviousAction(move, gameTime); } void Unit::pass(const Action & move, const TimeType & gameTime) { updateMoveActionTime(gameTime + Constants::Pass_Move_Duration); updateAttackActionTime(gameTime + Constants::Pass_Move_Duration); setPreviousAction(move, gameTime); } const PositionType Unit::getDistanceSqToUnit(const Unit & u, const TimeType & gameTime) const { return getDistanceSqToPosition(u.currentPosition(gameTime), gameTime); } const PositionType Unit::getDistanceSqToPosition(const Position & p, const TimeType & gameTime) const { return currentPosition(gameTime).getDistanceSq(p); } // returns current position based on game time const Position & Unit::currentPosition(const TimeType & gameTime) const { // if the previous move was MOVE, then we need to calculate where the unit is now if (_previousAction.type() == ActionTypes::MOVE) { // if gameTime is equal to previous move time then we haven't moved yet if (gameTime == _previousActionTime) { return _previousPosition; } // else if game time is >= time we can move, then we have arrived at the destination else if (gameTime >= _timeCanMove) { return _position; } // otherwise we are still moving, so calculate the current position else if (gameTime == _prevCurrentPosTime) { return _prevCurrentPos; } else { TimeType moveDuration = _timeCanMove - _previousActionTime; float moveTimeRatio = (float)(gameTime - _previousActionTime) / moveDuration; _prevCurrentPosTime = gameTime; // calculate the new current position _prevCurrentPos = _position; _prevCurrentPos.subtractPosition(_previousPosition); _prevCurrentPos.scalePosition(moveTimeRatio); _prevCurrentPos.addPosition(_previousPosition); //_prevCurrentPos = _previousPosition + (_position - _previousPosition).scale(moveTimeRatio); return _prevCurrentPos; } } // if it wasn't a MOVE, then we just return the Unit position else { return _position; } } void Unit::setPreviousPosition(const TimeType & gameTime) { TimeType moveDuration = _timeCanMove - _previousActionTime; float moveTimeRatio = (float)(gameTime - _previousActionTime) / moveDuration; _prevCurrentPosTime = gameTime; _prevCurrentPos = _previousPosition + (_position - _previousPosition).scale(moveTimeRatio); } // returns the damage a unit does const HealthType Unit::damage() const { return _unitType == BWAPI::UnitTypes::Protoss_Zealot ? 2 * (HealthType)_unitType.groundWeapon().damageAmount() : (HealthType)_unitType.groundWeapon().damageAmount(); } const HealthType Unit::healAmount() const { return canHeal() ? 6 : 0; } void Unit::print() const { printf("%s %5d [%5d %5d] (%5d, %5d)\n", _unitType.getName().c_str(), currentHP(), nextAttackActionTime(), nextMoveActionTime(), x(), y()); } void Unit::updateCurrentHP(const HealthType & newHP) { _currentHP = std::min(maxHP(), newHP); } void Unit::updateAttackActionTime(const TimeType & newTime) { _timeCanAttack = newTime; } void Unit::updateMoveActionTime(const TimeType & newTime) { _timeCanMove = newTime; } void Unit::setCooldown(TimeType attack, TimeType move) { _timeCanAttack = attack; _timeCanMove = move; } void Unit::setUnitID(const size_t & id) { _unitID = id; } void Unit::setPreviousAction(const Action & m, const TimeType & previousMoveTime) { // if it was an attack move, store the unitID of the opponent unit _previousAction = m; _previousActionTime = previousMoveTime; } const bool Unit::canAttackNow() const { return !canHeal() && _timeCanAttack <= _timeCanMove; } const bool Unit::canMoveNow() const { return isMobile() && _timeCanMove <= _timeCanAttack; } const bool Unit::canHealNow() const { return canHeal() && (currentEnergy() >= healCost()) && (_timeCanAttack <= _timeCanMove); } const bool Unit::canKite() const { return _timeCanMove < _timeCanAttack; } const bool Unit::isMobile() const { return _unitType.canMove(); } const bool Unit::canHeal() const { return _unitType == BWAPI::UnitTypes::Terran_Medic; } const bool Unit::isOrganic() const { return _unitType.isOrganic(); } const size_t Unit::ID() const { return _unitID; } const size_t Unit::player() const { return _playerID; } const Position & Unit::pos() const { return _position; } const PositionType Unit::x() const { return _position.x(); } const PositionType Unit::y() const { return _position.y(); } const PositionType Unit::range() const { return _range; } const PositionType Unit::healRange() const { return canHeal() ? 96 : 0; } const HealthType Unit::maxHP() const { return (HealthType)_unitType.maxHitPoints() + (HealthType)_unitType.maxShields(); } const HealthType Unit::currentHP() const { return (HealthType)_currentHP; } const HealthType Unit::currentEnergy() const { return (HealthType)_currentEnergy; } const HealthType Unit::maxEnergy() const { return (HealthType)_unitType.maxEnergy(); } const HealthType Unit::healCost() const { return 3; } const float Unit::dpf() const { return (float)std::max(Constants::Min_Unit_DPF, (float)damage() / ((float)attackCooldown() + 1)); } const TimeType Unit::moveCooldown() const { return (TimeType)((double)Constants::Move_Distance / _unitType.topSpeed()); } const TimeType Unit::attackCooldown() const { return (TimeType)_unitType.groundWeapon().damageCooldown(); } const TimeType Unit::healCooldown() const { return (TimeType)8; } const TimeType Unit::nextAttackActionTime() const { return _timeCanAttack; } const TimeType Unit::nextMoveActionTime() const { return _timeCanMove; } const TimeType Unit::previousActionTime() const { return _previousActionTime; } const TimeType Unit::firstTimeFree() const { return _timeCanAttack <= _timeCanMove ? _timeCanAttack : _timeCanMove; } const TimeType Unit::attackInitFrameTime() const { return AnimationFrameData::getAttackFrames(_unitType).first; } const TimeType Unit::attackRepeatFrameTime() const { return AnimationFrameData::getAttackFrames(_unitType).second; } const int Unit::typeID() const { return _unitType.getID(); } const double Unit::speed() const { return _unitType.topSpeed(); } const BWAPI::UnitType Unit::type() const { return _unitType; } const Action & Unit::previousAction() const { return _previousAction; } const BWAPI::UnitSizeType Unit::getSize() const { return _unitType.size(); } const PlayerWeapon Unit::getWeapon(const Unit & target) const { return PlayerWeapon(&PlayerProperties::Get(player()), target.type().isFlyer() ? _unitType.airWeapon() : _unitType.groundWeapon()); } const HealthType Unit::getArmor() const { return UnitProperties::Get(type()).GetArmor(PlayerProperties::Get(player())); } const BWAPI::WeaponType Unit::getWeapon(BWAPI::UnitType target) const { return target.isFlyer() ? _unitType.airWeapon() : _unitType.groundWeapon(); } const std::string Unit::name() const { std::string n(_unitType.getName()); std::replace(n.begin(), n.end(), ' ', '_'); return n; } // calculates the hash of this unit based on a given game time const HashType Unit::calculateHash(const size_t & hashNum, const TimeType & gameTime) const { Position currentPos = currentPosition(gameTime); return Hash::values[hashNum].positionHash(_playerID, currentPos.x(), currentPos.y()) ^ Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime) ^ Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime) ^ Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP()) ^ Hash::values[hashNum].getUnitTypeHash(_playerID, typeID()); } // calculates the hash of this unit based on a given game time, and prints debug info void Unit::debugHash(const size_t & hashNum, const TimeType & gameTime) const { std::cout << " Pos " << Hash::values[hashNum].positionHash(_playerID, position().x(), position().y()); std::cout << " Att " << Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime); std::cout << " Mov " << Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime); std::cout << " HP " << Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP()); std::cout << " Typ " << Hash::values[hashNum].getUnitTypeHash(_playerID, typeID()) << "\n";; HashType hash = Hash::values[hashNum].positionHash(_playerID, position().x(), position().y()); std::cout << hash << "\n"; hash ^= Hash::values[hashNum].getAttackHash(_playerID, nextAttackActionTime() - gameTime) ; std::cout << hash << "\n"; hash ^= Hash::values[hashNum].getMoveHash(_playerID, nextMoveActionTime() - gameTime); std::cout << hash << "\n"; hash ^= Hash::values[hashNum].getCurrentHPHash(_playerID, currentHP()); std::cout << hash << "\n"; hash ^= Hash::values[hashNum].getUnitTypeHash(_playerID, typeID()); std::cout << hash << "\n"; } const std::string Unit::debugString() const { std::stringstream ss; ss << "Unit Type: " << type().getName() << "\n"; ss << "Unit ID: " << (int)ID() << "\n"; ss << "Player: " << (int)player() << "\n"; ss << "Range: " << range() << "\n"; ss << "Position: " << "(" << _position.x() << "," << _position.y() << ")\n"; ss << "Current HP: " << currentHP() << "\n"; ss << "Next Move Time: " << nextMoveActionTime() << "\n"; ss << "Next Attack Time: " << nextAttackActionTime() << "\n"; ss << "Previous Action: " << previousAction().debugString() << "\n"; ss << "Previous Pos Time: " << _prevCurrentPosTime << "\n"; ss << "Previous Pos: " << "(" << _prevCurrentPos.x() << "," << _prevCurrentPos.y() << ")\n"; return ss.str(); } ================================================ FILE: SparCraft/source/Unit.h ================================================ #pragma once #include "Common.h" #include "Action.h" #include "Position.hpp" #include "Hash.h" #include "PlayerProperties.h" #include "UnitProperties.h" #include "AnimationFrameData.h" #include namespace SparCraft { class Action; class Unit { BWAPI::UnitType _unitType; // the BWAPI unit type that we are mimicing PositionType _range; Position _position; // current location in a possibly infinite space size_t _unitID; // unique unit ID to the state it's contained in size_t _playerID; // the player who controls the unit HealthType _currentHP; // current HP of the unit HealthType _currentEnergy; TimeType _timeCanMove; // time the unit can next move TimeType _timeCanAttack; // time the unit can next attack Action _previousAction; // the previous action that the unit performed TimeType _previousActionTime; // the time the previous move was performed Position _previousPosition; mutable TimeType _prevCurrentPosTime; mutable Position _prevCurrentPos; public: Unit(); Unit(const BWAPI::UnitType unitType, const size_t & playerID, const Position & pos); Unit(const BWAPI::UnitType unitType, const Position & pos, const size_t & unitID, const size_t & playerID, const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta); const bool operator < (const Unit & rhs) const; // action functions void setPreviousAction(const Action & m, const TimeType & previousMoveTime); void updateAttackActionTime(const TimeType & newTime); void updateMoveActionTime(const TimeType & newTime); void attack(const Action & move, const Unit & target, const TimeType & gameTime); void heal(const Action & move, const Unit & target, const TimeType & gameTime); void move(const Action & move, const TimeType & gameTime) ; void waitUntilAttack(const Action & move, const TimeType & gameTime); void pass(const Action & move, const TimeType & gameTime); void takeAttack(const Unit & attacker); void takeHeal(const Unit & healer); // conditional functions const bool isMobile() const; const bool isOrganic() const; const bool isAlive() const; const bool canAttackNow() const; const bool canMoveNow() const; const bool canHealNow() const; const bool canKite() const; const bool canHeal() const; const bool equalsID(const Unit & rhs) const; bool canSeeTarget(const Unit & unit, const TimeType & gameTime) const; const bool canAttackTarget(const Unit & unit, const TimeType & gameTime) const; const bool canHealTarget(const Unit & unit, const TimeType & gameTime) const; // id related void setUnitID(const size_t & id); const size_t ID() const; const size_t player() const; // position related functions const Position & position() const; const Position & pos() const; const PositionType x() const; const PositionType y() const; const PositionType range() const; const PositionType healRange() const; const PositionType getDistanceSqToUnit(const Unit & u, const TimeType & gameTime) const; const PositionType getDistanceSqToPosition(const Position & p, const TimeType & gameTime) const; const Position & currentPosition(const TimeType & gameTime) const; void setPreviousPosition(const TimeType & gameTime); // health and damage related functions const HealthType damage() const; const HealthType healAmount() const; const HealthType maxHP() const; const HealthType currentHP() const; const HealthType currentEnergy() const; const HealthType maxEnergy() const; const HealthType healCost() const; const HealthType getArmor() const; const float dpf() const; void updateCurrentHP(const HealthType & newHP); const BWAPI::UnitSizeType getSize() const; const BWAPI::WeaponType getWeapon(BWAPI::UnitType target) const; const HealthType getDamageTo(const Unit & unit) const; const PlayerWeapon getWeapon(const Unit & target) const; // time and cooldown related functions const TimeType moveCooldown() const; const TimeType attackCooldown() const; const TimeType healCooldown() const; const TimeType nextAttackActionTime() const; const TimeType nextMoveActionTime() const; const TimeType previousActionTime() const; const TimeType firstTimeFree() const; const TimeType attackInitFrameTime() const; const TimeType attackRepeatFrameTime() const; void setCooldown(TimeType attack, TimeType move); // other functions const int typeID() const; const double speed() const; const BWAPI::UnitType type() const; const Action & previousAction() const; const std::string name() const; void print() const; const std::string debugString() const; // hash functions const HashType calculateHash(const size_t & hashNum, const TimeType & gameTime) const; void debugHash(const size_t & hashNum, const TimeType & gameTime) const; }; class UnitPtrCompare { public: const bool operator() (Unit * u1, Unit * u2) const { return *u1 < *u2; } }; } ================================================ FILE: SparCraft/source/UnitAction.hpp ================================================ #pragma once #include "Common.h" #include "Position.hpp" namespace SparCraft { namespace UnitActionTypes { enum {NONE, ATTACK, RELOAD, MOVE, PASS, HEAL}; }; class UnitAction { public: IDType _unit, _player, _moveType, _moveIndex; Position _p; UnitAction() : _unit(255) , _player(255) , _moveType(UnitActionTypes::NONE) , _moveIndex(255) { } UnitAction( const IDType & unitIndex, const IDType & player, const IDType & type, const IDType & moveIndex, const Position & dest) : _unit(unitIndex) , _player(player) , _moveType(type) , _moveIndex(moveIndex) , _p(dest) { } UnitAction( const IDType & unitIndex, const IDType & player, const IDType & type, const IDType & moveIndex) : _unit(unitIndex) , _player(player) , _moveType(type) , _moveIndex(moveIndex) { } const bool operator == (const UnitAction & rhs) { return _unit == rhs._unit && _player == rhs._player && _moveType == rhs._moveType && _moveIndex == rhs._moveIndex && _p == rhs._p; } const IDType & unit() const { return _unit; } const IDType & player() const { return _player; } const IDType & type() const { return _moveType; } const IDType & index() const { return _moveIndex; } const Position & pos() const { return _p; } const std::string moveString() const { if (_moveType == UnitActionTypes::ATTACK) { return "ATTACK"; } else if (_moveType == UnitActionTypes::MOVE) { return "MOVE"; } else if (_moveType == UnitActionTypes::RELOAD) { return "RELOAD"; } else if (_moveType == UnitActionTypes::PASS) { return "PASS"; } else if (_moveType == UnitActionTypes::HEAL) { return "HEAL"; } return "NONE"; } const Position getDir() const { return Position(Constants::Move_Dir[_moveIndex][0], Constants::Move_Dir[_moveIndex][1]); } const std::string debugString() const { std::stringstream ss; ss << moveString() << ": (" << (int)unit() << "," << (int)player() << "," << (int)type() << "," << (int)index() << ") " << "(" << pos().x() << "," << pos().y() << ")"; return ss.str(); } }; class AlphaBetaMove { std::vector _move; bool _isValid; public: AlphaBetaMove() : _isValid(false) { } AlphaBetaMove(const std::vector & move, const bool & isValid) : _move(move) , _isValid(isValid) { } const bool isValid() const { return _isValid; } const std::vector & moveVec() const { return _move; } }; class TTBestMove { AlphaBetaMove _firstMove; AlphaBetaMove _secondMove; public: TTBestMove() { } TTBestMove(const AlphaBetaMove & first, const AlphaBetaMove & second) : _firstMove(first) , _secondMove(second) { } const AlphaBetaMove & firstMove() const { return _firstMove; } const AlphaBetaMove & secondMove() const { return _secondMove; } }; class AlphaBetaValue { StateEvalScore _score; AlphaBetaMove _move; public: AlphaBetaValue() { } AlphaBetaValue(const StateEvalScore & score, const AlphaBetaMove & abMove) : _score(score) , _move(abMove) { } const StateEvalScore & score() const { return _score; } const AlphaBetaMove & abMove() const { return _move; } }; } ================================================ FILE: SparCraft/source/UnitProperties.cpp ================================================ #include "UnitProperties.h" using namespace SparCraft; using namespace BWAPI::UpgradeTypes; UnitProperties UnitProperties::props[256]; UnitProperties::UnitProperties() : capacityUpgrade(BWAPI::UpgradeTypes::None), maxEnergyUpgrade(BWAPI::UpgradeTypes::None), sightUpgrade(BWAPI::UpgradeTypes::None), extraArmorUpgrade(BWAPI::UpgradeTypes::None), speedUpgrade(BWAPI::UpgradeTypes::None) { capacity[0] = capacity[1] = 0; } void UnitProperties::SetType(BWAPI::UnitType type) { this->type = type; maxEnergy[0] = maxEnergy[1] = type.maxEnergy(); sightRange[0] = sightRange[1] = type.sightRange() << pixelShift; extraArmor[0] = extraArmor[1] = 0; speed[0] = speed[1] = static_cast((1 << pixelShift) * type.topSpeed()); } void UnitProperties::SetSpeedUpgrade(BWAPI::UpgradeType upgrade, double rate) { speedUpgrade = upgrade; speed[1] = static_cast((1 << pixelShift) * rate); } void UnitProperties::SetCapacityUpgrade(BWAPI::UpgradeType upgrade, int capacity0, int capacity1) { capacityUpgrade = upgrade; capacity[0] = capacity0; capacity[1] = capacity1; } void UnitProperties::SetEnergyUpgrade(BWAPI::UpgradeType upgrade) { maxEnergyUpgrade = upgrade; maxEnergy[1] = 250; } void UnitProperties::SetSightUpgrade(BWAPI::UpgradeType upgrade, int range) { sightUpgrade = upgrade; sightRange[1] = (range << 5) << pixelShift; } void UnitProperties::SetExtraArmorUpgrade(BWAPI::UpgradeType upgrade, int amount) { extraArmorUpgrade = upgrade; extraArmor[1] = amount; } using namespace BWAPI::UnitTypes; void UnitProperties::Init() { for (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes()) { props[type.getID()].SetType(type); } const double standardSpeed(Terran_SCV.topSpeed()); props[BWAPI::UnitTypes::Terran_Ghost.getID() ].SetEnergyUpgrade(Moebius_Reactor); props[BWAPI::UnitTypes::Terran_Ghost.getID() ].SetSightUpgrade(Ocular_Implants, 11); props[BWAPI::UnitTypes::Terran_Medic.getID() ].SetEnergyUpgrade(Caduceus_Reactor); props[BWAPI::UnitTypes::Terran_Vulture.getID() ].SetSpeedUpgrade(Ion_Thrusters, standardSpeed * 1.881); props[BWAPI::UnitTypes::Terran_Wraith.getID() ].SetEnergyUpgrade(Apollo_Reactor); props[BWAPI::UnitTypes::Terran_Battlecruiser.getID() ].SetEnergyUpgrade(Colossus_Reactor); props[BWAPI::UnitTypes::Terran_Science_Vessel.getID() ].SetEnergyUpgrade(Titan_Reactor); props[BWAPI::UnitTypes::Zerg_Zergling.getID() ].SetSpeedUpgrade(Metabolic_Boost, standardSpeed * 1.615); props[BWAPI::UnitTypes::Zerg_Hydralisk.getID() ].SetSpeedUpgrade(Muscular_Augments, standardSpeed * 1.105); props[BWAPI::UnitTypes::Zerg_Ultralisk.getID() ].SetExtraArmorUpgrade(Chitinous_Plating, 2); props[BWAPI::UnitTypes::Zerg_Ultralisk.getID() ].SetSpeedUpgrade(Anabolic_Synthesis, standardSpeed * 1.556); props[BWAPI::UnitTypes::Zerg_Defiler.getID() ].SetEnergyUpgrade(Metasynaptic_Node); props[BWAPI::UnitTypes::Zerg_Overlord.getID() ].SetSightUpgrade(Antennae, 11); props[BWAPI::UnitTypes::Zerg_Overlord.getID() ].SetSpeedUpgrade(Pneumatized_Carapace, Protoss_Carrier.topSpeed()); props[BWAPI::UnitTypes::Zerg_Queen.getID() ].SetEnergyUpgrade(Gamete_Meiosis); props[BWAPI::UnitTypes::Protoss_Zealot.getID() ].SetSpeedUpgrade(Leg_Enhancements, standardSpeed * 1.167); props[BWAPI::UnitTypes::Protoss_High_Templar.getID()].SetEnergyUpgrade(Khaydarin_Amulet); props[BWAPI::UnitTypes::Protoss_Reaver.getID() ].SetCapacityUpgrade(Reaver_Capacity, 5, 10); props[BWAPI::UnitTypes::Protoss_Dark_Archon.getID() ].SetEnergyUpgrade(Argus_Talisman); props[BWAPI::UnitTypes::Protoss_Observer.getID() ].SetSightUpgrade(Sensor_Array, 11); props[BWAPI::UnitTypes::Protoss_Observer.getID() ].SetSpeedUpgrade(Gravitic_Boosters, Protoss_Corsair.topSpeed()); props[BWAPI::UnitTypes::Protoss_Shuttle.getID() ].SetSpeedUpgrade(Gravitic_Drive, Protoss_Corsair.topSpeed()); props[BWAPI::UnitTypes::Protoss_Scout.getID() ].SetSightUpgrade(Apial_Sensors, 10); props[BWAPI::UnitTypes::Protoss_Scout.getID() ].SetSpeedUpgrade(Gravitic_Thrusters, Protoss_Corsair.topSpeed()); props[BWAPI::UnitTypes::Protoss_Corsair.getID() ].SetEnergyUpgrade(Argus_Jewel); props[BWAPI::UnitTypes::Protoss_Carrier.getID() ].SetCapacityUpgrade(Carrier_Capacity, 4, 8); props[BWAPI::UnitTypes::Protoss_Arbiter.getID() ].SetEnergyUpgrade(Khaydarin_Core); } ================================================ FILE: SparCraft/source/UnitProperties.h ================================================ #pragma once #include "Common.h" #include "PlayerProperties.h" #include "WeaponProperties.h" namespace SparCraft { class WeaponProperties; class PlayerProperties; class UnitProperties { static UnitProperties props[256]; BWAPI::UnitType type; BWAPI::UpgradeType capacityUpgrade; BWAPI::UpgradeType extraArmorUpgrade; BWAPI::UpgradeType maxEnergyUpgrade; BWAPI::UpgradeType sightUpgrade; BWAPI::UpgradeType speedUpgrade; int capacity[2]; int extraArmor[2]; int maxEnergy[2]; int sightRange[2]; int speed[2]; void SetCapacityUpgrade(BWAPI::UpgradeType upgrade, int capacity0, int capacity1); void SetEnergyUpgrade(BWAPI::UpgradeType upgrade); void SetExtraArmorUpgrade(BWAPI::UpgradeType upgrade, int amount); void SetSightUpgrade(BWAPI::UpgradeType upgrade, int range); void SetSpeedUpgrade(BWAPI::UpgradeType upgrade, double rate); void SetType(BWAPI::UnitType type); public: UnitProperties(); int GetArmor(const PlayerProperties & player) const { return type.armor() + player.GetUpgradeLevel(type.armorUpgrade()) + extraArmor[player.GetUpgradeLevel(extraArmorUpgrade)]; } int GetCapacity(const PlayerProperties & player) const { return capacity[player.GetUpgradeLevel(capacityUpgrade)]; } int GetMaxEnergy(const PlayerProperties & player) const { return maxEnergy[player.GetUpgradeLevel(maxEnergyUpgrade)]; } int GetSight(const PlayerProperties & player) const { return sightRange[player.GetUpgradeLevel(sightUpgrade)]; } int GetSpeed(const PlayerProperties & player) const { return speed[player.GetUpgradeLevel(speedUpgrade)]; } const WeaponProperties & GetGroundWeapon() const { return WeaponProperties::Get(type.groundWeapon()); } const WeaponProperties & GetAirWeapon() const { return WeaponProperties::Get(type.airWeapon()); } static const UnitProperties & Get(BWAPI::UnitType type) { return props[type.getID()]; } static void Init(); }; } ================================================ FILE: SparCraft/source/UnitScriptData.cpp ================================================ #include "UnitScriptData.h" using namespace SparCraft; UnitScriptData::UnitScriptData() { } std::vector & UnitScriptData::getMoves(const size_t & player, const size_t & actualScript) { return _allScriptMoves[player][actualScript]; } Action & UnitScriptData::getMove(const size_t & player, const size_t & unitIndex, const size_t & actualScript) { return _allScriptMoves[player][actualScript][unitIndex]; } void UnitScriptData::calculateMoves(const size_t & player, MoveArray & moves, GameState & state, std::vector & moveVec) { // generate all script moves for this player at this state and store them in allScriptMoves for (size_t scriptIndex(0); scriptIndex<_scriptVec[player].size(); ++scriptIndex) { // get the associated player pointer const PlayerPtr & pp = getPlayerPtr(player, scriptIndex); // get the actual script we are working with const size_t actualScript = getScript(player, scriptIndex); // generate the moves inside the appropriate vector getMoves(player, actualScript).clear(); pp->getMoves(state, moves, getMoves(player, actualScript)); } // for each unit the player has to move, populate the move vector with the appropriate script move for (size_t unitIndex(0); unitIndex < moves.numUnits(); ++unitIndex) { // the unit from the state const Unit & unit = state.getUnit(player, unitIndex); // the move it would choose to do based on its associated script preference Action unitMove = getMove(player, unitIndex, getUnitScript(unit)); // put the unit into the move vector moveVec.push_back(unitMove); } } const size_t & UnitScriptData::getUnitScript(const size_t & player, const int & id) const { return (*_unitScriptMap[player].find(id)).second; } const size_t & UnitScriptData::getUnitScript(const Unit & unit) const { return getUnitScript(unit.player(), unit.ID()); } const size_t & UnitScriptData::getScript(const size_t & player, const size_t & index) { return _scriptVec[player][index]; } const PlayerPtr & UnitScriptData::getPlayerPtr(const size_t & player, const size_t & index) { return _playerPtrVec[player][index]; } const size_t UnitScriptData::getNumScripts(const size_t & player) const { return _scriptSet[player].size(); } void UnitScriptData::setUnitScript(const size_t & player, const int & id, const size_t & script) { if (_scriptSet[player].find(script) == _scriptSet[player].end()) { _scriptSet[player].insert(script); _scriptVec[player].push_back(script); _playerPtrVec[player].push_back(PlayerPtr(AllPlayers::getPlayerPtr(player, script))); } _unitScriptMap[player][id] = script; } void UnitScriptData::setUnitScript(const Unit & unit, const size_t & script) { setUnitScript(unit.player(), unit.ID(), script); } ================================================ FILE: SparCraft/source/UnitScriptData.h ================================================ #pragma once #include "Common.h" #include "GameState.h" #include "Player.h" #include "AllPlayers.h" #include "Action.h" #include #include namespace SparCraft { typedef std::shared_ptr PlayerPtr; class UnitScriptData { // map from UnitID to PlayerModel std::map _unitScriptMap[2]; std::set _scriptSet[2]; std::vector _scriptVec[2]; std::vector _playerPtrVec[2]; std::vector _allScriptMoves[2][PlayerModels::Size]; std::vector & getMoves(const size_t & player, const size_t & actualScript); Action & getMove(const size_t & player, const size_t & unitIndex, const size_t & actualScript); public: UnitScriptData(); void calculateMoves(const size_t & player, MoveArray & moves, GameState & state, std::vector & moveVec); void setUnitScript(const size_t & player, const int & id, const size_t & script); void setUnitScript(const Unit & unit, const size_t & script); const size_t & getUnitScript(const size_t & player, const int & id) const; const size_t & getUnitScript(const Unit & unit) const; const size_t & getScript(const size_t & player, const size_t & index); const PlayerPtr & getPlayerPtr(const size_t & player, const size_t & index); const size_t getNumScripts(const size_t & player) const; }; } ================================================ FILE: SparCraft/source/UnitType.hpp ================================================ #pragma once #include "Location.hpp" class Unit { int _damage, _maxHP, _currentHP, _range, _moveCooldown, _weaponCooldown, _lastMove, _lastAttack; public: Unit() : _damage(0) , _maxHP(0) , _currentHP(0) , _range(0) , _moveCooldown(0) , _weaponCooldown(0) , _lastMove(-1) , _lastAttack(-1) { } Unit(const int & damage, const int & maxHP, const int & currentHP, const int & range, const int & moveCooldown, const int & weaponCooldown) : _damage(damage) , _maxHP(maxHP) , _currentHP(currentHP) , _range(range) , _moveCooldown(moveCooldown) , _weaponCooldown(weaponCooldown) , _lastMove(-1) , _lastAttack(-1) { } const int damage() const { return _damage; } const int maxHP() const { return _maxHP; } const int currentHP() const { return _currentHP; } const int range() const { return _range; } const int moveCooldown() const { return _moveCooldown; } const int weaponCooldown() const { return _weaponCooldown; } const int lastMove() const { return _lastMove; } const int lastAttack() const { return _lastAttack; } }; ================================================ FILE: SparCraft/source/WeaponProperties.cpp ================================================ #include "WeaponProperties.h" using namespace SparCraft; using namespace BWAPI::UpgradeTypes; namespace SparCraft { const int pixelShift(10); const float damageMultipliers[7][6] = { {0, 0, 0, 0, 0, 0}, {0, .5f, .75f, 1, 0, 0}, {0, 1, .5f, .25, 0, 0}, {0, 1, 1, 1, 0, 0}, {0, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }; WeaponProperties WeaponProperties::props[256]; } WeaponProperties::WeaponProperties() : rangeUpgrade(BWAPI::UpgradeTypes::None), speedUpgrade(BWAPI::UpgradeTypes::None) { } void WeaponProperties::SetType(BWAPI::WeaponType type) { this->type = type; cooldown[0] = type.damageCooldown(); cooldown[1] = type.damageCooldown(); maxRange[0] = type.maxRange(); maxRange[1] = type.maxRange(); } void WeaponProperties::SetRangeUpgrade(BWAPI::UpgradeType upgrade, int maxRange) { rangeUpgrade = upgrade; this->maxRange[1] = (maxRange << 5); } void WeaponProperties::SetSpeedUpgrade(BWAPI::UpgradeType upgrade, int cooldown) { speedUpgrade = upgrade; this->cooldown[1] = cooldown; } using namespace BWAPI::WeaponTypes; void WeaponProperties::Init() { for (const BWAPI::WeaponType & type : BWAPI::WeaponTypes::allWeaponTypes()) { props[type.getID()].SetType(type); } props[Gauss_Rifle.getID() ].SetRangeUpgrade(U_238_Shells, 5); // Terran Marine ground/air attack props[Hellfire_Missile_Pack.getID() ].SetRangeUpgrade(Charon_Boosters, 8); // Terran Goliath air attack props[Claws.getID() ].SetSpeedUpgrade(Adrenal_Glands, 6); // Zerg Zergling ground attack props[Needle_Spines.getID() ].SetRangeUpgrade(Grooved_Spines, 5); // Zerg Hydralisk ground/air attack props[Phase_Disruptor.getID() ].SetRangeUpgrade(Singularity_Charge, 6); // Protoss Dragoon ground/air attack } int WeaponProperties::GetDamageBase(const PlayerProperties & player) const { return type.damageAmount() + player.GetUpgradeLevel(type.upgradeType()) * type.damageFactor(); } float WeaponProperties::GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const { return damageMultipliers[type.damageType().getID()][targetSize.getID()]; } int WeaponProperties::GetCooldown(const PlayerProperties & player) const { return cooldown[player.GetUpgradeLevel(speedUpgrade)]; } int WeaponProperties::GetMaxRange(const PlayerProperties & player) const { return maxRange[player.GetUpgradeLevel(rangeUpgrade)]; } const WeaponProperties & WeaponProperties::Get(BWAPI::WeaponType type) { return props[type.getID()]; } ================================================ FILE: SparCraft/source/WeaponProperties.h ================================================ #pragma once #include "Common.h" #include "PlayerProperties.h" namespace SparCraft { class PlayerProperties; extern const int pixelShift; extern const float damageMultipliers[7][6]; class WeaponProperties { static WeaponProperties props[256]; BWAPI::WeaponType type; BWAPI::UpgradeType rangeUpgrade; BWAPI::UpgradeType speedUpgrade; int cooldown[2]; int maxRange[2]; void SetRangeUpgrade(BWAPI::UpgradeType upgrade, int maxRange); void SetSpeedUpgrade(BWAPI::UpgradeType upgrade, int cooldown); void SetType(BWAPI::WeaponType type); public: WeaponProperties(); int GetDamageBase(const PlayerProperties & player) const; float GetDamageMultiplier(BWAPI::UnitSizeType targetSize) const; int GetCooldown(const PlayerProperties & player) const; int GetMaxRange(const PlayerProperties & player) const; static const WeaponProperties & Get(BWAPI::WeaponType type); static void Init(); }; } ================================================ FILE: SparCraft/source/glext/glext.h ================================================ #ifndef __glext_h_ #define __glext_h_ #ifdef __cplusplus extern "C" { #endif /* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: This software was created using the ** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has ** not been independently verified as being compliant with the OpenGL(R) ** version 1.2.1 Specification. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ /* Header file version number, required by OpenGL ABI for Linux */ /* glext.h last updated 2005/06/20 */ /* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */ #define GL_GLEXT_VERSION 29 #ifndef GL_VERSION_1_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_RESCALE_NORMAL 0x803A #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #endif #ifndef GL_ARB_imaging #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_FUNC_ADD 0x8006 #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_BLEND_EQUATION 0x8009 #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 #define GL_CONVOLUTION_BORDER_MODE 0x8013 #define GL_CONVOLUTION_FILTER_SCALE 0x8014 #define GL_CONVOLUTION_FILTER_BIAS 0x8015 #define GL_REDUCE 0x8016 #define GL_CONVOLUTION_FORMAT 0x8017 #define GL_CONVOLUTION_WIDTH 0x8018 #define GL_CONVOLUTION_HEIGHT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH 0x801A #define GL_MAX_CONVOLUTION_HEIGHT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F #define GL_POST_CONVOLUTION_RED_BIAS 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 #define GL_HISTOGRAM 0x8024 #define GL_PROXY_HISTOGRAM 0x8025 #define GL_HISTOGRAM_WIDTH 0x8026 #define GL_HISTOGRAM_FORMAT 0x8027 #define GL_HISTOGRAM_RED_SIZE 0x8028 #define GL_HISTOGRAM_GREEN_SIZE 0x8029 #define GL_HISTOGRAM_BLUE_SIZE 0x802A #define GL_HISTOGRAM_ALPHA_SIZE 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C #define GL_HISTOGRAM_SINK 0x802D #define GL_MINMAX 0x802E #define GL_MINMAX_FORMAT 0x802F #define GL_MINMAX_SINK 0x8030 #define GL_TABLE_TOO_LARGE 0x8031 #define GL_COLOR_MATRIX 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB #define GL_COLOR_TABLE 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 #define GL_PROXY_COLOR_TABLE 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 #define GL_COLOR_TABLE_SCALE 0x80D6 #define GL_COLOR_TABLE_BIAS 0x80D7 #define GL_COLOR_TABLE_FORMAT 0x80D8 #define GL_COLOR_TABLE_WIDTH 0x80D9 #define GL_COLOR_TABLE_RED_SIZE 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 #endif #ifndef GL_VERSION_1_3 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #endif #ifndef GL_VERSION_1_4 #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_COMPARE_R_TO_TEXTURE 0x884E #endif #ifndef GL_VERSION_1_5 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE #define GL_FOG_COORD GL_FOG_COORDINATE #define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE #define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE #define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE #define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER #define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY #define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING #define GL_SRC0_RGB GL_SOURCE0_RGB #define GL_SRC1_RGB GL_SOURCE1_RGB #define GL_SRC2_RGB GL_SOURCE2_RGB #define GL_SRC0_ALPHA GL_SOURCE0_ALPHA #define GL_SRC1_ALPHA GL_SOURCE1_ALPHA #define GL_SRC2_ALPHA GL_SOURCE2_ALPHA #endif #ifndef GL_VERSION_2_0 #define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_COORDS 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #endif #ifndef GL_ARB_multitexture #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #endif #ifndef GL_ARB_transpose_matrix #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 #endif #ifndef GL_ARB_multisample #define GL_MULTISAMPLE_ARB 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F #define GL_SAMPLE_COVERAGE_ARB 0x80A0 #define GL_SAMPLE_BUFFERS_ARB 0x80A8 #define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA #define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 #endif #ifndef GL_ARB_texture_env_add #endif #ifndef GL_ARB_texture_cube_map #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif #ifndef GL_ARB_texture_compression #define GL_COMPRESSED_ALPHA_ARB 0x84E9 #define GL_COMPRESSED_LUMINANCE_ARB 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB #define GL_COMPRESSED_INTENSITY_ARB 0x84EC #define GL_COMPRESSED_RGB_ARB 0x84ED #define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #endif #ifndef GL_ARB_texture_border_clamp #define GL_CLAMP_TO_BORDER_ARB 0x812D #endif #ifndef GL_ARB_point_parameters #define GL_POINT_SIZE_MIN_ARB 0x8126 #define GL_POINT_SIZE_MAX_ARB 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 #define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 #endif #ifndef GL_ARB_vertex_blend #define GL_MAX_VERTEX_UNITS_ARB 0x86A4 #define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 #define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 #define GL_VERTEX_BLEND_ARB 0x86A7 #define GL_CURRENT_WEIGHT_ARB 0x86A8 #define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA #define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB #define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC #define GL_WEIGHT_ARRAY_ARB 0x86AD #define GL_MODELVIEW0_ARB 0x1700 #define GL_MODELVIEW1_ARB 0x850A #define GL_MODELVIEW2_ARB 0x8722 #define GL_MODELVIEW3_ARB 0x8723 #define GL_MODELVIEW4_ARB 0x8724 #define GL_MODELVIEW5_ARB 0x8725 #define GL_MODELVIEW6_ARB 0x8726 #define GL_MODELVIEW7_ARB 0x8727 #define GL_MODELVIEW8_ARB 0x8728 #define GL_MODELVIEW9_ARB 0x8729 #define GL_MODELVIEW10_ARB 0x872A #define GL_MODELVIEW11_ARB 0x872B #define GL_MODELVIEW12_ARB 0x872C #define GL_MODELVIEW13_ARB 0x872D #define GL_MODELVIEW14_ARB 0x872E #define GL_MODELVIEW15_ARB 0x872F #define GL_MODELVIEW16_ARB 0x8730 #define GL_MODELVIEW17_ARB 0x8731 #define GL_MODELVIEW18_ARB 0x8732 #define GL_MODELVIEW19_ARB 0x8733 #define GL_MODELVIEW20_ARB 0x8734 #define GL_MODELVIEW21_ARB 0x8735 #define GL_MODELVIEW22_ARB 0x8736 #define GL_MODELVIEW23_ARB 0x8737 #define GL_MODELVIEW24_ARB 0x8738 #define GL_MODELVIEW25_ARB 0x8739 #define GL_MODELVIEW26_ARB 0x873A #define GL_MODELVIEW27_ARB 0x873B #define GL_MODELVIEW28_ARB 0x873C #define GL_MODELVIEW29_ARB 0x873D #define GL_MODELVIEW30_ARB 0x873E #define GL_MODELVIEW31_ARB 0x873F #endif #ifndef GL_ARB_matrix_palette #define GL_MATRIX_PALETTE_ARB 0x8840 #define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 #define GL_MAX_PALETTE_MATRICES_ARB 0x8842 #define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 #define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 #define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 #define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 #endif #ifndef GL_ARB_texture_env_combine #define GL_COMBINE_ARB 0x8570 #define GL_COMBINE_RGB_ARB 0x8571 #define GL_COMBINE_ALPHA_ARB 0x8572 #define GL_SOURCE0_RGB_ARB 0x8580 #define GL_SOURCE1_RGB_ARB 0x8581 #define GL_SOURCE2_RGB_ARB 0x8582 #define GL_SOURCE0_ALPHA_ARB 0x8588 #define GL_SOURCE1_ALPHA_ARB 0x8589 #define GL_SOURCE2_ALPHA_ARB 0x858A #define GL_OPERAND0_RGB_ARB 0x8590 #define GL_OPERAND1_RGB_ARB 0x8591 #define GL_OPERAND2_RGB_ARB 0x8592 #define GL_OPERAND0_ALPHA_ARB 0x8598 #define GL_OPERAND1_ALPHA_ARB 0x8599 #define GL_OPERAND2_ALPHA_ARB 0x859A #define GL_RGB_SCALE_ARB 0x8573 #define GL_ADD_SIGNED_ARB 0x8574 #define GL_INTERPOLATE_ARB 0x8575 #define GL_SUBTRACT_ARB 0x84E7 #define GL_CONSTANT_ARB 0x8576 #define GL_PRIMARY_COLOR_ARB 0x8577 #define GL_PREVIOUS_ARB 0x8578 #endif #ifndef GL_ARB_texture_env_crossbar #endif #ifndef GL_ARB_texture_env_dot3 #define GL_DOT3_RGB_ARB 0x86AE #define GL_DOT3_RGBA_ARB 0x86AF #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif #ifndef GL_ARB_depth_texture #define GL_DEPTH_COMPONENT16_ARB 0x81A5 #define GL_DEPTH_COMPONENT24_ARB 0x81A6 #define GL_DEPTH_COMPONENT32_ARB 0x81A7 #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif #ifndef GL_ARB_shadow #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D #define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E #endif #ifndef GL_ARB_shadow_ambient #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif #ifndef GL_ARB_window_pos #endif #ifndef GL_ARB_vertex_program #define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_PROGRAM_LENGTH_ARB 0x8627 #define GL_PROGRAM_STRING_ARB 0x8628 #define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E #define GL_MAX_PROGRAM_MATRICES_ARB 0x862F #define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 #define GL_CURRENT_MATRIX_ARB 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #define GL_PROGRAM_ERROR_POSITION_ARB 0x864B #define GL_PROGRAM_BINDING_ARB 0x8677 #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 #define GL_PROGRAM_FORMAT_ARB 0x8876 #define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 #define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 #define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 #define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 #define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 #define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 #define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 #define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 #define GL_PROGRAM_PARAMETERS_ARB 0x88A8 #define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 #define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA #define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB #define GL_PROGRAM_ATTRIBS_ARB 0x88AC #define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD #define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE #define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF #define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 #define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 #define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 #define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 #define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 #define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 #define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 #define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 #define GL_MATRIX0_ARB 0x88C0 #define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX3_ARB 0x88C3 #define GL_MATRIX4_ARB 0x88C4 #define GL_MATRIX5_ARB 0x88C5 #define GL_MATRIX6_ARB 0x88C6 #define GL_MATRIX7_ARB 0x88C7 #define GL_MATRIX8_ARB 0x88C8 #define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC #define GL_MATRIX13_ARB 0x88CD #define GL_MATRIX14_ARB 0x88CE #define GL_MATRIX15_ARB 0x88CF #define GL_MATRIX16_ARB 0x88D0 #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 #define GL_MATRIX23_ARB 0x88D7 #define GL_MATRIX24_ARB 0x88D8 #define GL_MATRIX25_ARB 0x88D9 #define GL_MATRIX26_ARB 0x88DA #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF #endif #ifndef GL_ARB_fragment_program #define GL_FRAGMENT_PROGRAM_ARB 0x8804 #define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 #define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 #define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 #define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 #define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 #define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A #define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B #define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C #define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D #define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E #define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F #define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #endif #ifndef GL_ARB_vertex_buffer_object #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F #define GL_READ_ONLY_ARB 0x88B8 #define GL_WRITE_ONLY_ARB 0x88B9 #define GL_READ_WRITE_ARB 0x88BA #define GL_BUFFER_ACCESS_ARB 0x88BB #define GL_BUFFER_MAPPED_ARB 0x88BC #define GL_BUFFER_MAP_POINTER_ARB 0x88BD #define GL_STREAM_DRAW_ARB 0x88E0 #define GL_STREAM_READ_ARB 0x88E1 #define GL_STREAM_COPY_ARB 0x88E2 #define GL_STATIC_DRAW_ARB 0x88E4 #define GL_STATIC_READ_ARB 0x88E5 #define GL_STATIC_COPY_ARB 0x88E6 #define GL_DYNAMIC_DRAW_ARB 0x88E8 #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA #endif #ifndef GL_ARB_occlusion_query #define GL_QUERY_COUNTER_BITS_ARB 0x8864 #define GL_CURRENT_QUERY_ARB 0x8865 #define GL_QUERY_RESULT_ARB 0x8866 #define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 #define GL_SAMPLES_PASSED_ARB 0x8914 #endif #ifndef GL_ARB_shader_objects #define GL_PROGRAM_OBJECT_ARB 0x8B40 #define GL_SHADER_OBJECT_ARB 0x8B48 #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 #define GL_INT_VEC2_ARB 0x8B53 #define GL_INT_VEC3_ARB 0x8B54 #define GL_INT_VEC4_ARB 0x8B55 #define GL_BOOL_ARB 0x8B56 #define GL_BOOL_VEC2_ARB 0x8B57 #define GL_BOOL_VEC3_ARB 0x8B58 #define GL_BOOL_VEC4_ARB 0x8B59 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #define GL_SAMPLER_1D_ARB 0x8B5D #define GL_SAMPLER_2D_ARB 0x8B5E #define GL_SAMPLER_3D_ARB 0x8B5F #define GL_SAMPLER_CUBE_ARB 0x8B60 #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 #endif #ifndef GL_ARB_vertex_shader #define GL_VERTEX_SHADER_ARB 0x8B31 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A #endif #ifndef GL_ARB_fragment_shader #define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B #endif #ifndef GL_ARB_shading_language_100 #define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C #endif #ifndef GL_ARB_texture_non_power_of_two #endif #ifndef GL_ARB_point_sprite #define GL_POINT_SPRITE_ARB 0x8861 #define GL_COORD_REPLACE_ARB 0x8862 #endif #ifndef GL_ARB_fragment_program_shadow #endif #ifndef GL_ARB_draw_buffers #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 #define GL_DRAW_BUFFER0_ARB 0x8825 #define GL_DRAW_BUFFER1_ARB 0x8826 #define GL_DRAW_BUFFER2_ARB 0x8827 #define GL_DRAW_BUFFER3_ARB 0x8828 #define GL_DRAW_BUFFER4_ARB 0x8829 #define GL_DRAW_BUFFER5_ARB 0x882A #define GL_DRAW_BUFFER6_ARB 0x882B #define GL_DRAW_BUFFER7_ARB 0x882C #define GL_DRAW_BUFFER8_ARB 0x882D #define GL_DRAW_BUFFER9_ARB 0x882E #define GL_DRAW_BUFFER10_ARB 0x882F #define GL_DRAW_BUFFER11_ARB 0x8830 #define GL_DRAW_BUFFER12_ARB 0x8831 #define GL_DRAW_BUFFER13_ARB 0x8832 #define GL_DRAW_BUFFER14_ARB 0x8833 #define GL_DRAW_BUFFER15_ARB 0x8834 #endif #ifndef GL_ARB_texture_rectangle #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 #endif #ifndef GL_ARB_color_buffer_float #define GL_RGBA_FLOAT_MODE_ARB 0x8820 #define GL_CLAMP_VERTEX_COLOR_ARB 0x891A #define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B #define GL_CLAMP_READ_COLOR_ARB 0x891C #define GL_FIXED_ONLY_ARB 0x891D #endif #ifndef GL_ARB_half_float_pixel #define GL_HALF_FLOAT_ARB 0x140B #endif #ifndef GL_ARB_texture_float #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 #define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 #define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 #define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 #define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #define GL_ALPHA32F_ARB 0x8816 #define GL_INTENSITY32F_ARB 0x8817 #define GL_LUMINANCE32F_ARB 0x8818 #define GL_LUMINANCE_ALPHA32F_ARB 0x8819 #define GL_RGBA16F_ARB 0x881A #define GL_RGB16F_ARB 0x881B #define GL_ALPHA16F_ARB 0x881C #define GL_INTENSITY16F_ARB 0x881D #define GL_LUMINANCE16F_ARB 0x881E #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif #ifndef GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif #ifndef GL_EXT_abgr #define GL_ABGR_EXT 0x8000 #endif #ifndef GL_EXT_blend_color #define GL_CONSTANT_COLOR_EXT 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 #define GL_CONSTANT_ALPHA_EXT 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 #define GL_BLEND_COLOR_EXT 0x8005 #endif #ifndef GL_EXT_polygon_offset #define GL_POLYGON_OFFSET_EXT 0x8037 #define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 #define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 #endif #ifndef GL_EXT_texture #define GL_ALPHA4_EXT 0x803B #define GL_ALPHA8_EXT 0x803C #define GL_ALPHA12_EXT 0x803D #define GL_ALPHA16_EXT 0x803E #define GL_LUMINANCE4_EXT 0x803F #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE12_EXT 0x8041 #define GL_LUMINANCE16_EXT 0x8042 #define GL_LUMINANCE4_ALPHA4_EXT 0x8043 #define GL_LUMINANCE6_ALPHA2_EXT 0x8044 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_LUMINANCE12_ALPHA4_EXT 0x8046 #define GL_LUMINANCE12_ALPHA12_EXT 0x8047 #define GL_LUMINANCE16_ALPHA16_EXT 0x8048 #define GL_INTENSITY_EXT 0x8049 #define GL_INTENSITY4_EXT 0x804A #define GL_INTENSITY8_EXT 0x804B #define GL_INTENSITY12_EXT 0x804C #define GL_INTENSITY16_EXT 0x804D #define GL_RGB2_EXT 0x804E #define GL_RGB4_EXT 0x804F #define GL_RGB5_EXT 0x8050 #define GL_RGB8_EXT 0x8051 #define GL_RGB10_EXT 0x8052 #define GL_RGB12_EXT 0x8053 #define GL_RGB16_EXT 0x8054 #define GL_RGBA2_EXT 0x8055 #define GL_RGBA4_EXT 0x8056 #define GL_RGB5_A1_EXT 0x8057 #define GL_RGBA8_EXT 0x8058 #define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA12_EXT 0x805A #define GL_RGBA16_EXT 0x805B #define GL_TEXTURE_RED_SIZE_EXT 0x805C #define GL_TEXTURE_GREEN_SIZE_EXT 0x805D #define GL_TEXTURE_BLUE_SIZE_EXT 0x805E #define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F #define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 #define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 #define GL_REPLACE_EXT 0x8062 #define GL_PROXY_TEXTURE_1D_EXT 0x8063 #define GL_PROXY_TEXTURE_2D_EXT 0x8064 #define GL_TEXTURE_TOO_LARGE_EXT 0x8065 #endif #ifndef GL_EXT_texture3D #define GL_PACK_SKIP_IMAGES_EXT 0x806B #define GL_PACK_IMAGE_HEIGHT_EXT 0x806C #define GL_UNPACK_SKIP_IMAGES_EXT 0x806D #define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E #define GL_TEXTURE_3D_EXT 0x806F #define GL_PROXY_TEXTURE_3D_EXT 0x8070 #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 #endif #ifndef GL_SGIS_texture_filter4 #define GL_FILTER4_SGIS 0x8146 #define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 #endif #ifndef GL_EXT_subtexture #endif #ifndef GL_EXT_copy_texture #endif #ifndef GL_EXT_histogram #define GL_HISTOGRAM_EXT 0x8024 #define GL_PROXY_HISTOGRAM_EXT 0x8025 #define GL_HISTOGRAM_WIDTH_EXT 0x8026 #define GL_HISTOGRAM_FORMAT_EXT 0x8027 #define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 #define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 #define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A #define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C #define GL_HISTOGRAM_SINK_EXT 0x802D #define GL_MINMAX_EXT 0x802E #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 #endif #ifndef GL_EXT_convolution #define GL_CONVOLUTION_1D_EXT 0x8010 #define GL_CONVOLUTION_2D_EXT 0x8011 #define GL_SEPARABLE_2D_EXT 0x8012 #define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 #define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 #define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 #define GL_REDUCE_EXT 0x8016 #define GL_CONVOLUTION_FORMAT_EXT 0x8017 #define GL_CONVOLUTION_WIDTH_EXT 0x8018 #define GL_CONVOLUTION_HEIGHT_EXT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A #define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F #define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 #endif #ifndef GL_SGI_color_matrix #define GL_COLOR_MATRIX_SGI 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB #endif #ifndef GL_SGI_color_table #define GL_COLOR_TABLE_SGI 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 #define GL_PROXY_COLOR_TABLE_SGI 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 #define GL_COLOR_TABLE_SCALE_SGI 0x80D6 #define GL_COLOR_TABLE_BIAS_SGI 0x80D7 #define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 #define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 #define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF #endif #ifndef GL_SGIS_pixel_texture #define GL_PIXEL_TEXTURE_SGIS 0x8353 #define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 #define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 #define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 #endif #ifndef GL_SGIX_pixel_texture #define GL_PIXEL_TEX_GEN_SGIX 0x8139 #define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B #endif #ifndef GL_SGIS_texture4D #define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 #define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 #define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 #define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 #define GL_TEXTURE_4D_SGIS 0x8134 #define GL_PROXY_TEXTURE_4D_SGIS 0x8135 #define GL_TEXTURE_4DSIZE_SGIS 0x8136 #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F #endif #ifndef GL_SGI_texture_color_table #define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC #define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD #endif #ifndef GL_EXT_cmyka #define GL_CMYK_EXT 0x800C #define GL_CMYKA_EXT 0x800D #define GL_PACK_CMYK_HINT_EXT 0x800E #define GL_UNPACK_CMYK_HINT_EXT 0x800F #endif #ifndef GL_EXT_texture_object #define GL_TEXTURE_PRIORITY_EXT 0x8066 #define GL_TEXTURE_RESIDENT_EXT 0x8067 #define GL_TEXTURE_1D_BINDING_EXT 0x8068 #define GL_TEXTURE_2D_BINDING_EXT 0x8069 #define GL_TEXTURE_3D_BINDING_EXT 0x806A #endif #ifndef GL_SGIS_detail_texture #define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 #define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 #define GL_LINEAR_DETAIL_SGIS 0x8097 #define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 #define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 #define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A #define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B #define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C #endif #ifndef GL_SGIS_sharpen_texture #define GL_LINEAR_SHARPEN_SGIS 0x80AD #define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE #define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF #define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 #endif #ifndef GL_EXT_packed_pixels #define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 #define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 #define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 #endif #ifndef GL_SGIS_texture_lod #define GL_TEXTURE_MIN_LOD_SGIS 0x813A #define GL_TEXTURE_MAX_LOD_SGIS 0x813B #define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C #define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D #endif #ifndef GL_SGIS_multisample #define GL_MULTISAMPLE_SGIS 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F #define GL_SAMPLE_MASK_SGIS 0x80A0 #define GL_1PASS_SGIS 0x80A1 #define GL_2PASS_0_SGIS 0x80A2 #define GL_2PASS_1_SGIS 0x80A3 #define GL_4PASS_0_SGIS 0x80A4 #define GL_4PASS_1_SGIS 0x80A5 #define GL_4PASS_2_SGIS 0x80A6 #define GL_4PASS_3_SGIS 0x80A7 #define GL_SAMPLE_BUFFERS_SGIS 0x80A8 #define GL_SAMPLES_SGIS 0x80A9 #define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA #define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB #define GL_SAMPLE_PATTERN_SGIS 0x80AC #endif #ifndef GL_EXT_rescale_normal #define GL_RESCALE_NORMAL_EXT 0x803A #endif #ifndef GL_EXT_vertex_array #define GL_VERTEX_ARRAY_EXT 0x8074 #define GL_NORMAL_ARRAY_EXT 0x8075 #define GL_COLOR_ARRAY_EXT 0x8076 #define GL_INDEX_ARRAY_EXT 0x8077 #define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 #define GL_EDGE_FLAG_ARRAY_EXT 0x8079 #define GL_VERTEX_ARRAY_SIZE_EXT 0x807A #define GL_VERTEX_ARRAY_TYPE_EXT 0x807B #define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C #define GL_VERTEX_ARRAY_COUNT_EXT 0x807D #define GL_NORMAL_ARRAY_TYPE_EXT 0x807E #define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F #define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 #define GL_COLOR_ARRAY_SIZE_EXT 0x8081 #define GL_COLOR_ARRAY_TYPE_EXT 0x8082 #define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 #define GL_COLOR_ARRAY_COUNT_EXT 0x8084 #define GL_INDEX_ARRAY_TYPE_EXT 0x8085 #define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 #define GL_INDEX_ARRAY_COUNT_EXT 0x8087 #define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A #define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B #define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C #define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D #define GL_VERTEX_ARRAY_POINTER_EXT 0x808E #define GL_NORMAL_ARRAY_POINTER_EXT 0x808F #define GL_COLOR_ARRAY_POINTER_EXT 0x8090 #define GL_INDEX_ARRAY_POINTER_EXT 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 #endif #ifndef GL_EXT_misc_attribute #endif #ifndef GL_SGIS_generate_mipmap #define GL_GENERATE_MIPMAP_SGIS 0x8191 #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif #ifndef GL_SGIX_clipmap #define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 #define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 #define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 #define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 #define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 #define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 #define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 #define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 #define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 #define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D #define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E #define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F #endif #ifndef GL_SGIX_shadow #define GL_TEXTURE_COMPARE_SGIX 0x819A #define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B #define GL_TEXTURE_LEQUAL_R_SGIX 0x819C #define GL_TEXTURE_GEQUAL_R_SGIX 0x819D #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_CLAMP_TO_EDGE_SGIS 0x812F #endif #ifndef GL_SGIS_texture_border_clamp #define GL_CLAMP_TO_BORDER_SGIS 0x812D #endif #ifndef GL_EXT_blend_minmax #define GL_FUNC_ADD_EXT 0x8006 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #define GL_BLEND_EQUATION_EXT 0x8009 #endif #ifndef GL_EXT_blend_subtract #define GL_FUNC_SUBTRACT_EXT 0x800A #define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B #endif #ifndef GL_EXT_blend_logic_op #endif #ifndef GL_SGIX_interlace #define GL_INTERLACE_SGIX 0x8094 #endif #ifndef GL_SGIX_pixel_tiles #define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E #define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F #define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 #define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 #define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 #define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 #define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 #define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 #endif #ifndef GL_SGIS_texture_select #define GL_DUAL_ALPHA4_SGIS 0x8110 #define GL_DUAL_ALPHA8_SGIS 0x8111 #define GL_DUAL_ALPHA12_SGIS 0x8112 #define GL_DUAL_ALPHA16_SGIS 0x8113 #define GL_DUAL_LUMINANCE4_SGIS 0x8114 #define GL_DUAL_LUMINANCE8_SGIS 0x8115 #define GL_DUAL_LUMINANCE12_SGIS 0x8116 #define GL_DUAL_LUMINANCE16_SGIS 0x8117 #define GL_DUAL_INTENSITY4_SGIS 0x8118 #define GL_DUAL_INTENSITY8_SGIS 0x8119 #define GL_DUAL_INTENSITY12_SGIS 0x811A #define GL_DUAL_INTENSITY16_SGIS 0x811B #define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C #define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D #define GL_QUAD_ALPHA4_SGIS 0x811E #define GL_QUAD_ALPHA8_SGIS 0x811F #define GL_QUAD_LUMINANCE4_SGIS 0x8120 #define GL_QUAD_LUMINANCE8_SGIS 0x8121 #define GL_QUAD_INTENSITY4_SGIS 0x8122 #define GL_QUAD_INTENSITY8_SGIS 0x8123 #define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 #define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 #endif #ifndef GL_SGIX_sprite #define GL_SPRITE_SGIX 0x8148 #define GL_SPRITE_MODE_SGIX 0x8149 #define GL_SPRITE_AXIS_SGIX 0x814A #define GL_SPRITE_TRANSLATION_SGIX 0x814B #define GL_SPRITE_AXIAL_SGIX 0x814C #define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D #define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E #endif #ifndef GL_EXT_point_parameters #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 #endif #ifndef GL_SGIS_point_parameters #define GL_POINT_SIZE_MIN_SGIS 0x8126 #define GL_POINT_SIZE_MAX_SGIS 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 #define GL_DISTANCE_ATTENUATION_SGIS 0x8129 #endif #ifndef GL_SGIX_instruments #define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 #define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 #endif #ifndef GL_SGIX_texture_scale_bias #define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 #define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A #define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B #define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C #endif #ifndef GL_SGIX_framezoom #define GL_FRAMEZOOM_SGIX 0x818B #define GL_FRAMEZOOM_FACTOR_SGIX 0x818C #define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D #endif #ifndef GL_SGIX_tag_sample_buffer #endif #ifndef GL_FfdMaskSGIX #define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 #define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 #endif #ifndef GL_SGIX_polynomial_ffd #define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 #define GL_TEXTURE_DEFORMATION_SGIX 0x8195 #define GL_DEFORMATIONS_MASK_SGIX 0x8196 #define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 #endif #ifndef GL_SGIX_reference_plane #define GL_REFERENCE_PLANE_SGIX 0x817D #define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E #endif #ifndef GL_SGIX_flush_raster #endif #ifndef GL_SGIX_depth_texture #define GL_DEPTH_COMPONENT16_SGIX 0x81A5 #define GL_DEPTH_COMPONENT24_SGIX 0x81A6 #define GL_DEPTH_COMPONENT32_SGIX 0x81A7 #endif #ifndef GL_SGIS_fog_function #define GL_FOG_FUNC_SGIS 0x812A #define GL_FOG_FUNC_POINTS_SGIS 0x812B #define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C #endif #ifndef GL_SGIX_fog_offset #define GL_FOG_OFFSET_SGIX 0x8198 #define GL_FOG_OFFSET_VALUE_SGIX 0x8199 #endif #ifndef GL_HP_image_transform #define GL_IMAGE_SCALE_X_HP 0x8155 #define GL_IMAGE_SCALE_Y_HP 0x8156 #define GL_IMAGE_TRANSLATE_X_HP 0x8157 #define GL_IMAGE_TRANSLATE_Y_HP 0x8158 #define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 #define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A #define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B #define GL_IMAGE_MAG_FILTER_HP 0x815C #define GL_IMAGE_MIN_FILTER_HP 0x815D #define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E #define GL_CUBIC_HP 0x815F #define GL_AVERAGE_HP 0x8160 #define GL_IMAGE_TRANSFORM_2D_HP 0x8161 #define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 #define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 #endif #ifndef GL_HP_convolution_border_modes #define GL_IGNORE_BORDER_HP 0x8150 #define GL_CONSTANT_BORDER_HP 0x8151 #define GL_REPLICATE_BORDER_HP 0x8153 #define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 #endif #ifndef GL_INGR_palette_buffer #endif #ifndef GL_SGIX_texture_add_env #define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE #endif #ifndef GL_EXT_color_subtable #endif #ifndef GL_PGI_vertex_hints #define GL_VERTEX_DATA_HINT_PGI 0x1A22A #define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B #define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C #define GL_MAX_VERTEX_HINT_PGI 0x1A22D #define GL_COLOR3_BIT_PGI 0x00010000 #define GL_COLOR4_BIT_PGI 0x00020000 #define GL_EDGEFLAG_BIT_PGI 0x00040000 #define GL_INDEX_BIT_PGI 0x00080000 #define GL_MAT_AMBIENT_BIT_PGI 0x00100000 #define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 #define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 #define GL_MAT_EMISSION_BIT_PGI 0x00800000 #define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 #define GL_MAT_SHININESS_BIT_PGI 0x02000000 #define GL_MAT_SPECULAR_BIT_PGI 0x04000000 #define GL_NORMAL_BIT_PGI 0x08000000 #define GL_TEXCOORD1_BIT_PGI 0x10000000 #define GL_TEXCOORD2_BIT_PGI 0x20000000 #define GL_TEXCOORD3_BIT_PGI 0x40000000 #define GL_TEXCOORD4_BIT_PGI 0x80000000 #define GL_VERTEX23_BIT_PGI 0x00000004 #define GL_VERTEX4_BIT_PGI 0x00000008 #endif #ifndef GL_PGI_misc_hints #define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 #define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD #define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE #define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 #define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 #define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 #define GL_ALWAYS_FAST_HINT_PGI 0x1A20C #define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D #define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E #define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F #define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 #define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 #define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 #define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 #define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 #define GL_FULL_STIPPLE_HINT_PGI 0x1A219 #define GL_CLIP_NEAR_HINT_PGI 0x1A220 #define GL_CLIP_FAR_HINT_PGI 0x1A221 #define GL_WIDE_LINE_HINT_PGI 0x1A222 #define GL_BACK_NORMALS_HINT_PGI 0x1A223 #endif #ifndef GL_EXT_paletted_texture #define GL_COLOR_INDEX1_EXT 0x80E2 #define GL_COLOR_INDEX2_EXT 0x80E3 #define GL_COLOR_INDEX4_EXT 0x80E4 #define GL_COLOR_INDEX8_EXT 0x80E5 #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED #endif #ifndef GL_EXT_clip_volume_hint #define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 #endif #ifndef GL_SGIX_list_priority #define GL_LIST_PRIORITY_SGIX 0x8182 #endif #ifndef GL_SGIX_ir_instrument1 #define GL_IR_INSTRUMENT1_SGIX 0x817F #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E #define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F #define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SHADOW_AMBIENT_SGIX 0x80BF #endif #ifndef GL_EXT_index_texture #endif #ifndef GL_EXT_index_material #define GL_INDEX_MATERIAL_EXT 0x81B8 #define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 #define GL_INDEX_MATERIAL_FACE_EXT 0x81BA #endif #ifndef GL_EXT_index_func #define GL_INDEX_TEST_EXT 0x81B5 #define GL_INDEX_TEST_FUNC_EXT 0x81B6 #define GL_INDEX_TEST_REF_EXT 0x81B7 #endif #ifndef GL_EXT_index_array_formats #define GL_IUI_V2F_EXT 0x81AD #define GL_IUI_V3F_EXT 0x81AE #define GL_IUI_N3F_V2F_EXT 0x81AF #define GL_IUI_N3F_V3F_EXT 0x81B0 #define GL_T2F_IUI_V2F_EXT 0x81B1 #define GL_T2F_IUI_V3F_EXT 0x81B2 #define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 #define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 #endif #ifndef GL_EXT_cull_vertex #define GL_CULL_VERTEX_EXT 0x81AA #define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB #define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC #endif #ifndef GL_SGIX_ycrcb #define GL_YCRCB_422_SGIX 0x81BB #define GL_YCRCB_444_SGIX 0x81BC #endif #ifndef GL_SGIX_fragment_lighting #define GL_FRAGMENT_LIGHTING_SGIX 0x8400 #define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 #define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 #define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 #define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 #define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 #define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 #define GL_LIGHT_ENV_MODE_SGIX 0x8407 #define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 #define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 #define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A #define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B #define GL_FRAGMENT_LIGHT0_SGIX 0x840C #define GL_FRAGMENT_LIGHT1_SGIX 0x840D #define GL_FRAGMENT_LIGHT2_SGIX 0x840E #define GL_FRAGMENT_LIGHT3_SGIX 0x840F #define GL_FRAGMENT_LIGHT4_SGIX 0x8410 #define GL_FRAGMENT_LIGHT5_SGIX 0x8411 #define GL_FRAGMENT_LIGHT6_SGIX 0x8412 #define GL_FRAGMENT_LIGHT7_SGIX 0x8413 #endif #ifndef GL_IBM_rasterpos_clip #define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 #endif #ifndef GL_HP_texture_lighting #define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 #define GL_TEXTURE_POST_SPECULAR_HP 0x8168 #define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 #endif #ifndef GL_EXT_draw_range_elements #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 #endif #ifndef GL_WIN_phong_shading #define GL_PHONG_WIN 0x80EA #define GL_PHONG_HINT_WIN 0x80EB #endif #ifndef GL_WIN_specular_fog #define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC #endif #ifndef GL_EXT_light_texture #define GL_FRAGMENT_MATERIAL_EXT 0x8349 #define GL_FRAGMENT_NORMAL_EXT 0x834A #define GL_FRAGMENT_COLOR_EXT 0x834C #define GL_ATTENUATION_EXT 0x834D #define GL_SHADOW_ATTENUATION_EXT 0x834E #define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F #define GL_TEXTURE_LIGHT_EXT 0x8350 #define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 #define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 /* reuse GL_FRAGMENT_DEPTH_EXT */ #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_ALPHA_MIN_SGIX 0x8320 #define GL_ALPHA_MAX_SGIX 0x8321 #endif #ifndef GL_SGIX_impact_pixel_texture #define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 #define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 #define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 #define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 #define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 #define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 #define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A #endif #ifndef GL_EXT_bgra #define GL_BGR_EXT 0x80E0 #define GL_BGRA_EXT 0x80E1 #endif #ifndef GL_SGIX_async #define GL_ASYNC_MARKER_SGIX 0x8329 #endif #ifndef GL_SGIX_async_pixel #define GL_ASYNC_TEX_IMAGE_SGIX 0x835C #define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D #define GL_ASYNC_READ_PIXELS_SGIX 0x835E #define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F #define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 #define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 #endif #ifndef GL_SGIX_async_histogram #define GL_ASYNC_HISTOGRAM_SGIX 0x832C #define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D #endif #ifndef GL_INTEL_texture_scissor #endif #ifndef GL_INTEL_parallel_arrays #define GL_PARALLEL_ARRAYS_INTEL 0x83F4 #define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 #endif #ifndef GL_HP_occlusion_test #define GL_OCCLUSION_TEST_HP 0x8165 #define GL_OCCLUSION_TEST_RESULT_HP 0x8166 #endif #ifndef GL_EXT_pixel_transform #define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 #define GL_PIXEL_MAG_FILTER_EXT 0x8331 #define GL_PIXEL_MIN_FILTER_EXT 0x8332 #define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 #define GL_CUBIC_EXT 0x8334 #define GL_AVERAGE_EXT 0x8335 #define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 #define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 #define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 #endif #ifndef GL_EXT_pixel_transform_color_table #endif #ifndef GL_EXT_shared_texture_palette #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB #endif #ifndef GL_EXT_separate_specular_color #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 #define GL_SINGLE_COLOR_EXT 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA #endif #ifndef GL_EXT_secondary_color #define GL_COLOR_SUM_EXT 0x8458 #define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D #define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E #endif #ifndef GL_EXT_texture_perturb_normal #define GL_PERTURB_EXT 0x85AE #define GL_TEXTURE_NORMAL_EXT 0x85AF #endif #ifndef GL_EXT_multi_draw_arrays #endif #ifndef GL_EXT_fog_coord #define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 #define GL_FOG_COORDINATE_EXT 0x8451 #define GL_FRAGMENT_DEPTH_EXT 0x8452 #define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 #define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 #endif #ifndef GL_REND_screen_coordinates #define GL_SCREEN_COORDINATES_REND 0x8490 #define GL_INVERTED_SCREEN_W_REND 0x8491 #endif #ifndef GL_EXT_coordinate_frame #define GL_TANGENT_ARRAY_EXT 0x8439 #define GL_BINORMAL_ARRAY_EXT 0x843A #define GL_CURRENT_TANGENT_EXT 0x843B #define GL_CURRENT_BINORMAL_EXT 0x843C #define GL_TANGENT_ARRAY_TYPE_EXT 0x843E #define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F #define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 #define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 #define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 #define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 #define GL_MAP1_TANGENT_EXT 0x8444 #define GL_MAP2_TANGENT_EXT 0x8445 #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 #endif #ifndef GL_EXT_texture_env_combine #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_ADD_SIGNED_EXT 0x8574 #define GL_INTERPOLATE_EXT 0x8575 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE2_RGB_EXT 0x8582 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 #define GL_SOURCE2_ALPHA_EXT 0x858A #define GL_OPERAND0_RGB_EXT 0x8590 #define GL_OPERAND1_RGB_EXT 0x8591 #define GL_OPERAND2_RGB_EXT 0x8592 #define GL_OPERAND0_ALPHA_EXT 0x8598 #define GL_OPERAND1_ALPHA_EXT 0x8599 #define GL_OPERAND2_ALPHA_EXT 0x859A #endif #ifndef GL_APPLE_specular_vector #define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 #endif #ifndef GL_APPLE_transform_hint #define GL_TRANSFORM_HINT_APPLE 0x85B1 #endif #ifndef GL_SGIX_fog_scale #define GL_FOG_SCALE_SGIX 0x81FC #define GL_FOG_SCALE_VALUE_SGIX 0x81FD #endif #ifndef GL_SUNX_constant_data #define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 #define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 #endif #ifndef GL_SUN_global_alpha #define GL_GLOBAL_ALPHA_SUN 0x81D9 #define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA #endif #ifndef GL_SUN_triangle_list #define GL_RESTART_SUN 0x0001 #define GL_REPLACE_MIDDLE_SUN 0x0002 #define GL_REPLACE_OLDEST_SUN 0x0003 #define GL_TRIANGLE_LIST_SUN 0x81D7 #define GL_REPLACEMENT_CODE_SUN 0x81D8 #define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 #define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 #define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 #define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 #define GL_R1UI_V3F_SUN 0x85C4 #define GL_R1UI_C4UB_V3F_SUN 0x85C5 #define GL_R1UI_C3F_V3F_SUN 0x85C6 #define GL_R1UI_N3F_V3F_SUN 0x85C7 #define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 #define GL_R1UI_T2F_V3F_SUN 0x85C9 #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB #endif #ifndef GL_SUN_vertex #endif #ifndef GL_EXT_blend_func_separate #define GL_BLEND_DST_RGB_EXT 0x80C8 #define GL_BLEND_SRC_RGB_EXT 0x80C9 #define GL_BLEND_DST_ALPHA_EXT 0x80CA #define GL_BLEND_SRC_ALPHA_EXT 0x80CB #endif #ifndef GL_INGR_color_clamp #define GL_RED_MIN_CLAMP_INGR 0x8560 #define GL_GREEN_MIN_CLAMP_INGR 0x8561 #define GL_BLUE_MIN_CLAMP_INGR 0x8562 #define GL_ALPHA_MIN_CLAMP_INGR 0x8563 #define GL_RED_MAX_CLAMP_INGR 0x8564 #define GL_GREEN_MAX_CLAMP_INGR 0x8565 #define GL_BLUE_MAX_CLAMP_INGR 0x8566 #define GL_ALPHA_MAX_CLAMP_INGR 0x8567 #endif #ifndef GL_INGR_interlace_read #define GL_INTERLACE_READ_INGR 0x8568 #endif #ifndef GL_EXT_stencil_wrap #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 #endif #ifndef GL_EXT_422_pixels #define GL_422_EXT 0x80CC #define GL_422_REV_EXT 0x80CD #define GL_422_AVERAGE_EXT 0x80CE #define GL_422_REV_AVERAGE_EXT 0x80CF #endif #ifndef GL_NV_texgen_reflection #define GL_NORMAL_MAP_NV 0x8511 #define GL_REFLECTION_MAP_NV 0x8512 #endif #ifndef GL_EXT_texture_cube_map #define GL_NORMAL_MAP_EXT 0x8511 #define GL_REFLECTION_MAP_EXT 0x8512 #define GL_TEXTURE_CUBE_MAP_EXT 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif #ifndef GL_SUN_convolution_border_modes #define GL_WRAP_BORDER_SUN 0x81D4 #endif #ifndef GL_EXT_texture_env_add #endif #ifndef GL_EXT_texture_lod_bias #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif #ifndef GL_EXT_vertex_weighting #define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH #define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 #define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX #define GL_MODELVIEW1_MATRIX_EXT 0x8506 #define GL_VERTEX_WEIGHTING_EXT 0x8509 #define GL_MODELVIEW0_EXT GL_MODELVIEW #define GL_MODELVIEW1_EXT 0x850A #define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B #define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C #define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D #define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 #endif #ifndef GL_NV_light_max_exponent #define GL_MAX_SHININESS_NV 0x8504 #define GL_MAX_SPOT_EXPONENT_NV 0x8505 #endif #ifndef GL_NV_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_NV 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E #define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 #endif #ifndef GL_NV_register_combiners #define GL_REGISTER_COMBINERS_NV 0x8522 #define GL_VARIABLE_A_NV 0x8523 #define GL_VARIABLE_B_NV 0x8524 #define GL_VARIABLE_C_NV 0x8525 #define GL_VARIABLE_D_NV 0x8526 #define GL_VARIABLE_E_NV 0x8527 #define GL_VARIABLE_F_NV 0x8528 #define GL_VARIABLE_G_NV 0x8529 #define GL_CONSTANT_COLOR0_NV 0x852A #define GL_CONSTANT_COLOR1_NV 0x852B #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D #define GL_SPARE0_NV 0x852E #define GL_SPARE1_NV 0x852F #define GL_DISCARD_NV 0x8530 #define GL_E_TIMES_F_NV 0x8531 #define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 #define GL_UNSIGNED_IDENTITY_NV 0x8536 #define GL_UNSIGNED_INVERT_NV 0x8537 #define GL_EXPAND_NORMAL_NV 0x8538 #define GL_EXPAND_NEGATE_NV 0x8539 #define GL_HALF_BIAS_NORMAL_NV 0x853A #define GL_HALF_BIAS_NEGATE_NV 0x853B #define GL_SIGNED_IDENTITY_NV 0x853C #define GL_SIGNED_NEGATE_NV 0x853D #define GL_SCALE_BY_TWO_NV 0x853E #define GL_SCALE_BY_FOUR_NV 0x853F #define GL_SCALE_BY_ONE_HALF_NV 0x8540 #define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 #define GL_COMBINER_INPUT_NV 0x8542 #define GL_COMBINER_MAPPING_NV 0x8543 #define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 #define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 #define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 #define GL_COMBINER_MUX_SUM_NV 0x8547 #define GL_COMBINER_SCALE_NV 0x8548 #define GL_COMBINER_BIAS_NV 0x8549 #define GL_COMBINER_AB_OUTPUT_NV 0x854A #define GL_COMBINER_CD_OUTPUT_NV 0x854B #define GL_COMBINER_SUM_OUTPUT_NV 0x854C #define GL_MAX_GENERAL_COMBINERS_NV 0x854D #define GL_NUM_GENERAL_COMBINERS_NV 0x854E #define GL_COLOR_SUM_CLAMP_NV 0x854F #define GL_COMBINER0_NV 0x8550 #define GL_COMBINER1_NV 0x8551 #define GL_COMBINER2_NV 0x8552 #define GL_COMBINER3_NV 0x8553 #define GL_COMBINER4_NV 0x8554 #define GL_COMBINER5_NV 0x8555 #define GL_COMBINER6_NV 0x8556 #define GL_COMBINER7_NV 0x8557 /* reuse GL_TEXTURE0_ARB */ /* reuse GL_TEXTURE1_ARB */ /* reuse GL_ZERO */ /* reuse GL_NONE */ /* reuse GL_FOG */ #endif #ifndef GL_NV_fog_distance #define GL_FOG_DISTANCE_MODE_NV 0x855A #define GL_EYE_RADIAL_NV 0x855B #define GL_EYE_PLANE_ABSOLUTE_NV 0x855C /* reuse GL_EYE_PLANE */ #endif #ifndef GL_NV_texgen_emboss #define GL_EMBOSS_LIGHT_NV 0x855D #define GL_EMBOSS_CONSTANT_NV 0x855E #define GL_EMBOSS_MAP_NV 0x855F #endif #ifndef GL_NV_blend_square #endif #ifndef GL_NV_texture_env_combine4 #define GL_COMBINE4_NV 0x8503 #define GL_SOURCE3_RGB_NV 0x8583 #define GL_SOURCE3_ALPHA_NV 0x858B #define GL_OPERAND3_RGB_NV 0x8593 #define GL_OPERAND3_ALPHA_NV 0x859B #endif #ifndef GL_MESA_resize_buffers #endif #ifndef GL_MESA_window_pos #endif #ifndef GL_EXT_texture_compression_s3tc #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif #ifndef GL_IBM_cull_vertex #define GL_CULL_VERTEX_IBM 103050 #endif #ifndef GL_IBM_multimode_draw_arrays #endif #ifndef GL_IBM_vertex_array_lists #define GL_VERTEX_ARRAY_LIST_IBM 103070 #define GL_NORMAL_ARRAY_LIST_IBM 103071 #define GL_COLOR_ARRAY_LIST_IBM 103072 #define GL_INDEX_ARRAY_LIST_IBM 103073 #define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 #define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 #define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 #define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 #define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 #define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 #define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 #define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 #define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 #endif #ifndef GL_SGIX_subsample #define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 #define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 #define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 #define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 #define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 #endif #ifndef GL_SGIX_ycrcb_subsample #endif #ifndef GL_SGIX_ycrcba #define GL_YCRCB_SGIX 0x8318 #define GL_YCRCBA_SGIX 0x8319 #endif #ifndef GL_SGI_depth_pass_instrument #define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 #define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 #define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 #define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 #endif #ifndef GL_3DFX_multisample #define GL_MULTISAMPLE_3DFX 0x86B2 #define GL_SAMPLE_BUFFERS_3DFX 0x86B3 #define GL_SAMPLES_3DFX 0x86B4 #define GL_MULTISAMPLE_BIT_3DFX 0x20000000 #endif #ifndef GL_3DFX_tbuffer #endif #ifndef GL_EXT_multisample #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #define GL_SAMPLE_MASK_EXT 0x80A0 #define GL_1PASS_EXT 0x80A1 #define GL_2PASS_0_EXT 0x80A2 #define GL_2PASS_1_EXT 0x80A3 #define GL_4PASS_0_EXT 0x80A4 #define GL_4PASS_1_EXT 0x80A5 #define GL_4PASS_2_EXT 0x80A6 #define GL_4PASS_3_EXT 0x80A7 #define GL_SAMPLE_BUFFERS_EXT 0x80A8 #define GL_SAMPLES_EXT 0x80A9 #define GL_SAMPLE_MASK_VALUE_EXT 0x80AA #define GL_SAMPLE_MASK_INVERT_EXT 0x80AB #define GL_SAMPLE_PATTERN_EXT 0x80AC #define GL_MULTISAMPLE_BIT_EXT 0x20000000 #endif #ifndef GL_SGIX_vertex_preclip #define GL_VERTEX_PRECLIP_SGIX 0x83EE #define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF #endif #ifndef GL_SGIX_convolution_accuracy #define GL_CONVOLUTION_HINT_SGIX 0x8316 #endif #ifndef GL_SGIX_resample #define GL_PACK_RESAMPLE_SGIX 0x842C #define GL_UNPACK_RESAMPLE_SGIX 0x842D #define GL_RESAMPLE_REPLICATE_SGIX 0x842E #define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F #define GL_RESAMPLE_DECIMATE_SGIX 0x8430 #endif #ifndef GL_SGIS_point_line_texgen #define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 #define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 #define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 #define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 #define GL_EYE_POINT_SGIS 0x81F4 #define GL_OBJECT_POINT_SGIS 0x81F5 #define GL_EYE_LINE_SGIS 0x81F6 #define GL_OBJECT_LINE_SGIS 0x81F7 #endif #ifndef GL_SGIS_texture_color_mask #define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF #endif #ifndef GL_EXT_texture_env_dot3 #define GL_DOT3_RGB_EXT 0x8740 #define GL_DOT3_RGBA_EXT 0x8741 #endif #ifndef GL_ATI_texture_mirror_once #define GL_MIRROR_CLAMP_ATI 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 #endif #ifndef GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif #ifndef GL_IBM_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_IBM 0x8370 #endif #ifndef GL_NV_evaluators #define GL_EVAL_2D_NV 0x86C0 #define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 #define GL_MAP_TESSELLATION_NV 0x86C2 #define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 #define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 #define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 #define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 #define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 #define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 #define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 #define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA #define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB #define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC #define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD #define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE #define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF #define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 #define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 #define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 #define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 #define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 #endif #ifndef GL_NV_packed_depth_stencil #define GL_DEPTH_STENCIL_NV 0x84F9 #define GL_UNSIGNED_INT_24_8_NV 0x84FA #endif #ifndef GL_NV_register_combiners2 #define GL_PER_STAGE_CONSTANTS_NV 0x8535 #endif #ifndef GL_NV_texture_compression_vtc #endif #ifndef GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 #endif #ifndef GL_NV_texture_shader #define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C #define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D #define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E #define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 #define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA #define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB #define GL_DSDT_MAG_INTENSITY_NV 0x86DC #define GL_SHADER_CONSISTENT_NV 0x86DD #define GL_TEXTURE_SHADER_NV 0x86DE #define GL_SHADER_OPERATION_NV 0x86DF #define GL_CULL_MODES_NV 0x86E0 #define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 #define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV #define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV #define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV #define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 #define GL_CONST_EYE_NV 0x86E5 #define GL_PASS_THROUGH_NV 0x86E6 #define GL_CULL_FRAGMENT_NV 0x86E7 #define GL_OFFSET_TEXTURE_2D_NV 0x86E8 #define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 #define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA #define GL_DOT_PRODUCT_NV 0x86EC #define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED #define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE #define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 #define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 #define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 #define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 #define GL_HILO_NV 0x86F4 #define GL_DSDT_NV 0x86F5 #define GL_DSDT_MAG_NV 0x86F6 #define GL_DSDT_MAG_VIB_NV 0x86F7 #define GL_HILO16_NV 0x86F8 #define GL_SIGNED_HILO_NV 0x86F9 #define GL_SIGNED_HILO16_NV 0x86FA #define GL_SIGNED_RGBA_NV 0x86FB #define GL_SIGNED_RGBA8_NV 0x86FC #define GL_SIGNED_RGB_NV 0x86FE #define GL_SIGNED_RGB8_NV 0x86FF #define GL_SIGNED_LUMINANCE_NV 0x8701 #define GL_SIGNED_LUMINANCE8_NV 0x8702 #define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 #define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 #define GL_SIGNED_ALPHA_NV 0x8705 #define GL_SIGNED_ALPHA8_NV 0x8706 #define GL_SIGNED_INTENSITY_NV 0x8707 #define GL_SIGNED_INTENSITY8_NV 0x8708 #define GL_DSDT8_NV 0x8709 #define GL_DSDT8_MAG8_NV 0x870A #define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B #define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C #define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D #define GL_HI_SCALE_NV 0x870E #define GL_LO_SCALE_NV 0x870F #define GL_DS_SCALE_NV 0x8710 #define GL_DT_SCALE_NV 0x8711 #define GL_MAGNITUDE_SCALE_NV 0x8712 #define GL_VIBRANCE_SCALE_NV 0x8713 #define GL_HI_BIAS_NV 0x8714 #define GL_LO_BIAS_NV 0x8715 #define GL_DS_BIAS_NV 0x8716 #define GL_DT_BIAS_NV 0x8717 #define GL_MAGNITUDE_BIAS_NV 0x8718 #define GL_VIBRANCE_BIAS_NV 0x8719 #define GL_TEXTURE_BORDER_VALUES_NV 0x871A #define GL_TEXTURE_HI_SIZE_NV 0x871B #define GL_TEXTURE_LO_SIZE_NV 0x871C #define GL_TEXTURE_DS_SIZE_NV 0x871D #define GL_TEXTURE_DT_SIZE_NV 0x871E #define GL_TEXTURE_MAG_SIZE_NV 0x871F #endif #ifndef GL_NV_texture_shader2 #define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF #endif #ifndef GL_NV_vertex_array_range2 #define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 #endif #ifndef GL_NV_vertex_program #define GL_VERTEX_PROGRAM_NV 0x8620 #define GL_VERTEX_STATE_PROGRAM_NV 0x8621 #define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 #define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 #define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 #define GL_CURRENT_ATTRIB_NV 0x8626 #define GL_PROGRAM_LENGTH_NV 0x8627 #define GL_PROGRAM_STRING_NV 0x8628 #define GL_MODELVIEW_PROJECTION_NV 0x8629 #define GL_IDENTITY_NV 0x862A #define GL_INVERSE_NV 0x862B #define GL_TRANSPOSE_NV 0x862C #define GL_INVERSE_TRANSPOSE_NV 0x862D #define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E #define GL_MAX_TRACK_MATRICES_NV 0x862F #define GL_MATRIX0_NV 0x8630 #define GL_MATRIX1_NV 0x8631 #define GL_MATRIX2_NV 0x8632 #define GL_MATRIX3_NV 0x8633 #define GL_MATRIX4_NV 0x8634 #define GL_MATRIX5_NV 0x8635 #define GL_MATRIX6_NV 0x8636 #define GL_MATRIX7_NV 0x8637 #define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 #define GL_CURRENT_MATRIX_NV 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 #define GL_PROGRAM_PARAMETER_NV 0x8644 #define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 #define GL_PROGRAM_TARGET_NV 0x8646 #define GL_PROGRAM_RESIDENT_NV 0x8647 #define GL_TRACK_MATRIX_NV 0x8648 #define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 #define GL_VERTEX_PROGRAM_BINDING_NV 0x864A #define GL_PROGRAM_ERROR_POSITION_NV 0x864B #define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 #define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 #define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 #define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 #define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 #define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 #define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 #define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 #define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 #define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 #define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A #define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B #define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C #define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D #define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E #define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F #define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 #define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 #define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 #define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 #define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 #define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 #define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 #define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 #define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 #define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 #define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A #define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B #define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C #define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D #define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E #define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F #define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 #define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 #define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 #define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 #define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 #define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 #define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 #define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 #define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 #define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 #define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A #define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B #define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C #define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D #define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E #define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 #define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A #define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B #endif #ifndef GL_SGIX_scalebias_hint #define GL_SCALEBIAS_HINT_SGIX 0x8322 #endif #ifndef GL_OML_interlace #define GL_INTERLACE_OML 0x8980 #define GL_INTERLACE_READ_OML 0x8981 #endif #ifndef GL_OML_subsample #define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 #define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 #endif #ifndef GL_OML_resample #define GL_PACK_RESAMPLE_OML 0x8984 #define GL_UNPACK_RESAMPLE_OML 0x8985 #define GL_RESAMPLE_REPLICATE_OML 0x8986 #define GL_RESAMPLE_ZERO_FILL_OML 0x8987 #define GL_RESAMPLE_AVERAGE_OML 0x8988 #define GL_RESAMPLE_DECIMATE_OML 0x8989 #endif #ifndef GL_NV_copy_depth_to_color #define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E #define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F #endif #ifndef GL_ATI_envmap_bumpmap #define GL_BUMP_ROT_MATRIX_ATI 0x8775 #define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 #define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 #define GL_BUMP_TEX_UNITS_ATI 0x8778 #define GL_DUDV_ATI 0x8779 #define GL_DU8DV8_ATI 0x877A #define GL_BUMP_ENVMAP_ATI 0x877B #define GL_BUMP_TARGET_ATI 0x877C #endif #ifndef GL_ATI_fragment_shader #define GL_FRAGMENT_SHADER_ATI 0x8920 #define GL_REG_0_ATI 0x8921 #define GL_REG_1_ATI 0x8922 #define GL_REG_2_ATI 0x8923 #define GL_REG_3_ATI 0x8924 #define GL_REG_4_ATI 0x8925 #define GL_REG_5_ATI 0x8926 #define GL_REG_6_ATI 0x8927 #define GL_REG_7_ATI 0x8928 #define GL_REG_8_ATI 0x8929 #define GL_REG_9_ATI 0x892A #define GL_REG_10_ATI 0x892B #define GL_REG_11_ATI 0x892C #define GL_REG_12_ATI 0x892D #define GL_REG_13_ATI 0x892E #define GL_REG_14_ATI 0x892F #define GL_REG_15_ATI 0x8930 #define GL_REG_16_ATI 0x8931 #define GL_REG_17_ATI 0x8932 #define GL_REG_18_ATI 0x8933 #define GL_REG_19_ATI 0x8934 #define GL_REG_20_ATI 0x8935 #define GL_REG_21_ATI 0x8936 #define GL_REG_22_ATI 0x8937 #define GL_REG_23_ATI 0x8938 #define GL_REG_24_ATI 0x8939 #define GL_REG_25_ATI 0x893A #define GL_REG_26_ATI 0x893B #define GL_REG_27_ATI 0x893C #define GL_REG_28_ATI 0x893D #define GL_REG_29_ATI 0x893E #define GL_REG_30_ATI 0x893F #define GL_REG_31_ATI 0x8940 #define GL_CON_0_ATI 0x8941 #define GL_CON_1_ATI 0x8942 #define GL_CON_2_ATI 0x8943 #define GL_CON_3_ATI 0x8944 #define GL_CON_4_ATI 0x8945 #define GL_CON_5_ATI 0x8946 #define GL_CON_6_ATI 0x8947 #define GL_CON_7_ATI 0x8948 #define GL_CON_8_ATI 0x8949 #define GL_CON_9_ATI 0x894A #define GL_CON_10_ATI 0x894B #define GL_CON_11_ATI 0x894C #define GL_CON_12_ATI 0x894D #define GL_CON_13_ATI 0x894E #define GL_CON_14_ATI 0x894F #define GL_CON_15_ATI 0x8950 #define GL_CON_16_ATI 0x8951 #define GL_CON_17_ATI 0x8952 #define GL_CON_18_ATI 0x8953 #define GL_CON_19_ATI 0x8954 #define GL_CON_20_ATI 0x8955 #define GL_CON_21_ATI 0x8956 #define GL_CON_22_ATI 0x8957 #define GL_CON_23_ATI 0x8958 #define GL_CON_24_ATI 0x8959 #define GL_CON_25_ATI 0x895A #define GL_CON_26_ATI 0x895B #define GL_CON_27_ATI 0x895C #define GL_CON_28_ATI 0x895D #define GL_CON_29_ATI 0x895E #define GL_CON_30_ATI 0x895F #define GL_CON_31_ATI 0x8960 #define GL_MOV_ATI 0x8961 #define GL_ADD_ATI 0x8963 #define GL_MUL_ATI 0x8964 #define GL_SUB_ATI 0x8965 #define GL_DOT3_ATI 0x8966 #define GL_DOT4_ATI 0x8967 #define GL_MAD_ATI 0x8968 #define GL_LERP_ATI 0x8969 #define GL_CND_ATI 0x896A #define GL_CND0_ATI 0x896B #define GL_DOT2_ADD_ATI 0x896C #define GL_SECONDARY_INTERPOLATOR_ATI 0x896D #define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E #define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F #define GL_NUM_PASSES_ATI 0x8970 #define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 #define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 #define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 #define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 #define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 #define GL_SWIZZLE_STR_ATI 0x8976 #define GL_SWIZZLE_STQ_ATI 0x8977 #define GL_SWIZZLE_STR_DR_ATI 0x8978 #define GL_SWIZZLE_STQ_DQ_ATI 0x8979 #define GL_SWIZZLE_STRQ_ATI 0x897A #define GL_SWIZZLE_STRQ_DQ_ATI 0x897B #define GL_RED_BIT_ATI 0x00000001 #define GL_GREEN_BIT_ATI 0x00000002 #define GL_BLUE_BIT_ATI 0x00000004 #define GL_2X_BIT_ATI 0x00000001 #define GL_4X_BIT_ATI 0x00000002 #define GL_8X_BIT_ATI 0x00000004 #define GL_HALF_BIT_ATI 0x00000008 #define GL_QUARTER_BIT_ATI 0x00000010 #define GL_EIGHTH_BIT_ATI 0x00000020 #define GL_SATURATE_BIT_ATI 0x00000040 #define GL_COMP_BIT_ATI 0x00000002 #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 #endif #ifndef GL_ATI_pn_triangles #define GL_PN_TRIANGLES_ATI 0x87F0 #define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 #define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 #define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 #define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 #define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 #define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 #define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 #define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 #endif #ifndef GL_ATI_vertex_array_object #define GL_STATIC_ATI 0x8760 #define GL_DYNAMIC_ATI 0x8761 #define GL_PRESERVE_ATI 0x8762 #define GL_DISCARD_ATI 0x8763 #define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 #endif #ifndef GL_EXT_vertex_shader #define GL_VERTEX_SHADER_EXT 0x8780 #define GL_VERTEX_SHADER_BINDING_EXT 0x8781 #define GL_OP_INDEX_EXT 0x8782 #define GL_OP_NEGATE_EXT 0x8783 #define GL_OP_DOT3_EXT 0x8784 #define GL_OP_DOT4_EXT 0x8785 #define GL_OP_MUL_EXT 0x8786 #define GL_OP_ADD_EXT 0x8787 #define GL_OP_MADD_EXT 0x8788 #define GL_OP_FRAC_EXT 0x8789 #define GL_OP_MAX_EXT 0x878A #define GL_OP_MIN_EXT 0x878B #define GL_OP_SET_GE_EXT 0x878C #define GL_OP_SET_LT_EXT 0x878D #define GL_OP_CLAMP_EXT 0x878E #define GL_OP_FLOOR_EXT 0x878F #define GL_OP_ROUND_EXT 0x8790 #define GL_OP_EXP_BASE_2_EXT 0x8791 #define GL_OP_LOG_BASE_2_EXT 0x8792 #define GL_OP_POWER_EXT 0x8793 #define GL_OP_RECIP_EXT 0x8794 #define GL_OP_RECIP_SQRT_EXT 0x8795 #define GL_OP_SUB_EXT 0x8796 #define GL_OP_CROSS_PRODUCT_EXT 0x8797 #define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 #define GL_OP_MOV_EXT 0x8799 #define GL_OUTPUT_VERTEX_EXT 0x879A #define GL_OUTPUT_COLOR0_EXT 0x879B #define GL_OUTPUT_COLOR1_EXT 0x879C #define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D #define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E #define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F #define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 #define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 #define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 #define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 #define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 #define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 #define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 #define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 #define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 #define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 #define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA #define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB #define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC #define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD #define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE #define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF #define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 #define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 #define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 #define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 #define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 #define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 #define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 #define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 #define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 #define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 #define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA #define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB #define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC #define GL_OUTPUT_FOG_EXT 0x87BD #define GL_SCALAR_EXT 0x87BE #define GL_VECTOR_EXT 0x87BF #define GL_MATRIX_EXT 0x87C0 #define GL_VARIANT_EXT 0x87C1 #define GL_INVARIANT_EXT 0x87C2 #define GL_LOCAL_CONSTANT_EXT 0x87C3 #define GL_LOCAL_EXT 0x87C4 #define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 #define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 #define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 #define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 #define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA #define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE #define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF #define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 #define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 #define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 #define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 #define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 #define GL_X_EXT 0x87D5 #define GL_Y_EXT 0x87D6 #define GL_Z_EXT 0x87D7 #define GL_W_EXT 0x87D8 #define GL_NEGATIVE_X_EXT 0x87D9 #define GL_NEGATIVE_Y_EXT 0x87DA #define GL_NEGATIVE_Z_EXT 0x87DB #define GL_NEGATIVE_W_EXT 0x87DC #define GL_ZERO_EXT 0x87DD #define GL_ONE_EXT 0x87DE #define GL_NEGATIVE_ONE_EXT 0x87DF #define GL_NORMALIZED_RANGE_EXT 0x87E0 #define GL_FULL_RANGE_EXT 0x87E1 #define GL_CURRENT_VERTEX_EXT 0x87E2 #define GL_MVP_MATRIX_EXT 0x87E3 #define GL_VARIANT_VALUE_EXT 0x87E4 #define GL_VARIANT_DATATYPE_EXT 0x87E5 #define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 #define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 #define GL_VARIANT_ARRAY_EXT 0x87E8 #define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 #define GL_INVARIANT_VALUE_EXT 0x87EA #define GL_INVARIANT_DATATYPE_EXT 0x87EB #define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC #define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED #endif #ifndef GL_ATI_vertex_streams #define GL_MAX_VERTEX_STREAMS_ATI 0x876B #define GL_VERTEX_STREAM0_ATI 0x876C #define GL_VERTEX_STREAM1_ATI 0x876D #define GL_VERTEX_STREAM2_ATI 0x876E #define GL_VERTEX_STREAM3_ATI 0x876F #define GL_VERTEX_STREAM4_ATI 0x8770 #define GL_VERTEX_STREAM5_ATI 0x8771 #define GL_VERTEX_STREAM6_ATI 0x8772 #define GL_VERTEX_STREAM7_ATI 0x8773 #define GL_VERTEX_SOURCE_ATI 0x8774 #endif #ifndef GL_ATI_element_array #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A #endif #ifndef GL_SUN_mesh_array #define GL_QUAD_MESH_SUN 0x8614 #define GL_TRIANGLE_MESH_SUN 0x8615 #endif #ifndef GL_SUN_slice_accum #define GL_SLICE_ACCUM_SUN 0x85CC #endif #ifndef GL_NV_multisample_filter_hint #define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif #ifndef GL_NV_depth_clamp #define GL_DEPTH_CLAMP_NV 0x864F #endif #ifndef GL_NV_occlusion_query #define GL_PIXEL_COUNTER_BITS_NV 0x8864 #define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 #define GL_PIXEL_COUNT_NV 0x8866 #define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 #endif #ifndef GL_NV_point_sprite #define GL_POINT_SPRITE_NV 0x8861 #define GL_COORD_REPLACE_NV 0x8862 #define GL_POINT_SPRITE_R_MODE_NV 0x8863 #endif #ifndef GL_NV_texture_shader3 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 #define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 #define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 #define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 #define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 #define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A #define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B #define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C #define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D #define GL_HILO8_NV 0x885E #define GL_SIGNED_HILO8_NV 0x885F #define GL_FORCE_BLUE_TO_ONE_NV 0x8860 #endif #ifndef GL_NV_vertex_program1_1 #endif #ifndef GL_EXT_shadow_funcs #endif #ifndef GL_EXT_stencil_two_side #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 #endif #ifndef GL_ATI_text_fragment_shader #define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 #endif #ifndef GL_APPLE_client_storage #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif #ifndef GL_APPLE_element_array #define GL_ELEMENT_ARRAY_APPLE 0x8768 #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769 #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A #endif #ifndef GL_APPLE_fence #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x8A0B #endif #ifndef GL_APPLE_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 #endif #ifndef GL_APPLE_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF #endif #ifndef GL_APPLE_ycbcr_422 #define GL_YCBCR_422_APPLE 0x85B9 #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif #ifndef GL_S3_s3tc #define GL_RGB_S3TC 0x83A0 #define GL_RGB4_S3TC 0x83A1 #define GL_RGBA_S3TC 0x83A2 #define GL_RGBA4_S3TC 0x83A3 #endif #ifndef GL_ATI_draw_buffers #define GL_MAX_DRAW_BUFFERS_ATI 0x8824 #define GL_DRAW_BUFFER0_ATI 0x8825 #define GL_DRAW_BUFFER1_ATI 0x8826 #define GL_DRAW_BUFFER2_ATI 0x8827 #define GL_DRAW_BUFFER3_ATI 0x8828 #define GL_DRAW_BUFFER4_ATI 0x8829 #define GL_DRAW_BUFFER5_ATI 0x882A #define GL_DRAW_BUFFER6_ATI 0x882B #define GL_DRAW_BUFFER7_ATI 0x882C #define GL_DRAW_BUFFER8_ATI 0x882D #define GL_DRAW_BUFFER9_ATI 0x882E #define GL_DRAW_BUFFER10_ATI 0x882F #define GL_DRAW_BUFFER11_ATI 0x8830 #define GL_DRAW_BUFFER12_ATI 0x8831 #define GL_DRAW_BUFFER13_ATI 0x8832 #define GL_DRAW_BUFFER14_ATI 0x8833 #define GL_DRAW_BUFFER15_ATI 0x8834 #endif #ifndef GL_ATI_pixel_format_float #define GL_TYPE_RGBA_FLOAT_ATI 0x8820 #define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 #endif #ifndef GL_ATI_texture_env_combine3 #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SIGNED_ADD_ATI 0x8745 #define GL_MODULATE_SUBTRACT_ATI 0x8746 #endif #ifndef GL_ATI_texture_float #define GL_RGBA_FLOAT32_ATI 0x8814 #define GL_RGB_FLOAT32_ATI 0x8815 #define GL_ALPHA_FLOAT32_ATI 0x8816 #define GL_INTENSITY_FLOAT32_ATI 0x8817 #define GL_LUMINANCE_FLOAT32_ATI 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 #define GL_RGBA_FLOAT16_ATI 0x881A #define GL_RGB_FLOAT16_ATI 0x881B #define GL_ALPHA_FLOAT16_ATI 0x881C #define GL_INTENSITY_FLOAT16_ATI 0x881D #define GL_LUMINANCE_FLOAT16_ATI 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F #endif #ifndef GL_NV_float_buffer #define GL_FLOAT_R_NV 0x8880 #define GL_FLOAT_RG_NV 0x8881 #define GL_FLOAT_RGB_NV 0x8882 #define GL_FLOAT_RGBA_NV 0x8883 #define GL_FLOAT_R16_NV 0x8884 #define GL_FLOAT_R32_NV 0x8885 #define GL_FLOAT_RG16_NV 0x8886 #define GL_FLOAT_RG32_NV 0x8887 #define GL_FLOAT_RGB16_NV 0x8888 #define GL_FLOAT_RGB32_NV 0x8889 #define GL_FLOAT_RGBA16_NV 0x888A #define GL_FLOAT_RGBA32_NV 0x888B #define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C #define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D #define GL_FLOAT_RGBA_MODE_NV 0x888E #endif #ifndef GL_NV_fragment_program #define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 #define GL_FRAGMENT_PROGRAM_NV 0x8870 #define GL_MAX_TEXTURE_COORDS_NV 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 #define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 #define GL_PROGRAM_ERROR_STRING_NV 0x8874 #endif #ifndef GL_NV_half_float #define GL_HALF_FLOAT_NV 0x140B #endif #ifndef GL_NV_pixel_data_range #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 #define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D #endif #ifndef GL_NV_primitive_restart #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 #endif #ifndef GL_NV_texture_expand_normal #define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F #endif #ifndef GL_NV_vertex_program2 #endif #ifndef GL_ATI_map_object_buffer #endif #ifndef GL_ATI_separate_stencil #define GL_STENCIL_BACK_FUNC_ATI 0x8800 #define GL_STENCIL_BACK_FAIL_ATI 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 #endif #ifndef GL_ATI_vertex_attrib_array_object #endif #ifndef GL_OES_read_format #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif #ifndef GL_EXT_depth_bounds_test #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 #define GL_DEPTH_BOUNDS_EXT 0x8891 #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_MIRROR_CLAMP_EXT 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 #define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 #endif #ifndef GL_EXT_blend_equation_separate #define GL_BLEND_EQUATION_RGB_EXT GL_BLEND_EQUATION #define GL_BLEND_EQUATION_ALPHA_EXT 0x883D #endif #ifndef GL_MESA_pack_invert #define GL_PACK_INVERT_MESA 0x8758 #endif #ifndef GL_MESA_ycbcr_texture #define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB #define GL_YCBCR_MESA 0x8757 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_EXT 0x88EB #define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF #endif #ifndef GL_NV_fragment_program_option #endif #ifndef GL_NV_fragment_program2 #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 #define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 #define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 #endif #ifndef GL_NV_vertex_program2_option /* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ /* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ #endif #ifndef GL_NV_vertex_program3 /* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ #endif #ifndef GL_EXT_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #define GL_STENCIL_ATTACHMENT_EXT 0x8D20 #define GL_FRAMEBUFFER_EXT 0x8D40 #define GL_RENDERBUFFER_EXT 0x8D41 #define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 #define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 #define GL_STENCIL_INDEX1_EXT 0x8D46 #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 #define GL_STENCIL_INDEX16_EXT 0x8D49 #define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #endif #ifndef GL_GREMEDY_string_marker #endif /*************************************************************/ #include #ifndef GL_VERSION_2_0 /* GL type for program/shader text */ typedef char GLchar; /* native character */ #endif #ifndef GL_VERSION_1_5 /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; #endif #ifndef GL_ARB_vertex_buffer_object /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; #endif #ifndef GL_ARB_shader_objects /* GL types for handling shader object handles and program/shader text */ typedef char GLcharARB; /* native character */ typedef unsigned int GLhandleARB; /* shader object handle */ #endif /* GL types for "half" precision (s10e5) float data in host memory */ #ifndef GL_ARB_half_float_pixel typedef unsigned short GLhalfARB; #endif #ifndef GL_NV_half_float typedef unsigned short GLhalfNV; #endif #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf); GLAPI void APIENTRY glBlendEquation (GLenum); GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei); GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint); GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean); GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean); GLAPI void APIENTRY glResetHistogram (GLenum); GLAPI void APIENTRY glResetMinmax (GLenum); GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTexture (GLenum); GLAPI void APIENTRY glClientActiveTexture (GLenum); GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble); GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat); GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint); GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort); GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *); GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *); GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *); GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *); GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *); GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean); GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glFogCoordf (GLfloat); GLAPI void APIENTRY glFogCoordfv (const GLfloat *); GLAPI void APIENTRY glFogCoordd (GLdouble); GLAPI void APIENTRY glFogCoorddv (const GLdouble *); GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *); GLAPI void APIENTRY glPointParameteri (GLenum, GLint); GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *); GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *); GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *); GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *); GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint); GLAPI void APIENTRY glSecondaryColor3iv (const GLint *); GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort); GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *); GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *); GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint); GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *); GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort); GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *); GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dv (const GLdouble *); GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fv (const GLfloat *); GLAPI void APIENTRY glWindowPos2i (GLint, GLint); GLAPI void APIENTRY glWindowPos2iv (const GLint *); GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2sv (const GLshort *); GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dv (const GLdouble *); GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fv (const GLfloat *); GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3iv (const GLint *); GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3sv (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); #endif #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsQuery (GLuint); GLAPI void APIENTRY glBeginQuery (GLenum, GLuint); GLAPI void APIENTRY glEndQuery (GLenum); GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *); GLAPI void APIENTRY glBindBuffer (GLenum, GLuint); GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *); GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsBuffer (GLuint); GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum); GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *); GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *); GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum); GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum); GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum); GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *); GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint); GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint); GLAPI void APIENTRY glAttachShader (GLuint, GLuint); GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *); GLAPI void APIENTRY glCompileShader (GLuint); GLAPI GLuint APIENTRY glCreateProgram (void); GLAPI GLuint APIENTRY glCreateShader (GLenum); GLAPI void APIENTRY glDeleteProgram (GLuint); GLAPI void APIENTRY glDeleteShader (GLuint); GLAPI void APIENTRY glDetachShader (GLuint, GLuint); GLAPI void APIENTRY glDisableVertexAttribArray (GLuint); GLAPI void APIENTRY glEnableVertexAttribArray (GLuint); GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *); GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *); GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *); GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *); GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *); GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgram (GLuint); GLAPI GLboolean APIENTRY glIsShader (GLuint); GLAPI void APIENTRY glLinkProgram (GLuint); GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *); GLAPI void APIENTRY glUseProgram (GLuint); GLAPI void APIENTRY glUniform1f (GLint, GLfloat); GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat); GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform1i (GLint, GLint); GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint); GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glValidateProgram (GLuint); GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTextureARB (GLenum); GLAPI void APIENTRY glClientActiveTextureARB (GLenum); GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble); GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat); GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint); GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort); GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); #endif #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *); GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *); GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *); GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); #endif #ifndef GL_ARB_multisample #define GL_ARB_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); #endif #ifndef GL_ARB_texture_env_add #define GL_ARB_texture_env_add 1 #endif #ifndef GL_ARB_texture_cube_map #define GL_ARB_texture_cube_map 1 #endif #ifndef GL_ARB_texture_compression #define GL_ARB_texture_compression 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 #endif #ifndef GL_ARB_point_parameters #define GL_ARB_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_ARB_vertex_blend #define GL_ARB_vertex_blend 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *); GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *); GLAPI void APIENTRY glWeightivARB (GLint, const GLint *); GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *); GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *); GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *); GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *); GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *); GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexBlendARB (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); #endif #ifndef GL_ARB_matrix_palette #define GL_ARB_matrix_palette 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint); GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *); GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *); GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *); GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_ARB_texture_env_combine #define GL_ARB_texture_env_combine 1 #endif #ifndef GL_ARB_texture_env_crossbar #define GL_ARB_texture_env_crossbar 1 #endif #ifndef GL_ARB_texture_env_dot3 #define GL_ARB_texture_env_dot3 1 #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat 1 #endif #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture 1 #endif #ifndef GL_ARB_shadow #define GL_ARB_shadow 1 #endif #ifndef GL_ARB_shadow_ambient #define GL_ARB_shadow_ambient 1 #endif #ifndef GL_ARB_window_pos #define GL_ARB_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *); GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *); GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint); GLAPI void APIENTRY glWindowPos2ivARB (const GLint *); GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2svARB (const GLshort *); GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *); GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *); GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3ivARB (const GLint *); GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3svARB (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); #endif #ifndef GL_ARB_vertex_program #define GL_ARB_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint); GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint); GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *); GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *); GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgramARB (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #endif #ifndef GL_ARB_fragment_program #define GL_ARB_fragment_program 1 /* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ #endif #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint); GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *); GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsBufferARB (GLuint); GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *); GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *); GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum); GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum); GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_ARB_occlusion_query #define GL_ARB_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsQueryARB (GLuint); GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint); GLAPI void APIENTRY glEndQueryARB (GLenum); GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB); GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum); GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB); GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum); GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); GLAPI void APIENTRY glCompileShaderARB (GLhandleARB); GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB); GLAPI void APIENTRY glLinkProgramARB (GLhandleARB); GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB); GLAPI void APIENTRY glValidateProgramARB (GLhandleARB); GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat); GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat); GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform1iARB (GLint, GLint); GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint); GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *); GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *); GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *); GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *); GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *); GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *); GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); #endif #ifndef GL_ARB_fragment_shader #define GL_ARB_fragment_shader 1 #endif #ifndef GL_ARB_shading_language_100 #define GL_ARB_shading_language_100 1 #endif #ifndef GL_ARB_texture_non_power_of_two #define GL_ARB_texture_non_power_of_two 1 #endif #ifndef GL_ARB_point_sprite #define GL_ARB_point_sprite 1 #endif #ifndef GL_ARB_fragment_program_shadow #define GL_ARB_fragment_program_shadow 1 #endif #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ARB_texture_rectangle #define GL_ARB_texture_rectangle 1 #endif #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClampColorARB (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); #endif #ifndef GL_ARB_half_float_pixel #define GL_ARB_half_float_pixel 1 #endif #ifndef GL_ARB_texture_float #define GL_ARB_texture_float 1 #endif #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 #endif #ifndef GL_EXT_abgr #define GL_EXT_abgr 1 #endif #ifndef GL_EXT_blend_color #define GL_EXT_blend_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); #endif #ifndef GL_EXT_polygon_offset #define GL_EXT_polygon_offset 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); #endif #ifndef GL_EXT_texture #define GL_EXT_texture 1 #endif #ifndef GL_EXT_texture3D #define GL_EXT_texture3D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGIS_texture_filter4 #define GL_SGIS_texture_filter4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #endif #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_EXT_copy_texture #define GL_EXT_copy_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_EXT_histogram #define GL_EXT_histogram 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean); GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean); GLAPI void APIENTRY glResetHistogramEXT (GLenum); GLAPI void APIENTRY glResetMinmaxEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); #endif #ifndef GL_EXT_convolution #define GL_EXT_convolution 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint); GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); #endif #ifndef GL_EXT_color_matrix #define GL_EXT_color_matrix 1 #endif #ifndef GL_SGI_color_table #define GL_SGI_color_table 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); #endif #ifndef GL_SGIX_pixel_texture #define GL_SGIX_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenSGIX (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); #endif #ifndef GL_SGIS_pixel_texture #define GL_SGIS_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint); GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *); GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat); GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *); GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *); GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGI_texture_color_table #define GL_SGI_texture_color_table 1 #endif #ifndef GL_EXT_cmyka #define GL_EXT_cmyka 1 #endif #ifndef GL_EXT_texture_object #define GL_EXT_texture_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *); GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint); GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); #endif #ifndef GL_SGIS_detail_texture #define GL_SGIS_detail_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *); GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_SGIS_sharpen_texture #define GL_SGIS_sharpen_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *); GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_EXT_packed_pixels #define GL_EXT_packed_pixels 1 #endif #ifndef GL_SGIS_texture_lod #define GL_SGIS_texture_lod 1 #endif #ifndef GL_SGIS_multisample #define GL_SGIS_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean); GLAPI void APIENTRY glSamplePatternSGIS (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); #endif #ifndef GL_EXT_rescale_normal #define GL_EXT_rescale_normal 1 #endif #ifndef GL_EXT_vertex_array #define GL_EXT_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glArrayElementEXT (GLint); GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei); GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *); GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *); GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); #endif #ifndef GL_EXT_misc_attribute #define GL_EXT_misc_attribute 1 #endif #ifndef GL_SGIS_generate_mipmap #define GL_SGIS_generate_mipmap 1 #endif #ifndef GL_SGIX_clipmap #define GL_SGIX_clipmap 1 #endif #ifndef GL_SGIX_shadow #define GL_SGIX_shadow 1 #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_SGIS_texture_edge_clamp 1 #endif #ifndef GL_SGIS_texture_border_clamp #define GL_SGIS_texture_border_clamp 1 #endif #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_blend_subtract #define GL_EXT_blend_subtract 1 #endif #ifndef GL_EXT_blend_logic_op #define GL_EXT_blend_logic_op 1 #endif #ifndef GL_SGIX_interlace #define GL_SGIX_interlace 1 #endif #ifndef GL_SGIX_pixel_tiles #define GL_SGIX_pixel_tiles 1 #endif #ifndef GL_SGIX_texture_select #define GL_SGIX_texture_select 1 #endif #ifndef GL_SGIX_sprite #define GL_SGIX_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat); GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *); GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint); GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_SGIX_texture_multi_buffer 1 #endif #ifndef GL_EXT_point_parameters #define GL_EXT_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIS_point_parameters #define GL_SGIS_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIX_instruments #define GL_SGIX_instruments 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *); GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *); GLAPI void APIENTRY glReadInstrumentsSGIX (GLint); GLAPI void APIENTRY glStartInstrumentsSGIX (void); GLAPI void APIENTRY glStopInstrumentsSGIX (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); #endif #ifndef GL_SGIX_texture_scale_bias #define GL_SGIX_texture_scale_bias 1 #endif #ifndef GL_SGIX_framezoom #define GL_SGIX_framezoom 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameZoomSGIX (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); #endif #ifndef GL_SGIX_tag_sample_buffer #define GL_SGIX_tag_sample_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTagSampleBufferSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); #endif #ifndef GL_SGIX_polynomial_ffd #define GL_SGIX_polynomial_ffd 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *); GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *); GLAPI void APIENTRY glDeformSGIX (GLbitfield); GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); #endif #ifndef GL_SGIX_reference_plane #define GL_SGIX_reference_plane 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); #endif #ifndef GL_SGIX_flush_raster #define GL_SGIX_flush_raster 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushRasterSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); #endif #ifndef GL_SGIX_depth_texture #define GL_SGIX_depth_texture 1 #endif #ifndef GL_SGIS_fog_function #define GL_SGIS_fog_function 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *); GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); #endif #ifndef GL_SGIX_fog_offset #define GL_SGIX_fog_offset 1 #endif #ifndef GL_HP_image_transform #define GL_HP_image_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint); GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_HP_convolution_border_modes #define GL_HP_convolution_border_modes 1 #endif #ifndef GL_SGIX_texture_add_env #define GL_SGIX_texture_add_env 1 #endif #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif #ifndef GL_PGI_vertex_hints #define GL_PGI_vertex_hints 1 #endif #ifndef GL_PGI_misc_hints #define GL_PGI_misc_hints 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glHintPGI (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); #endif #ifndef GL_EXT_paletted_texture #define GL_EXT_paletted_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_EXT_clip_volume_hint #define GL_EXT_clip_volume_hint 1 #endif #ifndef GL_SGIX_list_priority #define GL_SGIX_list_priority 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *); GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat); GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *); GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint); GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_ir_instrument1 #define GL_SGIX_ir_instrument1 1 #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_SGIX_calligraphic_fragment 1 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_SGIX_texture_lod_bias 1 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SGIX_shadow_ambient 1 #endif #ifndef GL_EXT_index_texture #define GL_EXT_index_texture 1 #endif #ifndef GL_EXT_index_material #define GL_EXT_index_material 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_EXT_index_func #define GL_EXT_index_func 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); #endif #ifndef GL_EXT_index_array_formats #define GL_EXT_index_array_formats 1 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_EXT_compiled_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei); GLAPI void APIENTRY glUnlockArraysEXT (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); #endif #ifndef GL_EXT_cull_vertex #define GL_EXT_cull_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *); GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIX_ycrcb #define GL_SGIX_ycrcb 1 #endif #ifndef GL_SGIX_fragment_lighting #define GL_SGIX_fragment_lighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum); GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint); GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat); GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint); GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *); GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint); GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *); GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); #endif #ifndef GL_IBM_rasterpos_clip #define GL_IBM_rasterpos_clip 1 #endif #ifndef GL_HP_texture_lighting #define GL_HP_texture_lighting 1 #endif #ifndef GL_EXT_draw_range_elements #define GL_EXT_draw_range_elements 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); #endif #ifndef GL_WIN_phong_shading #define GL_WIN_phong_shading 1 #endif #ifndef GL_WIN_specular_fog #define GL_WIN_specular_fog 1 #endif #ifndef GL_EXT_light_texture #define GL_EXT_light_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glApplyTextureEXT (GLenum); GLAPI void APIENTRY glTextureLightEXT (GLenum); GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_SGIX_blend_alpha_minmax 1 #endif #ifndef GL_EXT_bgra #define GL_EXT_bgra 1 #endif #ifndef GL_SGIX_async #define GL_SGIX_async 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint); GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *); GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *); GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei); GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei); GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); #endif #ifndef GL_SGIX_async_pixel #define GL_SGIX_async_pixel 1 #endif #ifndef GL_SGIX_async_histogram #define GL_SGIX_async_histogram 1 #endif #ifndef GL_INTEL_parallel_arrays #define GL_INTEL_parallel_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *); GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *); GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *); GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); #endif #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test 1 #endif #ifndef GL_EXT_pixel_transform #define GL_EXT_pixel_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint); GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); #endif #ifndef GL_EXT_pixel_transform_color_table #define GL_EXT_pixel_transform_color_table 1 #endif #ifndef GL_EXT_shared_texture_palette #define GL_EXT_shared_texture_palette 1 #endif #ifndef GL_EXT_separate_specular_color #define GL_EXT_separate_specular_color 1 #endif #ifndef GL_EXT_secondary_color #define GL_EXT_secondary_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *); GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *); GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *); GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *); GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *); GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *); GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint); GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *); GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort); GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *); GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_perturb_normal #define GL_EXT_texture_perturb_normal 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureNormalEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); #endif #ifndef GL_EXT_fog_coord #define GL_EXT_fog_coord 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordfEXT (GLfloat); GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *); GLAPI void APIENTRY glFogCoorddEXT (GLdouble); GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *); GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_REND_screen_coordinates #define GL_REND_screen_coordinates 1 #endif #ifndef GL_EXT_coordinate_frame #define GL_EXT_coordinate_frame 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *); GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *); GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *); GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glTangent3ivEXT (const GLint *); GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glTangent3svEXT (const GLshort *); GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *); GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *); GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *); GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glBinormal3ivEXT (const GLint *); GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glBinormal3svEXT (const GLshort *); GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_env_combine #define GL_EXT_texture_env_combine 1 #endif #ifndef GL_APPLE_specular_vector #define GL_APPLE_specular_vector 1 #endif #ifndef GL_APPLE_transform_hint #define GL_APPLE_transform_hint 1 #endif #ifndef GL_SGIX_fog_scale #define GL_SGIX_fog_scale 1 #endif #ifndef GL_SUNX_constant_data #define GL_SUNX_constant_data 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFinishTextureSUNX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); #endif #ifndef GL_SUN_global_alpha #define GL_SUN_global_alpha 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte); GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort); GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint); GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat); GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble); GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte); GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort); GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); #endif #ifndef GL_SUN_triangle_list #define GL_SUN_triangle_list 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint); GLAPI void APIENTRY glReplacementCodeusSUN (GLushort); GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte); GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *); GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *); GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *); GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); #endif #ifndef GL_SUN_vertex #define GL_SUN_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat); GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *); GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *); GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #endif #ifndef GL_EXT_blend_func_separate #define GL_EXT_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_blend_func_separate #define GL_INGR_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_color_clamp #define GL_INGR_color_clamp 1 #endif #ifndef GL_INGR_interlace_read #define GL_INGR_interlace_read 1 #endif #ifndef GL_EXT_stencil_wrap #define GL_EXT_stencil_wrap 1 #endif #ifndef GL_EXT_422_pixels #define GL_EXT_422_pixels 1 #endif #ifndef GL_NV_texgen_reflection #define GL_NV_texgen_reflection 1 #endif #ifndef GL_SUN_convolution_border_modes #define GL_SUN_convolution_border_modes 1 #endif #ifndef GL_EXT_texture_env_add #define GL_EXT_texture_env_add 1 #endif #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias 1 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #endif #ifndef GL_EXT_vertex_weighting #define GL_EXT_vertex_weighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexWeightfEXT (GLfloat); GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *); GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_NV_light_max_exponent #define GL_NV_light_max_exponent 1 #endif #ifndef GL_NV_vertex_array_range #define GL_NV_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); #endif #ifndef GL_NV_register_combiners #define GL_NV_register_combiners 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *); GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat); GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *); GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint); GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean); GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); #endif #ifndef GL_NV_fog_distance #define GL_NV_fog_distance 1 #endif #ifndef GL_NV_texgen_emboss #define GL_NV_texgen_emboss 1 #endif #ifndef GL_NV_blend_square #define GL_NV_blend_square 1 #endif #ifndef GL_NV_texture_env_combine4 #define GL_NV_texture_env_combine4 1 #endif #ifndef GL_MESA_resize_buffers #define GL_MESA_resize_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glResizeBuffersMESA (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); #endif #ifndef GL_MESA_window_pos #define GL_MESA_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint); GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *); GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *); GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); #endif #ifndef GL_IBM_cull_vertex #define GL_IBM_cull_vertex 1 #endif #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint); GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); #endif #ifndef GL_IBM_vertex_array_lists #define GL_IBM_vertex_array_lists 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint); GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); #endif #ifndef GL_SGIX_subsample #define GL_SGIX_subsample 1 #endif #ifndef GL_SGIX_ycrcba #define GL_SGIX_ycrcba 1 #endif #ifndef GL_SGIX_ycrcb_subsample #define GL_SGIX_ycrcb_subsample 1 #endif #ifndef GL_SGIX_depth_pass_instrument #define GL_SGIX_depth_pass_instrument 1 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_3DFX_texture_compression_FXT1 1 #endif #ifndef GL_3DFX_multisample #define GL_3DFX_multisample 1 #endif #ifndef GL_3DFX_tbuffer #define GL_3DFX_tbuffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTbufferMask3DFX (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); #endif #ifndef GL_EXT_multisample #define GL_EXT_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean); GLAPI void APIENTRY glSamplePatternEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); #endif #ifndef GL_SGIX_vertex_preclip #define GL_SGIX_vertex_preclip 1 #endif #ifndef GL_SGIX_convolution_accuracy #define GL_SGIX_convolution_accuracy 1 #endif #ifndef GL_SGIX_resample #define GL_SGIX_resample 1 #endif #ifndef GL_SGIS_point_line_texgen #define GL_SGIS_point_line_texgen 1 #endif #ifndef GL_SGIS_texture_color_mask #define GL_SGIS_texture_color_mask 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #endif #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); #endif #ifndef GL_EXT_texture_env_dot3 #define GL_EXT_texture_env_dot3 1 #endif #ifndef GL_ATI_texture_mirror_once #define GL_ATI_texture_mirror_once 1 #endif #ifndef GL_NV_fence #define GL_NV_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsFenceNV (GLuint); GLAPI GLboolean APIENTRY glTestFenceNV (GLuint); GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glFinishFenceNV (GLuint); GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #endif #ifndef GL_NV_evaluators #define GL_NV_evaluators 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *); GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *); GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); #endif #ifndef GL_NV_packed_depth_stencil #define GL_NV_packed_depth_stencil 1 #endif #ifndef GL_NV_register_combiners2 #define GL_NV_register_combiners2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); #endif #ifndef GL_NV_texture_compression_vtc #define GL_NV_texture_compression_vtc 1 #endif #ifndef GL_NV_texture_rectangle #define GL_NV_texture_rectangle 1 #endif #ifndef GL_NV_texture_shader #define GL_NV_texture_shader 1 #endif #ifndef GL_NV_texture_shader2 #define GL_NV_texture_shader2 1 #endif #ifndef GL_NV_vertex_array_range2 #define GL_NV_vertex_array_range2 1 #endif #ifndef GL_NV_vertex_program #define GL_NV_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *); GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint); GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *); GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *); GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *); GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgramNV (GLuint); GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *); GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *); GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *); GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum); GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v); typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_SGIX_texture_coordinate_clamp 1 #endif #ifndef GL_SGIX_scalebias_hint #define GL_SGIX_scalebias_hint 1 #endif #ifndef GL_OML_interlace #define GL_OML_interlace 1 #endif #ifndef GL_OML_subsample #define GL_OML_subsample 1 #endif #ifndef GL_OML_resample #define GL_OML_resample 1 #endif #ifndef GL_NV_copy_depth_to_color #define GL_NV_copy_depth_to_color 1 #endif #ifndef GL_ATI_envmap_bumpmap #define GL_ATI_envmap_bumpmap 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *); GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *); GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); #endif #ifndef GL_ATI_fragment_shader #define GL_ATI_fragment_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint); GLAPI void APIENTRY glBindFragmentShaderATI (GLuint); GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint); GLAPI void APIENTRY glBeginFragmentShaderATI (void); GLAPI void APIENTRY glEndFragmentShaderATI (void); GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum); GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum); GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); #endif #ifndef GL_ATI_pn_triangles #define GL_ATI_pn_triangles 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint); GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_vertex_array_object #define GL_ATI_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum); GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint); GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum); GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *); GLAPI void APIENTRY glFreeObjectBufferATI (GLuint); GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *); GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); #endif #ifndef GL_EXT_vertex_shader #define GL_EXT_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVertexShaderEXT (void); GLAPI void APIENTRY glEndVertexShaderEXT (void); GLAPI void APIENTRY glBindVertexShaderEXT (GLuint); GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint); GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint); GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint); GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint); GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint); GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint); GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *); GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *); GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *); GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *); GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *); GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *); GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *); GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *); GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *); GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint); GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint); GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum); GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindParameterEXT (GLenum); GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum); GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *); GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); #endif #ifndef GL_ATI_vertex_streams #define GL_ATI_vertex_streams 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort); GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint); GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat); GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble); GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort); GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint); GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *); GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *); GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *); GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum); GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint); GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_element_array #define GL_ATI_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *); GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei); GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif #ifndef GL_SUN_mesh_array #define GL_SUN_mesh_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); #endif #ifndef GL_SUN_slice_accum #define GL_SUN_slice_accum 1 #endif #ifndef GL_NV_multisample_filter_hint #define GL_NV_multisample_filter_hint 1 #endif #ifndef GL_NV_depth_clamp #define GL_NV_depth_clamp 1 #endif #ifndef GL_NV_occlusion_query #define GL_NV_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint); GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint); GLAPI void APIENTRY glEndOcclusionQueryNV (void); GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_NV_point_sprite #define GL_NV_point_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint); GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_NV_texture_shader3 #define GL_NV_texture_shader3 1 #endif #ifndef GL_NV_vertex_program1_1 #define GL_NV_vertex_program1_1 1 #endif #ifndef GL_EXT_shadow_funcs #define GL_EXT_shadow_funcs 1 #endif #ifndef GL_EXT_stencil_two_side #define GL_EXT_stencil_two_side 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); #endif #ifndef GL_ATI_text_fragment_shader #define GL_ATI_text_fragment_shader 1 #endif #ifndef GL_APPLE_client_storage #define GL_APPLE_client_storage 1 #endif #ifndef GL_APPLE_element_array #define GL_APPLE_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *); GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei); GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei); GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #endif #ifndef GL_APPLE_fence #define GL_APPLE_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *); GLAPI void APIENTRY glSetFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint); GLAPI void APIENTRY glFinishFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint); GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); #endif #ifndef GL_APPLE_vertex_array_object #define GL_APPLE_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint); GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *); GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); #endif #ifndef GL_APPLE_vertex_array_range #define GL_APPLE_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *); GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *); GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); #endif #ifndef GL_APPLE_ycbcr_422 #define GL_APPLE_ycbcr_422 1 #endif #ifndef GL_S3_s3tc #define GL_S3_s3tc 1 #endif #ifndef GL_ATI_draw_buffers #define GL_ATI_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ATI_pixel_format_float #define GL_ATI_pixel_format_float 1 /* This is really a WGL extension, but defines some associated GL enums. * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. */ #endif #ifndef GL_ATI_texture_env_combine3 #define GL_ATI_texture_env_combine3 1 #endif #ifndef GL_ATI_texture_float #define GL_ATI_texture_float 1 #endif #ifndef GL_NV_float_buffer #define GL_NV_float_buffer 1 #endif #ifndef GL_NV_fragment_program #define GL_NV_fragment_program 1 /* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *); GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *); GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #endif #ifndef GL_NV_half_float #define GL_NV_half_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *); GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *); GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *); GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV); GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glFogCoordhNV (GLhalfNV); GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *); GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV); GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV); GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); #endif #ifndef GL_NV_pixel_data_range #define GL_NV_pixel_data_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *); GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); #endif #ifndef GL_NV_primitive_restart #define GL_NV_primitive_restart 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPrimitiveRestartNV (void); GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); #endif #ifndef GL_NV_texture_expand_normal #define GL_NV_texture_expand_normal 1 #endif #ifndef GL_NV_vertex_program2 #define GL_NV_vertex_program2 1 #endif #ifndef GL_ATI_map_object_buffer #define GL_ATI_map_object_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint); GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); #endif #ifndef GL_ATI_separate_stencil #define GL_ATI_separate_stencil 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #endif #ifndef GL_ATI_vertex_attrib_array_object #define GL_ATI_vertex_attrib_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); #endif #ifndef GL_OES_read_format #define GL_OES_read_format 1 #endif #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_EXT_texture_mirror_clamp 1 #endif #ifndef GL_EXT_blend_equation_separate #define GL_EXT_blend_equation_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); #endif #ifndef GL_MESA_pack_invert #define GL_MESA_pack_invert 1 #endif #ifndef GL_MESA_ycbcr_texture #define GL_MESA_ycbcr_texture 1 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_EXT_pixel_buffer_object 1 #endif #ifndef GL_NV_fragment_program_option #define GL_NV_fragment_program_option 1 #endif #ifndef GL_NV_fragment_program2 #define GL_NV_fragment_program2 1 #endif #ifndef GL_NV_vertex_program2_option #define GL_NV_vertex_program2_option 1 #endif #ifndef GL_NV_vertex_program3 #define GL_NV_vertex_program3 1 #endif #ifndef GL_EXT_framebuffer_object #define GL_EXT_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint); GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *); GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *); GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint); GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *); GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum); GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGenerateMipmapEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); #endif #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: SparCraft/source/glext/wglext.h ================================================ #ifndef __wglext_h_ #define __wglext_h_ #ifdef __cplusplus extern "C" { #endif /* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: This software was created using the ** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has ** not been independently verified as being compliant with the OpenGL(R) ** version 1.2.1 Specification. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ /* Header file version number */ /* wglext.h last updated 2005/01/07 */ /* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */ #define WGL_WGLEXT_VERSION 6 #ifndef WGL_ARB_buffer_region #define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 #define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 #define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 #define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 #endif #ifndef WGL_ARB_multisample #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #endif #ifndef WGL_ARB_extensions_string #endif #ifndef WGL_ARB_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_SWAP_EXCHANGE_ARB 0x2028 #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C #endif #ifndef WGL_ARB_make_current_read #define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 #endif #ifndef WGL_ARB_pbuffer #define WGL_DRAW_TO_PBUFFER_ARB 0x202D #define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E #define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F #define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 #define WGL_PBUFFER_LARGEST_ARB 0x2033 #define WGL_PBUFFER_WIDTH_ARB 0x2034 #define WGL_PBUFFER_HEIGHT_ARB 0x2035 #define WGL_PBUFFER_LOST_ARB 0x2036 #endif #ifndef WGL_ARB_render_texture #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 #define WGL_TEXTURE_FORMAT_ARB 0x2072 #define WGL_TEXTURE_TARGET_ARB 0x2073 #define WGL_MIPMAP_TEXTURE_ARB 0x2074 #define WGL_TEXTURE_RGB_ARB 0x2075 #define WGL_TEXTURE_RGBA_ARB 0x2076 #define WGL_NO_TEXTURE_ARB 0x2077 #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 #define WGL_TEXTURE_1D_ARB 0x2079 #define WGL_TEXTURE_2D_ARB 0x207A #define WGL_MIPMAP_LEVEL_ARB 0x207B #define WGL_CUBE_MAP_FACE_ARB 0x207C #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 #define WGL_FRONT_LEFT_ARB 0x2083 #define WGL_FRONT_RIGHT_ARB 0x2084 #define WGL_BACK_LEFT_ARB 0x2085 #define WGL_BACK_RIGHT_ARB 0x2086 #define WGL_AUX0_ARB 0x2087 #define WGL_AUX1_ARB 0x2088 #define WGL_AUX2_ARB 0x2089 #define WGL_AUX3_ARB 0x208A #define WGL_AUX4_ARB 0x208B #define WGL_AUX5_ARB 0x208C #define WGL_AUX6_ARB 0x208D #define WGL_AUX7_ARB 0x208E #define WGL_AUX8_ARB 0x208F #define WGL_AUX9_ARB 0x2090 #endif #ifndef WGL_ARB_pixel_format_float #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 #endif #ifndef WGL_EXT_make_current_read #define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 #endif #ifndef WGL_EXT_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 #define WGL_DRAW_TO_WINDOW_EXT 0x2001 #define WGL_DRAW_TO_BITMAP_EXT 0x2002 #define WGL_ACCELERATION_EXT 0x2003 #define WGL_NEED_PALETTE_EXT 0x2004 #define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 #define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 #define WGL_SWAP_METHOD_EXT 0x2007 #define WGL_NUMBER_OVERLAYS_EXT 0x2008 #define WGL_NUMBER_UNDERLAYS_EXT 0x2009 #define WGL_TRANSPARENT_EXT 0x200A #define WGL_TRANSPARENT_VALUE_EXT 0x200B #define WGL_SHARE_DEPTH_EXT 0x200C #define WGL_SHARE_STENCIL_EXT 0x200D #define WGL_SHARE_ACCUM_EXT 0x200E #define WGL_SUPPORT_GDI_EXT 0x200F #define WGL_SUPPORT_OPENGL_EXT 0x2010 #define WGL_DOUBLE_BUFFER_EXT 0x2011 #define WGL_STEREO_EXT 0x2012 #define WGL_PIXEL_TYPE_EXT 0x2013 #define WGL_COLOR_BITS_EXT 0x2014 #define WGL_RED_BITS_EXT 0x2015 #define WGL_RED_SHIFT_EXT 0x2016 #define WGL_GREEN_BITS_EXT 0x2017 #define WGL_GREEN_SHIFT_EXT 0x2018 #define WGL_BLUE_BITS_EXT 0x2019 #define WGL_BLUE_SHIFT_EXT 0x201A #define WGL_ALPHA_BITS_EXT 0x201B #define WGL_ALPHA_SHIFT_EXT 0x201C #define WGL_ACCUM_BITS_EXT 0x201D #define WGL_ACCUM_RED_BITS_EXT 0x201E #define WGL_ACCUM_GREEN_BITS_EXT 0x201F #define WGL_ACCUM_BLUE_BITS_EXT 0x2020 #define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 #define WGL_DEPTH_BITS_EXT 0x2022 #define WGL_STENCIL_BITS_EXT 0x2023 #define WGL_AUX_BUFFERS_EXT 0x2024 #define WGL_NO_ACCELERATION_EXT 0x2025 #define WGL_GENERIC_ACCELERATION_EXT 0x2026 #define WGL_FULL_ACCELERATION_EXT 0x2027 #define WGL_SWAP_EXCHANGE_EXT 0x2028 #define WGL_SWAP_COPY_EXT 0x2029 #define WGL_SWAP_UNDEFINED_EXT 0x202A #define WGL_TYPE_RGBA_EXT 0x202B #define WGL_TYPE_COLORINDEX_EXT 0x202C #endif #ifndef WGL_EXT_pbuffer #define WGL_DRAW_TO_PBUFFER_EXT 0x202D #define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E #define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F #define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 #define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 #define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 #define WGL_PBUFFER_LARGEST_EXT 0x2033 #define WGL_PBUFFER_WIDTH_EXT 0x2034 #define WGL_PBUFFER_HEIGHT_EXT 0x2035 #endif #ifndef WGL_EXT_depth_float #define WGL_DEPTH_FLOAT_EXT 0x2040 #endif #ifndef WGL_3DFX_multisample #define WGL_SAMPLE_BUFFERS_3DFX 0x2060 #define WGL_SAMPLES_3DFX 0x2061 #endif #ifndef WGL_EXT_multisample #define WGL_SAMPLE_BUFFERS_EXT 0x2041 #define WGL_SAMPLES_EXT 0x2042 #endif #ifndef WGL_I3D_digital_video_control #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 #define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 #define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 #endif #ifndef WGL_I3D_gamma #define WGL_GAMMA_TABLE_SIZE_I3D 0x204E #define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F #endif #ifndef WGL_I3D_genlock #define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 #define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 #define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 #define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 #define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 #define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 #define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A #define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B #define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C #endif #ifndef WGL_I3D_image_buffer #define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 #define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 #endif #ifndef WGL_I3D_swap_frame_lock #endif #ifndef WGL_NV_render_depth_texture #define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 #define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 #define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 #define WGL_DEPTH_COMPONENT_NV 0x20A7 #endif #ifndef WGL_NV_render_texture_rectangle #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 #define WGL_TEXTURE_RECTANGLE_NV 0x20A2 #endif #ifndef WGL_ATI_pixel_format_float #define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 #endif #ifndef WGL_NV_float_buffer #define WGL_FLOAT_COMPONENTS_NV 0x20B0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 #define WGL_TEXTURE_FLOAT_R_NV 0x20B5 #define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 #define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 #define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 #endif /*************************************************************/ #ifndef WGL_ARB_pbuffer DECLARE_HANDLE(HPBUFFERARB); #endif #ifndef WGL_EXT_pbuffer DECLARE_HANDLE(HPBUFFEREXT); #endif #ifndef WGL_ARB_buffer_region #define WGL_ARB_buffer_region 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT); extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE); extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int); extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); #endif #ifndef WGL_ARB_multisample #define WGL_ARB_multisample 1 #endif #ifndef WGL_ARB_extensions_string #define WGL_ARB_extensions_string 1 #ifdef WGL_WGLEXT_PROTOTYPES extern const char * WINAPI wglGetExtensionsStringARB (HDC); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); #endif #ifndef WGL_ARB_pixel_format #define WGL_ARB_pixel_format 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *); extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *); extern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); #endif #ifndef WGL_ARB_make_current_read #define WGL_ARB_make_current_read 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC); extern HDC WINAPI wglGetCurrentReadDCARB (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); #endif #ifndef WGL_ARB_pbuffer #define WGL_ARB_pbuffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *); extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB); extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC); extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB); extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); #endif #ifndef WGL_ARB_render_texture #define WGL_ARB_render_texture 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB, int); extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB, int); extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); #endif #ifndef WGL_ARB_pixel_format_float #define WGL_ARB_pixel_format_float 1 #endif #ifndef WGL_EXT_display_color_table #define WGL_EXT_display_color_table 1 #ifdef WGL_WGLEXT_PROTOTYPES extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort); extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint); extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort); extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); #endif #ifndef WGL_EXT_extensions_string #define WGL_EXT_extensions_string 1 #ifdef WGL_WGLEXT_PROTOTYPES extern const char * WINAPI wglGetExtensionsStringEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); #endif #ifndef WGL_EXT_make_current_read #define WGL_EXT_make_current_read 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC); extern HDC WINAPI wglGetCurrentReadDCEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); #endif #ifndef WGL_EXT_pbuffer #define WGL_EXT_pbuffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *); extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT); extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC); extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT); extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); #endif #ifndef WGL_EXT_pixel_format #define WGL_EXT_pixel_format 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *); extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *); extern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); #endif #ifndef WGL_EXT_swap_control #define WGL_EXT_swap_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglSwapIntervalEXT (int); extern int WINAPI wglGetSwapIntervalEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); #endif #ifndef WGL_EXT_depth_float #define WGL_EXT_depth_float 1 #endif #ifndef WGL_NV_vertex_array_range #define WGL_NV_vertex_array_range 1 #ifdef WGL_WGLEXT_PROTOTYPES extern void* WINAPI wglAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat); extern void WINAPI wglFreeMemoryNV (void *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); #endif #ifndef WGL_3DFX_multisample #define WGL_3DFX_multisample 1 #endif #ifndef WGL_EXT_multisample #define WGL_EXT_multisample 1 #endif #ifndef WGL_OML_sync_control #define WGL_OML_sync_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetSyncValuesOML (HDC, INT64 *, INT64 *, INT64 *); extern BOOL WINAPI wglGetMscRateOML (HDC, INT32 *, INT32 *); extern INT64 WINAPI wglSwapBuffersMscOML (HDC, INT64, INT64, INT64); extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC, int, INT64, INT64, INT64); extern BOOL WINAPI wglWaitForMscOML (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *); extern BOOL WINAPI wglWaitForSbcOML (HDC, INT64, INT64 *, INT64 *, INT64 *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); #endif #ifndef WGL_I3D_digital_video_control #define WGL_I3D_digital_video_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC, int, int *); extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC, int, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); #endif #ifndef WGL_I3D_gamma #define WGL_I3D_gamma 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC, int, int *); extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC, int, const int *); extern BOOL WINAPI wglGetGammaTableI3D (HDC, int, USHORT *, USHORT *, USHORT *); extern BOOL WINAPI wglSetGammaTableI3D (HDC, int, const USHORT *, const USHORT *, const USHORT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); #endif #ifndef WGL_I3D_genlock #define WGL_I3D_genlock 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglEnableGenlockI3D (HDC); extern BOOL WINAPI wglDisableGenlockI3D (HDC); extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC, BOOL *); extern BOOL WINAPI wglGenlockSourceI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSampleRateI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC, UINT *); extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC, UINT *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); #endif #ifndef WGL_I3D_image_buffer #define WGL_I3D_image_buffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern LPVOID WINAPI wglCreateImageBufferI3D (HDC, DWORD, UINT); extern BOOL WINAPI wglDestroyImageBufferI3D (HDC, LPVOID); extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT); extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC, const LPVOID *, UINT); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); #endif #ifndef WGL_I3D_swap_frame_lock #define WGL_I3D_swap_frame_lock 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglEnableFrameLockI3D (void); extern BOOL WINAPI wglDisableFrameLockI3D (void); extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *); extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); #endif #ifndef WGL_I3D_swap_frame_usage #define WGL_I3D_swap_frame_usage 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetFrameUsageI3D (float *); extern BOOL WINAPI wglBeginFrameTrackingI3D (void); extern BOOL WINAPI wglEndFrameTrackingI3D (void); extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *, DWORD *, float *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); #endif #ifndef WGL_ATI_pixel_format_float #define WGL_ATI_pixel_format_float 1 #endif #ifndef WGL_NV_float_buffer #define WGL_NV_float_buffer 1 #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: SparCraft/source/glfont2/glfont.cc ================================================ //********************************************************* //GLFONT.CPP -- glFont routines //Copyright (c) 1998 Brad Fish //Copyright (c) 2002 Henri Kyrki //See glFont.txt for terms of use //10.5 2002 //********************************************************* #include "glfont.h" #ifdef USING_VISUALIZATION_LIBRARIES //********************************************************* //GLFontBase //********************************************************* GLFontBase::GLFontBase() : ok(FALSE) { } void GLFontBase::CreateImpl(const std::string &Filename, GLuint Tex, bool PixelPerfect) { Font.Char = NULL; FreeResources(); FILE *Input; //Open font file if ((Input = fopen(Filename.c_str(), "rb")) == NULL) { printf("Can't open font\n"); throw GLFontError::InvalidFile(); } //Read glFont structure size_t rr = fread(&Font, sizeof(GLFONT), 1, Input); //Save texture number Font.Tex = Tex; //Get number of characters int Num = Font.IntEnd - Font.IntStart + 1; //Allocate memory for characters //if ((Font.Char = (GLFONTCHAR *)malloc(sizeof(GLFONTCHAR) * Num)) == NULL) Font.Char = new GLFONTCHAR[Num]; //Read glFont characters rr = fread(Font.Char, sizeof(GLFONTCHAR), Num, Input); //Get texture size Num = Font.TexWidth * Font.TexHeight * 2; //Allocate memory for texture data //TexBytes = (char *)malloc(Num) char *TexBytes = new char[Num]; //Read texture data rr = fread(TexBytes, sizeof(char), Num, Input); //Set texture attributes glBindTexture(GL_TEXTURE_2D, Font.Tex); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); if(PixelPerfect) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //Create texture glTexImage2D(GL_TEXTURE_2D, 0, 2, Font.TexWidth, Font.TexHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (void *)TexBytes); //Clean up delete []TexBytes; fclose(Input); ok = TRUE; } //********************************************************* void GLFontBase::FreeResources () { //Free character memory if (Font.Char != NULL) delete []Font.Char; ok = FALSE; } //********************************************************* void GLFontBase::Begin () { if (!ok) { throw GLFontError::InvalidFont(); } glBindTexture(GL_TEXTURE_2D, Font.Tex); } //********************************************************* GLFontBase::~GLFontBase () { FreeResources(); } //********************************************************* //PixelPerfectGLFont //********************************************************* PixelPerfectGLFont::PixelPerfectGLFont() { } //********************************************************* void PixelPerfectGLFont::Create(const std::string &Filename, GLuint Tex) { GLFontBase::CreateImpl(Filename, Tex, TRUE); for (int i = 0; i < Font.IntEnd - Font.IntStart + 1; i++) { Font.Char[i].width = (int)((Font.Char[i].tx2 - Font.Char[i].tx1)*Font.TexWidth); Font.Char[i].height = (int)((Font.Char[i].ty2 - Font.Char[i].ty1)*Font.TexHeight); } } //********************************************************* void PixelPerfectGLFont::TextOut (std::string String, int x, int y, int z) { //Return if we don't have a valid glFont if (!ok) { throw GLFontError::InvalidFont(); } //Get length of string int Length = String.length(); //Begin rendering quads glBegin(GL_QUADS); //Loop through characters for (int i = 0; i < Length; i++) { //Get pointer to glFont character GLFONTCHAR *Char = &Font.Char[(int)String[i] - Font.IntStart]; //Specify vertices and texture coordinates glTexCoord2f(Char->tx1, Char->ty1); glVertex3i(x, y, z); glTexCoord2f(Char->tx1, Char->ty2); glVertex3i(x, y + Char->height, z); glTexCoord2f(Char->tx2, Char->ty2); glVertex3i(x + Char->width, y + Char->height, z); glTexCoord2f(Char->tx2, Char->ty1); glVertex3i(x + Char->width, y, z); //Move to next character x += Char->width; } //Stop rendering quads glEnd(); } //********************************************************* //GLFont //********************************************************* GLFont::GLFont() { } //********************************************************* void GLFont::Create(const std::string &Filename, GLuint Tex) { GLFontBase::CreateImpl(Filename, Tex, FALSE); } //********************************************************* void GLFont::TextOut (std::string String, float x, float y, float z) { //Return if we don't have a valid glFont if (!ok) { throw GLFontError::InvalidFont(); } //Get length of string int Length = String.length(); //Begin rendering quads glBegin(GL_QUADS); //Loop through characters for (int i = 0; i < Length; i++) { //Get pointer to glFont character GLFONTCHAR *Char = &Font.Char[(int)String[i] - Font.IntStart]; //Specify vertices and texture coordinates glTexCoord2f(Char->tx1, Char->ty1); glVertex3f(x, y, z); glTexCoord2f(Char->tx1, Char->ty2); glVertex3f(x, y + Char->dy, z); glTexCoord2f(Char->tx2, Char->ty2); glVertex3f(x + Char->dx, y + Char->dy, z); glTexCoord2f(Char->tx2, Char->ty1); glVertex3f(x + Char->dx, y, z); //Move to next character x += Char->dx; } //Stop rendering quads glEnd(); } //End of file #endif ================================================ FILE: SparCraft/source/glfont2/glfont.h ================================================ #include "../Common.h" #ifdef USING_VISUALIZATION_LIBRARIES #pragma once //********************************************************* //GLFONT.H -- Header for GLFONT.CPP //Copyright (c) 1998 Brad Fish //Copyright (c) 2002 Henri Kyrki //See glFont.txt for terms of use //10.5 2002 //********************************************************* #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #include #include #include #include namespace GLFontError { struct InvalidFile{}; struct InvalidFont{}; } class GLFontBase { public: GLFontBase(); void Begin(); virtual ~GLFontBase(); protected: void CreateImpl(const std::string &FileName, GLuint Tex, bool PixelPerfect = FALSE); typedef struct { union { float dx; int width; }; union { float dy; int height; }; float tx1, ty1; float tx2, ty2; } GLFONTCHAR; typedef struct { int Tex; int TexWidth, TexHeight; int IntStart, IntEnd; GLFONTCHAR *Char; } GLFONT; GLFONT Font; bool ok; private: void FreeResources(); }; class GLFont : public GLFontBase { public: GLFont(); void Create(const std::string &FileName, GLuint Tex); void TextOut (std::string String, float x, float y, float z); }; class PixelPerfectGLFont : public GLFontBase { public: PixelPerfectGLFont(); void Create(const std::string &FileName, GLuint Tex); void TextOut (std::string String, int x, int y, int z); }; #endif ================================================ FILE: SparCraft/source/gui/GUI.cpp ================================================ #include "GUI.h" #include "BWAPI.h" #include #include using namespace SparCraft; const size_t MaxStarCraftTextures = 512; const int GUI::TextureFont = 256; GLfloat ColorWhite[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GUI::GUI(int width, int height) : _initialWidth(width) , _initialHeight(height) , _cameraX(0) , _cameraY(0) , _previousMouseX(0) , _previousMouseY(0) , _isStarted(false) , _mousePressed(false) , _shiftPressed(false) , _currentFrame(0) , _previousRenderTime(0) , _guiGame(*this) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cout << "Could not initialize SDL\n"; exit(-1); } onStart(); } GUI::~GUI() { SDL_Quit(); } bool GUI::isStarted() const { return _isStarted; } // This function must be called before OnFrame void GUI::onStart() { // if we've already called OnStart, don't re-initialize everything if (_isStarted) { return; } // the top-left corner of the scene will be 0, 0 _cameraX = 0; _cameraY = 0; // double buffer and swap attributes, makes switching scenes fast SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetSwapInterval(1); // set up the window that the OpenGL context will be bound to _window = SDL_CreateWindow("StarCraft OpenGL Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initialWidth, _initialHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); // set the glcontext to the window we just created _glcontext = SDL_GL_CreateContext(_window); // load all the Starcraft textures that we'll need loadTextures(); // enable alpha blending for transparency glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); // set up the viewport glViewport(0, 0, width(), height()); _isStarted = true; } void GUI::onFrame() { SPARCRAFT_ASSERT(isStarted(), "Must initialize GUI before calling OnFrame()"); // Handle input events handleEvents(); // Render the frame glClear(GL_COLOR_BUFFER_BIT); render(); SDL_GL_SwapWindow(_window); } void GUI::handleEvents() { // Handle SDL events SDL_Event event; while (SDL_PollEvent(&event)) { const bool pressed(event.key.state == SDL_PRESSED); switch (event.type) { case SDL_MOUSEMOTION: { if ((_previousMouseX != 0 || _previousMouseY != 0) && (event.motion.state & SDL_BUTTON_LEFT)) { _cameraX -= event.motion.xrel; _cameraY -= event.motion.yrel; } _previousMouseX = event.motion.x; _previousMouseY = event.motion.y; break; } case SDL_KEYDOWN: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: _shiftPressed = pressed; break; case SDLK_p: { } } break; } case SDL_KEYUP: { switch (event.key.keysym.sym) { case SDLK_LSHIFT: _shiftPressed = pressed; break; } break; } case SDL_MOUSEWHEEL: { break; } case SDL_MOUSEBUTTONDOWN: { break; } case SDL_MOUSEBUTTONUP: { if (event.button.button == SDL_BUTTON_LEFT) { } break; } case SDL_WINDOWEVENT_RESIZED: { break; } case SDL_QUIT: { std::cerr << "SDL_QUIT caught\n\n"; exit(0); } } } } void GUI::render() { Timer renderTimer; renderTimer.start(); glViewport(0, 0, width(), height()); glMatrixMode(GL_PROJECTION); glPushMatrix(); { glOrtho(0, width(), height(), 0, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); { glTranslatef(static_cast(-_cameraX),static_cast(-_cameraY),0); _guiGame.onFrame(); //drawAllBWAPIUnits(); //GUITools::DrawTexturedRect(Position(0,0), Position(200,200), TextureFont, ColorWhite); //GUITools::DrawString(Position(300, 300), "Test String", ColorWhite); } glPopMatrix(); } glMatrixMode(GL_PROJECTION); glPopMatrix(); _currentFrame++; } int GUI::width() { int x, y; SDL_GetWindowSize(_window, &x, &y); return x; } int GUI::height() { int x, y; SDL_GetWindowSize(_window, &x, &y); return y; } void GUI::setCenter(int x, int y) { _cameraX = -(width() - x) / 2; _cameraY = -(height() - y) / 2; } void GUI::drawAllBWAPIUnits() { Position p(0, 0); size_t maxHeight = 0; std::vector allIDs; for (const auto & kv : _techTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & kv : _upgradeTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & kv : _unitTypeTextureID) { allIDs.push_back(kv.second); } for (const auto & id : allIDs) { if (p.x() + _textureSizes[id].x() > width()) { p = Position(0, p.y() + maxHeight); maxHeight = 0; } GUITools::DrawTexturedRect(p, p + _textureSizes[id], id, ColorWhite); maxHeight = std::max((size_t)_textureSizes[id].y(), maxHeight); p = p + (Position(_textureSizes[id].x(), 0)); } } void GUI::drawUnitType(const BWAPI::UnitType & type, const Position & p) { const int id = _unitTypeTextureID[type]; //GUITools::DrawString(p, type.getName(), ColorWhite); Position pos = p - Position(_textureSizes[id].x()/2, _textureSizes[id].y()/2); GUITools::DrawTexturedRect(pos, pos + _textureSizes[id], id, ColorWhite); } void GUI::loadTextures() { std::string imageDir = "../asset/images/"; // set up the vectors that will hold the textures _textures = std::vector(MaxStarCraftTextures, 0); _textureSizes = std::vector(MaxStarCraftTextures); glGenTextures(MaxStarCraftTextures, &_textures[0]); // load all the starcraft unit textures size_t textureNumber = 1; for (const BWAPI::UnitType & type : BWAPI::UnitTypes::allUnitTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _unitTypeTextureID[type] = textureNumber; textureNumber++; } } for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _techTypeTextureID[type] = textureNumber; textureNumber++; } } for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes()) { if (loadTexture(textureNumber, imageDir + GetTextureFileName(type))) { _upgradeTypeTextureID[type] = textureNumber; textureNumber++; } } loadTexture(TextureFont, imageDir + "fonts/alpha_trans.png"); std::cout << "\n\nSuccessfully loaded " << textureNumber << " textures\n\n"; } bool GUI::loadTexture(int textureNumber, const std::string & fileName) { struct stat buf; if (stat(fileName.c_str(), &buf) == -1) { //std::cout << "Couldn't find texture: " << fileName << std::endl; return false; } SDL_Surface *surface2 = IMG_Load(fileName.c_str()); GLenum texture_format = GL_RGBA; GLint nOfColors = 4; if (surface2 != NULL) { glBindTexture( GL_TEXTURE_2D, textureNumber ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, texture_format, surface2->w, surface2->h, 0, texture_format, GL_UNSIGNED_BYTE, surface2->pixels); } else { printf("SDL could not load image: %s\n", SDL_GetError()); } if (surface2) { _textureSizes[textureNumber] = Position(surface2->w, surface2->h); SDL_FreeSurface( surface2 ); } //std::cout << textureNumber << "Loaded: " << fileName << std::endl; return true; } bool GUI::saveScreenshotBMP(const std::string & filename) { SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, width(), height(), 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); glReadBuffer(GL_FRONT); glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_SaveBMP(image, filename.c_str()); SDL_FreeSurface(image); return true; } std::string GUI::GetTextureFileName(const BWAPI::TechType & type) { std::string filename = "command_icons/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } std::string GUI::GetTextureFileName(const BWAPI::UnitType & type) { std::string filename = "units/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } std::string GUI::GetTextureFileName(const BWAPI::UpgradeType & type) { std::string filename = "command_icons/" + type.getName() + ".png"; for (size_t i(0); i < filename.size(); ++i) { if (filename[i] == ' ') { filename[i] = '_'; } } return filename; } void GUI::setGame(const Game & game) { _guiGame.setGame(game); } const Game & GUI::getGame() const { return _guiGame.getGame(); } ================================================ FILE: SparCraft/source/gui/GUI.h ================================================ #pragma once #include "../SparCraft.h" #include "../Timer.h" #include "../Position.hpp" #include "BWAPI.h" #include "GUITools.h" #include "GUIGame.h" #include #include #undef main #include #include #include "GUITools.h" #include namespace SparCraft { class GUI { int _initialWidth; int _initialHeight; int _windowSizeY; int _cameraX; int _cameraY; bool _isStarted; int _previousMouseX; int _previousMouseY; bool _mousePressed; bool _shiftPressed; double _previousRenderTime; size_t _currentFrame; SDL_Window * _window; SDL_Surface * _surface; SDL_GLContext _glcontext; GUIGame _guiGame; std::vector _textures; std::vector _textureSizes; std::map _unitTypeTextureID; std::map _techTypeTextureID; std::map _upgradeTypeTextureID; void handleEvents(); void render(); void renderTextGlut(int x, int y, std::string & s); void loadTextures(); bool loadTexture(int textureNumber, const std::string & fileName); void onResize(SDL_Event & event); void drawAllBWAPIUnits(); void onStart(); void testRender(); bool isStarted() const; static std::string GetTextureFileName(const BWAPI::UnitType & type); static std::string GetTextureFileName(const BWAPI::UpgradeType & type); static std::string GetTextureFileName(const BWAPI::TechType & type); public: static const int TextureASCIIOffset; static const int TextureFont; GUI(int width, int height); ~GUI(); int width(); int height(); void onFrame(); void setCenter(int x, int y); void setGame(const Game & game); void drawUnitType(const BWAPI::UnitType & type, const Position & p); const Game & getGame() const; bool saveScreenshotBMP(const std::string & filename); }; } ================================================ FILE: SparCraft/source/gui/GUIGame.cpp ================================================ #include "GUIGame.h" #include "GUITools.h" #include "GUI.h" using namespace SparCraft; GLfloat White[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat PlayerColors[2][4] = {{1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f, 1.0f}}; GLfloat PlayerColorsDark[2][4] = {{0.7f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.7f, 0.0f, 1.0f}}; GUIGame::GUIGame(GUI & gui) : _game(GameState(), 0) , _gui(gui) { } void GUIGame::onFrame() { drawGame(); drawHPBars(); Timer turnTimer; turnTimer.start(); if (!_game.gameOver()) { _game.playNextTurn(); _previousTurnTimer = turnTimer.getElapsedTimeInMilliSec(); for (size_t p(0); p < 2; ++p) { Player_UCT * uct = dynamic_cast (_game.getPlayer(p).get()); Player_AlphaBeta * ab = dynamic_cast (_game.getPlayer(p).get()); if (uct) { setParams(p, uct->getParams().getDescription()); setResults(p, uct->getResults().getDescription()); } if (ab) { setParams(p, ab->getParams().getDescription()); setResults(p, ab->results().getDescription()); } } } drawParameters(5, 15); drawSearchResults(5, 150); drawInfo(); } void GUIGame::drawInfo() { std::stringstream ss; ss << "Frame Draw Time: " << _previousDrawGameTimer << "ms\n\n"; ss << "Turn Time: " << _previousTurnTimer << "ms"; GUITools::DrawString(Position(5, _gui.height()-20), ss.str(), White); } void GUIGame::drawGame() { Timer drawGameTimer; drawGameTimer.start(); const GameState & state = _game.getState(); for (size_t p(0); p < 2; ++p) { for (size_t u(0); u < state.numUnits(p); u++) { drawUnit(state.getUnit(p, u)); } } _previousDrawGameTimer = drawGameTimer.getElapsedTimeInMilliSec(); } void GUIGame::drawHPBars() { const GameState & state = _game.getState(); for (IDType p(0); p 0 && p<_params[pp][0].size(); ++p) { GUITools::DrawString(Position(x+pp*playerspacing, y+((p+1)*(size+spacing))), _params[pp][0][p], White); GUITools::DrawString(Position(x+pp*playerspacing+colwidth, y+((p+1)*(size+spacing))), _params[pp][1][p], White); } } //// Player 1 Settings //if (_params[0].size() > 0) //{ // GUITools::DrawString(Position(x, y), "Player 1 Settings", PlayerColors[0]); // for (size_t p(0); _params[0].size() > 0 && p<_params[0][0].size(); ++p) // { // GUITools::DrawString(Position(x, y+((p+1)*(size+spacing))), _params[0][0][p], White); // GUITools::DrawString(Position(x+colwidth, y+((p+1)*(size+spacing))), _params[0][1][p], White); // } //} //if (_params[1].size() > 0) //{ // // Player 2 Settings // x += playerspacing; // glColor3f(0.0, 1.0, 0.0); // DrawText(x, y , size, "Player 2 Settings"); // glColor3f(1.0, 1.0, 1.0); // for (size_t p(0); params[1].size() > 0 && p 0 && p<_results[pp][0].size(); ++p) { GUITools::DrawString(Position(x+pp*playerspacing, y+((p+1)*(size+spacing))), _results[pp][0][p], White); GUITools::DrawString(Position(x+pp*playerspacing+colwidth, y+((p+1)*(size+spacing))), _results[pp][1][p], White); } } } void GUIGame::drawUnit(const Unit & unit) { if (!unit.isAlive()) { return; } const int healthBoxHeight = 4; const GameState & state = _game.getState(); const BWAPI::UnitType & type = unit.type(); const Position pos(unit.currentPosition(state.getTime())); _gui.drawUnitType(unit.type(), pos); const int x0(pos.x() - type.dimensionUp()); const int x1(pos.x() + type.dimensionDown()); const int y0(pos.y() - type.dimensionUp()); const int y1(pos.y() + type.dimensionDown()); double percHP = (double)unit.currentHP() / (double)unit.maxHP(); int cw = (int)((x1-x0) * percHP); int xx = pos.x() - (x1-x0)/2; int yy = pos.y() - healthBoxHeight - (y1-y0)/2 - 5; GUITools::DrawRect(Position(xx, yy), Position(xx+cw, yy+healthBoxHeight), PlayerColors[unit.player()]); const Action & action = unit.previousAction(); if (action.type() == ActionTypes::MOVE) { glColor4f(1, 1, 1, 0.75); glBegin(GL_LINES); glVertex2i(pos.x(), pos.y()); glVertex2i(unit.pos().x(), unit.pos().y()); glEnd( ); } else if (action.type() == ActionTypes::ATTACK) { const Unit & target(state.getUnit(state.getEnemy(unit.player()), action.index())); const Position targetPos(target.currentPosition(state.getTime())); GUITools::DrawLine(pos, targetPos, 1, PlayerColors[unit.player()]); } } void GUIGame::setGame(const Game & g) { _game = g; _initialState = g.getState(); } const Game & GUIGame::getGame() const { return _game; } void GUIGame::setResults(const IDType & player, const std::vector > & r) { _results[player] = r; } void GUIGame::setParams(const IDType & player, const std::vector > & p) { _params[player] = p; } ================================================ FILE: SparCraft/source/gui/GUIGame.h ================================================ #pragma once #include "../SparCraft.h" namespace SparCraft { class GUI; class GUIGame { GUI & _gui; Game _game; double _previousDrawGameTimer; double _previousTurnTimer; GameState _initialState; std::vector > _params[2]; std::vector > _results[2]; std::vector > _exp; void drawGame(); void drawInfo(); void drawHPBars(); void drawUnit(const Unit & unit); void drawParameters(int x, int y); void drawSearchResults(int x, int y); void setResults(const IDType & player, const std::vector > & r); void setParams(const IDType & player, const std::vector > & p); public: GUIGame(GUI & gui); const Game & getGame() const; void setGame(const Game & g); void onFrame(); }; } ================================================ FILE: SparCraft/source/gui/GUITools.cpp ================================================ #include "GUITools.h" #include "GUI.h" namespace SparCraft { namespace GUITools { void DrawString(const Position & p, const std::string & text, const GLfloat * rgba) { Position origin(p); Position fontSize(8,8); int linePos = 0; for (size_t i(0); i < text.length(); ++i) { if (text[i] == '\n') { origin = Position(p.x(), origin.y() + fontSize.y()); linePos = 0; } else { Position charStart = Position(origin.x() + linePos*fontSize.x(), origin.y() - fontSize.y()); Position charEnd = charStart + fontSize; DrawChar(charStart, charEnd, text[i], rgba); linePos++; } } } const size_t FontTextureSize = 128; const size_t CharSize = 8; const float CharDelta = 1.0f / 16.0f; void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba) { float xPos = ((ch % 16) / 16.0f); float yPos = (ch >> 4) / 16.0f; glPushMatrix(); glEnable( GL_TEXTURE_2D ); glColor4fv(rgba); glBindTexture( GL_TEXTURE_2D, GUI::TextureFont ); glBegin( GL_QUADS ); glTexCoord2f(xPos,yPos); glVertex2i(tl.x(), tl.y()); glTexCoord2f(xPos+CharDelta,yPos); glVertex2i(br.x(), tl.y()); glTexCoord2f(xPos+CharDelta,yPos+CharDelta); glVertex2i(br.x(), br.y()); glTexCoord2f(xPos,yPos+CharDelta); glVertex2i(tl.x(), br.y()); glEnd(); glDisable( GL_TEXTURE_2D ); glPopMatrix(); } void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba) { glPushMatrix(); glLineWidth(thickness); glColor4fv(rgba); glBegin(GL_LINES); glVertex2i(p1.x(),p1.y()); glVertex2i(p2.x(),p2.y()); glEnd(); glPopMatrix(); } void DrawCircle(const Position & pos, float r, int num_segments) { float theta = 2 * (float)3.1415926 / float(num_segments); float c = cosf(theta);//precalculate the sine and cosine float s = sinf(theta); float t; float x = r;//we start at angle = 0 float y = 0; glBegin(GL_LINE_LOOP); for(int ii = 0; ii < num_segments; ii++) { glVertex2f(x + pos.x(), y + pos.y());//output vertex //apply the rotation matrix t = x; x = c * x - s * y; y = s * t + c * y; } glEnd(); } void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba) { glPushMatrix(); glColor4fv(rgba); glBegin(GL_QUADS); glVertex2i(tl.x(),tl.y()); glVertex2i(br.x(),tl.y()); glVertex2i(br.x(),br.y()); glVertex2i(tl.x(),br.y()); glEnd(); glPopMatrix(); } void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight) { glPushMatrix(); glBegin(GL_QUADS); glColor4fv(rgbaLeft); glVertex2i(tl.x(),tl.y()); glColor4fv(rgbaRight); glVertex2i(br.x(),tl.y()); glColor4fv(rgbaRight); glVertex2i(br.x(),br.y()); glColor4fv(rgbaLeft); glVertex2i(tl.x(),br.y()); glEnd(); glPopMatrix(); } void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba) { glPushMatrix(); glEnable( GL_TEXTURE_2D ); glColor4fv(rgba); glBindTexture( GL_TEXTURE_2D, textureID ); glBegin( GL_QUADS ); glTexCoord2f(0.0,0.0); glVertex2i(tl.x(),tl.y()); glTexCoord2f(1.0,0.0); glVertex2i(br.x(),tl.y()); glTexCoord2f(1.0,1.0); glVertex2i(br.x(),br.y()); glTexCoord2f(0.0,1.0); glVertex2i(tl.x(),br.y()); glEnd(); glDisable( GL_TEXTURE_2D ); glPopMatrix(); } void DrawIconAndText(const Position & tl, const Position & br, const int & textureID, const int & textureID2, const GLfloat * rgba) { GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; Position iconSize = br - tl; Position statusNumPos = tl + Position(-iconSize.scale(0.15f).x(), iconSize.scale(0.4f).y()); GUITools::DrawTexturedRect(tl, br, textureID, rgba); GUITools::DrawTexturedRect(statusNumPos, statusNumPos + iconSize.scale(0.65f), textureID2, rgba); } } } ================================================ FILE: SparCraft/source/gui/GUITools.h ================================================ #pragma once #include "../SparCraft.h" #include #include namespace SparCraft { namespace GUITools { const int FLIP_VERTICAL = 1; const int FLIP_HORIZONTAL = 2; void DrawLine(const Position & p1, const Position & p2, const float thickness, const GLfloat * rgba); void DrawString(const Position & p, const std::string & text, const GLfloat * rgba); void DrawChar(const Position & tl, const Position & br, char ch, const GLfloat * rgba); void DrawCircle(const Position & p, float r, int num_segments); void DrawTexturedRect(const Position & tl, const Position & br, const int & textureID, const GLfloat * rgba); void DrawRect(const Position & tl, const Position & br, const GLfloat * rgba); void DrawRectGradient(const Position & tl, const Position & br, const GLfloat * rgbaLeft, const GLfloat * rgbaRight); void SetColor(const GLfloat * src, GLfloat * dest); void SetColor(const GLfloat * src, GLfloat * dest); } } ================================================ FILE: SparCraft/source/main/SearchExperiment.cpp ================================================ #include "SearchExperiment.h" using namespace SparCraft; SearchExperiment::SearchExperiment(const std::string & configFile) : map(NULL) , showDisplay(false) , appendTimeStamp(true) , rand(0, std::numeric_limits::max(), 0) { configFileSmall = getBaseFilename(configFile); map = new Map(40, 22); setCurrentDateTime(); parseConfigFile(configFile); writeConfig(configFile); setupResults(); } SearchExperiment::~SearchExperiment() { if (map) { delete map; } } void SearchExperiment::setupResults() { size_t np1 = players[0].size(); size_t np2 = players[1].size(); resultsStateNumber = ivvv(np1, ivv(np2, iv())); resultsNumUnits = ivvv(np1, ivv(np2, iv())); resultsEval = ivvv(np1, ivv(np2, iv())); resultsRounds = ivvv(np1, ivv(np2, iv())); resultsTime = dvvv(np1, dvv(np2, dv())); numGames = ivv(np1, iv(np2, 0)); numWins = ivv(np1, iv(np2, 0)); numLosses = ivv(np1, iv(np2, 0)); numDraws = ivv(np1, iv(np2, 0)); } void SearchExperiment::writeConfig(const std::string & configfile) { std::ofstream config(getConfigOutFileName().c_str()); if (!config.is_open()) { System::FatalError("Problem Opening Output File: Config"); } std::vector lines(getLines(configfile)); for (size_t l(0); l 0) { score = ((double)numWins[p1][p2] / (double)(numGames[p1][p2])) + 0.5*((double)numDraws[p1][p2] / (double)numGames[p1][p2]); } results << std::setiosflags(std::ios::fixed) << std::setw(12) << std::setprecision(7) << score << " "; } results << std::endl; } results.close(); } void SearchExperiment::padString(std::string & str, const size_t & length) { while (str.length() < length) { str = str + " "; } } std::string SearchExperiment::getResultsSummaryFileName() { std::string res = resultsFile; if (appendTimeStamp) { res += "_" + getDateTimeString(); } res += "_results_summary.txt"; return res; } std::string SearchExperiment::getResultsOutFileName() { std::string res = resultsFile; if (appendTimeStamp) { res += "_" + getDateTimeString(); } res += "_results_raw.txt"; return res; } std::string SearchExperiment::getConfigOutFileName() { std::string conf = resultsFile; if (appendTimeStamp) { conf += "_" + getDateTimeString(); } conf += "_config.txt"; return conf; } std::string SearchExperiment::getDateTimeString() { return timeString; } void SearchExperiment::setCurrentDateTime() { time_t now = time(0); struct tm tstruct; char buf[80]; std::fill(buf, buf+80, '0'); tstruct = *localtime(&now); strftime(buf, sizeof(buf), "%Y-%m-%d_%X", &tstruct); //strftime(buf, sizeof(buf), "%X", &tstruct); // need to replace ':' for windows filenames for (int i(0); i<80; i++) { if (buf[i] == ':') { buf[i] = '-'; } } timeString = std::string(buf); } std::vector SearchExperiment::getLines(const std::string & filename) { // set up the file std::ifstream fin(filename.c_str()); if (!fin.is_open()) { System::FatalError("Problem Opening File: " + filename); } std::string line; std::vector lines; // each line of the file will be a new player to add while (fin.good()) { // get the line and set up the string stream getline(fin, line); // skip blank lines and comments if (line.length() > 1 && line[0] != '#') { lines.push_back(line); } } fin.close(); return lines; } void SearchExperiment::parseConfigFile(const std::string & filename) { std::vector lines(getLines(filename)); for (size_t l(0); l> option; if (strcmp(option.c_str(), "Player") == 0) { addPlayer(lines[l]); } else if (strcmp(option.c_str(), "State") == 0) { addState(lines[l]); } else if (strcmp(option.c_str(), "MapFile") == 0) { std::string fileString; iss >> fileString; map = new Map; map->load(fileString); } else if (strcmp(option.c_str(), "Display") == 0) { std::string option; iss >> option; iss >> imageDir; if (strcmp(option.c_str(), "true") == 0) { showDisplay = true; } } else if (strcmp(option.c_str(), "ResultsFile") == 0) { std::string fileString; std::string append; iss >> fileString; iss >> append; resultsFile = fileString; appendTimeStamp = strcmp(append.c_str(), "true") == 0 ? true : false; } else if (strcmp(option.c_str(), "PlayerUpgrade") == 0) { int playerID(0); std::string upgradeName; int upgradeLevel(0); iss >> playerID; iss >> upgradeName; iss >> upgradeLevel; for (const BWAPI::UpgradeType & type : BWAPI::UpgradeTypes::allUpgradeTypes()) { if (type.getName().compare(upgradeName) == 0) { PlayerProperties::Get(playerID).SetUpgradeLevel(type, upgradeLevel); break; } } } else if (strcmp(option.c_str(), "PlayerTech") == 0) { int playerID(0); std::string techName; iss >> playerID; iss >> techName; for (const BWAPI::TechType & type : BWAPI::TechTypes::allTechTypes()) { if (type.getName().compare(techName) == 0) { PlayerProperties::Get(playerID).SetResearched(type, true); break; } } } else { System::FatalError("Invalid Option in Configuration File: " + option); } } } void SearchExperiment::addState(const std::string & line) { std::istringstream iss(line); // the first number is the playerID std::string state; std::string stateType; int numStates; iss >> state; iss >> stateType; iss >> numStates; if (strcmp(stateType.c_str(), "StateSymmetric") == 0) { int xLimit, yLimit; iss >> xLimit; iss >> yLimit; std::vector unitVec; std::vector numUnitVec; std::string unitType; int numUnits; while (iss >> unitType) { iss >> numUnits; unitVec.push_back(unitType); numUnitVec.push_back(numUnits); } //std::cout << "\nAdding " << numStates << " Symmetric State(s)\n\n"; for (int s(0); s> filename; for (int i(0); i> filename; for (int i(0); i> xLimit; iss >> yLimit; iss >> cx1; iss >> cy1; iss >> cx2; iss >> cy2; std::vector unitVec; std::vector numUnitVec; std::string unitType; int numUnits; while (iss >> unitType) { iss >> numUnits; unitVec.push_back(unitType); numUnitVec.push_back(numUnits); } //std::cout << "\nAdding " << numStates << " Symmetric State(s)\n\n"; for (int s(0); s lines = getLines(fileName); GameState currentState; for (size_t u(0); u> unitType; iss >> playerID; iss >> x; iss >> y; currentState.addUnit(getUnitType(unitType), (IDType)playerID, Position(x, y)); } states.push_back(currentState); } BWAPI::UnitType SearchExperiment::getUnitType(const std::string & unitTypeString) { BWAPI::UnitType type; for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes()) { if (t.getName().compare(unitTypeString) == 0) { type = t; } } System::checkSupportedUnitType(type); return type; } void SearchExperiment::addGameState(const GameState & state) { if (states.size() >= 10000) { System::FatalError("Search Experiment cannot contain more than 10,000 states."); } } void SearchExperiment::addPlayer(const std::string & line) { std::istringstream iss(line); // Regular expressions for line validation (if I ever want to use them) //std::regex ScriptRegex("[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]*"); //std::regex AlphaBetaRegex("[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]*"); //std::regex UCTRegex("[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[0-9.]+[ ]+[0-9]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]+[a-zA-Z]+[ ]*"); //std::regex PortfolioRegex("[a-zA-Z]+[ ]+[0-1][ ]+[a-zA-Z]+[ ]+[0-9]+[ ]+[a-zA-Z]+[ ]+[0-9]+[ ][0-9]+[ ]*"); // the first number is the playerID std::string player; int playerID; int playerModelID; std::string playerModelString; iss >> player; iss >> playerID; iss >> playerModelString; playerStrings[playerID].push_back(playerModelString); playerModelID = PlayerModels::getID(playerModelString); //std::cout << "Player " << playerID << " adding type " << playerModelString << " (" << playerModelID << ")" << std::endl; if (playerModelID == PlayerModels::AttackClosest) { players[playerID].push_back(PlayerPtr(new Player_AttackClosest(playerID))); } else if (playerModelID == PlayerModels::AttackDPS) { players[playerID].push_back(PlayerPtr(new Player_AttackDPS(playerID))); } else if (playerModelID == PlayerModels::AttackWeakest) { players[playerID].push_back(PlayerPtr(new Player_AttackWeakest(playerID))); } else if (playerModelID == PlayerModels::Kiter) { players[playerID].push_back(PlayerPtr(new Player_Kiter(playerID))); } else if (playerModelID == PlayerModels::KiterDPS) { players[playerID].push_back(PlayerPtr(new Player_KiterDPS(playerID))); } else if (playerModelID == PlayerModels::Kiter_NOKDPS) { players[playerID].push_back(PlayerPtr(new Player_Kiter_NOKDPS(playerID))); } else if (playerModelID == PlayerModels::Cluster) { players[playerID].push_back(PlayerPtr(new Player_Cluster(playerID))); } else if (playerModelID == PlayerModels::NOKDPS) { players[playerID].push_back(PlayerPtr(new Player_NOKDPS(playerID))); } else if (playerModelID == PlayerModels::Random) { players[playerID].push_back(PlayerPtr(new Player_Random(playerID))); } else if (playerModelID == PlayerModels::PortfolioGreedySearch) { std::string enemyPlayerModel; size_t timeLimit(0); int iterations(1); int responses(0); iss >> timeLimit; iss >> enemyPlayerModel; iss >> iterations; iss >> responses; players[playerID].push_back(PlayerPtr(new Player_PortfolioGreedySearch(playerID, PlayerModels::getID(enemyPlayerModel), iterations, responses, timeLimit))); } else if (playerModelID == PlayerModels::AlphaBeta) { int timeLimitMS; int maxChildren; std::string moveOrdering; std::string evalMethod; std::string playoutScript1; std::string playoutScript2; std::string playerToMoveMethod; std::string opponentModelScript; // read in the values iss >> timeLimitMS; iss >> maxChildren; iss >> moveOrdering; iss >> evalMethod; iss >> playoutScript1; iss >> playoutScript2; iss >> playerToMoveMethod; iss >> opponentModelScript; // convert them to the proper enum types int moveOrderingID = MoveOrderMethod::getID(moveOrdering); int evalMethodID = EvaluationMethods::getID(evalMethod); int playoutScriptID1 = PlayerModels::getID(playoutScript1); int playoutScriptID2 = PlayerModels::getID(playoutScript2); int playerToMoveID = PlayerToMove::getID(playerToMoveMethod); int opponentModelID = PlayerModels::getID(opponentModelScript); // construct the parameter object AlphaBetaSearchParameters params; // give the default parameters we can't set via options params.setMaxDepth(50); params.setSearchMethod(SearchMethods::IDAlphaBeta); // set the parameters from the options in the file params.setMaxPlayer(playerID); params.setTimeLimit(timeLimitMS); params.setMaxChildren(maxChildren); params.setMoveOrderingMethod(moveOrderingID); params.setEvalMethod(evalMethodID); params.setSimScripts(playoutScriptID1, playoutScriptID2); params.setPlayerToMoveMethod(playerToMoveID); // add scripts for move ordering if (moveOrderingID == MoveOrderMethod::ScriptFirst) { params.addOrderedMoveScript(PlayerModels::NOKDPS); params.addOrderedMoveScript(PlayerModels::KiterDPS); //params.addOrderedMoveScript(PlayerModels::Cluster); //params.addOrderedMoveScript(PlayerModels::AttackWeakest); } // set opponent modeling if it's not none if (opponentModelID != PlayerModels::None) { if (playerID == 0) { params.setSimScripts(playoutScriptID1, opponentModelID); params.setPlayerModel(1, playoutScriptID2); } else { params.setSimScripts(opponentModelID, playoutScriptID2); params.setPlayerModel(0, playoutScriptID1); } } PlayerPtr abPlayer(new Player_AlphaBeta(playerID, params, TTPtr((TranspositionTable *)NULL))); players[playerID].push_back(abPlayer); } else if (playerModelID == PlayerModels::UCT) { int timeLimitMS; double cValue; int maxTraversals; int maxChildren; std::string moveOrdering; std::string evalMethod; std::string playoutScript1; std::string playoutScript2; std::string playerToMoveMethod; std::string opponentModelScript; // read in the values iss >> timeLimitMS; iss >> cValue; iss >> maxTraversals; iss >> maxChildren; iss >> moveOrdering; iss >> evalMethod; iss >> playoutScript1; iss >> playoutScript2; iss >> playerToMoveMethod; iss >> opponentModelScript; // convert them to the proper enum types int moveOrderingID = MoveOrderMethod::getID(moveOrdering); int evalMethodID = EvaluationMethods::getID(evalMethod); int playoutScriptID1 = PlayerModels::getID(playoutScript1); int playoutScriptID2 = PlayerModels::getID(playoutScript2); int playerToMoveID = PlayerToMove::getID(playerToMoveMethod); int opponentModelID = PlayerModels::getID(opponentModelScript); // construct the parameter object UCTSearchParameters params; // set the parameters from the options in the file params.setTimeLimit(timeLimitMS); params.setCValue(cValue); params.setMaxPlayer(playerID); params.setMaxTraversals(maxTraversals); params.setMaxChildren(maxChildren); params.setMoveOrderingMethod(moveOrderingID); params.setEvalMethod(evalMethodID); params.setSimScripts(playoutScriptID1, playoutScriptID2); params.setPlayerToMoveMethod(playerToMoveID); //params.setGraphVizFilename("__uct.txt"); // add scripts for move ordering if (moveOrderingID == MoveOrderMethod::ScriptFirst) { params.addOrderedMoveScript(PlayerModels::NOKDPS); params.addOrderedMoveScript(PlayerModels::KiterDPS); //params.addOrderedMoveScript(PlayerModels::Cluster); } // set opponent modeling if it's not none if (opponentModelID != PlayerModels::None) { if (playerID == 0) { params.setSimScripts(playoutScriptID1, opponentModelID); params.setPlayerModel(1, playoutScriptID2); } else { params.setSimScripts(opponentModelID, playoutScriptID2); params.setPlayerModel(0, playoutScriptID1); } } PlayerPtr uctPlayer(new Player_UCT(playerID, params)); players[playerID].push_back(uctPlayer); } else { System::FatalError("Invalid Player Type in Configuration File: " + playerModelString); } } Position SearchExperiment::getRandomPosition(const PositionType & xlimit, const PositionType & ylimit) { int x = xlimit - (rand.nextInt() % (2*xlimit)); int y = ylimit - (rand.nextInt() % (2*ylimit)); return Position(x, y); } GameState SearchExperiment::getSymmetricState( std::vector & unitTypes, std::vector & numUnits, const PositionType & xLimit, const PositionType & yLimit) { GameState state; Position mid(640, 360); //std::cout << " Adding"; // for each unit type to add for (size_t i(0); i & unitTypes, std::vector & numUnits, const PositionType cx1, const PositionType cy1, const PositionType cx2, const PositionType cy2, const PositionType & xLimit, const PositionType & yLimit) { GameState state; GameState state2; // for each unit type to add for (size_t i(0); igetType()); desc[1].push_back(ss.str()); ss.str(std::string()); ss << PlayerModels::getName(players[1][p2Ind]->getType()); desc[1].push_back(ss.str()); ss.str(std::string()); ss << state << " of " << states.size(); desc[1].push_back(ss.str()); ss.str(std::string()); ss << states[state].numUnits(0); desc[1].push_back(ss.str()); ss.str(std::string()); for (size_t p1(0); p1 < players[0].size(); ++p1) { desc[1].push_back(PlayerModels::getName(players[0][p1]->getType())); } for (size_t p2(0); p2 < players[1].size(); ++p2) { desc[1].push_back(PlayerModels::getName(players[1][p2]->getType())); } char buf[30]; for (size_t p1(0); p1 < players[0].size(); ++p1) { for (size_t p2(0); p2 < players[1].size(); ++p2) { double score = 0; if (numGames[p1][p2] > 0) { score = ((double)numWins[p1][p2] / (double)(numGames[p1][p2])) + 0.5*((double)numDraws[p1][p2] / (double)numGames[p1][p2]); } sprintf(buf, "%.7lf", score); desc[1].push_back(std::string(buf)); } } return desc; } std::string SearchExperiment::getBaseFilename(const std::string & filename) { for (int i(filename.length()-1); i>=0; --i) { if (filename[i] == '/' || filename[i] == '\\') { return filename.substr(i+1,filename.length()); } } return filename; } void SearchExperiment::runExperiment() { std::ofstream results(getResultsOutFileName().c_str()); if (!results.is_open()) { System::FatalError("Problem Opening Output File: Results Raw"); } // set the map file for all states for (size_t state(0); state < states.size(); ++state) { states[state].setMap(map); } #ifdef USING_VISUALIZATION_LIBRARIES GUI * disp = NULL; if (showDisplay) { disp = new GUI(map ? map->getBuildTileWidth() : 40, map ? map->getBuildTileHeight() : 22); disp->SetImageDir(imageDir); disp->OnStart(); disp->LoadMapTexture(map, 19); } #endif results << " P1 P2 ST UNIT EVAL RND MS | UnitType PlayerID CurrentHP XPos YPos\n"; // for each player one player for (size_t p1Player(0); p1Player < players[0].size(); p1Player++) { // for each player two player for (size_t p2Player(0); p2Player < players[1].size(); p2Player++) { // for each state we care about for (size_t state(2); state < states.size(); ++state) { char buf[255]; fprintf(stderr, "%s ", configFileSmall.c_str()); fprintf(stderr, "%5d %5d %5d %5d", (int)p1Player, (int)p2Player, (int)state, (int)states[state].numUnits(Players::Player_One)); sprintf(buf, "%5d %5d %5d %5d", (int)p1Player, (int)p2Player, (int)state, (int)states[state].numUnits(Players::Player_One)); results << buf; resultsPlayers[0].push_back(p1Player); resultsPlayers[1].push_back(p2Player); resultsStateNumber[p1Player][p2Player].push_back(state); resultsNumUnits[p1Player][p2Player].push_back(states[state].numUnits(Players::Player_One)); // get player one PlayerPtr playerOne(players[0][p1Player]); // give it a new transposition table if it's an alpha beta player Player_AlphaBeta * p1AB = dynamic_cast(playerOne.get()); if (p1AB) { p1AB->setTranspositionTable(TTPtr(new TranspositionTable())); } // get player two PlayerPtr playerTwo(players[1][p2Player]); Player_AlphaBeta * p2AB = dynamic_cast(playerTwo.get()); if (p2AB) { p2AB->setTranspositionTable(TTPtr(new TranspositionTable())); } // construct the game Game g(states[state], playerOne, playerTwo, 20000); ScoreType gameEval = 0; if (showDisplay) { static GUI gui(1280, 720); gui.setGame(g); while (!gui.getGame().gameOver()) { gui.onFrame(); } gameEval = gui.getGame().getState().eval(Players::Player_One, SparCraft::EvaluationMethods::LTD2).val(); } else { gameEval = g.getState().eval(Players::Player_One, SparCraft::EvaluationMethods::LTD2).val(); } numGames[p1Player][p2Player]++; if (gameEval > 0) { numWins[p1Player][p2Player]++; } else if (gameEval < 0) { numLosses[p1Player][p2Player]++; } else if (gameEval == 0) { numDraws[p1Player][p2Player]++; } double ms = g.getTime(); sprintf(buf, " %10d %6d %12.2lf", gameEval, g.getRounds(), ms); fprintf(stderr, "%12d %12.2lf\n", gameEval, ms); resultsEval[p1Player][p2Player].push_back(gameEval); resultsRounds[p1Player][p2Player].push_back(g.getRounds()); resultsTime[p1Player][p2Player].push_back(ms); results << buf; printStateUnits(results, g.getState()); results << std::endl; writeResultsSummary(); } } } results.close(); } void SearchExperiment::printStateUnits(std::ofstream & results, GameState & state) { std::stringstream ss; for (size_t p(0); p namespace SparCraft { class SearchExperiment; } typedef std::vector sv; typedef std::vector svv; typedef std::vector iv; typedef std::vector ivv; typedef std::vector ivvv; typedef std::vector dv; typedef std::vector dvv; typedef std::vector dvvv; class TranspositionTable; namespace SparCraft { class SearchExperiment { std::vector players[2]; std::vector playerStrings[2]; std::vector states; Map * map; bool showDisplay; std::string resultsFile; bool appendTimeStamp; std::string timeString; std::string configFileFull; std::string configFileSmall; std::string imageDir; iv resultsPlayers[2]; ivvv resultsStateNumber; ivvv resultsNumUnits; ivvv resultsEval; ivvv resultsRounds; dvvv resultsTime; ivv numGames; ivv numWins; ivv numLosses; ivv numDraws; RandomInt rand; void setupResults(); void addPlayer(const std::string & line); void addState(const std::string & line); void padString(std::string & str, const size_t & length); void setCurrentDateTime(); std::string getDateTimeString(); svv getExpDescription(const size_t & p1, const size_t & p2, const size_t & state); std::vector getLines(const std::string & filename); Position getRandomPosition( const PositionType & xlimit, const PositionType & ylimit); void addSeparatedState( std::vector & unitTypes, std::vector & numUnits, const int cx1, const int cy1, const int cx2, const int cy2, const PositionType & xLimit, const PositionType & yLimit); GameState getSymmetricState( std::vector & unitTypes, std::vector & numUnits, const PositionType & xLimit, const PositionType & yLimit); GameState getLineState( const BWAPI::UnitType type1, const size_t & num1, const BWAPI::UnitType type2, const size_t & num2, const size_t xSpace, const size_t ySpace); void addLineStates( std::vector & states, int num); std::string getBaseFilename(const std::string & filename); BWAPI::UnitType getUnitType(const std::string & unitTypeString); void parseStateDescriptionFile(const std::string & fileName); void parseConfigFile(const std::string & filename); void writeConfig(const std::string & configfile); std::string getResultsSummaryFileName(); std::string getResultsOutFileName(); std::string getConfigOutFileName(); std::string currentDateTime(); void printStateUnits(std::ofstream & results, GameState & state); void addGameState(const GameState & state); public: SearchExperiment(const std::string & configFile); ~SearchExperiment(); void runExperiment(); void writeResultsSummary(); }; } ================================================ FILE: SparCraft/source/main/main.cpp ================================================ #ifndef WIN32 #define APIENTRY #define APIENTRYP #endif #include "../SparCraft.h" #include "SearchExperiment.h" int main(int argc, char *argv[]) { SparCraft::init(); try { if (argc == 2) { SparCraft::SearchExperiment exp(argv[1]); exp.runExperiment(); } else { SparCraft::System::FatalError("Please provide experiment file as only argument"); } } catch(int e) { if (e == SparCraft::System::SPARCRAFT_FATAL_ERROR) { std::cerr << "\nSparCraft FatalError Exception, Shutting Down\n\n"; } else { std::cerr << "\nUnknown Exception, Shutting Down\n\n"; } } return 0; } ================================================ FILE: UAlbertaBot/.gitignore ================================================ VisualStudio/Release VisualStudio/Debug source/*.o ================================================ FILE: UAlbertaBot/Source/AutoObserver.cpp ================================================ #include "AutoObserver.h" #include "WorkerManager.h" #include "Global.h" using namespace UAlbertaBot; AutoObserver::AutoObserver() { } void AutoObserver::onFrame() { bool pickUnitToFollow = !m_observerFollowingUnit || !m_observerFollowingUnit->exists() || (BWAPI::Broodwar->getFrameCount() - m_cameraLastMoved > m_unitFollowFrames); if (pickUnitToFollow) { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->isUnderAttack() || unit->isAttacking()) { m_cameraLastMoved = BWAPI::Broodwar->getFrameCount(); m_unitFollowFrames = 6; m_observerFollowingUnit = unit; pickUnitToFollow = false; break; } } } if (pickUnitToFollow) { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->isBeingConstructed() && (unit->getRemainingBuildTime() < 12)) { m_cameraLastMoved = BWAPI::Broodwar->getFrameCount(); m_unitFollowFrames = 24; m_observerFollowingUnit = unit; pickUnitToFollow = false; break; } } } if (pickUnitToFollow) { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (Global::Workers().isWorkerScout(unit)) { m_cameraLastMoved = BWAPI::Broodwar->getFrameCount(); m_unitFollowFrames = 6; m_observerFollowingUnit = unit; pickUnitToFollow = false; break; } } } if (m_observerFollowingUnit && m_observerFollowingUnit->exists()) { BWAPI::Broodwar->setScreenPosition(m_observerFollowingUnit->getPosition() - BWAPI::Position(320, 180)); } } ================================================ FILE: UAlbertaBot/Source/AutoObserver.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { class AutoObserver { int m_cameraLastMoved = 0; int m_unitFollowFrames = 0; BWAPI::Unit m_observerFollowingUnit = nullptr; public: AutoObserver(); void onFrame(); }; } ================================================ FILE: UAlbertaBot/Source/BOSSManager.cpp ================================================ #include "Common.h" #include "BOSSManager.h" #include "UnitUtil.h" #include "Global.h" #include "ProductionManager.h" #include "WorkerManager.h" #include "StrategyManager.h" #include "Logger.h" using namespace UAlbertaBot; // constructor BOSSManager::BOSSManager() { } void BOSSManager::reset() { m_previousSearchResults = BOSS::DFBB_BuildOrderSearchResults(); m_searchInProgress = false; m_previousBuildOrder.clear(); } // start a new search for a new goal void BOSSManager::startNewSearch(const std::vector & goalUnits) { size_t numWorkers = UnitUtil::GetAllUnitCount(BWAPI::Broodwar->self()->getRace().getWorker()); size_t numDepots = UnitUtil::GetAllUnitCount(BWAPI::Broodwar->self()->getRace().getResourceDepot()) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive); if (numWorkers == 0) { m_previousStatus = "\x08No Workers :("; return; } if (numDepots == 0) { m_previousStatus = "\x08No Depots :("; return; } // convert from UAlbertaBot's meta goal type to BOSS ActionType goal try { BOSS::BuildOrderSearchGoal goal = GetGoal(goalUnits); BOSS::GameState initialState(BWAPI::Broodwar, BWAPI::Broodwar->self(), Global::Production().buildingsQueued()); m_smartSearch = SearchPtr(new BOSS::DFBB_BuildOrderSmartSearch(initialState.getRace())); m_smartSearch->setGoal(GetGoal(goalUnits)); m_smartSearch->setState(initialState); m_searchInProgress = true; m_previousSearchStartFrame = BWAPI::Broodwar->getFrameCount(); m_totalPreviousSearchTime = 0; m_previousGoalUnits = goalUnits; } catch (const BOSS::BOSSException) { BWAPI::BroodwarPtr->printf("Exception in BOSS::GameState constructor, will try again next frame"); } } void BOSSManager::drawSearchInformation(int x, int y) { if (!Config::Debug::DrawBuildOrderSearchInfo) { return; } // draw the background int width = 155; int height = 80; BWAPI::Broodwar->drawBoxScreen(BWAPI::Position(x-5,y), BWAPI::Position(x+width, y+height), BWAPI::Colors::Black, true); x += 5; y+=3; BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y), "%cBuildOrderSearch:", '\x04'); y += 10; BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y), "%s", m_previousStatus.c_str()); for (size_t i(0); i < m_previousGoalUnits.size(); ++i) { if (m_previousGoalUnits[i].second > 0) { y += 10; BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x,y), "%d %s", m_previousGoalUnits[i].second, m_previousGoalUnits[i].first.getName().c_str()); } } BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+25), "Time (ms): %.3lf", m_totalPreviousSearchTime); BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+35), "Nodes: %d", m_savedSearchResults.nodesExpanded); BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x, y+45), "BO Size: %d", (int)m_savedSearchResults.buildOrder.size()); } void BOSSManager::drawStateInformation(int x, int y) { if (!Config::Debug::DrawBOSSStateInfo) { return; } BOSS::GameState currentState(BWAPI::Broodwar, BWAPI::Broodwar->self(), Global::Production().buildingsQueued()); BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x-100, y+30), "\x04%s", currentState.getBuildingData().toString().c_str()); BWAPI::Broodwar->drawTextScreen(BWAPI::Position(x+150, y), "\x04%s", currentState.toString().c_str()); } // tell the search to keep going for however long we have this frame void BOSSManager::update(double timeLimit) { PROFILE_FUNCTION(); // if there's a search in progress, resume it if (isSearchInProgress()) { m_previousStatus.clear(); // give the search at least 5ms to search this frame double realTimeLimit = timeLimit < 0 ? 5 : timeLimit; m_smartSearch->setTimeLimit((int)realTimeLimit); bool caughtException = false; try { // call the search to continue searching // this will resume a search in progress or start a new search if not yet started m_smartSearch->search(); } // catch any errors that might happen in the search catch (const BOSS::BOSSException & exception) { UAB_ASSERT_WARNING(false, "BOSS SmartSearch Exception: %s", exception.what()); BWAPI::Broodwar->drawTextScreen(0, 0, "Previous search didn't find a solution, resorting to Naive Build Order"); m_previousStatus = "BOSSExeption"; caughtException = true; } m_totalPreviousSearchTime += m_smartSearch->getResults().timeElapsed; // after the search finishes for this frame, check to see if we have a solution or if we hit the overall time limit bool searchTimeOut = (BWAPI::Broodwar->getFrameCount() > (m_previousSearchStartFrame + Config::Macro::BOSSFrameLimit)); bool previousSearchComplete = searchTimeOut || m_smartSearch->getResults().solved || caughtException; if (previousSearchComplete) { bool solved = m_smartSearch->getResults().solved && m_smartSearch->getResults().solutionFound; // if we've found a solution, let us know if (m_smartSearch->getResults().solved && Config::Debug::DrawBuildOrderSearchInfo) { //BWAPI::Broodwar->printf("Build order SOLVED in %d nodes", (int)_smartSearch->getResults().nodesExpanded); } if (m_smartSearch->getResults().solved) { if (m_smartSearch->getResults().solutionFound) { m_previousStatus = std::string("\x07") + "BOSS Solve Solution\n"; } else { m_previousStatus = std::string("\x03") + "BOSS Solve NoSolution\n"; } } // re-set all the search information to get read for the next search m_searchInProgress = false; m_previousSearchFinishFrame = BWAPI::Broodwar->getFrameCount(); m_previousSearchResults = m_smartSearch->getResults(); m_savedSearchResults = m_previousSearchResults; m_previousBuildOrder = m_previousSearchResults.buildOrder; if (solved && m_previousBuildOrder.size() == 0) { m_previousStatus = std::string("\x07") + "BOSS Trivial Solve\n"; } // if our search resulted in a build order of size 0 then something failed if (!solved && m_previousBuildOrder.size() == 0) { // log the debug information since this shouldn't happen if everything goes to plan /*std::stringstream ss; ss << _smartSearch->getParameters().toString() << "\n"; ss << "searchTimeOut: " << (searchTimeOut ? "true" : "false") << "\n"; ss << "caughtException: " << (caughtException ? "true" : "false") << "\n"; ss << "getResults().solved: " << (_smartSearch->getResults().solved ? "true" : "false") << "\n"; ss << "getResults().solutionFound: " << (_smartSearch->getResults().solutionFound ? "true" : "false") << "\n"; ss << "nodes: " << _savedSearchResults.nodesExpanded << "\n"; ss << "time: " << _savedSearchResults.timeElapsed << "\n"; Logger::LogOverwriteToFile("bwapi-data/AI/LastBadBuildOrder.txt", ss.str());*/ // so try another naive build order search as a last resort BOSS::NaiveBuildOrderSearch nbos(m_smartSearch->getParameters().initialState, m_smartSearch->getParameters().goal); try { if (searchTimeOut) { m_previousStatus = std::string("\x02") + "BOSS Timeout\n"; } if (caughtException) { m_previousStatus = std::string("\x02") + "BOSS Exception\n"; } m_previousBuildOrder = nbos.solve(); m_previousStatus += "\x03NBOS Solution"; return; } // and if that search doesn't work then we're out of luck, no build orders forus catch (const BOSS::BOSSException & exception) { UAB_ASSERT_WARNING(false, "BOSS Timeout Naive Search Exception: %s", exception.what()); m_previousStatus += "\x08Naive Exception"; if (Config::Debug::DrawBuildOrderSearchInfo) { BWAPI::Broodwar->drawTextScreen(0, 20, "No legal BuildOrder found, returning empty Build Order"); } m_previousBuildOrder = BOSS::BuildOrder(); return; } } } } } void BOSSManager::logBadSearch() { std::string s = m_smartSearch->getParameters().toString(); } BOSS::BuildOrderSearchGoal BOSSManager::GetGoal(const std::vector & goalUnits) { BOSS::BuildOrderSearchGoal goal(BOSS::Races::GetRaceID(BWAPI::Broodwar->self()->getRace())); for (size_t i=0; iself()->getRace(); if (r == BWAPI::Races::Protoss) { return BOSS::Races::Protoss; } else if (r == BWAPI::Races::Terran) { return BOSS::Races::Terran; } else if (r == BWAPI::Races::Zerg) { return BOSS::Races::Zerg; } else { BOSS_ASSERT(false, "We should have had a valid race from BWAPI"); return BOSS::Races::None; } } bool BOSSManager::isSearchInProgress() { return m_searchInProgress; } // converts SearchResults.buildOrder vector into vector of MetaType std::vector BOSSManager::GetMetaVector(const BOSS::BuildOrder & buildOrder) { std::vector metaVector; for (size_t i(0); iself()->getRace(), GetMetaVector(m_previousBuildOrder)); } BOSS::ActionType BOSSManager::GetActionType(const MetaType & t) { // set the appropriate type if (t.isUnit()) { return BOSS::ActionType(t.getUnitType()); } else if (t.isUpgrade()) { return BOSS::ActionType(t.getUpgradeType()); } else if (t.isTech()) { return BOSS::ActionType(t.getTechType()); } else { UAB_ASSERT(false, "Should have found a valid type here"); } return BOSS::ActionType(); } MetaType BOSSManager::GetMetaType(const BOSS::ActionType & a) { // set the appropriate type if (a.isUnit()) { return MetaType(a.getUnitType()); } else if (a.isUpgrade()) { return MetaType(a.getUpgradeType()); } else if (a.isTech()) { return MetaType(a.getTechType()); } else { UAB_ASSERT(false, "Should have found a valid type here"); } return MetaType(); } ================================================ FILE: UAlbertaBot/Source/BOSSManager.h ================================================ #pragma once #include "Common.h" #include "../../BOSS/source/BOSS.h" #include #include "MetaType.h" namespace UAlbertaBot { typedef std::shared_ptr SearchPtr; class BuildOrder; class BOSSManager { friend class Global; int m_previousSearchStartFrame = 0; int m_savedSearchStartFrame = 0; int m_previousSearchFinishFrame = 0; bool m_searchInProgress = false; double m_totalPreviousSearchTime = 0; std::string m_previousStatus = "No Searches"; SearchPtr m_smartSearch; std::vector m_previousGoalUnits; BOSS::DFBB_BuildOrderSearchResults m_previousSearchResults; BOSS::DFBB_BuildOrderSearchResults m_savedSearchResults; BOSS::BuildOrder m_previousBuildOrder; BOSS::GameState getStartState(); const BOSS::RaceID getRace() const; void logBadSearch(); public: BOSSManager(); void update(double timeLimit); void reset(); void startNewSearch(const std::vector & goalUnits); void drawSearchInformation(int x, int y); void drawStateInformation(int x, int y); bool isSearchInProgress(); BuildOrder getBuildOrder(); static BOSS::BuildOrderSearchGoal GetGoal(const std::vector & goalUnits); static std::vector GetMetaVector(const BOSS::BuildOrder & buildOrder); static BOSS::ActionType GetActionType(const MetaType & t); static MetaType GetMetaType(const BOSS::ActionType & a); }; } ================================================ FILE: UAlbertaBot/Source/BaseLocation.cpp ================================================ #include "Common.h" #include "BaseLocation.h" #include "MapTools.h" #include "Global.h" #include #include using namespace UAlbertaBot; const int NearBaseLocationTileDistance = 20; BaseLocation::BaseLocation(int baseID, const std::vector & resources) : m_baseID(baseID) { PROFILE_FUNCTION(); m_isPlayerStartLocation[BWAPI::Broodwar->self()] = false; m_isPlayerStartLocation[BWAPI::Broodwar->enemy()] = false; m_isPlayerOccupying[BWAPI::Broodwar->self()] = false; m_isPlayerOccupying[BWAPI::Broodwar->enemy()] = false; int resourceCenterX = 0; int resourceCenterY = 0; // add each of the resources to its corresponding container for (auto & resource : resources) { if (resource->getType().isMineralField()) { m_minerals.push_back(resource); m_mineralPositions.push_back(resource->getPosition()); // add the position of the minerals to the center resourceCenterX += resource->getPosition().x; resourceCenterY += resource->getPosition().y; } else { m_geysers.push_back(resource); m_geyserPositions.push_back(resource->getPosition()); // pull the resource center toward the geyser if it exists resourceCenterX += resource->getPosition().x; resourceCenterY += resource->getPosition().y; } // set the limits of the base location bounding box const int resWidth = 32; const int resHeight = 32; m_left = std::min(m_left, resource->getPosition().x - resWidth); m_right = std::max(m_right, resource->getPosition().x + resWidth); m_top = std::max(m_top, resource->getPosition().y + resHeight); m_bottom = std::min(m_bottom, resource->getPosition().y - resHeight); } // calculate the center of the resources const size_t numResources = m_minerals.size() + m_geysers.size(); m_centerOfResources = BWAPI::Position(m_left + (m_right-m_left)/2, m_top + (m_bottom-m_top)/2); // compute this BaseLocation's DistanceMap, which will compute the ground distance // from the center of its recourses to every other tile on the map m_distanceMap = DistanceMap(); m_distanceMap.computeDistanceMap(BWAPI::TilePosition(m_centerOfResources)); // check to see if this is a start location for the map for (auto & startTilePos : BWAPI::Broodwar->getStartLocations()) { auto groundDistance = getGroundDistance(startTilePos); if (containsPosition(BWAPI::Position(startTilePos))) { m_isStartLocation = true; m_depotPosition = BWAPI::TilePosition(startTilePos); m_startPosition = startTilePos; break; } } // if this base location position is near our own resource depot, it's our start location for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if (unit->getPlayer() == BWAPI::Broodwar->self() && unit->getType().isResourceDepot()) { if (containsPosition(unit->getPosition())) { m_isPlayerStartLocation[BWAPI::Broodwar->self()] = true; m_isStartLocation = true; m_isPlayerOccupying[BWAPI::Broodwar->self()] = true; break; } } } // if it's not a start location, we need to calculate the depot position if (!isStartLocation()) { const BWAPI::UnitType depot = BWAPI::Broodwar->self()->getRace().getResourceDepot(); const int offsetX = 1; const int offsetY = 1; // the position of the depot will be the closest spot we can build one from the resource center for (auto & tile : getClosestTiles()) { // the build position will be up-left of where this tile is // this means we are positioning the center of the resouce depot const BWAPI::TilePosition buildTile(tile.x - offsetX, tile.y - offsetY); if (BWAPI::Broodwar->canBuildHere(buildTile, depot)) { m_depotPosition = buildTile; break; } } } } // TODO: calculate the actual depot position const BWAPI::TilePosition & BaseLocation::getDepotPosition() const { return m_depotPosition; } void BaseLocation::setPlayerOccupying(BWAPI::Player player, bool occupying) { m_isPlayerOccupying[player] = occupying; // if this base is a start location that's occupied by the enemy, it's that enemy's start location if (occupying && player == BWAPI::Broodwar->enemy() && isStartLocation() && m_isPlayerStartLocation[player] == false) { m_isPlayerStartLocation[player] = true; } } bool BaseLocation::isInResourceBox(int tileX, int tileY) const { const int px = tileX * 32; const int py = tileY * 32; return px >= m_left && px < m_right && py < m_top && py >= m_bottom; } bool BaseLocation::isOccupiedByPlayer(BWAPI::Player player) const { return m_isPlayerOccupying.at(player); } bool BaseLocation::isExplored() const { return BWAPI::Broodwar->isExplored(BWAPI::TilePosition(m_centerOfResources)); } bool BaseLocation::isPlayerStartLocation(BWAPI::Player player) const { return m_isPlayerStartLocation.at(player); } bool BaseLocation::isConnected(const BWAPI::Position& pos) const { return getGroundDistance(pos) >= 0; } bool BaseLocation::containsPosition(const BWAPI::Position & pos) const { if (!pos.isValid() || (pos.x == 0 && pos.y == 0) || !isConnected(pos)) { return false; } return (getGroundDistance(pos) < NearBaseLocationTileDistance); } const std::vector & BaseLocation::getGeysers() const { return m_geysers; } const std::vector & BaseLocation::getMinerals() const { return m_minerals; } const BWAPI::Position & BaseLocation::getPosition() const { return m_centerOfResources; } int BaseLocation::getGroundDistance(const BWAPI::Position & pos) const { return m_distanceMap.getDistance(pos); } int BaseLocation::getGroundDistance(const BWAPI::TilePosition & pos) const { return m_distanceMap.getDistance(pos); } bool BaseLocation::isStartLocation() const { return m_isStartLocation; } const std::vector & BaseLocation::getClosestTiles() const { return m_distanceMap.getSortedTiles(); } void BaseLocation::draw() { int radius = 16; BWAPI::Broodwar->drawCircleMap(m_centerOfResources, 16, BWAPI::Color(255, 255, 0), true); if (m_startPosition.x != 0) { BWAPI::Broodwar->drawLineMap(m_centerOfResources, BWAPI::Position(m_startPosition), BWAPI::Colors::Red); } std::stringstream ss; ss << "BaseLocation: " << m_baseID << "\n"; ss << "Start Loc: " << (isStartLocation() ? "true" : "false") << "\n"; ss << "Minerals: " << m_mineralPositions.size() << "\n"; ss << "Geysers: " << m_geyserPositions.size() << "\n"; ss << "Occupied By: "; if (isOccupiedByPlayer(BWAPI::Broodwar->self())) { ss << "Self "; } if (isOccupiedByPlayer(BWAPI::Broodwar->enemy())) { ss << "Enemy "; } BWAPI::Broodwar->drawTextMap(BWAPI::Position(m_left, m_top + 3), ss.str().c_str()); BWAPI::Broodwar->drawTextMap(BWAPI::Position(m_left, m_bottom), ss.str().c_str()); // draw the base bounding box BWAPI::Broodwar->drawLineMap(m_left, m_top, m_right, m_top, BWAPI::Colors::White); BWAPI::Broodwar->drawLineMap(m_right, m_top, m_right, m_bottom, BWAPI::Colors::White); BWAPI::Broodwar->drawLineMap(m_right, m_bottom, m_left, m_bottom, BWAPI::Colors::White); BWAPI::Broodwar->drawLineMap(m_left, m_bottom, m_left, m_top, BWAPI::Colors::White); for (auto & mineralPos : m_mineralPositions) { const BWAPI::TilePosition mineralTile(mineralPos); Global::Map().drawTile(mineralTile.x, mineralTile.y, BWAPI::Color(0, 255, 255)); Global::Map().drawTile(mineralTile.x-1, mineralTile.y, BWAPI::Color(0, 255, 255)); } for (auto & geyserPos : m_geyserPositions) { const BWAPI::TilePosition geyserTile(geyserPos); Global::Map().drawTile(geyserTile.x, geyserTile.y, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x+1, geyserTile.y, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x-1, geyserTile.y, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x-2, geyserTile.y, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x, geyserTile.y-1, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x+1, geyserTile.y-1, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x-1, geyserTile.y-1, BWAPI::Color(0, 255, 0)); Global::Map().drawTile(geyserTile.x-2, geyserTile.y-1, BWAPI::Color(0, 255, 0)); BWAPI::Broodwar->drawCircleMap(geyserPos, radius, BWAPI::Color(0, 255, 0), true); } if (m_isStartLocation) { BWAPI::Broodwar->drawCircleMap(BWAPI::Position(m_depotPosition), radius, BWAPI::Color(255, 0, 0)); } BWAPI::Broodwar->drawBoxMap(m_depotPosition.x, m_depotPosition.y, m_depotPosition.x+32, m_depotPosition.y+32, BWAPI::Color(0, 0, 255)); //m_distanceMap.draw(); } bool BaseLocation::isMineralOnly() const { return getGeysers().empty(); } ================================================ FILE: UAlbertaBot/Source/BaseLocation.h ================================================ #pragma once #include "DistanceMap.h" #include #include namespace UAlbertaBot { class BaseLocation { int m_baseID = 0; int m_left = std::numeric_limits::max(); int m_right = std::numeric_limits::lowest(); int m_top = std::numeric_limits::lowest(); int m_bottom = std::numeric_limits::max(); bool m_isStartLocation = false; BWAPI::TilePosition m_startPosition; DistanceMap m_distanceMap; BWAPI::TilePosition m_depotPosition; BWAPI::Position m_centerOfResources; std::vector m_geysers; std::vector m_minerals; std::vector m_mineralPositions; std::vector m_geyserPositions; std::map m_isPlayerOccupying; std::map m_isPlayerStartLocation; public: BaseLocation(int baseID, const std::vector& resources); bool isConnected(const BWAPI::Position& pos) const; int getGroundDistance(const BWAPI::Position& pos) const; int getGroundDistance(const BWAPI::TilePosition& pos) const; bool isStartLocation() const; bool isPlayerStartLocation(BWAPI::Player player) const; bool isMineralOnly() const; bool containsPosition(const BWAPI::Position& pos) const; const BWAPI::TilePosition& getDepotPosition() const; const BWAPI::Position& getPosition() const; const std::vector& getGeysers() const; const std::vector& getMinerals() const; bool isOccupiedByPlayer(BWAPI::Player player) const; bool isExplored() const; bool isInResourceBox(int x, int y) const; void setPlayerOccupying(BWAPI::Player player, bool occupying); const std::vector& getClosestTiles() const; void draw(); }; } ================================================ FILE: UAlbertaBot/Source/BaseLocationManager.cpp ================================================ #include "Common.h" #include "BaseLocationManager.h" #include "InformationManager.h" #include "MapTools.h" #include "Global.h" #include "UnitData.h" using namespace UAlbertaBot; BaseLocationManager::BaseLocationManager() { onStart(); } BWAPI::Position BaseLocationManager::calcCenter(const std::vector & units) { if (units.empty()) { return BWAPI::Position(0, 0); } int cx = 0; int cy = 0; for (auto & unit : units) { cx += unit->getPosition().x; cy += unit->getPosition().y; } return BWAPI::Position(cx / units.size(), cy / units.size()); } void BaseLocationManager::onStart() { PROFILE_FUNCTION(); m_tileBaseLocations = std::vector>(BWAPI::Broodwar->mapWidth(), std::vector(BWAPI::Broodwar->mapHeight(), nullptr)); m_playerStartingBaseLocations[BWAPI::Broodwar->self()] = nullptr; m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = nullptr; // Use StarDraft to find the borders of the bases on the map m_baseBorders = BaseBorderFinder(Global::Map().getStarDraftMap()); for (size_t baseID = 0; baseID < m_baseBorders.getBaseBorders().size(); baseID++) { const auto & border = m_baseBorders.getBaseBorders()[baseID]; // fill a vector with all the resource units in the border std::vector resources; // for each static unit on the map for (auto unit : BWAPI::Broodwar->getStaticNeutralUnits()) { // if it's a resource if (unit->getType().isMineralField() || unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser) { BWAPI::TilePosition tile(unit->getPosition()); // if it's inside the border, add it to the vector if (border.contains(tile.x, tile.y)) { resources.push_back(unit); } } } // add a baselocation containing these resources m_baseLocationData.push_back(BaseLocation(baseID, resources)); } // construct the vectors of base location pointers, this is safe since they will never change for (auto & baseLocation : m_baseLocationData) { m_baseLocationPtrs.push_back(&baseLocation); // if it's a start location, add it to the start locations if (baseLocation.isStartLocation()) { m_startingBaseLocations.push_back(&baseLocation); } // if it's our starting location, set the pointer if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->self())) { m_playerStartingBaseLocations[BWAPI::Broodwar->self()] = &baseLocation; } if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->enemy())) { m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = &baseLocation; } } // construct the map of tile positions to base locations for (int x=0; x < BWAPI::Broodwar->mapWidth(); ++x) { for (int y = 0; y < BWAPI::Broodwar->mapHeight(); ++y) { for (auto & baseLocation : m_baseLocationData) { BWAPI::Position pos(BWAPI::TilePosition(x, y)); if (baseLocation.containsPosition(pos)) { m_tileBaseLocations[x][y] = &baseLocation; break; } } } } // construct the sets of occupied base locations m_occupiedBaseLocations[BWAPI::Broodwar->self()] = std::set(); m_occupiedBaseLocations[BWAPI::Broodwar->enemy()] = std::set(); } void BaseLocationManager::onFrame() { PROFILE_FUNCTION(); drawBaseLocations(); // reset the player occupation information for each location for (auto & baseLocation : m_baseLocationData) { baseLocation.setPlayerOccupying(BWAPI::Broodwar->self(), false); baseLocation.setPlayerOccupying(BWAPI::Broodwar->self(), false); } // for each unit on the map, update which base location it may be occupying for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { // we only care about buildings on the ground if (!unit->getType().isBuilding() || unit->isFlying()) { continue; } BaseLocation * baseLocation = getBaseLocation(unit->getPosition()); if (baseLocation != nullptr) { baseLocation->setPlayerOccupying(unit->getPlayer(), true); } } // update enemy base occupations for (const auto & kv : Global::Info().getUnitInfo(BWAPI::Broodwar->enemy())) { const UnitInfo & ui = kv.second; if (ui.type.isBuilding()) { continue; } BaseLocation * baseLocation = getBaseLocation(ui.lastPosition); if (baseLocation != nullptr) { baseLocation->setPlayerOccupying(BWAPI::Broodwar->enemy(), true); } } // update the starting locations of the enemy player // this will happen one of two ways: // 1. we've seen the enemy base directly, so the baselocation will know if (m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] == nullptr) { for (auto & baseLocation : m_baseLocationData) { if (baseLocation.isPlayerStartLocation(BWAPI::Broodwar->enemy())) { m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = &baseLocation; } } } // 2. we've explored every other start location and haven't seen the enemy yet if (m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] == nullptr) { const int numStartLocations = (int)getStartingBaseLocations().size(); int numExploredLocations = 0; BaseLocation * unexplored = nullptr; for (auto & baseLocation : m_baseLocationData) { if (!baseLocation.isStartLocation()) { continue; } if (baseLocation.isExplored()) { numExploredLocations++; } else { unexplored = &baseLocation; } } // if we have explored all but one location, then the unexplored one is the enemy start location if (numExploredLocations == numStartLocations - 1 && unexplored != nullptr) { m_playerStartingBaseLocations[BWAPI::Broodwar->enemy()] = unexplored; unexplored->setPlayerOccupying(BWAPI::Broodwar->enemy(), true); } } // update the occupied base locations for each player m_occupiedBaseLocations[BWAPI::Broodwar->self()] = std::set(); m_occupiedBaseLocations[BWAPI::Broodwar->enemy()] = std::set(); for (auto & baseLocation : m_baseLocationData) { if (baseLocation.isOccupiedByPlayer(BWAPI::Broodwar->self())) { m_occupiedBaseLocations[BWAPI::Broodwar->self()].insert(&baseLocation); } if (baseLocation.isOccupiedByPlayer(BWAPI::Broodwar->enemy())) { m_occupiedBaseLocations[BWAPI::Broodwar->enemy()].insert(&baseLocation); } } // sanity check: make sure we have as many starting locations as BWAPI says if (getStartingBaseLocations().size() != BWAPI::Broodwar->getStartLocations().size()) { std::cout << "\nWARNING: BaseLocationManager start location mismatch: " << BWAPI::Broodwar->mapFileName() << "\n"; std::cout << " BaseLocationManager found " << getStartingBaseLocations().size() << " starting locations\n"; std::cout << " BWAPI says that there are " << BWAPI::Broodwar->getStartLocations().size() << " starting locations\n\n"; for (auto tp : BWAPI::Broodwar->getStartLocations()) { BWAPI::Broodwar->drawCircleMap(BWAPI::Position(tp), 64, BWAPI::Colors::Red, true); } } } BaseLocation * BaseLocationManager::getBaseLocation(const BWAPI::Position & pos) const { if (!pos.isValid()) { return nullptr; } return m_tileBaseLocations[pos.x / 32][pos.y / 32]; } void BaseLocationManager::drawBaseLocations() { for (auto & baseLocation : m_baseLocationData) { baseLocation.draw(); } // draw a purple sphere at the next expansion location //BWAPI::TilePosition nextExpansionPosition = getNextExpansion(BWAPI::Broodwar->self()); //BWAPI::Broodwar->drawCircleMap(BWAPI::Position(nextExpansionPosition), 32, BWAPI::Color(255, 0, 255), true); //BWAPI::Broodwar->drawTextMap(BWAPI::Position(nextExpansionPosition), "Next Expansion Location", BWAPI::Color(255, 0, 255)); } const std::vector & BaseLocationManager::getBaseLocations() const { return m_baseLocationPtrs; } const std::vector & BaseLocationManager::getStartingBaseLocations() const { return m_startingBaseLocations; } const BaseLocation * BaseLocationManager::getPlayerStartingBaseLocation(BWAPI::Player player) const { return m_playerStartingBaseLocations.at(player); } const std::set & BaseLocationManager::getOccupiedBaseLocations(BWAPI::Player player) const { return m_occupiedBaseLocations.at(player); } BWAPI::TilePosition BaseLocationManager::getNextExpansion(BWAPI::Player player) const { PROFILE_FUNCTION(); const BaseLocation * homeBase = getPlayerStartingBaseLocation(player); const BaseLocation * closestBase = nullptr; int minDistance = std::numeric_limits::max(); BWAPI::TilePosition homeTile(homeBase->getPosition()); for (auto & base : getBaseLocations()) { // skip mineral only and starting locations (TODO: fix this) if (base->isMineralOnly() || base->isStartLocation()) { continue; } // get the tile position of the base BWAPI::TilePosition tile = base->getDepotPosition(); bool buildingInTheWay = false; // TODO: check if there are any units on the tile if (buildingInTheWay) { continue; } // the base's distance from our main nexus int distanceFromHome = homeBase->getGroundDistance(tile); // if it is not connected, continue if (distanceFromHome < 0) { continue; } if (!closestBase || distanceFromHome < minDistance) { closestBase = base; minDistance = distanceFromHome; } } return closestBase ? closestBase->getDepotPosition() : BWAPI::TilePosition(0, 0); } ================================================ FILE: UAlbertaBot/Source/BaseLocationManager.h ================================================ #pragma once #include "BaseLocation.h" #include "stardraft/BaseBorderFinder.hpp" namespace UAlbertaBot { class BaseLocationManager { friend class Global; BaseBorderFinder m_baseBorders; std::vector m_baseLocationData; std::vector m_baseLocationPtrs; std::vector m_startingBaseLocations; std::map m_playerStartingBaseLocations; std::map> m_occupiedBaseLocations; std::vector> m_tileBaseLocations; BaseLocation * getBaseLocation(const BWAPI::Position & pos) const; BaseLocationManager(); public: void onStart(); void onFrame(); void drawBaseLocations(); BWAPI::Position calcCenter(const std::vector & units); const std::vector & getBaseLocations() const; const std::vector & getStartingBaseLocations() const; const std::set & getOccupiedBaseLocations(BWAPI::Player player) const; const BaseLocation * getPlayerStartingBaseLocation(BWAPI::Player player) const; BWAPI::TilePosition getNextExpansion(BWAPI::Player player) const; }; } ================================================ FILE: UAlbertaBot/Source/BuildOrder.cpp ================================================ #include "BuildOrder.h" using namespace UAlbertaBot; BuildOrder::BuildOrder() { } BuildOrder::BuildOrder(const BWAPI::Race & race) : m_race(race) { } BuildOrder::BuildOrder(const BWAPI::Race & race, const std::vector & metaVector) : m_race(race) , m_buildOrder(metaVector) { } void BuildOrder::add(const MetaType & t) { UAB_ASSERT(t.getRace() == getRace(), "Trying to add difference Race metatype to build order"); m_buildOrder.push_back(t); } const BWAPI::Race & BuildOrder::getRace() const { return m_race; } const size_t BuildOrder::size() const { return m_buildOrder.size(); } const MetaType & BuildOrder::operator [] (const size_t & index) const { return m_buildOrder[index]; } MetaType & BuildOrder::operator [] (const size_t & index) { return m_buildOrder[index]; } ================================================ FILE: UAlbertaBot/Source/BuildOrder.h ================================================ #pragma once #include "Common.h" #include "MetaType.h" namespace UAlbertaBot { class BuildOrder { BWAPI::Race m_race = BWAPI::Races::None; std::vector m_buildOrder; public: BuildOrder(); BuildOrder(const BWAPI::Race & race); BuildOrder(const BWAPI::Race & race, const std::vector & metaVector); void add(const MetaType & t); const size_t size() const; const BWAPI::Race & getRace() const; const MetaType & operator [] (const size_t & index) const; MetaType & operator [] (const size_t & index); }; } ================================================ FILE: UAlbertaBot/Source/BuildOrderQueue.cpp ================================================ #include "BuildOrderQueue.h" using namespace UAlbertaBot; BuildOrderQueue::BuildOrderQueue() { } void BuildOrderQueue::clearAll() { // clear the queue queue.clear(); // reset the priorities highestPriority = 0; lowestPriority = 0; } BuildOrderItem & BuildOrderQueue::getHighestPriorityItem() { // reset the number of skipped items to zero numSkippedItems = 0; // the queue will be sorted with the highest priority at the back return queue.back(); } BuildOrderItem & BuildOrderQueue::getNextHighestPriorityItem() { assert(queue.size() - 1 - numSkippedItems >= 0); // the queue will be sorted with the highest priority at the back return queue[queue.size() - 1 - numSkippedItems]; } void BuildOrderQueue::skipItem() { // make sure we can skip assert(canSkipItem()); // skip it numSkippedItems++; } bool BuildOrderQueue::canSkipItem() { // does the queue have more elements bool bigEnough = queue.size() > (size_t)(1 + numSkippedItems); if (!bigEnough) { return false; } // is the current highest priority item not blocking a skip bool highestNotBlocking = !queue[queue.size() - 1 - numSkippedItems].blocking; // this tells us if we can skip return highestNotBlocking; } void BuildOrderQueue::queueItem(BuildOrderItem b) { // if the queue is empty, set the highest and lowest priorities if (queue.empty()) { highestPriority = b.priority; lowestPriority = b.priority; } // push the item into the queue if (b.priority <= lowestPriority) { queue.push_front(b); } else { queue.push_back(b); } // if the item is somewhere in the middle, we have to sort again if ((queue.size() > 1) && (b.priority < highestPriority) && (b.priority > lowestPriority)) { // sort the list in ascending order, putting highest priority at the top std::sort(queue.begin(), queue.end()); } // update the highest or lowest if it is beaten highestPriority = (b.priority > highestPriority) ? b.priority : highestPriority; lowestPriority = (b.priority < lowestPriority) ? b.priority : lowestPriority; } void BuildOrderQueue::queueAsHighestPriority(MetaType m, bool blocking, bool gasSteal) { // the new priority will be higher int newPriority = highestPriority + defaultPrioritySpacing; // queue the item queueItem(BuildOrderItem(m, newPriority, blocking, gasSteal)); } void BuildOrderQueue::queueAsLowestPriority(MetaType m, bool blocking) { // the new priority will be higher int newPriority = lowestPriority - defaultPrioritySpacing; // queue the item queueItem(BuildOrderItem(m, newPriority, blocking)); } void BuildOrderQueue::removeHighestPriorityItem() { // remove the back element of the vector queue.pop_back(); // if the list is not empty, set the highest accordingly highestPriority = queue.empty() ? 0 : queue.back().priority; lowestPriority = queue.empty() ? 0 : lowestPriority; } void BuildOrderQueue::removeCurrentHighestPriorityItem() { // remove the back element of the vector queue.erase(queue.begin() + queue.size() - 1 - numSkippedItems); //assert((int)(queue.size()) < size); // if the list is not empty, set the highest accordingly highestPriority = queue.empty() ? 0 : queue.back().priority; lowestPriority = queue.empty() ? 0 : lowestPriority; } size_t BuildOrderQueue::size() { return queue.size(); } bool BuildOrderQueue::isEmpty() { return (queue.size() == 0); } BuildOrderItem BuildOrderQueue::operator [] (int i) { return queue[i]; } void BuildOrderQueue::drawQueueInformation(int x, int y) { //x = x + 25; if (!Config::Debug::DrawProductionInfo) { return; } std::string prefix = "\x04"; size_t reps = queue.size() < 12 ? queue.size() : 12; // for each unit in the queue for (size_t i(0); i 0) { prefix = "\x03"; } else if (type.getUnitType().isRefinery()) { prefix = "\x1E"; } else if (type.isBuilding()) { prefix = "\x11"; } else if (type.getUnitType().groundWeapon() != BWAPI::WeaponTypes::None || type.getUnitType().airWeapon() != BWAPI::WeaponTypes::None) { prefix = "\x06"; } } BWAPI::Broodwar->drawTextScreen(x, y+(i*10), " %s%s", prefix.c_str(), type.getName().c_str()); } } ================================================ FILE: UAlbertaBot/Source/BuildOrderQueue.h ================================================ #pragma once #include "Common.h" #include "MetaType.h" namespace UAlbertaBot { struct BuildOrderItem { MetaType metaType; // the thing we want to 'build' int priority = 0; // the priority at which to place it in the queue bool blocking = false; // whether or not we block further items bool isGasSteal = false; BuildOrderItem(MetaType m, int p, bool b, bool gasSteal = false) : metaType(m) , priority(p) , blocking(b) , isGasSteal(gasSteal) { } bool operator<(const BuildOrderItem &x) const { return priority < x.priority; } }; class BuildOrderQueue { std::deque queue; int lowestPriority = 0; int highestPriority = 0; int defaultPrioritySpacing = 10; int numSkippedItems = 0; public: BuildOrderQueue(); void clearAll(); // clears the entire build order queue void skipItem(); // increments skippedItems void queueAsHighestPriority(MetaType m, bool blocking, bool gasSteal = false); // queues something at the highest priority void queueAsLowestPriority(MetaType m, bool blocking); // queues something at the lowest priority void queueItem(BuildOrderItem b); // queues something with a given priority void removeHighestPriorityItem(); // removes the highest priority item void removeCurrentHighestPriorityItem(); int getHighestPriorityValue(); // returns the highest priority value int getLowestPriorityValue(); // returns the lowest priority value size_t size(); // returns the size of the queue bool isEmpty(); void removeAll(MetaType m); // removes all matching meta types from queue BuildOrderItem & getHighestPriorityItem(); // returns the highest priority item BuildOrderItem & getNextHighestPriorityItem(); // returns the highest priority item bool canSkipItem(); bool hasNextHighestPriorityItem(); // returns the highest priority item void drawQueueInformation(int x, int y); // overload the bracket operator for ease of use BuildOrderItem operator [] (int i); }; } ================================================ FILE: UAlbertaBot/Source/BuildingData.cpp ================================================ #include "BuildingData.h" using namespace UAlbertaBot; BuildingData::BuildingData() { } void BuildingData::removeBuilding(const Building & b) { auto & building = std::find(m_buildings.begin(), m_buildings.end(), b); if (building != m_buildings.end()) { m_buildings.erase(building); } } std::vector & BuildingData::getBuildings() { return m_buildings; } void BuildingData::addBuilding(const Building & b) { m_buildings.push_back(b); } bool BuildingData::isBeingBuilt(BWAPI::UnitType type) { for (auto & b : m_buildings) { if (b.type == type) { return true; } } return false; } void BuildingData::removeBuildings(const std::vector & buildings) { for (const auto & b : buildings) { removeBuilding(b); } } ================================================ FILE: UAlbertaBot/Source/BuildingData.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { namespace BuildingStatus { enum { Unassigned = 0, Assigned = 1, UnderConstruction = 2, Size = 3 }; } class Building { public: BWAPI::TilePosition desiredPosition = {0, 0}; BWAPI::TilePosition finalPosition = BWAPI::TilePositions::None; BWAPI::Position position = {0, 0}; BWAPI::UnitType type = BWAPI::UnitTypes::Unknown; BWAPI::Unit buildingUnit = nullptr; BWAPI::Unit builderUnit = nullptr; size_t status = BuildingStatus::Unassigned; int lastOrderFrame = 0; bool isGasSteal = false; bool buildCommandGiven = false; bool underConstruction = false; Building() { } // constructor we use most often Building(BWAPI::UnitType t, BWAPI::TilePosition desired) : desiredPosition (desired) , type (t) { } // equals operator bool operator==(const Building & b) { // buildings are equal if their worker unit or building unit are equal return (b.buildingUnit == buildingUnit) || (b.builderUnit == builderUnit); } }; class BuildingData { std::vector m_buildings; public: BuildingData(); std::vector & getBuildings(); void addBuilding(const Building & b); void removeBuilding(const Building & b); void removeBuildings(const std::vector & buildings); bool isBeingBuilt(BWAPI::UnitType type); }; } ================================================ FILE: UAlbertaBot/Source/BuildingManager.cpp ================================================ #include "Common.h" #include "BuildingManager.h" #include "Micro.h" #include "ScoutManager.h" #include "BaseLocationManager.h" #include "Global.h" #include "BuildingData.h" #include "WorkerManager.h" #include "BuildingPlacerManager.h" using namespace UAlbertaBot; BuildingManager::BuildingManager() { } // gets called every frame from GameCommander void BuildingManager::update() { PROFILE_FUNCTION(); validateWorkersAndBuildings(); // check to see if assigned workers have died en route or while constructing assignWorkersToUnassignedBuildings(); // assign workers to the unassigned buildings and label them 'planned' constructAssignedBuildings(); // for each planned building, if the worker isn't constructing, send the command checkForStartedConstruction(); // check to see if any buildings have started construction and update data structures checkForDeadTerranBuilders(); // if we are terran and a building is under construction without a worker, assign a new one checkForCompletedBuildings(); // check to see if any buildings have completed and update data structures drawBuildingInformation(200,50); m_buildingPlacer.drawReservedTiles(); } bool BuildingManager::isBeingBuilt(BWAPI::UnitType type) { for (auto & b : m_buildings) { if (b.type == type) { return true; } } return false; } // STEP 1: DO BOOK KEEPING ON WORKERS WHICH MAY HAVE DIED void BuildingManager::validateWorkersAndBuildings() { PROFILE_FUNCTION(); // TODO: if a terran worker dies while constructing and its building // is under construction, place unit back into buildingsNeedingBuilders std::vector toRemove; // find any buildings which have become obsolete for (auto & b : m_buildings) { if (b.status != BuildingStatus::UnderConstruction) { continue; } if (b.buildingUnit == nullptr || !b.buildingUnit->getType().isBuilding() || b.buildingUnit->getHitPoints() <= 0) { toRemove.push_back(b); } } removeBuildings(toRemove); } // STEP 2: ASSIGN WORKERS TO BUILDINGS WITHOUT THEM void BuildingManager::assignWorkersToUnassignedBuildings() { PROFILE_FUNCTION(); // for each building that doesn't have a builder, assign one for (Building & b : m_buildings) { if (b.status != BuildingStatus::Unassigned) { continue; } if (m_debugMode) { BWAPI::Broodwar->printf("Assigning Worker To: %s",b.type.getName().c_str()); } // grab a worker unit from WorkerManager which is closest to this final position BWAPI::Unit workerToAssign = Global::Workers().getBuilder(b); if (workerToAssign) { //BWAPI::Broodwar->printf("VALID WORKER BEING ASSIGNED: %d", workerToAssign->getID()); // TODO: special case of terran building whose worker died mid construction // send the right click command to the buildingUnit to resume construction // skip the buildingsAssigned step and push it back into buildingsUnderConstruction b.builderUnit = workerToAssign; BWAPI::TilePosition testLocation = getBuildingLocation(b); if (!testLocation.isValid()) { continue; } b.finalPosition = testLocation; // reserve this building's space m_buildingPlacer.reserveTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight()); b.status = BuildingStatus::Assigned; } } } // STEP 3: ISSUE CONSTRUCTION ORDERS TO ASSIGN BUILDINGS AS NEEDED void BuildingManager::constructAssignedBuildings() { PROFILE_FUNCTION(); for (auto & b : m_buildings) { if (b.status != BuildingStatus::Assigned) { continue; } // if that worker is not currently constructing if (!b.builderUnit->isConstructing()) { // if we haven't explored the build position, go there if (!isBuildingPositionExplored(b)) { Micro::SmartMove(b.builderUnit,BWAPI::Position(b.finalPosition)); } // if this is not the first time we've sent this guy to build this // it must be the case that something was in the way of building else if (b.buildCommandGiven) { // tell worker manager the unit we had is not needed now, since we might not be able // to get a valid location soon enough Global::Workers().finishedWithWorker(b.builderUnit); // free the previous location in reserved m_buildingPlacer.freeTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight()); // nullify its current builder unit b.builderUnit = nullptr; // reset the build command given flag b.buildCommandGiven = false; // add the building back to be assigned b.status = BuildingStatus::Unassigned; } else { // issue the build order! b.builderUnit->build(b.type,b.finalPosition); // set the flag to true b.buildCommandGiven = true; } } } } // STEP 4: UPDATE DATA STRUCTURES FOR BUILDINGS STARTING CONSTRUCTION void BuildingManager::checkForStartedConstruction() { PROFILE_FUNCTION(); // for each building unit which is being constructed for (auto & buildingStarted : BWAPI::Broodwar->self()->getUnits()) { // filter out units which aren't buildings under construction if (!buildingStarted->getType().isBuilding() || !buildingStarted->isBeingConstructed()) { continue; } // check all our building status objects to see if we have a match and if we do, update it for (auto & b : m_buildings) { if (b.status != BuildingStatus::Assigned) { continue; } // check if the positions match if (b.finalPosition == buildingStarted->getTilePosition()) { // the resources should now be spent, so unreserve them m_reservedMinerals -= buildingStarted->getType().mineralPrice(); m_reservedGas -= buildingStarted->getType().gasPrice(); // flag it as started and set the buildingUnit b.underConstruction = true; b.buildingUnit = buildingStarted; // if we are zerg, the buildingUnit now becomes nullptr since it's destroyed if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) { b.builderUnit = nullptr; // if we are protoss, give the worker back to worker manager } else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss) { // if this was the gas steal unit then it's the scout worker so give it back to the scout manager if (b.isGasSteal) { Global::Scout().setWorkerScout(b.builderUnit); } // otherwise tell the worker manager we're finished with this unit else { Global::Workers().finishedWithWorker(b.builderUnit); } b.builderUnit = nullptr; } // put it in the under construction vector b.status = BuildingStatus::UnderConstruction; // free this space m_buildingPlacer.freeTiles(b.finalPosition,b.type.tileWidth(),b.type.tileHeight()); // only one building will match break; } } } } // STEP 5: IF WE ARE TERRAN, THIS MATTERS, SO: LOL void BuildingManager::checkForDeadTerranBuilders() {} // STEP 6: CHECK FOR COMPLETED BUILDINGS void BuildingManager::checkForCompletedBuildings() { PROFILE_FUNCTION(); std::vector toRemove; // for each of our buildings under construction for (auto & b : m_buildings) { if (b.status != BuildingStatus::UnderConstruction) { continue; } // if the unit has completed if (b.buildingUnit->isCompleted()) { // if we are terran, give the worker back to worker manager if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran) { if (b.isGasSteal) { Global::Scout().setWorkerScout(b.builderUnit); } // otherwise tell the worker manager we're finished with this unit else { Global::Workers().finishedWithWorker(b.builderUnit); } } // remove this unit from the under construction vector toRemove.push_back(b); } } removeBuildings(toRemove); } // COMPLETED bool BuildingManager::isEvolvedBuilding(BWAPI::UnitType type) { if (type == BWAPI::UnitTypes::Zerg_Sunken_Colony || type == BWAPI::UnitTypes::Zerg_Spore_Colony || type == BWAPI::UnitTypes::Zerg_Lair || type == BWAPI::UnitTypes::Zerg_Hive || type == BWAPI::UnitTypes::Zerg_Greater_Spire) { return true; } return false; } // add a new building to be constructed void BuildingManager::addBuildingTask(BWAPI::UnitType type, BWAPI::TilePosition desiredLocation, bool isGasSteal) { m_reservedMinerals += type.mineralPrice(); m_reservedGas += type.gasPrice(); Building b(type, desiredLocation); b.isGasSteal = isGasSteal; b.status = BuildingStatus::Unassigned; m_buildings.push_back(b); } bool BuildingManager::isBuildingPositionExplored(const Building & b) const { BWAPI::TilePosition tile = b.finalPosition; // for each tile where the building will be built for (int x=0; xisExplored(tile.x + x,tile.y + y)) { return false; } } } return true; } char BuildingManager::getBuildingWorkerCode(const Building & b) const { return b.builderUnit == nullptr ? 'X' : 'W'; } int BuildingManager::getReservedMinerals() { return m_reservedMinerals; } int BuildingManager::getReservedGas() { return m_reservedGas; } void BuildingManager::drawBuildingInformation(int x,int y) { if (!Config::Debug::DrawBuildingInfo) { return; } PROFILE_FUNCTION(); for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { BWAPI::Broodwar->drawTextMap(unit->getPosition().x,unit->getPosition().y+5,"\x07%d",unit->getID()); } BWAPI::Broodwar->drawTextScreen(x,y,"\x04 Building Information:"); BWAPI::Broodwar->drawTextScreen(x,y+20,"\x04 Name"); BWAPI::Broodwar->drawTextScreen(x+150,y+20,"\x04 State"); int yspace = 0; for (const auto & b : m_buildings) { if (b.status == BuildingStatus::Unassigned) { BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),"\x03 %s",b.type.getName().c_str()); BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),"\x03 Need %c",getBuildingWorkerCode(b)); } else if (b.status == BuildingStatus::Assigned) { BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),"\x03 %s %d",b.type.getName().c_str(),b.builderUnit->getID()); BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),"\x03 A %c (%d,%d)",getBuildingWorkerCode(b),b.finalPosition.x,b.finalPosition.y); int x1 = b.finalPosition.x*32; int y1 = b.finalPosition.y*32; int x2 = (b.finalPosition.x + b.type.tileWidth())*32; int y2 = (b.finalPosition.y + b.type.tileHeight())*32; BWAPI::Broodwar->drawLineMap(b.builderUnit->getPosition().x,b.builderUnit->getPosition().y,(x1+x2)/2,(y1+y2)/2,BWAPI::Colors::Orange); BWAPI::Broodwar->drawBoxMap(x1,y1,x2,y2,BWAPI::Colors::Red,false); } else if (b.status == BuildingStatus::UnderConstruction) { BWAPI::Broodwar->drawTextScreen(x,y+40+((yspace)*10),"\x03 %s %d",b.type.getName().c_str(),b.buildingUnit->getID()); BWAPI::Broodwar->drawTextScreen(x+150,y+40+((yspace++)*10),"\x03 Const %c",getBuildingWorkerCode(b)); } } } std::vector BuildingManager::buildingsQueued() { std::vector buildingsQueued; for (const auto & b : m_buildings) { if (b.status == BuildingStatus::Unassigned || b.status == BuildingStatus::Assigned) { buildingsQueued.push_back(b.type); } } return buildingsQueued; } BWAPI::TilePosition BuildingManager::getBuildingLocation(const Building & b) { int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon); if (b.isGasSteal) { auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); UAB_ASSERT(enemyBaseLocation,"Should have enemy base location before attempting gas steal"); UAB_ASSERT(enemyBaseLocation->getGeysers().size() > 0,"Should have spotted an enemy geyser"); for (auto & unit : enemyBaseLocation->getGeysers()) { BWAPI::TilePosition tp(unit->getInitialTilePosition()); return tp; } } if (b.type.requiresPsi() && numPylons == 0) { return BWAPI::TilePositions::None; } if (b.type.isRefinery()) { return m_buildingPlacer.getRefineryPosition(); } if (b.type.isResourceDepot()) { // get the location auto tile = Global::Bases().getNextExpansion(BWAPI::Broodwar->self()); return tile; } // set the building padding specifically int distance = b.type == BWAPI::UnitTypes::Protoss_Photon_Cannon ? 0 : Config::Macro::BuildingSpacing; if (b.type == BWAPI::UnitTypes::Protoss_Pylon && (numPylons < 3)) { distance = Config::Macro::PylonSpacing; } // get a position within our region return m_buildingPlacer.getBuildLocationNear(b,distance,false); } void BuildingManager::removeBuildings(const std::vector & toRemove) { for (auto & b : toRemove) { auto & it = std::find(m_buildings.begin(), m_buildings.end(), b); if (it != m_buildings.end()) { m_buildings.erase(it); } } } ================================================ FILE: UAlbertaBot/Source/BuildingManager.h ================================================ #pragma once #include "Common.h" #include "BuildingData.h" #include "BuildingPlacerManager.h" namespace UAlbertaBot { class BuildingManager { BuildingPlacerManager m_buildingPlacer; std::vector m_buildings; bool m_debugMode = false; int m_reservedMinerals = 0; // minerals reserved for planned buildings int m_reservedGas = 0; // gas reserved for planned buildings bool isEvolvedBuilding(BWAPI::UnitType type); bool isBuildingPositionExplored(const Building & b) const; void removeBuildings(const std::vector & toRemove); void validateWorkersAndBuildings(); // STEP 1 void assignWorkersToUnassignedBuildings(); // STEP 2 void constructAssignedBuildings(); // STEP 3 void checkForStartedConstruction(); // STEP 4 void checkForDeadTerranBuilders(); // STEP 5 void checkForCompletedBuildings(); // STEP 6 char getBuildingWorkerCode(const Building & b) const; public: BuildingManager(); void update(); void addBuildingTask(BWAPI::UnitType type,BWAPI::TilePosition desiredLocation,bool isGasSteal); void drawBuildingInformation(int x,int y); int getReservedMinerals(); int getReservedGas(); bool isBeingBuilt(BWAPI::UnitType type); BWAPI::TilePosition getBuildingLocation(const Building & b); std::vector buildingsQueued(); }; } ================================================ FILE: UAlbertaBot/Source/BuildingPlacerManager.cpp ================================================ #include "Common.h" #include "BuildingPlacerManager.h" #include "BaseLocationManager.h" #include "Global.h" #include "BuildingData.h" #include "Global.h" #include "MapTools.h" using namespace UAlbertaBot; BuildingPlacerManager::BuildingPlacerManager() { m_reserveMap = Grid(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight(), 0); computeResourceBox(); } bool BuildingPlacerManager::isInResourceBox(int x, int y) const { int posX(x * 32); int posY(y * 32); return (posX >= m_boxLeft) && (posX < m_boxRight) && (posY >= m_boxTop) && (posY < m_boxBottom); } void BuildingPlacerManager::computeResourceBox() { PROFILE_FUNCTION(); BWAPI::Position start(BWAPI::Broodwar->self()->getStartLocation()); BWAPI::Unitset unitsAroundNexus; for (auto & unit : BWAPI::Broodwar->getAllUnits()) { // if the units are less than 400 away add them if they are resources if (unit->getDistance(start) < 300 && unit->getType().isMineralField()) { unitsAroundNexus.insert(unit); } } for (auto & unit : unitsAroundNexus) { int x = unit->getPosition().x; int y = unit->getPosition().y; int left = x - unit->getType().dimensionLeft(); int right = x + unit->getType().dimensionRight() + 1; int top = y - unit->getType().dimensionUp(); int bottom = y + unit->getType().dimensionDown() + 1; m_boxTop = top < m_boxTop ? top : m_boxTop; m_boxBottom = bottom > m_boxBottom ? bottom : m_boxBottom; m_boxLeft = left < m_boxLeft ? left : m_boxLeft; m_boxRight = right > m_boxRight ? right : m_boxRight; } //BWAPI::Broodwar->printf("%d %d %d %d", boxTop, boxBottom, boxLeft, boxRight); } // makes final checks to see if a building can be built at a certain location bool BuildingPlacerManager::canBuildHere(BWAPI::TilePosition position, const Building & b) const { /*if (!b.type.isRefinery() && !Global::Info().tileContainsUnit(position)) { return false; }*/ //returns true if we can build this type of unit here. Takes into account reserved tiles. if (!BWAPI::Broodwar->canBuildHere(position, b.type, b.builderUnit)) { return false; } // check the reserve map for (int x = position.x; x < position.x + b.type.tileWidth(); x++) { for (int y = position.y; y < position.y + b.type.tileHeight(); y++) { if (m_reserveMap.get(x, y) == 1) { return false; } } } // if it overlaps a base location return false if (tileOverlapsBaseLocation(position, b.type)) { return false; } return true; } bool BuildingPlacerManager::tileBlocksAddon(BWAPI::TilePosition position) const { for (int i=0; i<=2; ++i) { for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(position.x - i, position.y)) { if (unit->getType() == BWAPI::UnitTypes::Terran_Command_Center || unit->getType() == BWAPI::UnitTypes::Terran_Factory || unit->getType() == BWAPI::UnitTypes::Terran_Starport || unit->getType() == BWAPI::UnitTypes::Terran_Science_Facility) { return true; } } } return false; } //returns true if we can build this type of unit here with the specified amount of space. //space value is stored in this->buildDistance. bool BuildingPlacerManager::canBuildHereWithSpace(BWAPI::TilePosition position, const Building & b, int buildDist, bool horizontalOnly) const { PROFILE_FUNCTION(); BWAPI::UnitType type = b.type; //if we can't build here, we of course can't build here with space if (!canBuildHere(position, b)) { return false; } // height and width of the building int width(b.type.tileWidth()); int height(b.type.tileHeight()); //make sure we leave space for add-ons. These types of units can have addons: if (b.type==BWAPI::UnitTypes::Terran_Command_Center || b.type==BWAPI::UnitTypes::Terran_Factory || b.type==BWAPI::UnitTypes::Terran_Starport || b.type==BWAPI::UnitTypes::Terran_Science_Facility) { width += 2; } // define the rectangle of the building spot int startx = position.x - buildDist; int starty = position.y - buildDist; int endx = position.x + width + buildDist; int endy = position.y + height + buildDist; if (b.type.isAddon()) { const BWAPI::UnitType builderType = type.whatBuilds().first; BWAPI::TilePosition builderTile(position.x - builderType.tileWidth(), position.y + 2 - builderType.tileHeight()); startx = builderTile.x - buildDist; starty = builderTile.y - buildDist; endx = position.x + width + buildDist; endy = position.y + height + buildDist; } if (horizontalOnly) { starty += buildDist; endy -= buildDist; } // if this rectangle doesn't fit on the map we can't build here if (startx < 0 || starty < 0 || endx > BWAPI::Broodwar->mapWidth() || endx < position.x + width || endy > BWAPI::Broodwar->mapHeight()) { return false; } // if we can't build here, or space is reserved, or it's in the resource box, we can't build here for (int x = startx; x < endx; x++) { for (int y = starty; y < endy; y++) { if (!b.type.isRefinery()) { if (!buildable(b, x, y) || m_reserveMap.get(x, y) || ((b.type != BWAPI::UnitTypes::Protoss_Photon_Cannon) && isInResourceBox(x, y))) { return false; } } } } return true; } BWAPI::TilePosition BuildingPlacerManager::GetBuildLocation(const Building & b, int padding) const { return BWAPI::TilePosition(0, 0); } BWAPI::TilePosition BuildingPlacerManager::getBuildLocationNear(const Building & b, int buildDist, bool horizontalOnly) const { PROFILE_FUNCTION(); // get the precomputed vector of tile positions which are sorted closes to this location const std::vector & closestToBuilding = Global::Map().getClosestTilesTo(b.desiredPosition); // special easy case of having no pylons int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon); if (b.type.requiresPsi() && numPylons == 0) { return BWAPI::TilePositions::None; } // iterate through the list until we've found a suitable location for (size_t i(0); i < closestToBuilding.size(); ++i) { if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly)) { //BWAPI::Broodwar->printf("Building Placer Took %d iterations, lasting %lf ms @ %lf iterations/ms, %lf setup ms", i, ms, (i / ms), ms1); return closestToBuilding[i]; } } return BWAPI::TilePositions::None; } bool BuildingPlacerManager::tileOverlapsBaseLocation(BWAPI::TilePosition tile, BWAPI::UnitType type) const { // if it's a resource depot we don't care if it overlaps if (type.isResourceDepot()) { return false; } // dimensions of the proposed location int tx1 = tile.x; int ty1 = tile.y; int tx2 = tx1 + type.tileWidth(); int ty2 = ty1 + type.tileHeight(); // for each base location for (auto base : Global::Bases().getBaseLocations()) { // dimensions of the base location int bx1 = base->getDepotPosition().x; int by1 = base->getDepotPosition().y; int bx2 = bx1 + BWAPI::Broodwar->self()->getRace().getResourceDepot().tileWidth(); int by2 = by1 + BWAPI::Broodwar->self()->getRace().getResourceDepot().tileHeight(); // conditions for non-overlap are easy bool noOverlap = (tx2 < bx1) || (tx1 > bx2) || (ty2 < by1) || (ty1 > by2); // if the reverse is true, return true if (!noOverlap) { return true; } } // otherwise there is no overlap return false; } bool BuildingPlacerManager::buildable(const Building & b, int x, int y) const { BWAPI::TilePosition tp(x, y); //returns true if this tile is currently buildable, takes into account units on tile if (!BWAPI::Broodwar->isBuildable(x, y)) { return false; } if ((BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran) && tileBlocksAddon(BWAPI::TilePosition(x, y))) { return false; } for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(x, y)) { if ((b.builderUnit != nullptr) && (unit != b.builderUnit)) { return false; } } if (!tp.isValid()) { return false; } return true; } void BuildingPlacerManager::reserveTiles(BWAPI::TilePosition position, int width, int height) { for (int x = position.x; x < position.x + width && x < (int)m_reserveMap.width(); x++) { for (int y = position.y; y < position.y + height && y < (int)m_reserveMap.height(); y++) { m_reserveMap.set(x, y, 1); } } } void BuildingPlacerManager::drawReservedTiles() { if (!Config::Debug::DrawReservedBuildingTiles) { return; } PROFILE_FUNCTION(); for (int x = 0; x < (int)m_reserveMap.width(); ++x) { for (int y = 0; y < (int)m_reserveMap.height(); ++y) { if (m_reserveMap.get(x, y) || isInResourceBox(x, y)) { int x1 = x*32 + 8; int y1 = y*32 + 8; int x2 = (x+1)*32 - 8; int y2 = (y+1)*32 - 8; BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Yellow, false); } } } } void BuildingPlacerManager::freeTiles(BWAPI::TilePosition position, int width, int height) { for (int x = position.x; x < position.x + width && x < (int)m_reserveMap.width(); x++) { for (int y = position.y; y < position.y + height && y < (int)m_reserveMap.height(); y++) { m_reserveMap.set(x, y, 0); } } } BWAPI::TilePosition BuildingPlacerManager::getRefineryPosition() { BWAPI::TilePosition closestGeyser = BWAPI::TilePositions::None; double minGeyserDistanceFromHome = std::numeric_limits::max(); BWAPI::Position homePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); // for each geyser for (auto & geyser : BWAPI::Broodwar->getStaticGeysers()) { if (geyser->getType() != BWAPI::UnitTypes::Resource_Vespene_Geyser) { continue; } BWAPI::Position geyserPos = geyser->getInitialPosition(); BWAPI::TilePosition geyserTilePos = geyser->getInitialTilePosition(); // check to see if it's next to one of our depots bool nearDepot = false; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType().isResourceDepot() && unit->getDistance(geyserPos) < 300) { nearDepot = true; } } if (nearDepot) { double homeDistance = geyser->getDistance(homePosition); if (homeDistance < minGeyserDistanceFromHome) { minGeyserDistanceFromHome = homeDistance; closestGeyser = geyser->getInitialTilePosition(); } } } return closestGeyser; } bool BuildingPlacerManager::isReserved(int x, int y) const { if (x < 0 || y < 0 || x >= (int)m_reserveMap.width() || y >= (int)m_reserveMap.height()) { return false; } return m_reserveMap.get(x, y); } ================================================ FILE: UAlbertaBot/Source/BuildingPlacerManager.h ================================================ #pragma once #include "Common.h" #include "Grid.hpp" namespace UAlbertaBot { class Building; class BuildingPlacerManager { Grid m_reserveMap; int m_boxTop = std::numeric_limits::max(); int m_boxBottom = std::numeric_limits::lowest(); int m_boxLeft = std::numeric_limits::max(); int m_boxRight = std::numeric_limits::lowest(); public: BuildingPlacerManager(); // queries for various BuildingPlacer data bool buildable(const Building & b,int x,int y) const; bool isReserved(int x,int y) const; bool isInResourceBox(int x,int y) const; bool tileOverlapsBaseLocation(BWAPI::TilePosition tile,BWAPI::UnitType type) const; bool tileBlocksAddon(BWAPI::TilePosition position) const; BWAPI::TilePosition GetBuildLocation(const Building & b,int padding) const; // determines whether we can build at a given location bool canBuildHere(BWAPI::TilePosition position,const Building & b) const; bool canBuildHereWithSpace(BWAPI::TilePosition position,const Building & b,int buildDist,bool horizontalOnly = false) const; // returns a build location near a building's desired location BWAPI::TilePosition getBuildLocationNear(const Building & b,int buildDist,bool horizontalOnly = false) const; void reserveTiles(BWAPI::TilePosition position,int width,int height); void freeTiles(BWAPI::TilePosition position,int width,int height); void drawReservedTiles(); void computeResourceBox(); BWAPI::TilePosition getRefineryPosition(); }; } ================================================ FILE: UAlbertaBot/Source/CombatCommander.cpp ================================================ #include "CombatCommander.h" #include "UnitUtil.h" #include "BaseLocationManager.h" #include "Global.h" #include "WorkerManager.h" #include "UnitData.h" #include "MapTools.h" #include "InformationManager.h" #include "StrategyManager.h" #include "Squad.h" #include "SquadData.h" using namespace UAlbertaBot; const size_t IdlePriority = 0; const size_t AttackPriority = 1; const size_t BaseDefensePriority = 2; const size_t ScoutDefensePriority = 3; const size_t DropPriority = 4; CombatCommander::CombatCommander() { } void CombatCommander::initializeSquads() { SquadOrder idleOrder(SquadOrderTypes::Idle, BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()), 100, "Chill Out"); m_squadData.addSquad("Idle", Squad("Idle", idleOrder, IdlePriority)); // the main attack squad that will pressure the enemy's closest base location SquadOrder mainAttackOrder(SquadOrderTypes::Attack, getMainAttackLocation(), 800, "Attack Enemy Base"); m_squadData.addSquad("MainAttack", Squad("MainAttack", mainAttackOrder, AttackPriority)); BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); // the scout defense squad will handle chasing the enemy worker scout SquadOrder enemyScoutDefense(SquadOrderTypes::Defend, ourBasePosition, 900, "Get the scout"); m_squadData.addSquad("ScoutDefense", Squad("ScoutDefense", enemyScoutDefense, ScoutDefensePriority)); // add a drop squad if we are using a drop strategy if (Config::Strategy::StrategyName == "Protoss_Drop") { SquadOrder zealotDrop(SquadOrderTypes::Drop, ourBasePosition, 900, "Wait for transport"); m_squadData.addSquad("Drop", Squad("Drop", zealotDrop, DropPriority)); } m_initialized = true; } bool CombatCommander::isSquadUpdateFrame() { return BWAPI::Broodwar->getFrameCount() % 10 == 0; } void CombatCommander::update(const BWAPI::Unitset & combatUnits) { PROFILE_FUNCTION(); if (!Config::Modules::UsingCombatCommander) { return; } if (!m_initialized) { initializeSquads(); } m_combatUnits = combatUnits; if (isSquadUpdateFrame()) { updateIdleSquad(); updateDropSquads(); updateScoutDefenseSquad(); updateDefenseSquads(); updateAttackSquads(); } m_squadData.update(); } void CombatCommander::updateIdleSquad() { Squad & idleSquad = m_squadData.getSquad("Idle"); for (auto & unit : m_combatUnits) { // if it hasn't been assigned to a squad yet, put it in the low priority idle squad if (m_squadData.canAssignUnitToSquad(unit, idleSquad)) { idleSquad.addUnit(unit); } } } void CombatCommander::updateAttackSquads() { Squad & mainAttackSquad = m_squadData.getSquad("MainAttack"); for (auto & unit : m_combatUnits) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge && UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk) < 30) { continue; } // get every unit of a lower priority and put it into the attack squad if (!unit->getType().isWorker() && (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord) && m_squadData.canAssignUnitToSquad(unit, mainAttackSquad)) { m_squadData.assignUnitToSquad(unit, mainAttackSquad); } } SquadOrder mainAttackOrder(SquadOrderTypes::Attack, getMainAttackLocation(), 800, "Attack Enemy Base"); mainAttackSquad.setSquadOrder(mainAttackOrder); } void CombatCommander::updateDropSquads() { if (Config::Strategy::StrategyName != "Protoss_Drop") { return; } Squad & dropSquad = m_squadData.getSquad("Drop"); // figure out how many units the drop squad needs bool dropSquadHasTransport = false; int transportSpotsRemaining = 8; auto & dropUnits = dropSquad.getUnits(); for (auto & unit : dropUnits) { if (unit->isFlying() && unit->getType().spaceProvided() > 0) { dropSquadHasTransport = true; } else { transportSpotsRemaining -= unit->getType().spaceRequired(); } } // if there are still units to be added to the drop squad, do it if (transportSpotsRemaining > 0 || !dropSquadHasTransport) { // take our first amount of combat units that fill up a transport and add them to the drop squad for (auto & unit : m_combatUnits) { // if this is a transport unit and we don't have one in the squad yet, add it if (!dropSquadHasTransport && (unit->getType().spaceProvided() > 0 && unit->isFlying())) { m_squadData.assignUnitToSquad(unit, dropSquad); dropSquadHasTransport = true; continue; } if (unit->getType().spaceRequired() > transportSpotsRemaining) { continue; } // get every unit of a lower priority and put it into the attack squad if (!unit->getType().isWorker() && m_squadData.canAssignUnitToSquad(unit, dropSquad)) { m_squadData.assignUnitToSquad(unit, dropSquad); transportSpotsRemaining -= unit->getType().spaceRequired(); } } } // otherwise the drop squad is full, so execute the order else { SquadOrder dropOrder(SquadOrderTypes::Drop, getMainAttackLocation(), 800, "Attack Enemy Base"); dropSquad.setSquadOrder(dropOrder); } } void CombatCommander::updateScoutDefenseSquad() { if (m_combatUnits.empty()) { return; } // if the current squad has units in it then we can ignore this Squad & scoutDefenseSquad = m_squadData.getSquad("ScoutDefense"); // get the region that our base is located in auto myBase = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->self()); // get all of the enemy units in this region BWAPI::Unitset enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (myBase->containsPosition(unit->getPosition())) { enemyUnitsInRegion.insert(unit); } } // if there's an enemy worker in our region then assign someone to chase him bool assignScoutDefender = enemyUnitsInRegion.size() == 1 && (*enemyUnitsInRegion.begin())->getType().isWorker(); // if our current squad is empty and we should assign a worker, do it if (scoutDefenseSquad.isEmpty() && assignScoutDefender) { // the enemy worker that is attacking us BWAPI::Unit enemyWorker = *enemyUnitsInRegion.begin(); // get our worker unit that is mining that is closest to it BWAPI::Unit workerDefender = findClosestWorkerToTarget(m_combatUnits, enemyWorker); if (enemyWorker && workerDefender) { // grab it from the worker manager and put it in the squad if (m_squadData.canAssignUnitToSquad(workerDefender, scoutDefenseSquad)) { Global::Workers().setCombatWorker(workerDefender); m_squadData.assignUnitToSquad(workerDefender, scoutDefenseSquad); } } } // if our squad is not empty and we shouldn't have a worker chasing then take him out of the squad else if (!scoutDefenseSquad.isEmpty() && !assignScoutDefender) { for (auto & unit : scoutDefenseSquad.getUnits()) { unit->stop(); if (unit->getType().isWorker()) { Global::Workers().finishedWithWorker(unit); } } scoutDefenseSquad.clear(); } } void CombatCommander::updateDefenseSquads() { if (m_combatUnits.empty()) { return; } // for each of our occupied regions const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); for (const BaseLocation * myBaseLocation : Global::Bases().getOccupiedBaseLocations(BWAPI::Broodwar->self())) { // don't defend inside the enemy region, this will end badly when we are stealing gas or cannon rushing if (myBaseLocation == enemyBaseLocation) { continue; } BWAPI::Position basePosition = myBaseLocation->getPosition(); // start off assuming all enemy units in region are just workers int numDefendersPerEnemyUnit = 2; // all of the enemy units in this region std::vector enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's an overlord, don't worry about it for defense, we don't care what they see if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) { continue; } if (myBaseLocation->containsPosition(unit->getPosition())) { enemyUnitsInRegion.push_back(unit); } } // we can ignore the first enemy worker in our region since we assume it is a scout for (auto unit : enemyUnitsInRegion) { if (unit->getType().isWorker()) { enemyUnitsInRegion.erase(std::remove(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), unit), enemyUnitsInRegion.end()); break; } } // calculate how many units are flying / ground units int numEnemyFlyingInRegion = 0; int numEnemyGroundInRegion = 0; for (auto & unit : enemyUnitsInRegion) { if (unit->isFlying()) { numEnemyFlyingInRegion++; } else { numEnemyGroundInRegion++; } } std::stringstream squadName; squadName << "Base Defense " << basePosition.x << " " << basePosition.y; // if there's nothing in this region to worry about if (enemyUnitsInRegion.empty()) { // if a defense squad for this region exists, remove it if (m_squadData.squadExists(squadName.str())) { m_squadData.getSquad(squadName.str()).clear(); } // and return, nothing to defend here continue; } else { // if we don't have a squad assigned to this region already, create one if (!m_squadData.squadExists(squadName.str())) { SquadOrder defendRegion(SquadOrderTypes::Defend, basePosition, 32 * 25, "Defend Region!"); m_squadData.addSquad(squadName.str(), Squad(squadName.str(), defendRegion, BaseDefensePriority)); } } // assign units to the squad if (m_squadData.squadExists(squadName.str())) { Squad & defenseSquad = m_squadData.getSquad(squadName.str()); // figure out how many units we need on defense int flyingDefendersNeeded = numDefendersPerEnemyUnit * numEnemyFlyingInRegion; int groundDefensersNeeded = numDefendersPerEnemyUnit * numEnemyGroundInRegion; updateDefenseSquadUnits(defenseSquad, flyingDefendersNeeded, groundDefensersNeeded); } else { UAB_ASSERT(false, "Squad should have existed: %s", squadName.str().c_str()); } } // for each of our defense squads, if there aren't any enemy units near the position, remove the squad std::set uselessDefenseSquads; for (const auto & kv : m_squadData.getSquads()) { const Squad & squad = kv.second; const SquadOrder & order = squad.getSquadOrder(); if (order.getType() != SquadOrderTypes::Defend) { continue; } bool enemyUnitInRange = false; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getDistance(order.getPosition()) < order.getRadius()) { enemyUnitInRange = true; break; } } if (!enemyUnitInRange) { m_squadData.getSquad(squad.getName()).clear(); } } } void CombatCommander::updateDefenseSquadUnits(Squad & defenseSquad, const size_t & flyingDefendersNeeded, const size_t & groundDefendersNeeded) { const BWAPI::Unitset & squadUnits = defenseSquad.getUnits(); size_t flyingDefendersInSquad = std::count_if(squadUnits.begin(), squadUnits.end(), UnitUtil::CanAttackAir); size_t groundDefendersInSquad = std::count_if(squadUnits.begin(), squadUnits.end(), UnitUtil::CanAttackGround); // if there's nothing left to defend, clear the squad if (flyingDefendersNeeded == 0 && groundDefendersNeeded == 0) { defenseSquad.clear(); return; } // add flying defenders if we still need them size_t flyingDefendersAdded = 0; while (flyingDefendersNeeded > flyingDefendersInSquad + flyingDefendersAdded) { BWAPI::Unit defenderToAdd = findClosestDefender(defenseSquad, defenseSquad.getSquadOrder().getPosition(), true); // if we find a valid flying defender, add it to the squad if (defenderToAdd) { m_squadData.assignUnitToSquad(defenderToAdd, defenseSquad); ++flyingDefendersAdded; } // otherwise we'll never find another one so break out of this loop else { break; } } // add ground defenders if we still need them size_t groundDefendersAdded = 0; while (groundDefendersNeeded > groundDefendersInSquad + groundDefendersAdded) { BWAPI::Unit defenderToAdd = findClosestDefender(defenseSquad, defenseSquad.getSquadOrder().getPosition(), false); // if we find a valid ground defender add it if (defenderToAdd) { m_squadData.assignUnitToSquad(defenderToAdd, defenseSquad); ++groundDefendersAdded; } // otherwise we'll never find another one so break out of this loop else { break; } } } BWAPI::Unit CombatCommander::findClosestDefender(const Squad & defenseSquad, BWAPI::Position pos, bool flyingDefender) { BWAPI::Unit closestDefender = nullptr; double minDistance = std::numeric_limits::max(); int zerglingsInOurBase = numZerglingsInOurBase(); bool zerglingRush = zerglingsInOurBase > 0 && BWAPI::Broodwar->getFrameCount() < 5000; for (auto & unit : m_combatUnits) { if ((flyingDefender && !UnitUtil::CanAttackAir(unit)) || (!flyingDefender && !UnitUtil::CanAttackGround(unit))) { continue; } if (!m_squadData.canAssignUnitToSquad(unit, defenseSquad)) { continue; } // add workers to the defense squad if we are being rushed very quickly if (!Config::Micro::WorkersDefendRush || (unit->getType().isWorker() && !zerglingRush && !beingBuildingRushed())) { continue; } double dist = unit->getDistance(pos); if (!closestDefender || (dist < minDistance)) { closestDefender = unit; minDistance = dist; } } return closestDefender; } BWAPI::Position CombatCommander::getDefendLocation() { return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); } void CombatCommander::drawSquadInformation(int x, int y) { m_squadData.drawSquadInformation(x, y); } BWAPI::Position CombatCommander::getMainAttackLocation() { const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); // First choice: Attack an enemy region if we can see units inside it if (enemyBaseLocation) { BWAPI::Position enemyBasePosition = enemyBaseLocation->getPosition(); // get all known enemy units in the area BWAPI::Unitset enemyUnitsInArea; Global::Map().getUnits(enemyUnitsInArea, enemyBasePosition, 800, false, true); bool onlyOverlords = true; for (auto & unit : enemyUnitsInArea) { if (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord) { onlyOverlords = false; } } if (!BWAPI::Broodwar->isExplored(BWAPI::TilePosition(enemyBasePosition)) || !enemyUnitsInArea.empty()) { if (!onlyOverlords) { return enemyBaseLocation->getPosition(); } } } // Second choice: Attack known enemy buildings for (const auto & kv : Global::Info().getUnitInfo(BWAPI::Broodwar->enemy())) { const UnitInfo & ui = kv.second; if (ui.type.isBuilding() && ui.lastPosition != BWAPI::Positions::None) { return ui.lastPosition; } } // Third choice: Attack visible enemy units that aren't overlords for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) { continue; } if (UnitUtil::IsValidUnit(unit) && unit->isVisible()) { return unit->getPosition(); } } // Fourth choice: We can't see anything so explore the map attacking along the way return BWAPI::Position(Global::Map().getLeastRecentlySeenTile()); } BWAPI::Unit CombatCommander::findClosestWorkerToTarget(BWAPI::Unitset & unitsToAssign, BWAPI::Unit target) { UAB_ASSERT(target != nullptr, "target was null"); if (!target) { return nullptr; } BWAPI::Unit closestMineralWorker = nullptr; double closestDist = 100000; // for each of our workers for (auto & unit : unitsToAssign) { if (!unit->getType().isWorker()) { continue; } // if it is a move worker if (Global::Workers().isFree(unit)) { double dist = unit->getDistance(target); if (!closestMineralWorker || dist < closestDist) { closestMineralWorker = unit; dist = closestDist; } } } return closestMineralWorker; } // when do we want to defend with our workers? // this function can only be called if we have no fighters to defend with int CombatCommander::defendWithWorkers() { // our home nexus position BWAPI::Position homePosition(BWAPI::Broodwar->self()->getStartLocation()); // enemy units near our workers int enemyUnitsNearWorkers = 0; // defense radius of nexus int defenseRadius = 300; // fill the set with the types of units we're concerned about for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's a zergling or a worker we want to defend if (unit->getType() == BWAPI::UnitTypes::Zerg_Zergling) { if (unit->getDistance(homePosition) < defenseRadius) { enemyUnitsNearWorkers++; } } } // if there are enemy units near our workers, we want to defend return enemyUnitsNearWorkers; } int CombatCommander::numZerglingsInOurBase() { int concernRadius = 600; int zerglings = 0; BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); // check to see if the enemy has zerglings as the only attackers in our base for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType() != BWAPI::UnitTypes::Zerg_Zergling) { continue; } if (unit->getDistance(ourBasePosition) < concernRadius) { zerglings++; } } return zerglings; } bool CombatCommander::beingBuildingRushed() { int concernRadius = 1200; BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); // check to see if the enemy has zerglings as the only attackers in our base for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isBuilding()) { return true; } } return false; } ================================================ FILE: UAlbertaBot/Source/CombatCommander.h ================================================ #pragma once #include "Common.h" #include "SquadData.h" namespace UAlbertaBot { class Squad; class CombatCommander { SquadData m_squadData; BWAPI::Unitset m_combatUnits; bool m_initialized = false; void updateScoutDefenseSquad(); void updateDefenseSquads(); void updateAttackSquads(); void updateDropSquads(); void updateIdleSquad(); void initializeSquads(); void updateDefenseSquadUnits(Squad & defenseSquad, const size_t & flyingDefendersNeeded, const size_t & groundDefendersNeeded); int defendWithWorkers(); int numZerglingsInOurBase(); bool beingBuildingRushed(); bool isSquadUpdateFrame(); BWAPI::Unit findClosestDefender(const Squad & defenseSquad, BWAPI::Position pos, bool flyingDefender); BWAPI::Unit findClosestWorkerToTarget(BWAPI::Unitset & unitsToAssign, BWAPI::Unit target); BWAPI::Position getDefendLocation(); BWAPI::Position getMainAttackLocation(); public: CombatCommander(); void update(const BWAPI::Unitset & combatUnits); void drawSquadInformation(int x, int y); }; } ================================================ FILE: UAlbertaBot/Source/CombatSimulation.cpp ================================================ #include "CombatSimulation.h" #include "Global.h" #include "MapTools.h" #include "UnitData.h" #include "InformationManager.h" using namespace UAlbertaBot; CombatSimulation::CombatSimulation() { } // sets the starting states based on the combat units within a radius of a given position // this center will most likely be the position of the forwardmost combat unit we control void CombatSimulation::setCombatUnits(const BWAPI::Position & center, const int radius) { SparCraft::GameState s; BWAPI::Broodwar->drawCircleMap(center.x, center.y, 10, BWAPI::Colors::Red, true); BWAPI::Unitset ourCombatUnits; std::vector enemyCombatUnits; Global::Map().getUnits(ourCombatUnits, center, Config::Micro::CombatRegroupRadius, true, false); Global::Info().getNearbyForce(enemyCombatUnits, center, BWAPI::Broodwar->enemy(), Config::Micro::CombatRegroupRadius); for (auto & unit : ourCombatUnits) { if (unit->getType().isWorker()) { continue; } if (Global::Info().isCombatUnit(unit->getType()) && SparCraft::System::isSupportedUnitType(unit->getType())) { try { s.addUnit(getSparCraftUnit(unit)); } catch (int e) { e=1; BWAPI::Broodwar->printf("Problem Adding Self Unit with ID: %d", unit->getID()); } } } for (UnitInfo & ui : enemyCombatUnits) { if (ui.type.isWorker()) { continue; } if (ui.type == BWAPI::UnitTypes::Terran_Bunker) { double hpRatio = static_cast(ui.lastHealth) / ui.type.maxHitPoints(); SparCraft::Unit marine(BWAPI::UnitTypes::Terran_Marine, SparCraft::Position(ui.lastPosition), ui.unitID, getSparCraftPlayerID(ui.player), static_cast(BWAPI::UnitTypes::Terran_Marine.maxHitPoints() * hpRatio), 0, BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount()); for (size_t i(0); i < 5; ++i) { s.addUnit(marine); } continue; } if (!ui.type.isFlyer() && SparCraft::System::isSupportedUnitType(ui.type) && ui.completed) { try { s.addUnit(getSparCraftUnit(ui)); } catch (int e) { BWAPI::Broodwar->printf("Problem Adding Enemy Unit with ID: %d %d", ui.unitID, e); } } } s.finishedMoving(); m_state = s; } // Gets a SparCraft unit from a BWAPI::Unit, used for our own units since we have all their info const SparCraft::Unit CombatSimulation::getSparCraftUnit(BWAPI::Unit unit) const { return SparCraft::Unit(unit->getType(), SparCraft::Position(unit->getPosition()), unit->getID(), getSparCraftPlayerID(unit->getPlayer()), unit->getHitPoints() + unit->getShields(), 0, BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount()); } // Gets a SparCraft unit from a UnitInfo struct, needed to get units of enemy behind FoW const SparCraft::Unit CombatSimulation::getSparCraftUnit(const UnitInfo & ui) const { BWAPI::UnitType type = ui.type; // this is a hack, treat medics as a marine for now if (type == BWAPI::UnitTypes::Terran_Medic) { type = BWAPI::UnitTypes::Terran_Marine; } return SparCraft::Unit(ui.type, SparCraft::Position(ui.lastPosition), ui.unitID, getSparCraftPlayerID(ui.player), ui.lastHealth, 0, BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount()); } SparCraft::ScoreType CombatSimulation::simulateCombat() { PROFILE_FUNCTION(); try { SparCraft::GameState s1(m_state); SparCraft::PlayerPtr selfNOK(new SparCraft::Player_NOKDPS(getSparCraftPlayerID(BWAPI::Broodwar->self()))); SparCraft::PlayerPtr enemyNOK(new SparCraft::Player_NOKDPS(getSparCraftPlayerID(BWAPI::Broodwar->enemy()))); SparCraft::Game g (s1, selfNOK, enemyNOK, 2000); g.play(); SparCraft::ScoreType eval = g.getState().eval(SparCraft::Players::Player_One, SparCraft::EvaluationMethods::LTD2).val(); if (Config::Debug::DrawCombatSimulationInfo) { std::stringstream ss1; ss1 << "Initial State:\n"; ss1 << s1.toStringCompact() << "\n\n"; std::stringstream ss2; ss2 << "Predicted Outcome: " << eval << "\n"; ss2 << g.getState().toStringCompact() << "\n"; BWAPI::Broodwar->drawTextScreen(150, 200, "%s", ss1.str().c_str()); BWAPI::Broodwar->drawTextScreen(300, 200, "%s", ss2.str().c_str()); BWAPI::Broodwar->drawTextScreen(240, 280, "Combat Sim : %d", eval); } return eval; } catch (int e) { BWAPI::Broodwar->printf("SparCraft FatalError, simulateCombat() threw"); return e; } } const SparCraft::GameState & CombatSimulation::getSparCraftState() const { return m_state; } const size_t CombatSimulation::getSparCraftPlayerID(BWAPI::Player player) const { if (player == BWAPI::Broodwar->self()) { return SparCraft::Players::Player_One; } else if (player == BWAPI::Broodwar->enemy()) { return SparCraft::Players::Player_Two; } return SparCraft::Players::Player_None; } ================================================ FILE: UAlbertaBot/Source/CombatSimulation.h ================================================ #pragma once #include "Common.h" #ifdef USING_VISUALIZATION_LIBRARIES #include "Visualizer.h" #endif #include "..\..\SparCraft\source\GameState.h" #include "..\..\SparCraft\source\Game.h" #include "..\..\SparCraft\source\Unit.h" #include "..\..\SparCraft\source\AllPlayers.h" namespace UAlbertaBot { struct UnitInfo; class CombatSimulation { SparCraft::GameState m_state; public: CombatSimulation(); void setCombatUnits(const BWAPI::Position & center, const int radius); SparCraft::ScoreType simulateCombat(); const SparCraft::Unit getSparCraftUnit(const UnitInfo & ui) const; const SparCraft::Unit getSparCraftUnit(BWAPI::Unit unit) const; const SparCraft::GameState & getSparCraftState() const; const size_t getSparCraftPlayerID(BWAPI::Player player) const; }; } ================================================ FILE: UAlbertaBot/Source/Common.cpp ================================================ #include "Common.h" ================================================ FILE: UAlbertaBot/Source/Common.h ================================================ #pragma once #define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Config.h" #include "UABAssert.h" #include "Profiler.hpp" ================================================ FILE: UAlbertaBot/Source/Config.cpp ================================================ #include "Config.h" #include "UABAssert.h" namespace Bot { } namespace Config { namespace ConfigFile { bool ConfigFileFound = false; bool ConfigFileParsed = false; std::string ConfigFileLocation = "UAlbertaBot_Config.txt"; } namespace Strategy { std::string ProtossStrategyName = "Protoss_ZealotRush"; std::string TerranStrategyName = "Terran_MarineRush"; std::string ZergStrategyName = "Zerg_3HatchMuta"; std::string StrategyName = "Protoss_ZealotRush"; std::string ReadDir = "bwapi-data/read/"; std::string WriteDir = "bwapi-data/write/"; bool GasStealWithScout = false; bool ScoutHarassEnemy = true; bool UseEnemySpecificStrategy = false; bool FoundEnemySpecificStrategy = false; } namespace Modules { // the default tournament bot modules bool UsingGameCommander = true; // toggle GameCommander, effectively UAlbertaBot bool UsingScoutManager = true; bool UsingCombatCommander = true; bool UsingBuildOrderSearch = true; // toggle use of Build Order Search, currently no backup bool UsingAutoObserver = false; bool UsingStrategyIO = false; // toggle the use of file io for strategy bool UsingUnitCommandManager = false; // handles all unit commands // extra things, don't enable unless you know what they are bool UsingBuildOrderDemo = false; } namespace BotInfo { std::string BotName = "UAlbertaBot"; std::string Authors = "Dave Churchill"; bool PrintInfoOnStart = false; } namespace BWAPIOptions { int SetLocalSpeed = 42; int SetFrameSkip = 0; bool EnableUserInput = true; bool EnableCompleteMapInformation = false; } namespace Tournament { int GameEndFrame = 86400; } namespace Debug { bool DrawGameInfo = true; bool DrawUnitHealthBars = true; bool DrawProductionInfo = true; bool DrawBuildOrderSearchInfo = false; bool DrawScoutInfo = false; bool DrawResourceInfo = false; bool DrawWorkerInfo = false; bool DrawModuleTimers = false; bool DrawReservedBuildingTiles = false; bool DrawCombatSimulationInfo = false; bool DrawBuildingInfo = false; bool DrawMouseCursorInfo = false; bool DrawEnemyUnitInfo = false; bool DrawBWTAInfo = false; bool DrawMapGrid = false; bool DrawUnitTargetInfo = false; bool DrawSquadInfo = false; bool DrawBOSSStateInfo = false; bool DrawWalkableSectors = false; bool DrawTileInfo = false; bool PrintModuleTimeout = false; std::string ErrorLogFilename = "UAB_ErrorLog.txt"; bool LogAssertToErrorFile = false; BWAPI::Color ColorLineTarget = BWAPI::Colors::White; BWAPI::Color ColorLineMineral = BWAPI::Colors::Cyan; BWAPI::Color ColorUnitNearEnemy = BWAPI::Colors::Red; BWAPI::Color ColorUnitNotNearEnemy = BWAPI::Colors::Green; } namespace Micro { bool UseSparcraftSimulation = true; bool KiteWithRangedUnits = true; std::set KiteLongerRangedUnits; bool WorkersDefendRush = false; int RetreatMeleeUnitShields = 0; int RetreatMeleeUnitHP = 0; int CombatRadius = 1000; // radius of combat to consider units for Micro Search int CombatRegroupRadius = 300; // radius of units around frontmost unit we consider in regroup calculation int UnitNearEnemyRadius = 600; // radius to consider a unit 'near' to an enemy unit } namespace Macro { int BOSSFrameLimit = 160; int BOSSTimePerFrame = 30; int WorkersPerRefinery = 3; int BuildingSpacing = 1; int PylonSpacing = 3; } namespace Tools { extern int MAP_GRID_SIZE = 320; // size of grid spacing in MapGrid } } ================================================ FILE: UAlbertaBot/Source/Config.h ================================================ #pragma once #include "BWAPI.h" #include #include namespace Config { namespace ConfigFile { extern bool ConfigFileFound; extern bool ConfigFileParsed; extern std::string ConfigFileLocation; } namespace Modules { extern bool UsingGameCommander; extern bool UsingScoutManager; extern bool UsingCombatCommander; extern bool UsingUnitCommandManager; extern bool UsingBuildOrderSearch; extern bool UsingAutoObserver; extern bool UsingStrategyIO; } namespace BotInfo { extern std::string BotName; extern std::string Authors; extern bool PrintInfoOnStart; } namespace Strategy { extern std::string StrategyName; extern std::string ReadDir; extern std::string WriteDir; extern bool GasStealWithScout; extern bool ScoutHarassEnemy; extern bool UseEnemySpecificStrategy; extern bool FoundEnemySpecificStrategy; } namespace BWAPIOptions { extern int SetLocalSpeed; extern int SetFrameSkip; extern bool EnableUserInput; extern bool EnableCompleteMapInformation; } namespace Tournament { extern int GameEndFrame; } namespace Debug { extern bool DrawGameInfo; extern bool DrawBuildOrderSearchInfo; extern bool DrawUnitHealthBars; extern bool DrawResourceInfo; extern bool DrawProductionInfo; extern bool DrawScoutInfo; extern bool DrawWorkerInfo; extern bool DrawModuleTimers; extern bool DrawReservedBuildingTiles; extern bool DrawCombatSimulationInfo; extern bool DrawBuildingInfo; extern bool DrawMouseCursorInfo; extern bool DrawEnemyUnitInfo; extern bool DrawBWTAInfo; extern bool DrawMapGrid; extern bool DrawUnitTargetInfo; extern bool DrawSquadInfo; extern bool DrawBOSSStateInfo; extern bool DrawWalkableSectors; extern bool DrawTileInfo; extern bool PrintModuleTimeout; extern std::string ErrorLogFilename; extern bool LogAssertToErrorFile; extern BWAPI::Color ColorLineTarget; extern BWAPI::Color ColorLineMineral; extern BWAPI::Color ColorUnitNearEnemy; extern BWAPI::Color ColorUnitNotNearEnemy; } namespace Micro { extern bool UseSparcraftSimulation; extern bool KiteWithRangedUnits; extern std::set KiteLongerRangedUnits; extern bool WorkersDefendRush; extern int RetreatMeleeUnitShields; extern int RetreatMeleeUnitHP; extern int CombatRadius; extern int CombatRegroupRadius; extern int UnitNearEnemyRadius; } namespace Macro { extern int BOSSFrameLimit; extern int BOSSTimePerFrame; extern int WorkersPerRefinery; extern int BuildingSpacing; extern int PylonSpacing; } namespace Tools { extern int MAP_GRID_SIZE; } } ================================================ FILE: UAlbertaBot/Source/DetectorManager.cpp ================================================ #include "Common.h" #include "DetectorManager.h" #include "Global.h" #include "Micro.h" #include "MapTools.h" using namespace UAlbertaBot; DetectorManager::DetectorManager() { } void DetectorManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & detectorUnits = getUnits(); if (detectorUnits.empty()) { return; } for (size_t i(0); ienemy()->getUnits()) { // conditions for targeting if (unit->getType() == BWAPI::UnitTypes::Zerg_Lurker || unit->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar || unit->getType() == BWAPI::UnitTypes::Terran_Wraith) { cloakedUnits.insert(unit); m_cloakedUnitMap[unit] = false; } } bool detectorUnitInBattle = false; // for each detectorUnit for (auto & detectorUnit : detectorUnits) { // if we need to regroup, move the detectorUnit to that location if (!detectorUnitInBattle && unitClosestToEnemy && unitClosestToEnemy->getPosition().isValid()) { Micro::SmartMove(detectorUnit, unitClosestToEnemy->getPosition()); detectorUnitInBattle = true; } // otherwise there is no battle or no closest to enemy so we don't want our detectorUnit to die // send him to scout around the map else { BWAPI::Position explorePosition = BWAPI::Position(Global::Map().getLeastRecentlySeenTile()); Micro::SmartMove(detectorUnit, explorePosition); } } } BWAPI::Unit DetectorManager::closestCloakedUnit(const BWAPI::Unitset & cloakedUnits, BWAPI::Unit detectorUnit) { BWAPI::Unit closestCloaked = nullptr; double closestDist = 100000; for (auto & unit : cloakedUnits) { // if we haven't already assigned an detectorUnit to this cloaked unit if (!m_cloakedUnitMap[unit]) { double dist = unit->getDistance(detectorUnit); if (!closestCloaked || (dist < closestDist)) { closestCloaked = unit; closestDist = dist; } } } return closestCloaked; } ================================================ FILE: UAlbertaBot/Source/DetectorManager.h ================================================ #pragma once #include "MicroManager.h" namespace UAlbertaBot { class DetectorManager : public MicroManager { std::map m_cloakedUnitMap; BWAPI::Unit unitClosestToEnemy = nullptr; bool isAssigned(BWAPI::Unit unit); public: DetectorManager(); void setUnitClosestToEnemy(BWAPI::Unit unit) { unitClosestToEnemy = unit; } void executeMicro(const BWAPI::Unitset & targets); BWAPI::Unit closestCloakedUnit(const BWAPI::Unitset & cloakedUnits, BWAPI::Unit detectorUnit); }; } ================================================ FILE: UAlbertaBot/Source/DistanceMap.cpp ================================================ #include "DistanceMap.h" #include "MapTools.h" #include "Global.h" using namespace UAlbertaBot; const size_t LegalActions = 4; const int actionX[LegalActions] ={1, -1, 0, 0}; const int actionY[LegalActions] ={0, 0, 1, -1}; DistanceMap::DistanceMap() { } int DistanceMap::getDistance(int tileX, int tileY) const { UAB_ASSERT(tileX < m_width && tileY < m_height, "Index out of range: X = %d, Y = %d", tileX, tileY); return m_dist.get(tileX, tileY); } int DistanceMap::getDistance(const BWAPI::TilePosition & pos) const { return getDistance(pos.x, pos.y); } int DistanceMap::getDistance(const BWAPI::Position & pos) const { return getDistance(BWAPI::TilePosition(pos)); } const std::vector & DistanceMap::getSortedTiles() const { return m_sortedTiles; } // Computes m_dist[x][y] = ground distance from (startX, startY) to (x,y) // Uses BFS, since the map is quite large and DFS may cause a stack overflow void DistanceMap::computeDistanceMap(const BWAPI::TilePosition & startTile) { PROFILE_FUNCTION(); m_startTile = startTile; m_width = BWAPI::Broodwar->mapWidth(); m_height = BWAPI::Broodwar->mapHeight(); m_dist = Grid(m_width, m_height, -1); m_sortedTiles.reserve(m_width * m_height); // the fringe for the BFS we will perform to calculate distances std::vector fringe; fringe.reserve(m_width * m_height); fringe.push_back(startTile); m_sortedTiles.push_back(startTile); m_dist.set(startTile.x, startTile.y, 0); for (size_t fringeIndex=0; fringeIndexdrawTextMap(textPos, ss.str().c_str(), BWAPI::Colors::White); } } const BWAPI::TilePosition & DistanceMap::getStartTile() const { return m_startTile; } ================================================ FILE: UAlbertaBot/Source/DistanceMap.h ================================================ #pragma once #include "Common.h" #include "Grid.hpp" namespace UAlbertaBot { class DistanceMap { int m_width = 0; int m_height = 0; Grid m_dist; BWAPI::TilePosition m_startTile; std::vector m_sortedTiles; public: DistanceMap(); void computeDistanceMap(const BWAPI::TilePosition & startTile); int getDistance(int tileX, int tileY) const; int getDistance(const BWAPI::TilePosition & pos) const; int getDistance(const BWAPI::Position & pos) const; // given a position, get the position we should move to to minimize distance const std::vector & getSortedTiles() const; const BWAPI::TilePosition & getStartTile() const; void draw() const; }; } ================================================ FILE: UAlbertaBot/Source/GameCommander.cpp ================================================ #include "Common.h" #include "GameCommander.h" #include "UnitUtil.h" #include "BaseLocationManager.h" #include "Global.h" #include "BuildingPlacerManager.h" #include "BOSSManager.h" #include "MapTools.h" #include "InformationManager.h" #include "WorkerManager.h" #include "ProductionManager.h" #include "BuildingManager.h" #include "ScoutManager.h" #include "StrategyManager.h" #include "Squad.h" using namespace UAlbertaBot; GameCommander::GameCommander() : m_initialScoutSet(false) { } void GameCommander::update() { PROFILE_FUNCTION(); m_timerManager.startTimer(TimerManager::All); // populate the unit vectors we will pass into various managers handleUnitAssignments(); // utility managers m_timerManager.startTimer(TimerManager::InformationManager); Global::Info().update(); m_timerManager.stopTimer(TimerManager::InformationManager); m_timerManager.startTimer(TimerManager::MapTools); Global::Map().onFrame(); m_timerManager.stopTimer(TimerManager::MapTools); // economy and base managers m_timerManager.startTimer(TimerManager::Worker); Global::Workers().onFrame(); m_timerManager.stopTimer(TimerManager::Worker); m_timerManager.startTimer(TimerManager::Production); Global::Production().update(); m_timerManager.stopTimer(TimerManager::Production); // combat and scouting managers m_timerManager.startTimer(TimerManager::Combat); m_combatCommander.update(m_combatUnits); m_timerManager.stopTimer(TimerManager::Combat); m_timerManager.startTimer(TimerManager::Scout); Global::Scout().update(); m_timerManager.stopTimer(TimerManager::Scout); m_timerManager.stopTimer(TimerManager::All); Global::Bases().onFrame(); drawDebugInterface(); } void GameCommander::drawDebugInterface() { Global::Info().drawExtendedInterface(); Global::Info().drawUnitInformation(425,30); Global::Info().drawMapInformation(); Global::Production().drawProductionInformation(30, 50); m_combatCommander.drawSquadInformation(200, 30); m_timerManager.displayTimers(490, 225); drawGameInformation(4, 1); // draw position of mouse cursor if (Config::Debug::DrawMouseCursorInfo) { int mouseX = BWAPI::Broodwar->getMousePosition().x + BWAPI::Broodwar->getScreenPosition().x; int mouseY = BWAPI::Broodwar->getMousePosition().y + BWAPI::Broodwar->getScreenPosition().y; BWAPI::Broodwar->drawTextMap(mouseX + 20, mouseY, " %d %d", mouseX, mouseY); } } void GameCommander::drawGameInformation(int x, int y) { BWAPI::Broodwar->drawTextScreen(x, y, "\x04Players:"); BWAPI::Broodwar->drawTextScreen(x+50, y, "%c%s \x04vs. %c%s", BWAPI::Broodwar->self()->getTextColor(), BWAPI::Broodwar->self()->getName().c_str(), BWAPI::Broodwar->enemy()->getTextColor(), BWAPI::Broodwar->enemy()->getName().c_str()); y += 12; BWAPI::Broodwar->drawTextScreen(x, y, "\x04Strategy:"); BWAPI::Broodwar->drawTextScreen(x+50, y, "\x03%s %s", Config::Strategy::StrategyName.c_str(), Config::Strategy::FoundEnemySpecificStrategy ? "(enemy specific)" : ""); BWAPI::Broodwar->setTextSize(); y += 12; BWAPI::Broodwar->drawTextScreen(x, y, "\x04Map:"); BWAPI::Broodwar->drawTextScreen(x+50, y, "\x03%s", BWAPI::Broodwar->mapFileName().c_str()); BWAPI::Broodwar->setTextSize(); y += 12; BWAPI::Broodwar->drawTextScreen(x, y, "\x04Time:"); BWAPI::Broodwar->drawTextScreen(x+50, y, "\x04%d %4dm %3ds", BWAPI::Broodwar->getFrameCount(), (int)(BWAPI::Broodwar->getFrameCount()/(23.8*60)), (int)((int)(BWAPI::Broodwar->getFrameCount()/23.8)%60)); } // assigns units to various managers void GameCommander::handleUnitAssignments() { m_validUnits.clear(); m_combatUnits.clear(); // filter our units for those which are valid and usable setValidUnits(); // set each type of unit setScoutUnits(); setCombatUnits(); } bool GameCommander::isAssigned(BWAPI::Unit unit) const { return m_combatUnits.contains(unit) || m_scoutUnits.contains(unit); } // validates units as usable for distribution to various managers void GameCommander::setValidUnits() { // make sure the unit is completed and alive and usable for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (UnitUtil::IsValidUnit(unit)) { m_validUnits.insert(unit); } } } void GameCommander::setScoutUnits() { // if we haven't set a scout unit, do it if (m_scoutUnits.empty() && !m_initialScoutSet) { BWAPI::Unit supplyProvider = getFirstSupplyProvider(); // if it exists if (supplyProvider) { // grab the closest worker to the supply provider to send to scout BWAPI::Unit workerScout = getClosestWorkerToTarget(supplyProvider->getPosition()); // if we find a worker (which we should) add it to the scout units if (workerScout) { Global::Scout().setWorkerScout(workerScout); assignUnit(workerScout, m_scoutUnits); m_initialScoutSet = true; } } } } // sets combat units to be passed to CombatCommander void GameCommander::setCombatUnits() { for (auto & unit : m_validUnits) { if (!isAssigned(unit) && UnitUtil::IsCombatUnit(unit) || unit->getType().isWorker()) { assignUnit(unit, m_combatUnits); } } } BWAPI::Unit GameCommander::getFirstSupplyProvider() { BWAPI::Unit supplyProvider = nullptr; if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Spawning_Pool) { supplyProvider = unit; } } } else { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == BWAPI::Broodwar->self()->getRace().getSupplyProvider()) { supplyProvider = unit; } } } return supplyProvider; } void GameCommander::onUnitShow(BWAPI::Unit unit) { Global::Info().onUnitShow(unit); Global::Workers().onUnitShow(unit); } void GameCommander::onUnitHide(BWAPI::Unit unit) { Global::Info().onUnitHide(unit); } void GameCommander::onUnitCreate(BWAPI::Unit unit) { Global::Info().onUnitCreate(unit); } void GameCommander::onUnitComplete(BWAPI::Unit unit) { Global::Info().onUnitComplete(unit); } void GameCommander::onUnitRenegade(BWAPI::Unit unit) { Global::Info().onUnitRenegade(unit); } void GameCommander::onUnitDestroy(BWAPI::Unit unit) { Global::Production().onUnitDestroy(unit); Global::Workers().onUnitDestroy(unit); Global::Info().onUnitDestroy(unit); } void GameCommander::onUnitMorph(BWAPI::Unit unit) { Global::Info().onUnitMorph(unit); Global::Workers().onUnitMorph(unit); } BWAPI::Unit GameCommander::getClosestUnitToTarget(BWAPI::UnitType type, BWAPI::Position target) { BWAPI::Unit closestUnit = nullptr; double closestDist = 100000; for (auto & unit : m_validUnits) { if (unit->getType() == type) { double dist = unit->getDistance(target); if (!closestUnit || dist < closestDist) { closestUnit = unit; closestDist = dist; } } } return closestUnit; } BWAPI::Unit GameCommander::getClosestWorkerToTarget(BWAPI::Position target) { BWAPI::Unit closestUnit = nullptr; double closestDist = 100000; for (auto & unit : m_validUnits) { if (!isAssigned(unit) && unit->getType().isWorker() && Global::Workers().isFree(unit)) { double dist = unit->getDistance(target); if (!closestUnit || dist < closestDist) { closestUnit = unit; closestDist = dist; } } } return closestUnit; } void GameCommander::assignUnit(BWAPI::Unit unit, BWAPI::Unitset & set) { if (m_scoutUnits.contains(unit)) { m_scoutUnits.erase(unit); } else if (m_combatUnits.contains(unit)) { m_combatUnits.erase(unit); } set.insert(unit); } ================================================ FILE: UAlbertaBot/Source/GameCommander.h ================================================ #pragma once #include "Common.h" #include "CombatCommander.h" #include "TimerManager.h" namespace UAlbertaBot { class UnitToAssign { public: BWAPI::Unit unit; bool isAssigned = false; UnitToAssign(BWAPI::Unit u) : unit(u) { } }; class GameCommander { CombatCommander m_combatCommander; TimerManager m_timerManager; BWAPI::Unitset m_validUnits; BWAPI::Unitset m_combatUnits; BWAPI::Unitset m_scoutUnits; bool m_initialScoutSet = false; void assignUnit(BWAPI::Unit unit, BWAPI::Unitset & set); bool isAssigned(BWAPI::Unit unit) const; public: GameCommander(); void update(); void handleUnitAssignments(); void setValidUnits(); void setScoutUnits(); void setCombatUnits(); void drawDebugInterface(); void drawGameInformation(int x, int y); BWAPI::Unit getFirstSupplyProvider(); BWAPI::Unit getClosestUnitToTarget(BWAPI::UnitType type, BWAPI::Position target); BWAPI::Unit getClosestWorkerToTarget(BWAPI::Position target); void onUnitShow(BWAPI::Unit unit); void onUnitHide(BWAPI::Unit unit); void onUnitCreate(BWAPI::Unit unit); void onUnitComplete(BWAPI::Unit unit); void onUnitRenegade(BWAPI::Unit unit); void onUnitDestroy(BWAPI::Unit unit); void onUnitMorph(BWAPI::Unit unit); }; } ================================================ FILE: UAlbertaBot/Source/Global.cpp ================================================ #include "Global.h" #include "MapTools.h" #include "InformationManager.h" #include "BaseLocationManager.h" #include "WorkerManager.h" #include "StrategyManager.h" #include "BOSSManager.h" #include "ProductionManager.h" #include "BuildingManager.h" #include "ScoutManager.h" #include "BuildingPlacerManager.h" using namespace UAlbertaBot; Global::Global() { init(); } Global & Global::Instance() { static Global instance; return instance; } void Global::init() { reset(m_mapTools); reset(m_informationManager); reset(m_workerManager); reset(m_productionManager); reset(m_baseLocationManager); reset(m_strategyManager); reset(m_scoutManager); } void Global::GameStart() { Instance().init(); } MapTools & Global::Map() { return *get(Instance().m_mapTools); } BaseLocationManager & Global::Bases() { return *get(Instance().m_baseLocationManager); } InformationManager & Global::Info() { return *get(Instance().m_informationManager); } StrategyManager & Global::Strategy() { return *get(Instance().m_strategyManager); } WorkerManager & Global::Workers() { return *get(Instance().m_workerManager); } ProductionManager & Global::Production() { return *get(Instance().m_productionManager); } ScoutManager & Global::Scout() { return *get(Instance().m_scoutManager); } ================================================ FILE: UAlbertaBot/Source/Global.h ================================================ #pragma once #include namespace UAlbertaBot { class MapTools; class BaseLocationManager; class InformationManager; class StrategyManager; class WorkerManager; class ProductionManager; class ScoutManager; class Global { MapTools * m_mapTools = nullptr; BaseLocationManager * m_baseLocationManager = nullptr; InformationManager * m_informationManager = nullptr; StrategyManager * m_strategyManager = nullptr; WorkerManager * m_workerManager = nullptr; ProductionManager * m_productionManager = nullptr; ScoutManager * m_scoutManager = nullptr; template void reset(T *& ptr) { delete ptr; ptr = nullptr; } template static T * get(T *& ptr) { if (ptr == nullptr) { ptr = new T(); } return ptr; } Global(); static Global & Instance(); void init(); public: static void GameStart(); static MapTools & Map(); static BaseLocationManager & Bases(); static InformationManager & Info(); static StrategyManager & Strategy(); static WorkerManager & Workers(); static ProductionManager & Production(); static ScoutManager & Scout(); }; } ================================================ FILE: UAlbertaBot/Source/Grid.hpp ================================================ #pragma once #include // WARNING: ONLY USE THIS FOR BASE TYPES, IT COPIES namespace UAlbertaBot { template class Grid { size_t m_width = 0; size_t m_height = 0; std::vector> m_grid; public: Grid() {} Grid(size_t width, size_t height, T val) : m_width(width) , m_height(height) , m_grid(width, std::vector(height, val)) { } inline T get(size_t x, size_t y) { return m_grid[x][y]; } inline const T get(size_t x, size_t y) const { return m_grid[x][y]; } inline void set(size_t x, size_t y, T val) { m_grid[x][y] = val; } inline size_t width() const { return m_width; } inline size_t height() const { return m_height; } }; } ================================================ FILE: UAlbertaBot/Source/InformationManager.cpp ================================================ #include "Common.h" #include "InformationManager.h" #include "UnitData.h" using namespace UAlbertaBot; InformationManager::InformationManager() { update(); } void InformationManager::update() { updateUnitInfo(); } void InformationManager::updateUnitInfo() { PROFILE_FUNCTION(); for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { updateUnit(unit); } for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { updateUnit(unit); } // remove bad enemy units m_unitData[BWAPI::Broodwar->enemy()].removeBadUnits(); m_unitData[BWAPI::Broodwar->self()].removeBadUnits(); } const UIMap & InformationManager::getUnitInfo(BWAPI::Player player) const { return getUnitData(player).getUnits(); } void InformationManager::drawExtendedInterface() { if (!Config::Debug::DrawUnitHealthBars) { return; } int verticalOffset = -10; // draw enemy units for (const auto & kv : getUnitData(BWAPI::Broodwar->enemy()).getUnits()) { const UnitInfo & ui(kv.second); BWAPI::UnitType type(ui.type); int hitPoints = ui.lastHealth; int shields = ui.lastShields; const BWAPI::Position & pos = ui.lastPosition; int left = pos.x - type.dimensionLeft(); int right = pos.x + type.dimensionRight(); int top = pos.y - type.dimensionUp(); int bottom = pos.y + type.dimensionDown(); if (!BWAPI::Broodwar->isVisible(BWAPI::TilePosition(ui.lastPosition))) { BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false); BWAPI::Broodwar->drawTextMap(BWAPI::Position(left + 3, top + 4), "%s", ui.type.getName().c_str()); } if (!type.isResourceContainer() && type.maxHitPoints() > 0) { double hpRatio = (double)hitPoints / (double)type.maxHitPoints(); BWAPI::Color hpColor = BWAPI::Colors::Green; if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange; if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red; int ratioRight = left + (int)((right-left) * hpRatio); int hpTop = top + verticalOffset; int hpBottom = top + 4 + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right-1; i+=ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } if (!type.isResourceContainer() && type.maxShields() > 0) { double shieldRatio = (double)shields / (double)type.maxShields(); int ratioRight = left + (int)((right-left) * shieldRatio); int hpTop = top - 3 + verticalOffset; int hpBottom = top + 1 + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right-1; i+=ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } } // draw neutral units and our units for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if (unit->getPlayer() == BWAPI::Broodwar->enemy()) { continue; } const BWAPI::Position & pos = unit->getPosition(); int left = pos.x - unit->getType().dimensionLeft(); int right = pos.x + unit->getType().dimensionRight(); int top = pos.y - unit->getType().dimensionUp(); int bottom = pos.y + unit->getType().dimensionDown(); //BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false); if (!unit->getType().isResourceContainer() && unit->getType().maxHitPoints() > 0) { double hpRatio = (double)unit->getHitPoints() / (double)unit->getType().maxHitPoints(); BWAPI::Color hpColor = BWAPI::Colors::Green; if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange; if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red; int ratioRight = left + (int)((right-left) * hpRatio); int hpTop = top + verticalOffset; int hpBottom = top + 4 + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right-1; i+=ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } if (!unit->getType().isResourceContainer() && unit->getType().maxShields() > 0) { double shieldRatio = (double)unit->getShields() / (double)unit->getType().maxShields(); int ratioRight = left + (int)((right-left) * shieldRatio); int hpTop = top - 3 + verticalOffset; int hpBottom = top + 1 + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right-1; i+=ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } if (unit->getType().isResourceContainer() && unit->getInitialResources() > 0) { double mineralRatio = (double)unit->getResources() / (double)unit->getInitialResources(); int ratioRight = left + (int)((right-left) * mineralRatio); int hpTop = top + verticalOffset; int hpBottom = top + 4 + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Cyan, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right-1; i+=ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } } } void InformationManager::drawUnitInformation(int x, int y) { if (!Config::Debug::DrawEnemyUnitInfo) { return; } std::string prefix = "\x04"; BWAPI::Broodwar->drawTextScreen(x, y-10, "\x03 Self Loss:\x04 Minerals: \x1f%d \x04Gas: \x07%d", m_unitData[BWAPI::Broodwar->self()].getMineralsLost(), m_unitData[BWAPI::Broodwar->self()].getGasLost()); BWAPI::Broodwar->drawTextScreen(x, y, "\x03 Enemy Loss:\x04 Minerals: \x1f%d \x04Gas: \x07%d", m_unitData[BWAPI::Broodwar->enemy()].getMineralsLost(), m_unitData[BWAPI::Broodwar->enemy()].getGasLost()); BWAPI::Broodwar->drawTextScreen(x, y+10, "\x04 Enemy: %s", BWAPI::Broodwar->enemy()->getName().c_str()); BWAPI::Broodwar->drawTextScreen(x, y+20, "\x04 UNIT NAME"); BWAPI::Broodwar->drawTextScreen(x+140, y+20, "\x04#"); BWAPI::Broodwar->drawTextScreen(x+160, y+20, "\x04X"); int yspace = 0; // for each unit in the queue for (BWAPI::UnitType t : BWAPI::UnitTypes::allUnitTypes()) { int numUnits = m_unitData[BWAPI::Broodwar->enemy()].getNumUnits(t); int numDeadUnits = m_unitData[BWAPI::Broodwar->enemy()].getNumDeadUnits(t); // if there exist units in the vector if (numUnits > 0) { if (t.isDetector()) { prefix = "\x10"; } else if (t.canAttack()) { prefix = "\x08"; } else if (t.isBuilding()) { prefix = "\x03"; } else { prefix = "\x04"; } BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), " %s%s", prefix.c_str(), t.getName().c_str()); BWAPI::Broodwar->drawTextScreen(x+140, y+40+((yspace)*10), "%s%d", prefix.c_str(), numUnits); BWAPI::Broodwar->drawTextScreen(x+160, y+40+((yspace++)*10), "%s%d", prefix.c_str(), numDeadUnits); } } } void InformationManager::drawMapInformation() { if (!Config::Debug::DrawBWTAInfo) { return; } } void InformationManager::updateUnit(BWAPI::Unit unit) { if (!(unit->getPlayer() == BWAPI::Broodwar->self() || unit->getPlayer() == BWAPI::Broodwar->enemy())) { return; } m_unitData[unit->getPlayer()].updateUnit(unit); } // is the unit valid? bool InformationManager::isValidUnit(BWAPI::Unit unit) { // we only care about our units and enemy units if (unit->getPlayer() != BWAPI::Broodwar->self() && unit->getPlayer() != BWAPI::Broodwar->enemy()) { return false; } // if it's a weird unit, don't bother if (unit->getType() == BWAPI::UnitTypes::None || unit->getType() == BWAPI::UnitTypes::Unknown || unit->getType() == BWAPI::UnitTypes::Zerg_Larva || unit->getType() == BWAPI::UnitTypes::Zerg_Egg) { return false; } // if the position isn't valid throw it out if (!unit->getPosition().isValid()) { return false; } // s'all good baby baby return true; } void InformationManager::onUnitDestroy(BWAPI::Unit unit) { if (unit->getType().isNeutral()) { return; } m_unitData[unit->getPlayer()].removeUnit(unit); } bool InformationManager::isCombatUnit(BWAPI::UnitType type) const { if (type == BWAPI::UnitTypes::Zerg_Lurker/* || type == BWAPI::UnitTypes::Protoss_Dark_Templar*/) { return false; } // check for various types of combat units if (type.canAttack() || type == BWAPI::UnitTypes::Terran_Medic || type == BWAPI::UnitTypes::Protoss_Observer || type == BWAPI::UnitTypes::Terran_Bunker) { return true; } return false; } void InformationManager::getNearbyForce(std::vector & unitInfo, BWAPI::Position p, BWAPI::Player player, int radius) { bool hasBunker = false; // for each unit we know about for that player for (const auto & kv : getUnitData(player).getUnits()) { const UnitInfo & ui(kv.second); // if it's a combat unit we care about // and it's finished! if (isCombatUnit(ui.type) && ui.completed) { // determine its attack range int range = 0; if (ui.type.groundWeapon() != BWAPI::WeaponTypes::None) { range = ui.type.groundWeapon().maxRange() + 40; } // if it can attack into the radius we care about if (ui.lastPosition.getDistance(p) <= (radius + range)) { // add it to the vector unitInfo.push_back(ui); } } else if (ui.type.isDetector() && ui.lastPosition.getDistance(p) <= (radius + 250)) { // add it to the vector unitInfo.push_back(ui); } } } int InformationManager::getNumUnits(BWAPI::UnitType t, BWAPI::Player player) { return getUnitData(player).getNumUnits(t); } const UnitData & InformationManager::getUnitData(BWAPI::Player player) const { return m_unitData.find(player)->second; } bool InformationManager::enemyHasCloakedUnits() { for (const auto & kv : getUnitData(BWAPI::Broodwar->enemy()).getUnits()) { const UnitInfo & ui(kv.second); if (ui.type.isCloakable()) { return true; } // assume they're going dts if (ui.type == BWAPI::UnitTypes::Protoss_Citadel_of_Adun) { return true; } if (ui.type == BWAPI::UnitTypes::Protoss_Observatory) { return true; } } return false; } ================================================ FILE: UAlbertaBot/Source/InformationManager.h ================================================ #pragma once #include "Common.h" #include "UnitData.h" namespace UAlbertaBot { struct BaseInfo; typedef std::vector BaseInfoVector; class InformationManager { friend class Global; std::map m_unitData; void updateUnit(BWAPI::Unit unit); void updateUnitInfo(); bool isValidUnit(BWAPI::Unit unit); InformationManager(); public: void update(); // event driven stuff void onUnitShow(BWAPI::Unit unit) { updateUnit(unit); } void onUnitHide(BWAPI::Unit unit) { updateUnit(unit); } void onUnitCreate(BWAPI::Unit unit) { updateUnit(unit); } void onUnitComplete(BWAPI::Unit unit) { updateUnit(unit); } void onUnitMorph(BWAPI::Unit unit) { updateUnit(unit); } void onUnitRenegade(BWAPI::Unit unit) { updateUnit(unit); } void onUnitDestroy(BWAPI::Unit unit); int getNumUnits(BWAPI::UnitType type, BWAPI::Player player); bool isCombatUnit(BWAPI::UnitType type) const; void getNearbyForce(std::vector & unitInfo, BWAPI::Position p, BWAPI::Player player, int radius); bool enemyHasCloakedUnits(); void drawExtendedInterface(); void drawUnitInformation(int x, int y); void drawMapInformation(); const UIMap & getUnitInfo(BWAPI::Player player) const; const UnitData & getUnitData(BWAPI::Player player) const; }; } ================================================ FILE: UAlbertaBot/Source/JSONTools.cpp ================================================ #include "Common.h" #include "JSONTools.h" namespace UAlbertaBot { namespace JSONTools { void ReadBool(const char * key, const rapidjson::Value & value, bool & dest) { if (value.HasMember(key)) { UAB_ASSERT(value[key].IsBool(), "%s should be a bool", key); dest = value[key].GetBool(); } } void ReadString(const char * key, const rapidjson::Value & value, std::string & dest) { if (value.HasMember(key)) { UAB_ASSERT(value[key].IsString(), "%s should be a string", key); dest = value[key].GetString(); } } } } ================================================ FILE: UAlbertaBot/Source/JSONTools.h ================================================ #pragma once #include "rapidjson/rapidjson.h" #include "rapidjson/document.h" namespace UAlbertaBot { namespace JSONTools { template void ReadInt(const char * key, const rapidjson::Value & value, T & dest) { if (value.HasMember(key)) { UAB_ASSERT(value[key].IsInt(), "%s should be an int", key); dest = (T)value[key].GetInt(); } } void ReadBool(const char * key, const rapidjson::Value & value, bool & dest); void ReadString(const char * key, const rapidjson::Value & value, std::string & dest); } } ================================================ FILE: UAlbertaBot/Source/Logger.cpp ================================================ #include "Common.h" #include "Logger.h" #include "UABAssert.h" #include #include #include using namespace UAlbertaBot; void Logger::LogAppendToFile(const std::string & logFile, const std::string & msg) { std::ofstream logStream; logStream.open(logFile.c_str(), std::ofstream::app); logStream << msg; logStream.flush(); logStream.close(); } void Logger::LogAppendToFile(const std::string & logFile, const char *fmt, ...) { va_list arg; va_start(arg, fmt); //vfprintf(log_file, fmt, arg); char buff[256]; vsnprintf_s(buff, 256, fmt, arg); va_end(arg); std::ofstream logStream; logStream.open(logFile.c_str(), std::ofstream::app); logStream << buff; logStream.flush(); logStream.close(); } void Logger::LogOverwriteToFile(const std::string & logFile, const std::string & msg) { std::ofstream logStream(logFile.c_str()); logStream << msg; logStream.flush(); logStream.close(); } std::string FileUtils::ReadFile(const std::string & filename) { std::stringstream ss; FILE *file = fopen ( filename.c_str(), "r" ); if ( file != nullptr ) { char line [ 4096 ]; /* or other suitable maximum line size */ while ( fgets ( line, sizeof line, file ) != nullptr ) /* read a line */ { ss << line; } fclose ( file ); } else { BWAPI::Broodwar->printf("Could not open file: %s", filename.c_str()); } return ss.str(); } ================================================ FILE: UAlbertaBot/Source/Logger.h ================================================ #pragma once #include #include #include namespace UAlbertaBot { namespace Logger { void LogAppendToFile(const std::string & logFile, const std::string & msg); void LogAppendToFile(const std::string & logFile, const char *fmt, ...); void LogOverwriteToFile(const std::string & logFile, const std::string & msg); }; namespace FileUtils { std::string ReadFile(const std::string & filename); } } ================================================ FILE: UAlbertaBot/Source/MapTools.cpp ================================================ #include "MapTools.h" #include "BaseLocationManager.h" #include "Global.h" #include #include #include #include using namespace UAlbertaBot; const size_t LegalActions = 4; const int actionX[LegalActions] ={1, -1, 0, 0}; const int actionY[LegalActions] ={0, 0, 1, -1}; // constructor for MapTools MapTools::MapTools() { onStart(); } void MapTools::onStart() { PROFILE_FUNCTION(); m_width = BWAPI::Broodwar->mapWidth(); m_height = BWAPI::Broodwar->mapHeight(); m_walkable = Grid(m_width, m_height, 1); m_buildable = Grid(m_width, m_height, 0); m_depotBuildable = Grid(m_width, m_height, 0); m_lastSeen = Grid(m_width, m_height, 0); m_sectorNumber = Grid(m_width, m_height, 0); // Set the boolean grid data from the Map for (int x(0); x < m_width; ++x) { for (int y(0); y < m_height; ++y) { m_buildable.set(x, y, canBuild(x, y)); m_depotBuildable.set(x, y, canBuild(x, y)); m_walkable.set(x, y, m_buildable.get(x,y) || canWalk(x, y)); } } // set tiles that static resources are on as unbuildable for (auto & resource : BWAPI::Broodwar->getStaticNeutralUnits()) { if (!resource->getType().isResourceContainer()) { continue; } const int tileX = resource->getTilePosition().x; const int tileY = resource->getTilePosition().y; for (int x=tileX; xgetType().tileWidth(); ++x) { for (int y=tileY; ygetType().tileHeight(); ++y) { m_buildable.set(x, y, false); // depots can't be built within 3 tiles of any resource for (int rx=-3; rx<=3; rx++) { for (int ry=-3; ry<=3; ry++) { if (!BWAPI::TilePosition(x+rx, y+ry).isValid()) { continue; } m_depotBuildable.set(x+rx, y+ry, 0); } } } } } // compute the map connectivity computeConnectivity(); computeMap(); } void MapTools::onFrame() { PROFILE_FUNCTION(); for (int x=0; x 0) { return; } m_map = StarDraftMap(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight()); for (size_t x = 0; x < m_map.width(); x++) { for (size_t y = 0; y < m_map.height(); y++) { if (isDepotBuildableTile(x, y)) { m_map.set(x, y, TileType::BuildAll); } else if (isBuildable(x, y)) { m_map.set(x, y, TileType::NoDepot); } else if (isWalkable(x, y)) { m_map.set(x, y, TileType::Walk); } else { m_map.set(x, y, TileType::Unwalkable); } } } for (auto & mineral : BWAPI::Broodwar->getStaticMinerals()) { const BWAPI::TilePosition mineralTile(mineral->getPosition()); m_map.set(mineralTile.x, mineralTile.y, TileType::Mineral); m_map.set(mineralTile.x-1, mineralTile.y, TileType::Mineral); } for (auto & geyser : BWAPI::Broodwar->getStaticGeysers()) { const BWAPI::TilePosition geyserTile(geyser->getPosition()); m_map.set(geyserTile.x, geyserTile.y, TileType::Gas); m_map.set(geyserTile.x+1, geyserTile.y, TileType::Gas); m_map.set(geyserTile.x-1, geyserTile.y, TileType::Gas); m_map.set(geyserTile.x-2, geyserTile.y, TileType::Gas); m_map.set(geyserTile.x, geyserTile.y-1, TileType::Gas); m_map.set(geyserTile.x+1, geyserTile.y-1, TileType::Gas); m_map.set(geyserTile.x-1, geyserTile.y-1, TileType::Gas); m_map.set(geyserTile.x-2, geyserTile.y-1, TileType::Gas); } for (auto & tile : BWAPI::Broodwar->getStartLocations()) { m_map.addStartTile(tile.x, tile.y); } for (size_t x=0; x<4*m_map.width(); x++) { for (size_t y=0; y<4*m_map.height(); y++) { m_map.setWalk(x, y, BWAPI::Broodwar->isWalkable(x,y)); } } } void MapTools::computeConnectivity() { PROFILE_FUNCTION(); // the fringe data structe we will use to do our BFS searches std::vector> fringe; fringe.reserve(m_width*m_height); int sectorNumber = 0; // for every tile on the map, do a connected flood fill using BFS for (int x=0; xisExplored(tileX, tileY); } bool MapTools::isVisible(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return BWAPI::Broodwar->isVisible(BWAPI::TilePosition(tileX, tileY)); } bool MapTools::isPowered(int tileX, int tileY) const { return BWAPI::Broodwar->hasPower(BWAPI::TilePosition(tileX, tileY)); } int MapTools::getGroundDistance(const BWAPI::Position & src, const BWAPI::Position & dest) const { if (m_allMaps.size() > 50) { m_allMaps.clear(); } return getDistanceMap(dest).getDistance(src); } const DistanceMap & MapTools::getDistanceMap(const BWAPI::Position & pos) const { return getDistanceMap(BWAPI::TilePosition(pos)); } const DistanceMap & MapTools::getDistanceMap(const BWAPI::TilePosition & tile) const { std::pair pairTile(tile.x, tile.y); if (m_allMaps.find(pairTile) == m_allMaps.end()) { m_allMaps[pairTile] = DistanceMap(); m_allMaps[pairTile].computeDistanceMap(tile); } return m_allMaps[pairTile]; } int MapTools::getSectorNumber(int x, int y) const { if (!isValidTile(x, y)) { return 0; } return m_sectorNumber.get(x, y); } bool MapTools::isValidTile(int tileX, int tileY) const { return tileX >= 0 && tileY >= 0 && tileX < m_width && tileY < m_height; } bool MapTools::isValidTile(const BWAPI::TilePosition & tile) const { return isValidTile(tile.x, tile.y); } bool MapTools::isValidPosition(const BWAPI::Position & pos) const { return isValidTile(BWAPI::TilePosition(pos)); } bool MapTools::isConnected(int x1, int y1, int x2, int y2) const { if (!isValidTile(x1, y1) || !isValidTile(x2, y2)) { return false; } const int s1 = getSectorNumber(x1, y1); const int s2 = getSectorNumber(x2, y2); return s1 != 0 && (s1 == s2); } bool MapTools::isConnected(const BWAPI::TilePosition & p1, const BWAPI::TilePosition & p2) const { return isConnected(p1.x, p1.y, p2.x, p2.y); } bool MapTools::isConnected(const BWAPI::Position & p1, const BWAPI::Position & p2) const { return isConnected(BWAPI::TilePosition(p1), BWAPI::TilePosition(p2)); } bool MapTools::isBuildable(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_buildable.get(tileX, tileY); } bool MapTools::canBuildTypeAtPosition(int tileX, int tileY, const BWAPI::UnitType & type) const { return BWAPI::Broodwar->canBuildHere(BWAPI::TilePosition(tileX, tileY), type); } bool MapTools::isBuildable(const BWAPI::TilePosition & tile) const { return isBuildable(tile.x, tile.y); } void MapTools::printMap() const { std::stringstream ss; for (int y(0); y < m_height; ++y) { for (int x(0); x < m_width; ++x) { ss << isWalkable(x, y); } ss << "\n"; } std::ofstream out("map.txt"); out << ss.str(); out.close(); } bool MapTools::isDepotBuildableTile(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_depotBuildable.get(tileX, tileY); } bool MapTools::isWalkable(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_walkable.get(tileX, tileY); } bool MapTools::isWalkable(const BWAPI::TilePosition & tile) const { return isWalkable(tile.x, tile.y); } int MapTools::width() const { return m_width; } int MapTools::height() const { return m_height; } void MapTools::drawTile(int tileX, int tileY, const BWAPI::Color & color) const { const int padding = 2; const int px = tileX*32 + padding; const int py = tileY*32 + padding; const int d = 32 - 2*padding; BWAPI::Broodwar->drawLineMap(px, py, px + d, py, color); BWAPI::Broodwar->drawLineMap(px + d, py, px + d, py + d, color); BWAPI::Broodwar->drawLineMap(px + d, py + d, px, py + d, color); BWAPI::Broodwar->drawLineMap(px, py + d, px, py, color); } const std::vector & MapTools::getClosestTilesTo(const BWAPI::TilePosition & tilePos) const { return getDistanceMap(tilePos).getSortedTiles(); } const std::vector & MapTools::getClosestTilesTo(const BWAPI::Position & pos) const { return getClosestTilesTo(BWAPI::TilePosition(pos)); } BWAPI::TilePosition MapTools::getLeastRecentlySeenTile() const { int minSeen = std::numeric_limits::max(); BWAPI::TilePosition leastSeen; const BaseLocation * baseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->self()); UAB_ASSERT(baseLocation, "Null self baselocation is insanely bad"); for (auto & tile : baseLocation->getClosestTiles()) { UAB_ASSERT(isValidTile(tile), "How is this tile not valid?"); const int lastSeen = m_lastSeen.get(tile.x, tile.y); if (lastSeen < minSeen) { minSeen = lastSeen; leastSeen = tile; } } return leastSeen; } bool MapTools::canWalk(int tileX, int tileY) const { for (int i=0; i<4; ++i) { for (int j=0; j<4; ++j) { if (!BWAPI::Broodwar->isWalkable(tileX*4 + i, tileY*4 + j)) { return false; } } } return true; } bool MapTools::canBuild(int tileX, int tileY) const { return BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tileX, tileY)); } void MapTools::draw() const { const BWAPI::TilePosition screen(BWAPI::Broodwar->getScreenPosition()); const int sx = screen.x; const int sy = screen.y; const int ex = sx + 20; const int ey = sy + 15; for (int x = sx; x < ex; ++x) { for (int y = sy; y < ey; y++) { const BWAPI::TilePosition tilePos(x,y); if (!tilePos.isValid()) { continue; } if (Config::Debug::DrawWalkableSectors) { std::stringstream ss; ss << getSectorNumber(x, y); const BWAPI::Position pos = BWAPI::Position(tilePos) + BWAPI::Position(14,9); BWAPI::Broodwar->drawTextMap(pos, ss.str().c_str()); } if (Config::Debug::DrawTileInfo) { BWAPI::Color color = isWalkable(x, y) ? BWAPI::Color(0, 255, 0) : BWAPI::Color(255, 0, 0); if (isWalkable(x, y) && !isBuildable(x, y)) { color = BWAPI::Color(255, 255, 0); } if (isBuildable(x, y) && !isDepotBuildableTile(x, y)) { color = BWAPI::Color(127, 255, 255); } drawTile(x, y, color); } } } } void MapTools::getUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits) { const int radiusSq(radius * radius); if (ourUnits) { for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { BWAPI::Position d(unit->getPosition() - center); if(d.x * d.x + d.y * d.y <= radiusSq) { if (!units.contains(unit)) { units.insert(unit); } } } } if (oppUnits) { for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Unknown || !unit->isVisible()) { continue; } BWAPI::Position d(unit->getPosition() - center); if(d.x * d.x + d.y * d.y <= radiusSq) { if (!units.contains(unit)) { units.insert(unit); } } } } } const StarDraftMap & MapTools::getStarDraftMap() const { return m_map; } void MapTools::saveMapToFile(const std::string & path) const { // replace spaces with underscores std::string mapFile = BWAPI::Broodwar->mapFileName(); std::replace( mapFile.begin(), mapFile.end(), ' ', '_'); getStarDraftMap().save(mapFile + ".txt"); } ================================================ FILE: UAlbertaBot/Source/MapTools.h ================================================ #pragma once #include #include "DistanceMap.h" #include "Grid.hpp" #include "stardraft/StarDraft.h" namespace UAlbertaBot { class MapTools { friend class Global; StarDraftMap m_map; int m_width = 0; int m_height = 0; int m_frame = 0; // a cache of already computed distance maps, which is mutable since it only acts as a cache mutable std::map, DistanceMap> m_allMaps; Grid m_walkable; // whether a tile is buildable (includes static resources) Grid m_buildable; // whether a tile is buildable (includes static resources) Grid m_depotBuildable; // whether a depot is buildable on a tile (illegal within 3 tiles of static resource) Grid m_lastSeen; // the last time any of our units has seen this position on the map Grid m_sectorNumber; // connectivity sector number, two tiles are ground connected if they have the same number void computeMap(); void computeConnectivity(); int getSectorNumber(int x, int y) const; void printMap() const; bool canBuild(int tileX, int tileY) const; bool canWalk(int tileX, int tileY) const; MapTools(); public: void onStart(); void onFrame(); void draw() const; int width() const; int height() const; bool isValidTile(int tileX, int tileY) const; bool isValidTile(const BWAPI::TilePosition & tile) const; bool isValidPosition(const BWAPI::Position & pos) const; bool isPowered(int tileX, int tileY) const; bool isExplored(int tileX, int tileY) const; bool isExplored(const BWAPI::Position & pos) const; bool isExplored(const BWAPI::TilePosition & pos) const; bool isVisible(int tileX, int tileY) const; bool canBuildTypeAtPosition(int tileX, int tileY, const BWAPI::UnitType & type) const; void drawTile(int tileX, int tileY, const BWAPI::Color & color) const; const DistanceMap & getDistanceMap(const BWAPI::TilePosition & tile) const; const DistanceMap & getDistanceMap(const BWAPI::Position & tile) const; int getGroundDistance(const BWAPI::Position & src, const BWAPI::Position & dest) const; bool isConnected(int x1, int y1, int x2, int y2) const; bool isConnected(const BWAPI::TilePosition & from, const BWAPI::TilePosition & to) const; bool isConnected(const BWAPI::Position & from, const BWAPI::Position & to) const; bool isWalkable(int tileX, int tileY) const; bool isWalkable(const BWAPI::TilePosition & tile) const; bool isBuildable(int tileX, int tileY) const; bool isBuildable(const BWAPI::TilePosition & tile) const; bool isDepotBuildableTile(int tileX, int tileY) const; void getUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits); const StarDraftMap & getStarDraftMap() const; void saveMapToFile(const std::string & path) const; BWAPI::TilePosition getLeastRecentlySeenTile() const; // returns a list of all tiles on the map, sorted by 4-direcitonal walk distance from the given position const std::vector & getClosestTilesTo(const BWAPI::TilePosition & tilePos) const; const std::vector & getClosestTilesTo(const BWAPI::Position & pos) const; }; } ================================================ FILE: UAlbertaBot/Source/MedicManager.cpp ================================================ #include "Common.h" #include "MedicManager.h" #include "UnitUtil.h" #include "Micro.h" using namespace UAlbertaBot; MedicManager::MedicManager() { } void MedicManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & medics = getUnits(); // create a set of all medic targets BWAPI::Unitset medicTargets; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getHitPoints() < unit->getInitialHitPoints() && !unit->getType().isMechanical() && !unit->getType().isBuilding()) { medicTargets.insert(unit); } } BWAPI::Unitset availableMedics(medics); // for each target, send the closest medic to heal it for (auto & target : medicTargets) { // only one medic can heal a target at a time if (target->isBeingHealed()) { continue; } double closestMedicDist = std::numeric_limits::infinity(); BWAPI::Unit closestMedic = nullptr; for (auto & medic : availableMedics) { double dist = medic->getDistance(target); if (!closestMedic || (dist < closestMedicDist)) { closestMedic = medic; closestMedicDist = dist; } } // if we found a medic, send it to heal the target if (closestMedic) { closestMedic->useTech(BWAPI::TechTypes::Healing, target); availableMedics.erase(closestMedic); } // otherwise we didn't find a medic which means they're all in use so break else { break; } } // the remaining medics should head to the squad order position for (auto & medic : availableMedics) { Micro::SmartAttackMove(medic, m_order.getPosition()); } } ================================================ FILE: UAlbertaBot/Source/MedicManager.h ================================================ #pragma once #include "MicroManager.h" namespace UAlbertaBot { class MedicManager : public MicroManager { public: MedicManager(); void executeMicro(const BWAPI::Unitset & targets); }; } ================================================ FILE: UAlbertaBot/Source/MeleeManager.cpp ================================================ #include "MeleeManager.h" #include "UnitUtil.h" #include "Micro.h" using namespace UAlbertaBot; MeleeManager::MeleeManager() { } void MeleeManager::executeMicro(const BWAPI::Unitset & targets) { assignTargetsOld(targets); } void MeleeManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & meleeUnits = getUnits(); // figure out targets BWAPI::Unitset meleeUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType().isFlyer()) && !(target->isLifted()) && !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && target->isVisible()) { meleeUnitTargets.insert(target); } } // for each meleeUnit for (auto & meleeUnit : meleeUnits) { // if the order is to attack or defend if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend) { // run away if we meet the retreat critereon if (meleeUnitShouldRetreat(meleeUnit, targets)) { BWAPI::Position fleeTo(BWAPI::Broodwar->self()->getStartLocation()); Micro::SmartMove(meleeUnit, fleeTo); } // if there are targets else if (!meleeUnitTargets.empty()) { // find the best target for this meleeUnit BWAPI::Unit target = getTarget(meleeUnit, meleeUnitTargets); // attack it Micro::SmartAttackUnit(meleeUnit, target); } // if there are no targets else { // if we're not near the order position if (meleeUnit->getDistance(m_order.getPosition()) > 100) { // move to it Micro::SmartMove(meleeUnit, m_order.getPosition()); } } } if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(meleeUnit->getPosition().x, meleeUnit->getPosition().y, meleeUnit->getTargetPosition().x, meleeUnit->getTargetPosition().y, Config::Debug::ColorLineTarget); } } } std::pair MeleeManager::findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets) { std::pair closestPair(nullptr, nullptr); double closestDistance = std::numeric_limits::max(); for (auto & attacker : attackers) { BWAPI::Unit target = getTarget(attacker, targets); double dist = attacker->getDistance(attacker); if (!closestPair.first || (dist < closestDistance)) { closestPair.first = attacker; closestPair.second = target; closestDistance = dist; } } return closestPair; } // get a target for the meleeUnit to attack BWAPI::Unit MeleeManager::getTarget(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets) { int highPriority = 0; double closestDist = std::numeric_limits::infinity(); BWAPI::Unit closestTarget = nullptr; // for each target possiblity for (auto & unit : targets) { int priority = getAttackPriority(meleeUnit, unit); int distance = meleeUnit->getDistance(unit); // if it's a higher priority, or it's closer, set it if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist)) { closestDist = distance; highPriority = priority; closestTarget = unit; } } return closestTarget; } // get the attack priority of a type in relation to a zergling int MeleeManager::getAttackPriority(BWAPI::Unit attacker, BWAPI::Unit unit) { BWAPI::UnitType type = unit->getType(); if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar && unit->getType() == BWAPI::UnitTypes::Terran_Missile_Turret && (BWAPI::Broodwar->self()->deadUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) == 0)) { return 13; } if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar && unit->getType().isWorker()) { return 12; } // highest priority is something that can attack us or aid in combat if (type == BWAPI::UnitTypes::Terran_Bunker) { return 11; } else if (type == BWAPI::UnitTypes::Terran_Medic || (type.groundWeapon() != BWAPI::WeaponTypes::None && !type.isWorker()) || type == BWAPI::UnitTypes::Terran_Bunker || type == BWAPI::UnitTypes::Protoss_High_Templar || type == BWAPI::UnitTypes::Protoss_Reaver || (type.isWorker() && unitNearChokepoint(unit))) { return 10; } // next priority is worker else if (type.isWorker()) { return 9; } // next is special buildings else if (type == BWAPI::UnitTypes::Zerg_Spawning_Pool) { return 5; } // next is special buildings else if (type == BWAPI::UnitTypes::Protoss_Pylon) { return 5; } // next is buildings that cost gas else if (type.gasPrice() > 0) { return 4; } else if (type.mineralPrice() > 0) { return 3; } // then everything else else { return 1; } } BWAPI::Unit MeleeManager::closestMeleeUnit(BWAPI::Unit target, const BWAPI::Unitset & meleeUnitsToAssign) { double minDistance = 0; BWAPI::Unit closest = nullptr; for (auto & meleeUnit : meleeUnitsToAssign) { double distance = meleeUnit->getDistance(target); if (!closest || distance < minDistance) { minDistance = distance; closest = meleeUnit; } } return closest; } bool MeleeManager::meleeUnitShouldRetreat(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets) { // terran don't regen so it doesn't make any sense to retreat if (meleeUnit->getType().getRace() == BWAPI::Races::Terran) { return false; } // we don't want to retreat the melee unit if its shields or hit points are above the threshold set in the config file // set those values to zero if you never want the unit to retreat from combat individually if (meleeUnit->getShields() > Config::Micro::RetreatMeleeUnitShields || meleeUnit->getHitPoints() > Config::Micro::RetreatMeleeUnitHP) { return false; } // if there is a ranged enemy unit within attack range of this melee unit then we shouldn't bother retreating since it could fire and kill it anyway for (auto & unit : targets) { int groundWeaponRange = unit->getType().groundWeapon().maxRange(); if (groundWeaponRange >= 64 && unit->getDistance(meleeUnit) < groundWeaponRange) { return false; } } return true; } // still has bug in it somewhere, use Old version void MeleeManager::assignTargetsNew(const BWAPI::Unitset & targets) { const BWAPI::Unitset & meleeUnits = getUnits(); // figure out targets BWAPI::Unitset meleeUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType().isFlyer()) && !(target->isLifted()) && !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && target->isVisible()) { meleeUnitTargets.insert(target); } } BWAPI::Unitset meleeUnitsToAssign(meleeUnits); std::map attackersAssigned; for (auto & unit : meleeUnitTargets) { attackersAssigned[unit] = 0; } int smallThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 3 : 1; int bigThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 12 : 3; // keep assigning targets while we have attackers and targets remaining while (!meleeUnitsToAssign.empty() && !meleeUnitTargets.empty()) { auto attackerAssignment = findClosestUnitPair(meleeUnitsToAssign, meleeUnitTargets); BWAPI::Unit & attacker = attackerAssignment.first; BWAPI::Unit & target = attackerAssignment.second; UAB_ASSERT_WARNING(attacker, "We should have chosen an attacker!"); if (!attacker) { break; } if (!target) { Micro::SmartMove(attacker, m_order.getPosition()); continue; } Micro::SmartAttackUnit(attacker, target); // update the number of units assigned to attack the target we found int & assigned = attackersAssigned[attackerAssignment.second]; assigned++; // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned >= smallThreshold)) { meleeUnitTargets.erase(target); } // if it's a building and there's more than 10 things assigned to it already, don't assign more else if (assigned > bigThreshold) { meleeUnitTargets.erase(target); } meleeUnitsToAssign.erase(attacker); } // if there's no targets left, attack move to the order destination if (meleeUnitTargets.empty()) { for (auto & unit : meleeUnitsToAssign) { if (unit->getDistance(m_order.getPosition()) > 100) { // move to it Micro::SmartMove(unit, m_order.getPosition()); BWAPI::Broodwar->drawLineMap(unit->getPosition(), m_order.getPosition(), BWAPI::Colors::Yellow); } } } } ================================================ FILE: UAlbertaBot/Source/MeleeManager.h ================================================ #pragma once #include "MicroManager.h" namespace UAlbertaBot { class MeleeManager : public MicroManager { public: MeleeManager(); void executeMicro(const BWAPI::Unitset & targets); void assignTargetsNew(const BWAPI::Unitset & targets); void assignTargetsOld(const BWAPI::Unitset & targets); int getAttackPriority(BWAPI::Unit attacker, BWAPI::Unit unit); bool meleeUnitShouldRetreat(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets); BWAPI::Unit closestMeleeUnit(BWAPI::Unit target, const BWAPI::Unitset & meleeUnitToAssign); BWAPI::Unit getTarget(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets); std::pair findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets); }; } ================================================ FILE: UAlbertaBot/Source/MetaType.cpp ================================================ #include "MetaType.h" using namespace UAlbertaBot; MetaType::MetaType () { } MetaType::MetaType(const std::string & name) { std::string inputName(name); std::replace(inputName.begin(), inputName.end(), '_', ' '); for (const BWAPI::UnitType & unitType : BWAPI::UnitTypes::allUnitTypes()) { // check to see if the names match exactly std::string typeName = unitType.getName(); std::replace(typeName.begin(), typeName.end(), '_', ' '); if (typeName == inputName) { *this = MetaType(unitType); return; } // check to see if the names match without the race prefix const std::string & raceName = unitType.getRace().getName(); if ((typeName.length() > raceName.length()) && (typeName.compare(raceName.length() + 1, typeName.length(), inputName) == 0)) { *this = MetaType(unitType); return; } } for (const BWAPI::TechType & techType : BWAPI::TechTypes::allTechTypes()) { std::string typeName = techType.getName(); std::replace(typeName.begin(), typeName.end(), '_', ' '); if (typeName == inputName) { *this = MetaType(techType); return; } } for (const BWAPI::UpgradeType & upgradeType : BWAPI::UpgradeTypes::allUpgradeTypes()) { std::string typeName = upgradeType.getName(); std::replace(typeName.begin(), typeName.end(), '_', ' '); if (typeName == inputName) { *this = MetaType(upgradeType); return; } } UAB_ASSERT_WARNING(false, "Could not find MetaType with name: %s", name.c_str()); } MetaType::MetaType (BWAPI::UnitType t) : m_unitType(t) , m_type(MetaTypes::Unit) , m_race(t.getRace()) { } MetaType::MetaType (BWAPI::TechType t) : m_techType(t) , m_type(MetaTypes::Tech) , m_race(t.getRace()) { } MetaType::MetaType (BWAPI::UpgradeType t) : m_upgradeType(t) , m_type(MetaTypes::Upgrade) , m_race(t.getRace()) { } const size_t & MetaType::type() const { return m_type; } bool MetaType::isUnit() const { return m_type == MetaTypes::Unit; } bool MetaType::isTech() const { return m_type == MetaTypes::Tech; } bool MetaType::isUpgrade() const { return m_type == MetaTypes::Upgrade; } bool MetaType::isCommand() const { return m_type == MetaTypes::Command; } const BWAPI::Race & MetaType::getRace() const { return m_race; } bool MetaType::isBuilding() const { return m_type == MetaTypes::Unit && m_unitType.isBuilding(); } bool MetaType::isRefinery() const { return isBuilding() && m_unitType.isRefinery(); } const BWAPI::UnitType & MetaType::getUnitType() const { return m_unitType; } const BWAPI::TechType & MetaType::getTechType() const { return m_techType; } const BWAPI::UpgradeType & MetaType::getUpgradeType() const { return m_upgradeType; } int MetaType::supplyRequired() { if (isUnit()) { return m_unitType.supplyRequired(); } else { return 0; } } int MetaType::mineralPrice() const { return isUnit() ? m_unitType.mineralPrice() : (isTech() ? m_techType.mineralPrice() : m_upgradeType.mineralPrice()); } int MetaType::gasPrice() const { return isUnit() ? m_unitType.gasPrice() : (isTech() ? m_techType.gasPrice() : m_upgradeType.gasPrice()); } BWAPI::UnitType MetaType::whatBuilds() const { return isUnit() ? m_unitType.whatBuilds().first : (isTech() ? m_techType.whatResearches() : m_upgradeType.whatUpgrades()); } std::string MetaType::getName() const { if (isUnit()) { return m_unitType.getName(); } else if (isTech()) { return m_techType.getName(); } else if (isUpgrade()) { return m_upgradeType.getName(); } else { UAB_ASSERT(false, "MetaType not found"); return "LOL"; } } ================================================ FILE: UAlbertaBot/Source/MetaType.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { namespace MetaTypes { enum { Unit, Tech, Upgrade, Command, Default }; } class MetaType { size_t m_type = MetaTypes::Default; BWAPI::Race m_race = BWAPI::Races::None; BWAPI::UnitType m_unitType; BWAPI::TechType m_techType; BWAPI::UpgradeType m_upgradeType; public: MetaType (); MetaType (const std::string & name); MetaType (BWAPI::UnitType t); MetaType (BWAPI::TechType t); MetaType (BWAPI::UpgradeType t); bool isUnit() const; bool isTech() const; bool isUpgrade() const; bool isCommand() const; bool isBuilding() const; bool isRefinery() const; const size_t & type() const; const BWAPI::Race & getRace() const; const BWAPI::UnitType & getUnitType() const; const BWAPI::TechType & getTechType() const; const BWAPI::UpgradeType & getUpgradeType() const; int supplyRequired(); int mineralPrice() const; int gasPrice() const; BWAPI::UnitType whatBuilds() const; std::string getName() const; }; typedef std::pair MetaPair; typedef std::vector MetaPairVector; } ================================================ FILE: UAlbertaBot/Source/Micro.cpp ================================================ #include "Common.h" #include "Micro.h" #include "UnitUtil.h" using namespace UAlbertaBot; size_t TotalCommands = 0; const int dotRadius = 2; void Micro::SmartAttackUnit(BWAPI::Unit attacker, BWAPI::Unit target) { UAB_ASSERT(attacker, "SmartAttackUnit: Attacker not valid"); UAB_ASSERT(target, "SmartAttackUnit: Target not valid"); if (!attacker || !target) { return; } // if we have issued a command to this unit already this frame, ignore this one if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); // if we've already told this unit to attack this target, ignore this command if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit && currentCommand.getTarget() == target) { return; } // if nothing prevents it, attack the target attacker->attack(target); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::Red, true); BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Red, true); BWAPI::Broodwar->drawLineMap(attacker->getPosition(), target->getPosition(), BWAPI::Colors::Red); } } void Micro::SmartAttackMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition) { //UAB_ASSERT(attacker, "SmartAttackMove: Attacker not valid"); //UAB_ASSERT(targetPosition.isValid(), "SmartAttackMove: targetPosition not valid"); if (!attacker || !targetPosition.isValid()) { return; } // if we have issued a command to this unit already this frame, ignore this one if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); // if we've already told this unit to attack this target, ignore this command if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Move && currentCommand.getTargetPosition() == targetPosition) { return; } // if nothing prevents it, attack the target attacker->attack(targetPosition); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::Orange, true); BWAPI::Broodwar->drawCircleMap(targetPosition, dotRadius, BWAPI::Colors::Orange, true); BWAPI::Broodwar->drawLineMap(attacker->getPosition(), targetPosition, BWAPI::Colors::Orange); } } void Micro::SmartMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition) { //UAB_ASSERT(attacker, "SmartAttackMove: Attacker not valid"); //UAB_ASSERT(targetPosition.isValid(), "SmartAttackMove: targetPosition not valid"); if (!attacker || !targetPosition.isValid()) { return; } // if we have issued a command to this unit already this frame, ignore this one if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); // if we've already told this unit to move to this position, ignore this command if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Move) && (currentCommand.getTargetPosition() == targetPosition) && attacker->isMoving()) { return; } // if nothing prevents it, attack the target attacker->move(targetPosition); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::White, true); BWAPI::Broodwar->drawCircleMap(targetPosition, dotRadius, BWAPI::Colors::White, true); BWAPI::Broodwar->drawLineMap(attacker->getPosition(), targetPosition, BWAPI::Colors::White); } } void Micro::SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target) { UAB_ASSERT(unit, "SmartRightClick: Unit not valid"); UAB_ASSERT(target, "SmartRightClick: Target not valid"); if (!unit || !target) { return; } // if we have issued a command to this unit already this frame, ignore this one if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || unit->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(unit->getLastCommand()); // if we've already told this unit to move to this position, ignore this command if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Right_Click_Unit) && (currentCommand.getTargetPosition() == target->getPosition())) { return; } // if nothing prevents it, attack the target unit->rightClick(target); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(unit->getPosition(), dotRadius, BWAPI::Colors::Cyan, true); BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Cyan, true); BWAPI::Broodwar->drawLineMap(unit->getPosition(), target->getPosition(), BWAPI::Colors::Cyan); } } void Micro::SmartLaySpiderMine(BWAPI::Unit unit, BWAPI::Position pos) { if (!unit) { return; } if (!unit->canUseTech(BWAPI::TechTypes::Spider_Mines, pos)) { return; } BWAPI::UnitCommand currentCommand(unit->getLastCommand()); // if we've already told this unit to move to this position, ignore this command if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Use_Tech_Position) && (currentCommand.getTargetPosition() == pos)) { return; } unit->canUseTechPosition(BWAPI::TechTypes::Spider_Mines, pos); } void Micro::SmartRepair(BWAPI::Unit unit, BWAPI::Unit target) { UAB_ASSERT(unit, "SmartRightClick: Unit not valid"); UAB_ASSERT(target, "SmartRightClick: Target not valid"); if (!unit || !target) { return; } // if we have issued a command to this unit already this frame, ignore this one if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || unit->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(unit->getLastCommand()); // if we've already told this unit to move to this position, ignore this command if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Repair) && (currentCommand.getTarget() == target)) { return; } // if nothing prevents it, attack the target unit->repair(target); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(unit->getPosition(), dotRadius, BWAPI::Colors::Cyan, true); BWAPI::Broodwar->drawCircleMap(target->getPosition(), dotRadius, BWAPI::Colors::Cyan, true); BWAPI::Broodwar->drawLineMap(unit->getPosition(), target->getPosition(), BWAPI::Colors::Cyan); } } void Micro::SmartKiteTarget(BWAPI::Unit rangedUnit, BWAPI::Unit target) { UAB_ASSERT(rangedUnit, "SmartKiteTarget: Unit not valid"); UAB_ASSERT(target, "SmartKiteTarget: Target not valid"); if (!rangedUnit || !target) { return; } double range(rangedUnit->getType().groundWeapon().maxRange()); if (rangedUnit->getType() == BWAPI::UnitTypes::Protoss_Dragoon && BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge)) { range = 6*32; } // determine whether the target can be kited bool kiteLonger = Config::Micro::KiteLongerRangedUnits.find(rangedUnit->getType()) != Config::Micro::KiteLongerRangedUnits.end(); if (!kiteLonger && (range <= target->getType().groundWeapon().maxRange())) { // if we can't kite it, there's no point Micro::SmartAttackUnit(rangedUnit, target); return; } bool kite(true); double dist(rangedUnit->getDistance(target)); double speed(rangedUnit->getType().topSpeed()); // if the unit can't attack back don't kite if ((rangedUnit->isFlying() && !UnitUtil::CanAttackAir(target)) || (!rangedUnit->isFlying() && !UnitUtil::CanAttackGround(target))) { //kite = false; } double timeToEnter = std::max(0.0, (dist - range) / speed); if ((timeToEnter >= rangedUnit->getGroundWeaponCooldown())) { kite = false; } if (target->getType().isBuilding()) { kite = false; } // if we can't shoot, run away if (kite) { BWAPI::Position fleePosition(rangedUnit->getPosition() - target->getPosition() + rangedUnit->getPosition()); //BWAPI::Broodwar->drawLineMap(rangedUnit->getPosition(), fleePosition, BWAPI::Colors::Cyan); Micro::SmartMove(rangedUnit, fleePosition); } // otherwise shoot else { Micro::SmartAttackUnit(rangedUnit, target); } } void Micro::MutaDanceTarget(BWAPI::Unit muta, BWAPI::Unit target) { UAB_ASSERT(muta, "MutaDanceTarget: Muta not valid"); UAB_ASSERT(target, "MutaDanceTarget: Target not valid"); if (!muta || !target) { return; } const int cooldown = muta->getType().groundWeapon().damageCooldown(); const int latency = BWAPI::Broodwar->getLatency(); const double speed = muta->getType().topSpeed(); const double range = muta->getType().groundWeapon().maxRange(); const double distanceToTarget = muta->getDistance(target); const double distanceToFiringRange = std::max(distanceToTarget - range, 0.0); const double timeToEnterFiringRange = distanceToFiringRange / speed; const int framesToAttack = static_cast(timeToEnterFiringRange) + 2*latency; // How many frames are left before we can attack? const int currentCooldown = muta->isStartingAttack() ? cooldown : muta->getGroundWeaponCooldown(); BWAPI::Position fleeVector = GetKiteVector(target, muta); BWAPI::Position moveToPosition(muta->getPosition() + fleeVector); // If we can attack by the time we reach our firing range if (currentCooldown <= framesToAttack) { // Move towards and attack the target muta->attack(target); } else // Otherwise we cannot attack and should temporarily back off { // Determine direction to flee // Determine point to flee to if (moveToPosition.isValid()) { muta->rightClick(moveToPosition); } } } BWAPI::Position Micro::GetKiteVector(BWAPI::Unit unit, BWAPI::Unit target) { BWAPI::Position fleeVec(target->getPosition() - unit->getPosition()); double fleeAngle = atan2(fleeVec.y, fleeVec.x); fleeVec = BWAPI::Position(static_cast(64 * cos(fleeAngle)), static_cast(64 * sin(fleeAngle))); return fleeVec; } ================================================ FILE: UAlbertaBot/Source/Micro.h ================================================ #pragma once #include namespace UAlbertaBot { namespace Micro { void SmartAttackUnit(BWAPI::Unit attacker, BWAPI::Unit target); void SmartAttackMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition); void SmartMove(BWAPI::Unit attacker, const BWAPI::Position & targetPosition); void SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target); void SmartLaySpiderMine(BWAPI::Unit unit, BWAPI::Position pos); void SmartRepair(BWAPI::Unit unit, BWAPI::Unit target); void SmartKiteTarget(BWAPI::Unit rangedUnit, BWAPI::Unit target); void MutaDanceTarget(BWAPI::Unit muta, BWAPI::Unit target); BWAPI::Position GetKiteVector(BWAPI::Unit unit, BWAPI::Unit target); }; } ================================================ FILE: UAlbertaBot/Source/MicroManager.cpp ================================================ #include "MicroManager.h" #include "BaseLocationManager.h" #include "Global.h" #include "MapTools.h" #include "InformationManager.h" #include "Micro.h" using namespace UAlbertaBot; MicroManager::MicroManager() { } void MicroManager::setUnits(const BWAPI::Unitset & u) { m_units = u; } BWAPI::Position MicroManager::calcCenter() const { if (m_units.empty()) { if (Config::Debug::DrawSquadInfo) { BWAPI::Broodwar->printf("Squad::calcCenter() called on empty squad"); } return BWAPI::Position(0, 0); } BWAPI::Position accum(0, 0); for (auto & unit : m_units) { accum += unit->getPosition(); } return BWAPI::Position(accum.x / m_units.size(), accum.y / m_units.size()); } void MicroManager::execute(const SquadOrder & inputOrder) { // Nothing to do if we have no units if (m_units.empty() || !(inputOrder.getType() == SquadOrderTypes::Attack || inputOrder.getType() == SquadOrderTypes::Defend)) { return; } m_order = inputOrder; drawOrderText(); // Discover enemies within region of interest BWAPI::Unitset nearbyEnemies; // if the order is to defend, we only care about units in the radius of the defense if (m_order.getType() == SquadOrderTypes::Defend) { Global::Map().getUnits(nearbyEnemies, m_order.getPosition(), m_order.getRadius(), false, true); } // otherwise we want to see everything on the way else if (m_order.getType() == SquadOrderTypes::Attack) { Global::Map().getUnits(nearbyEnemies, m_order.getPosition(), m_order.getRadius(), false, true); for (auto & unit : m_units) { BWAPI::Unit u = unit; BWAPI::UnitType t = u->getType(); Global::Map().getUnits(nearbyEnemies, unit->getPosition(), m_order.getRadius(), false, true); } } // the following block of code attacks all units on the way to the order position // we want to do this if the order is attack, defend, or harass if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend) { // if this is a worker defense force if (m_units.size() == 1 && (*m_units.begin())->getType().isWorker()) { executeMicro(nearbyEnemies); } // otherwise it is a normal attack force else { // if this is a defense squad then we care about all units in the area if (m_order.getType() == SquadOrderTypes::Defend) { executeMicro(nearbyEnemies); } // otherwise we only care about workers if they are in their own region else { // if this is the an attack squad BWAPI::Unitset workersRemoved; for (auto & enemyUnit : nearbyEnemies) { // if its not a worker add it to the targets if (!enemyUnit->getType().isWorker()) { workersRemoved.insert(enemyUnit); } // if it is a worker else { for (auto enemyBase : Global::Bases().getOccupiedBaseLocations(BWAPI::Broodwar->enemy())) { // only add it if it's in their region if (enemyBase->containsPosition(enemyUnit->getPosition())) { workersRemoved.insert(enemyUnit); } } } } // Allow micromanager to handle enemies executeMicro(workersRemoved); } } } } const BWAPI::Unitset & MicroManager::getUnits() const { return m_units; } void MicroManager::regroup(const BWAPI::Position & regroupPosition) const { BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); int regroupDistanceFromBase = Global::Map().getGroundDistance(regroupPosition, ourBasePosition); // for each of the units we have for (auto & unit : m_units) { int unitDistanceFromBase = Global::Map().getGroundDistance(unit->getPosition(), ourBasePosition); // if the unit is outside the regroup area if (unitDistanceFromBase > regroupDistanceFromBase) { Micro::SmartMove(unit, ourBasePosition); } else if (unit->getDistance(regroupPosition) > 100) { // regroup it Micro::SmartMove(unit, regroupPosition); } else { Micro::SmartAttackMove(unit, unit->getPosition()); } } } bool MicroManager::unitNearEnemy(BWAPI::Unit unit) { assert(unit); BWAPI::Unitset enemyNear; Global::Map().getUnits(enemyNear, unit->getPosition(), 800, false, true); return enemyNear.size() > 0; } // returns true if position: // a) is walkable // b) doesn't have buildings on it // c) doesn't have a unit on it that can attack ground bool MicroManager::checkPositionWalkable(BWAPI::Position pos) { // get x and y from the position int x(pos.x), y(pos.y); // walkable tiles exist every 8 pixels bool good = BWAPI::Broodwar->isWalkable(x/8, y/8); // if it's not walkable throw it out if (!good) return false; // for each of those units, if it's a building or an attacking enemy unit we don't want to go there for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(x/32, y/32)) { if (unit->getType().isBuilding() || unit->getType().isResourceContainer() || (unit->getPlayer() != BWAPI::Broodwar->self() && unit->getType().groundWeapon() != BWAPI::WeaponTypes::None)) { return false; } } // otherwise it's okay return true; } void MicroManager::trainSubUnits(BWAPI::Unit unit) const { if (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) { unit->train(BWAPI::UnitTypes::Protoss_Scarab); } else if (unit->getType() == BWAPI::UnitTypes::Protoss_Carrier) { unit->train(BWAPI::UnitTypes::Protoss_Interceptor); } } bool MicroManager::unitNearChokepoint(BWAPI::Unit unit) const { // TODO: Chokepoint return false; } void MicroManager::drawOrderText() { for (auto & unit : m_units) { if (Config::Debug::DrawUnitTargetInfo) BWAPI::Broodwar->drawTextMap(unit->getPosition().x, unit->getPosition().y, "%s", m_order.getStatus().c_str()); } } ================================================ FILE: UAlbertaBot/Source/MicroManager.h ================================================ #pragma once #include "Common.h" #include "SquadOrder.h" namespace UAlbertaBot { struct AirThreat { BWAPI::Unit unit; double weight; }; struct GroundThreat { BWAPI::Unit unit; double weight; }; class MicroManager { BWAPI::Unitset m_units; protected: SquadOrder m_order; virtual void executeMicro(const BWAPI::Unitset & targets) = 0; bool checkPositionWalkable(BWAPI::Position pos); void drawOrderText(); bool unitNearEnemy(BWAPI::Unit unit); bool unitNearChokepoint(BWAPI::Unit unit) const; void trainSubUnits(BWAPI::Unit unit) const; public: MicroManager(); virtual ~MicroManager() {} const BWAPI::Unitset & getUnits() const; BWAPI::Position calcCenter() const; void setUnits(const BWAPI::Unitset & u); void execute(const SquadOrder & order); void regroup(const BWAPI::Position & regroupPosition) const; }; } ================================================ FILE: UAlbertaBot/Source/ParseUtils.cpp ================================================ #include "ParseUtils.h" #include "rapidjson\document.h" #include "JSONTools.h" #include "BuildOrder.h" #include "StrategyManager.h" #include "Global.h" using namespace UAlbertaBot; void ParseUtils::ParseConfigFile(const std::string & filename) { PROFILE_FUNCTION(); rapidjson::Document doc; BWAPI::Race race = BWAPI::Broodwar->self()->getRace(); const char * ourRace = race.getName().c_str(); std::string config = FileUtils::ReadFile(filename); if (config.length() == 0) { return; } Config::ConfigFile::ConfigFileFound = true; bool parsingFailed = doc.Parse(config.c_str()).HasParseError(); if (parsingFailed) { return; } // Parse the Bot Info if (doc.HasMember("Bot Info") && doc["Bot Info"].IsObject()) { const rapidjson::Value & info = doc["Bot Info"]; JSONTools::ReadString("BotName", info, Config::BotInfo::BotName); JSONTools::ReadString("Authors", info, Config::BotInfo::Authors); JSONTools::ReadBool("PrintInfoOnStart", info, Config::BotInfo::PrintInfoOnStart); } // Parse the BWAPI Options if (doc.HasMember("BWAPI") && doc["BWAPI"].IsObject()) { const rapidjson::Value & bwapi = doc["BWAPI"]; JSONTools::ReadInt("SetLocalSpeed", bwapi, Config::BWAPIOptions::SetLocalSpeed); JSONTools::ReadInt("SetFrameSkip", bwapi, Config::BWAPIOptions::SetFrameSkip); JSONTools::ReadBool("UserInput", bwapi, Config::BWAPIOptions::EnableUserInput); JSONTools::ReadBool("CompleteMapInformation", bwapi, Config::BWAPIOptions::EnableCompleteMapInformation); } // Parse the Micro Options if (doc.HasMember("Micro") && doc["Micro"].IsObject()) { const rapidjson::Value & micro = doc["Micro"]; JSONTools::ReadBool("UseSparcraftSimulation", micro, Config::Micro::UseSparcraftSimulation); JSONTools::ReadBool("KiteWithRangedUnits", micro, Config::Micro::KiteWithRangedUnits); JSONTools::ReadBool("WorkersDefendRush", micro, Config::Micro::WorkersDefendRush); JSONTools::ReadInt("RetreatMeleeUnitShields", micro, Config::Micro::RetreatMeleeUnitShields); JSONTools::ReadInt("RetreatMeleeUnitHP", micro, Config::Micro::RetreatMeleeUnitHP); JSONTools::ReadInt("InCombatRadius", micro, Config::Micro::CombatRadius); JSONTools::ReadInt("RegroupRadius", micro, Config::Micro::CombatRegroupRadius); JSONTools::ReadInt("UnitNearEnemyRadius", micro, Config::Micro::UnitNearEnemyRadius); if (micro.HasMember("KiteLongerRangedUnits") && micro["KiteLongerRangedUnits"].IsArray()) { const rapidjson::Value & kite = micro["KiteLongerRangedUnits"]; for (size_t i(0); i < kite.Size(); ++i) { if (kite[i].IsString()) { MetaType type(kite[i].GetString()); Config::Micro::KiteLongerRangedUnits.insert(type.getUnitType()); } } } } // Parse the Macro Options if (doc.HasMember("Macro") && doc["Macro"].IsObject()) { const rapidjson::Value & macro = doc["Macro"]; JSONTools::ReadInt("BOSSFrameLimit", macro, Config::Macro::BOSSFrameLimit); JSONTools::ReadInt("BuildingSpacing", macro, Config::Macro::BuildingSpacing); JSONTools::ReadInt("PylongSpacing", macro, Config::Macro::PylonSpacing); JSONTools::ReadInt("WorkersPerRefinery", macro, Config::Macro::WorkersPerRefinery); } // Parse the Debug Options if (doc.HasMember("Debug") && doc["Debug"].IsObject()) { const rapidjson::Value & debug = doc["Debug"]; JSONTools::ReadString("ErrorLogFilename", debug, Config::Debug::ErrorLogFilename); JSONTools::ReadBool("LogAssertToErrorFile", debug, Config::Debug::LogAssertToErrorFile); JSONTools::ReadBool("DrawGameInfo", debug, Config::Debug::DrawGameInfo); JSONTools::ReadBool("DrawBuildOrderSearchInfo", debug, Config::Debug::DrawBuildOrderSearchInfo); JSONTools::ReadBool("DrawUnitHealthBars", debug, Config::Debug::DrawUnitHealthBars); JSONTools::ReadBool("DrawResourceInfo", debug, Config::Debug::DrawResourceInfo); JSONTools::ReadBool("DrawWorkerInfo", debug, Config::Debug::DrawWorkerInfo); JSONTools::ReadBool("DrawProductionInfo", debug, Config::Debug::DrawProductionInfo); JSONTools::ReadBool("DrawScoutInfo", debug, Config::Debug::DrawScoutInfo); JSONTools::ReadBool("DrawSquadInfo", debug, Config::Debug::DrawSquadInfo); JSONTools::ReadBool("DrawCombatSimInfo", debug, Config::Debug::DrawCombatSimulationInfo); JSONTools::ReadBool("DrawBuildingInfo", debug, Config::Debug::DrawBuildingInfo); JSONTools::ReadBool("DrawModuleTimers", debug, Config::Debug::DrawModuleTimers); JSONTools::ReadBool("DrawMouseCursorInfo", debug, Config::Debug::DrawMouseCursorInfo); JSONTools::ReadBool("DrawEnemyUnitInfo", debug, Config::Debug::DrawEnemyUnitInfo); JSONTools::ReadBool("DrawBWTAInfo", debug, Config::Debug::DrawBWTAInfo); JSONTools::ReadBool("DrawMapGrid", debug, Config::Debug::DrawMapGrid); JSONTools::ReadBool("DrawUnitTargetInfo", debug, Config::Debug::DrawUnitTargetInfo); JSONTools::ReadBool("DrawReservedBuildingTiles", debug, Config::Debug::DrawReservedBuildingTiles); JSONTools::ReadBool("DrawBOSSStateInfo", debug, Config::Debug::DrawBOSSStateInfo); JSONTools::ReadBool("DrawTileInfo", debug, Config::Debug::DrawTileInfo); JSONTools::ReadBool("DrawWalkableSectors", debug, Config::Debug::DrawWalkableSectors); JSONTools::ReadBool("PrintModuleTimeout", debug, Config::Debug::PrintModuleTimeout); } // Parse the Module Options if (doc.HasMember("Modules") && doc["Modules"].IsObject()) { const rapidjson::Value & module = doc["Modules"]; JSONTools::ReadBool("UseGameCommander", module, Config::Modules::UsingGameCommander); JSONTools::ReadBool("UseScoutManager", module, Config::Modules::UsingScoutManager); JSONTools::ReadBool("UseCombatCommander", module, Config::Modules::UsingCombatCommander); JSONTools::ReadBool("UseBuildOrderSearch", module, Config::Modules::UsingBuildOrderSearch); JSONTools::ReadBool("UseStrategyIO", module, Config::Modules::UsingStrategyIO); JSONTools::ReadBool("UseUnitCommandManager", module, Config::Modules::UsingUnitCommandManager); JSONTools::ReadBool("UseAutoObserver", module, Config::Modules::UsingAutoObserver); } // Parse the Tool Options if (doc.HasMember("Tools") && doc["Tools"].IsObject()) { const rapidjson::Value & tool = doc["Tools"]; JSONTools::ReadInt("MapGridSize", tool, Config::Tools::MAP_GRID_SIZE); } // Parse the Strategy Options if (doc.HasMember("Strategy") && doc["Strategy"].IsObject()) { const rapidjson::Value & strategy = doc["Strategy"]; // read in the various strategic elements JSONTools::ReadBool("ScoutGasSteal", strategy, Config::Strategy::GasStealWithScout); JSONTools::ReadBool("ScoutHarassEnemy", strategy, Config::Strategy::ScoutHarassEnemy); JSONTools::ReadString("ReadDirectory", strategy, Config::Strategy::ReadDir); JSONTools::ReadString("WriteDirectory", strategy, Config::Strategy::WriteDir); // if we have set a strategy for the current race, use it if (strategy.HasMember(race.c_str()) && strategy[race.c_str()].IsString()) { Config::Strategy::StrategyName = strategy[race.c_str()].GetString(); } // check if we are using an enemy specific strategy JSONTools::ReadBool("UseEnemySpecificStrategy", strategy, Config::Strategy::UseEnemySpecificStrategy); if (Config::Strategy::UseEnemySpecificStrategy && strategy.HasMember("EnemySpecificStrategy") && strategy["EnemySpecificStrategy"].IsObject()) { const std::string enemyName = BWAPI::Broodwar->enemy()->getName(); const rapidjson::Value & specific = strategy["EnemySpecificStrategy"]; // check to see if our current enemy name is listed anywhere in the specific strategies if (specific.HasMember(enemyName.c_str()) && specific[enemyName.c_str()].IsObject()) { const rapidjson::Value & enemyStrategies = specific[enemyName.c_str()]; // if that enemy has a strategy listed for our current race, use it if (enemyStrategies.HasMember(ourRace) && enemyStrategies[ourRace].IsString()) { Config::Strategy::StrategyName = enemyStrategies[ourRace].GetString(); Config::Strategy::FoundEnemySpecificStrategy = true; } } } // Parse all the Strategies if (strategy.HasMember("Strategies") && strategy["Strategies"].IsObject()) { const rapidjson::Value & strategies = strategy["Strategies"]; for (rapidjson::Value::ConstMemberIterator itr = strategies.MemberBegin(); itr != strategies.MemberEnd(); ++itr) { const std::string & name = itr->name.GetString(); const rapidjson::Value & val = itr->value; BWAPI::Race strategyRace; if (val.HasMember("Race") && val["Race"].IsString()) { strategyRace = GetRace(val["Race"].GetString()); } else { UAB_ASSERT_WARNING(false, "Strategy must have a Race string. Skipping strategy %s", name.c_str()); continue; } BuildOrder buildOrder(strategyRace); if (val.HasMember("OpeningBuildOrder") && val["OpeningBuildOrder"].IsArray()) { const rapidjson::Value & build = val["OpeningBuildOrder"]; for (size_t b(0); b < build.Size(); ++b) { if (build[b].IsString()) { MetaType type(build[b].GetString()); if (type.getRace() != BWAPI::Races::None) { buildOrder.add(type); } } else { UAB_ASSERT_WARNING(false, "Build order item must be a string %s", name.c_str()); continue; } } } Global::Strategy().addStrategy(name, Strategy(name, strategyRace, buildOrder)); } } } Config::ConfigFile::ConfigFileParsed = true; } void ParseUtils::ParseTextCommand(const std::string & commandString) { std::stringstream ss(commandString); std::string command; std::transform(command.begin(), command.end(), command.begin(), ::tolower); std::string variableName; std::transform(variableName.begin(), variableName.end(), variableName.begin(), ::tolower); std::string val; ss >> command; ss >> variableName; ss >> val; if (command == "/set") { // BWAPI options if (variableName == "setlocalspeed") { Config::BWAPIOptions::SetLocalSpeed = GetIntFromString(val); BWAPI::Broodwar->setLocalSpeed(Config::BWAPIOptions::SetLocalSpeed); } else if (variableName == "setframeskip") { Config::BWAPIOptions::SetFrameSkip = GetIntFromString(val); BWAPI::Broodwar->setFrameSkip(Config::BWAPIOptions::SetFrameSkip); } else if (variableName == "userinput") { Config::BWAPIOptions::EnableUserInput = GetBoolFromString(val); if (Config::BWAPIOptions::EnableUserInput) BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); } else if (variableName == "completemapinformation") { Config::BWAPIOptions::EnableCompleteMapInformation = GetBoolFromString(val); if (Config::BWAPIOptions::EnableCompleteMapInformation) BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); } // Micro Options else if (variableName == "usesparcraftsimulation") { Config::Micro::UseSparcraftSimulation = GetBoolFromString(val); } else if (variableName == "workersdefendrush") { Config::Micro::WorkersDefendRush = GetBoolFromString(val); } else if (variableName == "incombatradius") { Config::Micro::CombatRadius = GetIntFromString(val); } else if (variableName == "regroupradius") { Config::Micro::CombatRegroupRadius = GetIntFromString(val); } else if (variableName == "unitnearenemyradius") { Config::Micro::UnitNearEnemyRadius = GetIntFromString(val); } // Macro Options else if (variableName == "buildingspacing") { Config::Macro::BuildingSpacing = GetIntFromString(val); } else if (variableName == "pylonspacing") { Config::Macro::PylonSpacing = GetIntFromString(val); } // Debug Options else if (variableName == "errorlogfilename") { Config::Debug::ErrorLogFilename = val; } else if (variableName == "printmoduletimeout") { Config::Debug::PrintModuleTimeout = GetBoolFromString(val); } else if (variableName == "drawbuildordersearchinfo") { Config::Debug::DrawBuildOrderSearchInfo = GetBoolFromString(val); } else if (variableName == "drawunithealthbars") { Config::Debug::DrawUnitHealthBars = GetBoolFromString(val); } else if (variableName == "drawproductioninfo") { Config::Debug::DrawProductionInfo = GetBoolFromString(val); } else if (variableName == "drawenemyunitinfo") { Config::Debug::DrawEnemyUnitInfo = GetBoolFromString(val); } else if (variableName == "drawmoduletimers") { Config::Debug::DrawModuleTimers = GetBoolFromString(val); } else if (variableName == "drawresourceinfo") { Config::Debug::DrawResourceInfo = GetBoolFromString(val); } else if (variableName == "drawcombatsiminfo") { Config::Debug::DrawCombatSimulationInfo = GetBoolFromString(val); } else if (variableName == "drawunittargetinfo") { Config::Debug::DrawUnitTargetInfo = GetBoolFromString(val); } else if (variableName == "drawbwtainfo") { Config::Debug::DrawBWTAInfo = GetBoolFromString(val); } else if (variableName == "drawmapgrid") { Config::Debug::DrawMapGrid = GetBoolFromString(val); } else if (variableName == "drawsquadinfo") { Config::Debug::DrawSquadInfo = GetBoolFromString(val); } else if (variableName == "drawworkerinfo") { Config::Debug::DrawWorkerInfo = GetBoolFromString(val); } else if (variableName == "drawmousecursorinfo") { Config::Debug::DrawMouseCursorInfo = GetBoolFromString(val); } else if (variableName == "drawbuildinginfo") { Config::Debug::DrawBuildingInfo = GetBoolFromString(val); } else if (variableName == "drawreservedbuildingtiles") { Config::Debug::DrawReservedBuildingTiles = GetBoolFromString(val); } // Module Options else if (variableName == "usegamecommander") { Config::Modules::UsingGameCommander = GetBoolFromString(val); } else if (variableName == "usescoutmanager") { Config::Modules::UsingScoutManager = GetBoolFromString(val); } else if (variableName == "usecombatcommander") { Config::Modules::UsingCombatCommander = GetBoolFromString(val); } else if (variableName == "usebuildordersearch") { Config::Modules::UsingBuildOrderSearch = GetBoolFromString(val); } else if (variableName == "useautoobserver") { Config::Modules::UsingAutoObserver = GetBoolFromString(val); } else if (variableName == "usestrategyio") { Config::Modules::UsingStrategyIO = GetBoolFromString(val); } else if (variableName == "useunitcommandmanager") { Config::Modules::UsingUnitCommandManager = GetBoolFromString(val); } else { UAB_ASSERT_WARNING(false, "Unknown variable name for /set: %s", variableName.c_str()); } } else { UAB_ASSERT_WARNING(false, "Unknown command: %s", command.c_str()); } } BWAPI::Race ParseUtils::GetRace(const std::string & raceName) { if (raceName == "Protoss") { return BWAPI::Races::Protoss; } if (raceName == "Terran") { return BWAPI::Races::Terran; } if (raceName == "Zerg") { return BWAPI::Races::Zerg; } if (raceName == "Random") { return BWAPI::Races::Random; } UAB_ASSERT_WARNING(false, "Race not found: %s", raceName.c_str()); return BWAPI::Races::None; } int ParseUtils::GetIntFromString(const std::string & str) { std::stringstream ss(str); int a = 0; ss >> a; return a; } bool ParseUtils::GetBoolFromString(const std::string & str) { std::string boolStr(str); std::transform(boolStr.begin(), boolStr.end(), boolStr.begin(), ::tolower); if (boolStr == "true" || boolStr == "t") { return true; } else if (boolStr == "false" || boolStr == "f") { return false; } else { UAB_ASSERT_WARNING(false, "Unknown bool from string: %s", str.c_str()); } return false; } ================================================ FILE: UAlbertaBot/Source/ParseUtils.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { namespace ParseUtils { void ParseConfigFile(const std::string & filename); void ParseTextCommand(const std::string & commandLine); BWAPI::Race GetRace(const std::string & raceName); int GetIntFromString(const std::string & str); bool GetBoolFromString(const std::string & str); } } ================================================ FILE: UAlbertaBot/Source/ProductionManager.cpp ================================================ #include "ProductionManager.h" #include "Global.h" #include "BuildingData.h" #include "BuildingManager.h" #include "StrategyManager.h" #include "BOSSManager.h" #include "InformationManager.h" #include "WorkerManager.h" using namespace UAlbertaBot; ProductionManager::ProductionManager() { setBuildOrder(Global::Strategy().getOpeningBookBuildOrder()); } void ProductionManager::setBuildOrder(const BuildOrder & buildOrder) { m_queue.clearAll(); for (size_t i(0); i 0) { setBuildOrder(buildOrder); m_bossManager.reset(); } else { if (!m_bossManager.isSearchInProgress()) { m_bossManager.startNewSearch(Global::Strategy().getBuildOrderGoal()); } } } void ProductionManager::update() { PROFILE_FUNCTION(); m_buildingManager.update(); // 30 ms per search update m_bossManager.update(Config::Macro::BOSSTimePerFrame); // check the _queue for stuff we can build manageBuildOrderQueue(); // if nothing is currently building, get a new goal from the strategy manager if ((m_queue.size() == 0) && (BWAPI::Broodwar->getFrameCount() > 10)) { if (Config::Debug::DrawBuildOrderSearchInfo) { BWAPI::Broodwar->drawTextScreen(150, 10, "Nothing left to build, new search!"); } performBuildOrderSearch(); } // detect if there's a build order deadlock once per second if ((BWAPI::Broodwar->getFrameCount() % 24 == 0) && detectBuildOrderDeadlock()) { if (Config::Debug::DrawBuildOrderSearchInfo) { BWAPI::Broodwar->printf("Supply deadlock detected, building supply!"); } m_queue.queueAsHighestPriority(MetaType(BWAPI::Broodwar->self()->getRace().getSupplyProvider()), true); } // if they have cloaked units get a new goal asap if (!m_enemyCloakedDetected && Global::Info().enemyHasCloakedUnits()) { if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss) { if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Protoss_Photon_Cannon) < 2) { m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Photon_Cannon), true); m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Photon_Cannon), true); } if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Protoss_Forge) == 0) { m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Protoss_Forge), true); } } else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran) { if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Missile_Turret) < 2) { m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Missile_Turret), true); m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Missile_Turret), true); } if (BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Engineering_Bay) == 0) { m_queue.queueAsHighestPriority(MetaType(BWAPI::UnitTypes::Terran_Engineering_Bay), true); } } if (Config::Debug::DrawBuildOrderSearchInfo) { BWAPI::Broodwar->printf("Enemy Cloaked Unit Detected!"); } m_enemyCloakedDetected = true; } m_bossManager.drawSearchInformation(490, 100); m_bossManager.drawStateInformation(250, 0); } // on unit destroy void ProductionManager::onUnitDestroy(BWAPI::Unit unit) { // we don't care if it's not our unit if (!unit || unit->getPlayer() != BWAPI::Broodwar->self()) { return; } if (Config::Modules::UsingBuildOrderSearch) { // if it's a worker or a building, we need to re-search for the current goal if ((unit->getType().isWorker() && !Global::Workers().isWorkerScout(unit)) || unit->getType().isBuilding()) { if (unit->getType() != BWAPI::UnitTypes::Zerg_Drone) { performBuildOrderSearch(); } } } } void ProductionManager::manageBuildOrderQueue() { PROFILE_FUNCTION(); // if there is nothing in the _queue, oh well if (m_queue.isEmpty()) { return; } // the current item to be used BuildOrderItem & currentItem = m_queue.getHighestPriorityItem(); // while there is still something left in the _queue while (!m_queue.isEmpty()) { // this is the unit which can produce the currentItem BWAPI::Unit producer = getProducer(currentItem.metaType); // check to see if we can make it right now bool canMake = canMakeNow(producer, currentItem.metaType); // if we try to build too many refineries manually remove it if (currentItem.metaType.isRefinery() && (BWAPI::Broodwar->self()->allUnitCount(BWAPI::Broodwar->self()->getRace().getRefinery() >= 3))) { m_queue.removeCurrentHighestPriorityItem(); break; } // if the next item in the list is a building and we can't yet make it if (currentItem.metaType.isBuilding() && !(producer && canMake) && currentItem.metaType.whatBuilds().isWorker()) { // construct a temporary building object Building b(currentItem.metaType.getUnitType(), BWAPI::Broodwar->self()->getStartLocation()); b.isGasSteal = currentItem.isGasSteal; // set the producer as the closest worker, but do not set its job yet producer = Global::Workers().getBuilder(b, false); // predict the worker movement to that building location predictWorkerMovement(b); } // if we can make the current item if (producer && canMake) { // create it create(producer, currentItem); m_assignedWorkerForThisBuilding = false; m_haveLocationForThisBuilding = false; // and remove it from the _queue m_queue.removeCurrentHighestPriorityItem(); // don't actually loop around in here break; } // otherwise, if we can skip the current item else if (m_queue.canSkipItem()) { // skip it m_queue.skipItem(); // and get the next one currentItem = m_queue.getNextHighestPriorityItem(); } else { // so break out break; } } } BWAPI::Unit ProductionManager::getProducer(MetaType t, BWAPI::Position closestTo) { PROFILE_FUNCTION(); // get the type of unit that builds this BWAPI::UnitType producerType = t.whatBuilds(); // make a set of all candidate producers BWAPI::Unitset candidateProducers; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(unit != nullptr, "Unit was null"); // reasons a unit can not train the desired type if (unit->getType() != producerType) { continue; } if (!unit->isCompleted()) { continue; } if (unit->isTraining()) { continue; } if (unit->isLifted()) { continue; } if (!unit->isPowered()) { continue; } // if the type is an addon, some special cases if (t.getUnitType().isAddon()) { // if the unit already has an addon, it can't make one if (unit->getAddon() != nullptr) { continue; } // if we just told this unit to build an addon, then it will not be building another one // this deals with the frame-delay of telling a unit to build an addon and it actually starting to build if (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Build_Addon && (BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() < 10)) { continue; } bool isBlocked = false; // if the unit doesn't have space to build an addon, it can't make one BWAPI::TilePosition addonPosition(unit->getTilePosition().x + unit->getType().tileWidth(), unit->getTilePosition().y + unit->getType().tileHeight() - t.getUnitType().tileHeight()); BWAPI::Broodwar->drawBoxMap(addonPosition.x*32, addonPosition.y*32, addonPosition.x*32 + 64, addonPosition.y*32 + 64, BWAPI::Colors::Red); for (int i=0; igetType().tileWidth() + t.getUnitType().tileWidth(); ++i) { for (int j=0; jgetType().tileHeight(); ++j) { BWAPI::TilePosition tilePos(unit->getTilePosition().x + i, unit->getTilePosition().y + j); // if the map won't let you build here, we can't build it if (!BWAPI::Broodwar->isBuildable(tilePos)) { isBlocked = true; BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red); } // if there are any units on the addon tile, we can't build it BWAPI::Unitset uot = BWAPI::Broodwar->getUnitsOnTile(tilePos.x, tilePos.y); if (uot.size() > 0 && !(uot.size() == 1 && *(uot.begin()) == unit)) { isBlocked = true;; BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red); } } } if (isBlocked) { continue; } } // if the type requires an addon and the producer doesn't have one typedef std::pair ReqPair; for (const ReqPair & pair : t.getUnitType().requiredUnits()) { BWAPI::UnitType requiredType = pair.first; if (requiredType.isAddon()) { if (!unit->getAddon() || (unit->getAddon()->getType() != requiredType)) { continue; } } } // if we haven't cut it, add it to the set of candidates candidateProducers.insert(unit); } return getClosestUnitToPosition(candidateProducers, closestTo); } BWAPI::Unit ProductionManager::getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo) { if (units.size() == 0) { return nullptr; } // if we don't care where the unit is return the first one we have if (closestTo == BWAPI::Positions::None) { return *(units.begin()); } BWAPI::Unit closestUnit = nullptr; double minDist(1000000); for (auto & unit : units) { UAB_ASSERT(unit != nullptr, "Unit was null"); double distance = unit->getDistance(closestTo); if (!closestUnit || distance < minDist) { closestUnit = unit; minDist = distance; } } return closestUnit; } // this function will check to see if all preconditions are met and then create a unit void ProductionManager::create(BWAPI::Unit producer, BuildOrderItem & item) { if (!producer) { return; } PROFILE_FUNCTION(); MetaType t = item.metaType; // if we're dealing with a building if (t.isUnit() && t.getUnitType().isBuilding() && t.getUnitType() != BWAPI::UnitTypes::Zerg_Lair && t.getUnitType() != BWAPI::UnitTypes::Zerg_Hive && t.getUnitType() != BWAPI::UnitTypes::Zerg_Greater_Spire && !t.getUnitType().isAddon()) { // send the building task to the building manager m_buildingManager.addBuildingTask(t.getUnitType(), BWAPI::Broodwar->self()->getStartLocation(), item.isGasSteal); } else if (t.getUnitType().isAddon()) { //BWAPI::TilePosition addonPosition(producer->getTilePosition().x + producer->getType().tileWidth(), producer->getTilePosition().y + producer->getType().tileHeight() - t.unitType.tileHeight()); producer->buildAddon(t.getUnitType()); } // if we're dealing with a non-building unit else if (t.isUnit()) { // if the race is zerg, morph the unit if (t.getUnitType().getRace() == BWAPI::Races::Zerg) { producer->morph(t.getUnitType()); // if not, train the unit } else { producer->train(t.getUnitType()); } } // if we're dealing with a tech research else if (t.isTech()) { producer->research(t.getTechType()); } else if (t.isUpgrade()) { //Logger::Instance().log("Produce Upgrade: " + t.getName() + "\n"); producer->upgrade(t.getUpgradeType()); } else { } } bool ProductionManager::canMakeNow(BWAPI::Unit producer, MetaType t) { //UAB_ASSERT(producer != nullptr, "Producer was null"); bool canMake = meetsReservedResources(t); if (canMake) { if (t.isUnit()) { canMake = BWAPI::Broodwar->canMake(t.getUnitType(), producer); } else if (t.isTech()) { canMake = BWAPI::Broodwar->canResearch(t.getTechType(), producer); } else if (t.isUpgrade()) { canMake = BWAPI::Broodwar->canUpgrade(t.getUpgradeType(), producer); } else { UAB_ASSERT(false, "Unknown type"); } } return canMake; } bool ProductionManager::detectBuildOrderDeadlock() { // if the _queue is empty there is no deadlock if (m_queue.size() == 0 || BWAPI::Broodwar->self()->supplyTotal() >= 390) { return false; } // are any supply providers being built currently bool supplyInProgress = m_buildingManager.isBeingBuilt(BWAPI::Broodwar->self()->getRace().getSupplyProvider()); for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg) { if (unit->getBuildType() == BWAPI::UnitTypes::Zerg_Overlord) { supplyInProgress = true; break; } } } // does the current item being built require more supply int supplyCost = m_queue.getHighestPriorityItem().metaType.supplyRequired(); int supplyAvailable = std::max(0, BWAPI::Broodwar->self()->supplyTotal() - BWAPI::Broodwar->self()->supplyUsed()); // if we don't have enough supply and none is being built, there's a deadlock if ((supplyAvailable < supplyCost) && !supplyInProgress) { // if we're zerg, check to see if a building is planned to be built if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg && m_buildingManager.buildingsQueued().size() > 0) { return false; } else { return true; } } return false; } // When the next item in the _queue is a building, this checks to see if we should move to it // This function is here as it needs to access prodction manager's reserved resources info void ProductionManager::predictWorkerMovement(const Building & b) { if (b.isGasSteal) { return; } // get a possible building location for the building if (!m_haveLocationForThisBuilding) { m_predictedTilePosition = m_buildingManager.getBuildingLocation(b); } if (m_predictedTilePosition != BWAPI::TilePositions::None) { m_haveLocationForThisBuilding = true; } else { return; } // draw a box where the building will be placed int x1 = m_predictedTilePosition.x * 32; int x2 = x1 + (b.type.tileWidth()) * 32; int y1 = m_predictedTilePosition.y * 32; int y2 = y1 + (b.type.tileHeight()) * 32; if (Config::Debug::DrawWorkerInfo) { BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Blue, false); } // where we want the worker to walk to BWAPI::Position walkToPosition = BWAPI::Position(x1 + (b.type.tileWidth()/2)*32, y1 + (b.type.tileHeight()/2)*32); // compute how many resources we need to construct this building int mineralsRequired = std::max(0, b.type.mineralPrice() - getFreeMinerals()); int gasRequired = std::max(0, b.type.gasPrice() - getFreeGas()); // get a candidate worker to move to this location BWAPI::Unit moveWorker = Global::Workers().getMoveWorker(walkToPosition); // Conditions under which to move the worker: // - there's a valid worker to move // - we haven't yet assigned a worker to move to this location // - the build position is valid // - we will have the required resources by the time the worker gets there if (moveWorker && m_haveLocationForThisBuilding && !m_assignedWorkerForThisBuilding && (m_predictedTilePosition != BWAPI::TilePositions::None) && Global::Workers().willHaveResources(mineralsRequired, gasRequired, moveWorker->getDistance(walkToPosition))) { // we have assigned a worker m_assignedWorkerForThisBuilding = true; // tell the worker manager to move this worker Global::Workers().setMoveWorker(mineralsRequired, gasRequired, walkToPosition); } } void ProductionManager::performCommand(BWAPI::UnitCommandType t) { // if it is a cancel construction, it is probably the extractor trick if (t == BWAPI::UnitCommandTypes::Cancel_Construction) { BWAPI::Unit extractor = nullptr; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Extractor) { extractor = unit; } } if (extractor) { extractor->cancelConstruction(); } } } int ProductionManager::getFreeMinerals() { return BWAPI::Broodwar->self()->minerals() - m_buildingManager.getReservedMinerals(); } int ProductionManager::getFreeGas() { return BWAPI::Broodwar->self()->gas() - m_buildingManager.getReservedGas(); } // return whether or not we meet resources, including building reserves bool ProductionManager::meetsReservedResources(MetaType type) { // return whether or not we meet the resources return (type.mineralPrice() <= getFreeMinerals()) && (type.gasPrice() <= getFreeGas()); } // selects a unit of a given type BWAPI::Unit ProductionManager::selectUnitOfType(BWAPI::UnitType type, BWAPI::Position closestTo) { // if we have none of the unit type, return nullptr right away if (BWAPI::Broodwar->self()->completedUnitCount(type) == 0) { return nullptr; } BWAPI::Unit unit = nullptr; // if we are concerned about the position of the unit, that takes priority if (closestTo != BWAPI::Positions::None) { double minDist(1000000); for (auto & u : BWAPI::Broodwar->self()->getUnits()) { if (u->getType() == type) { double distance = u->getDistance(closestTo); if (!unit || distance < minDist) { unit = u; minDist = distance; } } } // if it is a building and we are worried about selecting the unit with the least // amount of training time remaining } else if (type.isBuilding()) { for (auto & u : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(u != nullptr, "Unit was null"); if (u->getType() == type && u->isCompleted() && !u->isTraining() && !u->isLifted() &&u->isPowered()) { return u; } } // otherwise just return the first unit we come across } else { for (auto & u : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(u != nullptr, "Unit was null"); if (u->getType() == type && u->isCompleted() && u->getHitPoints() > 0 && !u->isLifted() &&u->isPowered()) { return u; } } } // return what we've found so far return nullptr; } void ProductionManager::drawProductionInformation(int x, int y) { if (!Config::Debug::DrawProductionInfo) { return; } // fill prod with each unit which is under construction std::vector prod; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(unit != nullptr, "Unit was null"); if (unit->isBeingConstructed()) { prod.push_back(unit); } } // sort it based on the time it was started std::sort(prod.begin(), prod.end(), CompareWhenStarted()); BWAPI::Broodwar->drawTextScreen(x-30, y+20, "\x04 TIME"); BWAPI::Broodwar->drawTextScreen(x, y+20, "\x04 UNIT NAME"); size_t reps = prod.size() < 10 ? prod.size() : 10; y += 30; int yy = y; // for each unit in the _queue for (auto & unit : prod) { std::string prefix = "\x07"; yy += 10; BWAPI::UnitType t = unit->getType(); if (t == BWAPI::UnitTypes::Zerg_Egg) { t = unit->getBuildType(); } BWAPI::Broodwar->drawTextScreen(x, yy, " %s%s", prefix.c_str(), t.getName().c_str()); BWAPI::Broodwar->drawTextScreen(x - 35, yy, "%s%6d", prefix.c_str(), unit->getRemainingBuildTime()); } m_queue.drawQueueInformation(x, yy+10); } void ProductionManager::queueGasSteal() { m_queue.queueAsHighestPriority(MetaType(BWAPI::Broodwar->self()->getRace().getRefinery()), true, true); } // this will return true if any unit is on the first frame if it's training time remaining // this can cause issues for the build order search system so don't plan a search on these frames bool ProductionManager::canPlanBuildOrderNow() const { for (const auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getRemainingTrainTime() == 0) { continue; } BWAPI::UnitType trainType = unit->getLastCommand().getUnitType(); if (unit->getRemainingTrainTime() == trainType.buildTime()) { return false; } } return true; } std::vector ProductionManager::buildingsQueued() { return m_buildingManager.buildingsQueued(); } ================================================ FILE: UAlbertaBot/Source/ProductionManager.h ================================================ #pragma once #include #include "BuildOrderQueue.h" #include "BOSSManager.h" #include "BuildingManager.h" namespace UAlbertaBot { typedef unsigned char Action; class Building; class BuildOrder; class ProductionManager { friend class Global; BuildingManager m_buildingManager; BOSSManager m_bossManager; BuildOrderQueue m_queue; BWAPI::TilePosition m_predictedTilePosition; bool m_enemyCloakedDetected = false; bool m_assignedWorkerForThisBuilding = false; bool m_haveLocationForThisBuilding = false; BWAPI::Unit getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo); BWAPI::Unit selectUnitOfType(BWAPI::UnitType type, BWAPI::Position closestTo = BWAPI::Position(0, 0)); void setBuildOrder(const BuildOrder & buildOrder); void create(BWAPI::Unit producer, BuildOrderItem & item); void manageBuildOrderQueue(); void performCommand(BWAPI::UnitCommandType t); void predictWorkerMovement(const Building & b); int getFreeMinerals(); int getFreeGas(); bool detectBuildOrderDeadlock(); bool canPlanBuildOrderNow() const; bool canMakeNow(BWAPI::Unit producer, MetaType t); bool meetsReservedResources(MetaType type); ProductionManager(); public: void update(); void onUnitDestroy(BWAPI::Unit unit); void performBuildOrderSearch(); void drawProductionInformation(int x, int y); void queueGasSteal(); std::vector buildingsQueued(); BWAPI::Unit getProducer(MetaType t, BWAPI::Position closestTo = BWAPI::Positions::None); }; class CompareWhenStarted { public: CompareWhenStarted() {} // the sorting operator bool operator() (BWAPI::Unit u1, BWAPI::Unit u2) { int startedU1 = BWAPI::Broodwar->getFrameCount() - (u1->getType().buildTime() - u1->getRemainingBuildTime()); int startedU2 = BWAPI::Broodwar->getFrameCount() - (u2->getType().buildTime() - u2->getRemainingBuildTime()); return startedU1 > startedU2; } }; } ================================================ FILE: UAlbertaBot/Source/Profiler.hpp ================================================ #pragma once #include #include #include #include #include //#define PROFILING 1 #ifdef PROFILING #define PROFILE_SCOPE(name) \ ProfileTimer timer##__LINE__(name) #define PROFILE_FUNCTION() \ PROFILE_SCOPE(__FUNCTION__) #else #define PROFILE_FUNCTION() #define PROFILE_SCOPE(name) #endif namespace UAlbertaBot { struct ProfileResult { std::string name = "Default"; long long start = 0; long long end = 0; size_t threadID = 0; }; class Profiler { std::string m_outputFile = "results.json"; size_t m_profileCount = 0; std::ofstream m_outputStream; std::mutex m_lock; Profiler() { m_outputStream = std::ofstream(m_outputFile); writeHeader(); } void writeHeader() { m_outputStream << "{\"otherData\": {},\"traceEvents\":["; } void writeFooter() { m_outputStream << "]}"; } public: static Profiler& Instance() { static Profiler instance; return instance; } ~Profiler() { writeFooter(); } void writeProfile(const ProfileResult& result) { std::lock_guard lock(m_lock); if (m_profileCount++ > 0) { m_outputStream << ","; } std::string name = result.name; std::replace(name.begin(), name.end(), '"', '\''); m_outputStream << "\n{"; m_outputStream << "\"cat\":\"function\","; m_outputStream << "\"dur\":" << (result.end - result.start) << ','; m_outputStream << "\"name\":\"" << name << "\","; m_outputStream << "\"ph\":\"X\","; m_outputStream << "\"pid\":0,"; m_outputStream << "\"tid\":" << result.threadID << ","; m_outputStream << "\"ts\":" << result.start; m_outputStream << "}"; } }; class ProfileTimer { ProfileResult m_result; bool m_stopped = false; std::chrono::time_point m_startTimepoint; public: ProfileTimer(const std::string & name) { m_result.name = name; m_startTimepoint = std::chrono::high_resolution_clock::now(); } ~ProfileTimer() { stop(); } void stop() { if (m_stopped) { return; } auto endTimepoint = std::chrono::high_resolution_clock::now(); m_result.start = std::chrono::time_point_cast(m_startTimepoint).time_since_epoch().count(); m_result.end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); m_result.threadID = std::hash{}(std::this_thread::get_id()); Profiler::Instance().writeProfile(m_result); m_stopped = true; } }; } ================================================ FILE: UAlbertaBot/Source/RangedManager.cpp ================================================ #include "RangedManager.h" #include "UnitUtil.h" #include "Micro.h" using namespace UAlbertaBot; RangedManager::RangedManager() { } void RangedManager::executeMicro(const BWAPI::Unitset & targets) { assignTargetsOld(targets); } void RangedManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u) { return u->isVisible(); }); for (auto & rangedUnit : rangedUnits) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); // if the order is to attack or defend if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!rangedUnitTargets.empty()) { // find the best target for this zealot BWAPI::Unit target = getTarget(rangedUnit, rangedUnitTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(rangedUnit->getPosition(), rangedUnit->getTargetPosition(), BWAPI::Colors::Purple); } // attack it if (Config::Micro::KiteWithRangedUnits) { if (rangedUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || rangedUnit->getType() == BWAPI::UnitTypes::Terran_Vulture) { Micro::MutaDanceTarget(rangedUnit, target); } else { Micro::SmartKiteTarget(rangedUnit, target); } } else { Micro::SmartAttackUnit(rangedUnit, target); } } // if there are no targets else { // if we're not near the order position if (rangedUnit->getDistance(m_order.getPosition()) > 100) { // move to it Micro::SmartAttackMove(rangedUnit, m_order.getPosition()); } } } } } std::pair RangedManager::findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets) { std::pair closestPair(nullptr, nullptr); double closestDistance = std::numeric_limits::max(); for (auto & attacker : attackers) { BWAPI::Unit target = getTarget(attacker, targets); double dist = attacker->getDistance(attacker); if (!closestPair.first || (dist < closestDistance)) { closestPair.first = attacker; closestPair.second = target; closestDistance = dist; } } return closestPair; } // get a target for the zealot to attack BWAPI::Unit RangedManager::getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets) { int bestPriorityDistance = 1000000; int bestPriority = 0; double bestLTD = 0; int highPriority = 0; double closestDist = std::numeric_limits::infinity(); BWAPI::Unit closestTarget = nullptr; for (const auto & target : targets) { double distance = rangedUnit->getDistance(target); double LTD = UnitUtil::CalculateLTD(target, rangedUnit); int priority = getAttackPriority(rangedUnit, target); bool targetIsThreat = LTD > 0; if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist)) { closestDist = distance; highPriority = priority; closestTarget = target; } } return closestTarget; } // get the attack priority of a type in relation to a zergling int RangedManager::getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target) { BWAPI::UnitType rangedType = rangedUnit->getType(); BWAPI::UnitType targetType = target->getType(); if (rangedUnit->getType() == BWAPI::UnitTypes::Zerg_Scourge) { if (target->getType() == BWAPI::UnitTypes::Protoss_Carrier) { return 100; } if (target->getType() == BWAPI::UnitTypes::Protoss_Corsair) { return 90; } } bool isThreat = rangedType.isFlyer() ? targetType.airWeapon() != BWAPI::WeaponTypes::None : targetType.groundWeapon() != BWAPI::WeaponTypes::None; if (target->getType().isWorker()) { isThreat = false; } if (target->getType() == BWAPI::UnitTypes::Zerg_Larva || target->getType() == BWAPI::UnitTypes::Zerg_Egg) { return 0; } if (rangedUnit->isFlying() && target->getType() == BWAPI::UnitTypes::Protoss_Carrier) { return 101; } // if the target is building something near our base something is fishy BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); if (target->getType().isWorker() && (target->isConstructing() || target->isRepairing()) && target->getDistance(ourBasePosition) < 1200) { return 100; } if (target->getType().isBuilding() && (target->isCompleted() || target->isBeingConstructed()) && target->getDistance(ourBasePosition) < 1200) { return 90; } // highest priority is something that can attack us or aid in combat if (targetType == BWAPI::UnitTypes::Terran_Bunker || isThreat) { return 11; } // next priority is worker else if (targetType.isWorker()) { if (rangedUnit->getType() == BWAPI::UnitTypes::Terran_Vulture) { return 11; } return 11; } // next is special buildings else if (targetType == BWAPI::UnitTypes::Zerg_Spawning_Pool) { return 5; } // next is special buildings else if (targetType == BWAPI::UnitTypes::Protoss_Pylon) { return 5; } // next is buildings that cost gas else if (targetType.gasPrice() > 0) { return 4; } else if (targetType.mineralPrice() > 0) { return 3; } // then everything else else { return 1; } } BWAPI::Unit RangedManager::closestrangedUnit(BWAPI::Unit target, std::set & rangedUnitsToAssign) { double minDistance = 0; BWAPI::Unit closest = nullptr; for (auto & rangedUnit : rangedUnitsToAssign) { double distance = rangedUnit->getDistance(target); if (!closest || distance < minDistance) { minDistance = distance; closest = rangedUnit; } } return closest; } // still has bug in it somewhere, use Old version void RangedManager::assignTargetsNew(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u) { return u->isVisible(); }); BWAPI::Unitset rangedUnitsToAssign(rangedUnits); std::map attackersAssigned; for (auto & unit : rangedUnitTargets) { attackersAssigned[unit] = 0; } // keep assigning targets while we have attackers and targets remaining while (!rangedUnitsToAssign.empty() && !rangedUnitTargets.empty()) { auto attackerAssignment = findClosestUnitPair(rangedUnitsToAssign, rangedUnitTargets); BWAPI::Unit & attacker = attackerAssignment.first; BWAPI::Unit & target = attackerAssignment.second; UAB_ASSERT_WARNING(attacker, "We should have chosen an attacker!"); if (!attacker) { break; } if (!target) { Micro::SmartAttackMove(attacker, m_order.getPosition()); continue; } if (Config::Micro::KiteWithRangedUnits) { if (attacker->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || attacker->getType() == BWAPI::UnitTypes::Terran_Vulture) { Micro::MutaDanceTarget(attacker, target); } else { Micro::SmartKiteTarget(attacker, target); } } else { Micro::SmartAttackUnit(attacker, target); } // update the number of units assigned to attack the target we found int & assigned = attackersAssigned[attackerAssignment.second]; assigned++; // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned > 2)) { rangedUnitTargets.erase(target); } // if it's a building and there's more than 10 things assigned to it already, don't assign more else if (target->getType().isBuilding() && (assigned > 10)) { rangedUnitTargets.erase(target); } rangedUnitsToAssign.erase(attacker); } // if there's no targets left, attack move to the order destination if (rangedUnitTargets.empty()) { for (auto & unit : rangedUnitsToAssign) { if (unit->getDistance(m_order.getPosition()) > 100) { // move to it Micro::SmartAttackMove(unit, m_order.getPosition()); } } } } ================================================ FILE: UAlbertaBot/Source/RangedManager.h ================================================ #pragma once #include #include "MicroManager.h" namespace UAlbertaBot { class RangedManager : public MicroManager { public: RangedManager(); void executeMicro(const BWAPI::Unitset & targets); void assignTargetsNew(const BWAPI::Unitset & targets); void assignTargetsOld(const BWAPI::Unitset & targets); int getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target); BWAPI::Unit closestrangedUnit(BWAPI::Unit target, std::set & rangedUnitsToAssign); BWAPI::Unit getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets); std::pair findClosestUnitPair(const BWAPI::Unitset & attackers, const BWAPI::Unitset & targets); }; } ================================================ FILE: UAlbertaBot/Source/ScoutManager.cpp ================================================ #include "ScoutManager.h" #include "ProductionManager.h" #include "BaseLocationManager.h" #include "Global.h" #include "MicroManager.h" #include "InformationManager.h" #include "Micro.h" #include "WorkerManager.h" #include "MapTools.h" using namespace UAlbertaBot; ScoutManager::ScoutManager() { } void ScoutManager::update() { PROFILE_FUNCTION(); if (!Config::Modules::UsingScoutManager) { return; } moveScouts(); drawScoutInformation(200, 320); } void ScoutManager::setWorkerScout(BWAPI::Unit unit) { // if we have a previous worker scout, release it back to the worker manager if (m_workerScout) { Global::Workers().finishedWithWorker(m_workerScout); } m_workerScout = unit; Global::Workers().setScoutWorker(m_workerScout); } void ScoutManager::drawScoutInformation(int x, int y) { if (!Config::Debug::DrawScoutInfo) { return; } BWAPI::Broodwar->drawTextScreen(x, y, "ScoutInfo: %s", m_scoutStatus.c_str()); BWAPI::Broodwar->drawTextScreen(x, y+10, "GasSteal: %s", m_gasStealStatus.c_str()); } void ScoutManager::moveScouts() { if (!m_workerScout || !m_workerScout->exists() || !(m_workerScout->getHitPoints() > 0)) { return; } const int scoutHP = m_workerScout->getHitPoints() + m_workerScout->getShields(); gasSteal(); // get the enemy base location, if we have one const BaseLocation * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); const int scoutDistanceThreshold = 30; if (m_workerScout->isCarryingGas()) { BWAPI::Broodwar->drawCircleMap(m_workerScout->getPosition(), 10, BWAPI::Colors::Purple, true); } // if we initiated a gas steal and the worker isn't idle, const bool finishedConstructingGasSteal = m_workerScout->isIdle() || m_workerScout->isCarryingGas(); if (!m_gasStealFinished && m_didGasSteal && !finishedConstructingGasSteal) { return; } // check to see if the gas steal is completed else if (m_didGasSteal && finishedConstructingGasSteal) { m_gasStealFinished = true; } // for each start location in the level if (!enemyBaseLocation) { m_scoutStatus = "Enemy base unknown, exploring"; for (auto startLocation : BWAPI::Broodwar->getStartLocations()) { // if we haven't explored it yet, explore it if (!BWAPI::Broodwar->isExplored(startLocation)) { Micro::SmartMove(m_workerScout, BWAPI::Position(startLocation)); BWAPI::Broodwar->drawCircleMap(BWAPI::Position(startLocation), 32, BWAPI::Colors::Purple); return; } } } // if we know where the enemy region is and where our scout is if (enemyBaseLocation) { const int scoutDistanceToEnemy = Global::Map().getGroundDistance(m_workerScout->getPosition(), enemyBaseLocation->getPosition()); const bool scoutInRangeOfenemy = scoutDistanceToEnemy <= scoutDistanceThreshold; // we only care if the scout is under attack within the enemy region // this ignores if their scout worker attacks it on the way to their base if (scoutHP < m_previousScoutHP) { m_scoutUnderAttack = true; } if (!m_workerScout->isUnderAttack() && !enemyWorkerInRadius()) { m_scoutUnderAttack = false; } // if the scout is in the enemy region if (scoutInRangeOfenemy) { // get the closest enemy worker BWAPI::Unit closestWorker = closestEnemyWorker(); // if the worker scout is not under attack if (!m_scoutUnderAttack) { // if there is a worker nearby, harass it if (Config::Strategy::ScoutHarassEnemy && (!Config::Strategy::GasStealWithScout || m_gasStealFinished) && closestWorker && (m_workerScout->getDistance(closestWorker) < 800)) { m_scoutStatus = "Harass enemy worker"; Micro::SmartAttackUnit(m_workerScout, closestWorker); } // otherwise keep moving to the enemy region else { m_scoutStatus = "Following perimeter"; Micro::SmartMove(m_workerScout, BWAPI::Position(enemyBaseLocation->getPosition())); } } // if the worker scout is under attack else { m_scoutStatus = "Under attack inside, fleeing"; fleeScout(); } } // if the scout is not in the enemy region else if (m_scoutUnderAttack) { m_scoutStatus = "Under attack inside, fleeing"; fleeScout(); } else { m_scoutStatus = "Enemy region known, going there"; // move to the enemy region Micro::SmartMove(m_workerScout, BWAPI::Position(enemyBaseLocation->getPosition())); } } m_previousScoutHP = scoutHP; } void ScoutManager::fleeScout() { const BWAPI::Position fleeTo = getFleePosition(); if (Config::Debug::DrawScoutInfo) { BWAPI::Broodwar->drawCircleMap(fleeTo, 5, BWAPI::Colors::Red, true); } Micro::SmartMove(m_workerScout, fleeTo); } void ScoutManager::gasSteal() { if (!Config::Strategy::GasStealWithScout) { m_gasStealStatus = "Not using gas steal"; return; } if (m_didGasSteal) { return; } if (!m_workerScout) { m_gasStealStatus = "No worker scout"; return; } auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); if (!enemyBaseLocation) { m_gasStealStatus = "No enemy base location found"; return; } const BWAPI::Unit enemyGeyser = getEnemyGeyser(); if (!enemyGeyser) { m_gasStealStatus = "No enemy geyser found"; false; } if (!m_didGasSteal) { Global::Production().queueGasSteal(); m_didGasSteal = true; Micro::SmartMove(m_workerScout, enemyGeyser->getPosition()); m_gasStealStatus = "Did Gas Steal"; } } BWAPI::Unit ScoutManager::closestEnemyWorker() { BWAPI::Unit enemyWorker = nullptr; BWAPI::Unit geyser = getEnemyGeyser(); double maxDist = 0; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isWorker() && unit->isConstructing()) { return unit; } } // for each enemy worker for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isWorker()) { const double dist = unit->getDistance(geyser); if (dist < 800 && dist > maxDist) { maxDist = dist; enemyWorker = unit; } } } return enemyWorker; } BWAPI::Unit ScoutManager::getEnemyGeyser() { BWAPI::Unit geyser = nullptr; const auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); for (auto & unit : enemyBaseLocation->getGeysers()) { geyser = unit; } return geyser; } bool ScoutManager::enemyWorkerInRadius() { for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isWorker() && (unit->getDistance(m_workerScout) < 300)) { return true; } } return false; } bool ScoutManager::immediateThreat() { BWAPI::Unitset enemyAttackingWorkers; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isWorker() && unit->isAttacking()) { enemyAttackingWorkers.insert(unit); } } if (m_workerScout->isUnderAttack()) { return true; } for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { const double dist = unit->getDistance(m_workerScout); const double range = unit->getType().groundWeapon().maxRange(); if (unit->getType().canAttack() && !unit->getType().isWorker() && (dist <= range + 32)) { return true; } } return false; } BWAPI::Position ScoutManager::getFleePosition() { return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); } ================================================ FILE: UAlbertaBot/Source/ScoutManager.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { class ScoutManager { friend class Global; BWAPI::Unit m_workerScout = nullptr; std::string m_scoutStatus = "None"; std::string m_gasStealStatus = "None"; int m_numWorkerScouts = 0; int m_previousScoutHP = 0; bool m_scoutUnderAttack = false; bool m_didGasSteal = false; bool m_gasStealFinished = false; bool enemyWorkerInRadius(); bool immediateThreat(); void gasSteal(); void fleeScout(); void moveScouts(); void drawScoutInformation(int x, int y); BWAPI::Position getFleePosition(); BWAPI::Unit getEnemyGeyser(); BWAPI::Unit closestEnemyWorker(); ScoutManager(); public: void update(); void setWorkerScout(BWAPI::Unit unit); }; } ================================================ FILE: UAlbertaBot/Source/Squad.cpp ================================================ #include "Squad.h" #include "UnitUtil.h" #include "Global.h" #include "WorkerManager.h" #include "UnitData.h" #include "MapTools.h" #include "StrategyManager.h" #include "CombatSimulation.h" #include "InformationManager.h" using namespace UAlbertaBot; Squad::Squad() { } Squad::Squad(const std::string & name, SquadOrder order, size_t priority) : m_name(name) , m_order(order) , m_lastRetreatSwitch(0) , m_lastRetreatSwitchVal(false) , m_priority(priority) { } Squad::~Squad() { clear(); } void Squad::update() { // update all necessary unit information within this squad updateUnits(); // determine whether or not we should regroup bool needToRegroup = needsToRegroup(); // draw some debug info if (Config::Debug::DrawSquadInfo && m_order.getType() == SquadOrderTypes::Attack) { BWAPI::Broodwar->drawTextScreen(200, 350, "%s", m_regroupStatus.c_str()); BWAPI::Unit closest = unitClosestToEnemy(); } // if we do need to regroup, do it if (needToRegroup) { BWAPI::Position regroupPosition = calcRegroupPosition(); if (Config::Debug::DrawCombatSimulationInfo) { BWAPI::Broodwar->drawTextScreen(200, 150, "REGROUP"); } BWAPI::Broodwar->drawCircleMap(regroupPosition.x, regroupPosition.y, 30, BWAPI::Colors::Purple, true); m_meleeManager.regroup(regroupPosition); m_rangedManager.regroup(regroupPosition); m_tankManager.regroup(regroupPosition); m_medicManager.regroup(regroupPosition); } else // otherwise, execute micro { m_meleeManager.execute(m_order); m_rangedManager.execute(m_order); m_tankManager.execute(m_order); m_medicManager.execute(m_order); m_transportManager.update(); m_detectorManager.setUnitClosestToEnemy(unitClosestToEnemy()); m_detectorManager.execute(m_order); } } bool Squad::isEmpty() const { return m_units.empty(); } size_t Squad::getPriority() const { return m_priority; } void Squad::setPriority(const size_t & priority) { m_priority = priority; } void Squad::updateUnits() { setAllUnits(); setNearEnemyUnits(); addUnitsToMicroManagers(); } void Squad::setAllUnits() { // clean up the m_units vector just in case one of them died BWAPI::Unitset goodUnits; for (auto & unit : m_units) { if (unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists() && unit->getPosition().isValid() && unit->getType() != BWAPI::UnitTypes::Unknown) { goodUnits.insert(unit); } } m_units = goodUnits; } void Squad::setNearEnemyUnits() { m_nearEnemy.clear(); for (auto & unit : m_units) { int x = unit->getPosition().x; int y = unit->getPosition().y; int left = unit->getType().dimensionLeft(); int right = unit->getType().dimensionRight(); int top = unit->getType().dimensionUp(); int bottom = unit->getType().dimensionDown(); m_nearEnemy[unit] = unitNearEnemy(unit); if (m_nearEnemy[unit]) { if (Config::Debug::DrawSquadInfo) BWAPI::Broodwar->drawBoxMap(x-left, y - top, x + right, y + bottom, Config::Debug::ColorUnitNearEnemy); } else { if (Config::Debug::DrawSquadInfo) BWAPI::Broodwar->drawBoxMap(x-left, y - top, x + right, y + bottom, Config::Debug::ColorUnitNotNearEnemy); } } } void Squad::addUnitsToMicroManagers() { BWAPI::Unitset meleeUnits; BWAPI::Unitset rangedUnits; BWAPI::Unitset detectorUnits; BWAPI::Unitset transportUnits; BWAPI::Unitset tankUnits; BWAPI::Unitset medicUnits; // add m_units to micro managers for (auto & unit : m_units) { if (unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists()) { // select dector m_units if (unit->getType() == BWAPI::UnitTypes::Terran_Medic) { medicUnits.insert(unit); } else if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode) { tankUnits.insert(unit); } else if (unit->getType().isDetector() && !unit->getType().isBuilding()) { detectorUnits.insert(unit); } // select transport m_units else if (unit->getType() == BWAPI::UnitTypes::Protoss_Shuttle || unit->getType() == BWAPI::UnitTypes::Terran_Dropship) { transportUnits.insert(unit); } // select ranged m_units else if ((unit->getType().groundWeapon().maxRange() > 32) || (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) || (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge)) { rangedUnits.insert(unit); } // select melee m_units else if (unit->getType().groundWeapon().maxRange() <= 32) { meleeUnits.insert(unit); } } } m_meleeManager.setUnits(meleeUnits); m_rangedManager.setUnits(rangedUnits); m_detectorManager.setUnits(detectorUnits); m_transportManager.setUnits(transportUnits); m_tankManager.setUnits(tankUnits); m_medicManager.setUnits(medicUnits); } // calculates whether or not to regroup bool Squad::needsToRegroup() { if (!Config::Micro::UseSparcraftSimulation) { return false; } // if we are not attacking, never regroup if (m_units.empty() || (m_order.getType() != SquadOrderTypes::Attack)) { m_regroupStatus = std::string("\x04 No combat units available"); return false; } BWAPI::Unit unitClosest = unitClosestToEnemy(); if (!unitClosest) { m_regroupStatus = std::string("\x04 No closest unit"); return false; } // if none of our units are in attack range of any enemy units, don't retreat std::vector enemyCombatUnits; const auto & enemyUnitInfo = Global::Info().getUnitInfo(BWAPI::Broodwar->enemy()); bool anyInRange = false; for (const auto & eui : enemyUnitInfo) { bool inRange = false; for (const auto & u : m_units) { int range = UnitUtil::GetAttackRange(eui.second.type, u->getType()); if (range + 128 >= eui.second.lastPosition.getDistance(u->getPosition())) { inRange = true; break; } } if (inRange) { anyInRange = true; break; } } if (!anyInRange) { m_regroupStatus = std::string("\x04 No enemy units in attack range"); return false; } SparCraft::ScoreType score = 0; //do the SparCraft Simulation! CombatSimulation sim; sim.setCombatUnits(unitClosest->getPosition(), Config::Micro::CombatRegroupRadius); score = sim.simulateCombat(); // if we are DT rushing and we haven't lost a DT yet, no retreat! if (Config::Strategy::StrategyName == "Protoss_DTRush" && (BWAPI::Broodwar->self()->deadUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) == 0)) { m_regroupStatus = std::string("\x04 DARK TEMPLAR HOOOOO!"); return false; } bool retreat = score < 0; int switchTime = 100; bool waiting = false; // we should not attack unless 5 seconds have passed since a retreat if (retreat != m_lastRetreatSwitchVal) { if (!retreat && (BWAPI::Broodwar->getFrameCount() - m_lastRetreatSwitch < switchTime)) { waiting = true; retreat = m_lastRetreatSwitchVal; } else { waiting = false; m_lastRetreatSwitch = BWAPI::Broodwar->getFrameCount(); m_lastRetreatSwitchVal = retreat; } } if (retreat) { m_regroupStatus = std::string("\x04 Retreat - simulation predicts defeat"); } else { m_regroupStatus = std::string("\x04 Attack - simulation predicts success"); } return retreat; } void Squad::setSquadOrder(const SquadOrder & so) { m_order = so; } bool Squad::containsUnit(BWAPI::Unit u) const { return m_units.contains(u); } void Squad::clear() { for (auto & unit : getUnits()) { if (unit->getType().isWorker()) { Global::Workers().finishedWithWorker(unit); } } m_units.clear(); } bool Squad::unitNearEnemy(BWAPI::Unit unit) { assert(unit); BWAPI::Unitset enemyNear; Global::Map().getUnits(enemyNear, unit->getPosition(), 400, false, true); return enemyNear.size() > 0; } BWAPI::Position Squad::calcCenter() { if (m_units.empty()) { if (Config::Debug::DrawSquadInfo) { BWAPI::Broodwar->printf("Squad::calcCenter() called on empty squad"); } return BWAPI::Position(0, 0); } BWAPI::Position accum(0, 0); for (auto & unit : m_units) { accum += unit->getPosition(); } return BWAPI::Position(accum.x / m_units.size(), accum.y / m_units.size()); } BWAPI::Position Squad::calcRegroupPosition() { BWAPI::Position regroup(0, 0); int minDist = 100000; for (auto & unit : m_units) { if (!m_nearEnemy[unit]) { int dist = unit->getDistance(m_order.getPosition()); if (dist < minDist) { minDist = dist; regroup = unit->getPosition(); } } } if (regroup == BWAPI::Position(0, 0)) { return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); } else { return regroup; } } BWAPI::Unit Squad::unitClosestToEnemy() { BWAPI::Unit closest = nullptr; int closestDist = 100000; for (auto & unit : m_units) { if (unit->getType() == BWAPI::UnitTypes::Protoss_Observer) { continue; } // the distance to the order position int dist = Global::Map().getGroundDistance(unit->getPosition(), m_order.getPosition()); if (dist != -1 && (!closest || dist < closestDist)) { closest = unit; closestDist = dist; } } if (!closest) { for (auto & unit : m_units) { if (unit->getType() == BWAPI::UnitTypes::Protoss_Observer) { continue; } // the distance to the order position int dist = unit->getDistance(BWAPI::Position(BWAPI::Broodwar->enemy()->getStartLocation())); if (dist != -1 && (!closest || dist < closestDist)) { closest = unit; closestDist = dist; } } } return closest; } int Squad::squadUnitsNear(BWAPI::Position p) { int numUnits = 0; for (auto & unit : m_units) { if (unit->getDistance(p) < 600) { numUnits++; } } return numUnits; } const BWAPI::Unitset & Squad::getUnits() const { return m_units; } const SquadOrder & Squad::getSquadOrder() const { return m_order; } void Squad::addUnit(BWAPI::Unit u) { m_units.insert(u); } void Squad::removeUnit(BWAPI::Unit u) { m_units.erase(u); } const std::string & Squad::getName() const { return m_name; } ================================================ FILE: UAlbertaBot/Source/Squad.h ================================================ #pragma once #include "Common.h" #include "MeleeManager.h" #include "RangedManager.h" #include "DetectorManager.h" #include "TransportManager.h" #include "SquadOrder.h" #include "TankManager.h" #include "MedicManager.h" namespace UAlbertaBot { class Squad { BWAPI::Unitset m_units; std::string m_name = "Default"; std::string m_regroupStatus = "Default"; int m_lastRetreatSwitch = 0; bool m_lastRetreatSwitchVal = false; size_t m_priority = 0; SquadOrder m_order; MeleeManager m_meleeManager; RangedManager m_rangedManager; DetectorManager m_detectorManager; TransportManager m_transportManager; TankManager m_tankManager; MedicManager m_medicManager; std::map m_nearEnemy; BWAPI::Unit unitClosestToEnemy(); void updateUnits(); void addUnitsToMicroManagers(); void setNearEnemyUnits(); void setAllUnits(); bool unitNearEnemy(BWAPI::Unit unit); bool needsToRegroup(); int squadUnitsNear(BWAPI::Position p); public: Squad(const std::string & name, SquadOrder order, size_t priority); Squad(); ~Squad(); void update(); void setSquadOrder(const SquadOrder & so); void addUnit(BWAPI::Unit u); void removeUnit(BWAPI::Unit u); bool containsUnit(BWAPI::Unit u) const; bool isEmpty() const; void clear(); size_t getPriority() const; void setPriority(const size_t & priority); const std::string & getName() const; BWAPI::Position calcCenter(); BWAPI::Position calcRegroupPosition(); const BWAPI::Unitset & getUnits() const; const SquadOrder & getSquadOrder() const; }; } ================================================ FILE: UAlbertaBot/Source/SquadData.cpp ================================================ #include "SquadData.h" #include "Global.h" #include "WorkerManager.h" #include "Squad.h" using namespace UAlbertaBot; SquadData::SquadData() { } void SquadData::update() { updateAllSquads(); verifySquadUniqueMembership(); } void SquadData::clearSquadData() { // give back workers who were in squads for (auto & kv : m_squads) { Squad & squad = kv.second; const BWAPI::Unitset & units = squad.getUnits(); for (auto & unit : units) { if (unit->getType().isWorker()) { Global::Workers().finishedWithWorker(unit); } } } m_squads.clear(); } void SquadData::removeSquad(const std::string & squadName) { auto & squadPtr = m_squads.find(squadName); UAB_ASSERT_WARNING(squadPtr != m_squads.end(), "Trying to clear a squad that didn't exist: %s", squadName.c_str()); if (squadPtr == m_squads.end()) { return; } for (auto & unit : squadPtr->second.getUnits()) { if (unit->getType().isWorker()) { Global::Workers().finishedWithWorker(unit); } } m_squads.erase(squadName); } const std::map & SquadData::getSquads() const { return m_squads; } bool SquadData::squadExists(const std::string & squadName) { return m_squads.find(squadName) != m_squads.end(); } void SquadData::addSquad(const std::string & squadName, const Squad & squad) { m_squads[squadName] = squad; } void SquadData::updateAllSquads() { for (auto & kv : m_squads) { kv.second.update(); } } void SquadData::drawSquadInformation(int x, int y) { if (!Config::Debug::DrawSquadInfo) { return; } BWAPI::Broodwar->drawTextScreen(x, y, "\x04Squads"); BWAPI::Broodwar->drawTextScreen(x, y+20, "\x04NAME"); BWAPI::Broodwar->drawTextScreen(x+150, y+20, "\x04SIZE"); BWAPI::Broodwar->drawTextScreen(x+200, y+20, "\x04LOCATION"); int yspace = 0; for (auto & kv : m_squads) { const Squad & squad = kv.second; const BWAPI::Unitset & units = squad.getUnits(); const SquadOrder & order = squad.getSquadOrder(); BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), "\x03%s", squad.getName().c_str()); BWAPI::Broodwar->drawTextScreen(x+150, y+40+((yspace)*10), "\x03%d", units.size()); BWAPI::Broodwar->drawTextScreen(x+200, y+40+((yspace++)*10), "\x03(%d,%d)", order.getPosition().x, order.getPosition().y); BWAPI::Broodwar->drawCircleMap(order.getPosition(), 10, BWAPI::Colors::Green, true); BWAPI::Broodwar->drawCircleMap(order.getPosition(), order.getRadius(), BWAPI::Colors::Red, false); BWAPI::Broodwar->drawTextMap(order.getPosition() + BWAPI::Position(0, 12), "%s", squad.getName().c_str()); for (const BWAPI::Unit unit : units) { BWAPI::Broodwar->drawTextMap(unit->getPosition() + BWAPI::Position(0, 10), "%s", squad.getName().c_str()); } } } void SquadData::verifySquadUniqueMembership() { BWAPI::Unitset assigned; for (const auto & kv : m_squads) { for (auto & unit : kv.second.getUnits()) { if (assigned.contains(unit)) { BWAPI::Broodwar->printf("Unit is in at least two squads: %s", unit->getType().getName().c_str()); } assigned.insert(unit); } } } bool SquadData::unitIsInSquad(BWAPI::Unit unit) const { return getUnitSquad(unit) != nullptr; } const Squad * SquadData::getUnitSquad(BWAPI::Unit unit) const { for (const auto & kv : m_squads) { if (kv.second.getUnits().contains(unit)) { return &kv.second; } } return nullptr; } Squad * SquadData::getUnitSquad(BWAPI::Unit unit) { for (auto & kv : m_squads) { if (kv.second.getUnits().contains(unit)) { return &kv.second; } } return nullptr; } void SquadData::assignUnitToSquad(BWAPI::Unit unit, Squad & squad) { UAB_ASSERT_WARNING(canAssignUnitToSquad(unit, squad), "We shouldn't be re-assigning this unit!"); Squad * previousSquad = getUnitSquad(unit); if (previousSquad) { previousSquad->removeUnit(unit); } squad.addUnit(unit); } bool SquadData::canAssignUnitToSquad(BWAPI::Unit unit, const Squad & squad) const { const Squad * unitSquad = getUnitSquad(unit); // make sure strictly less than so we don't reassign to the same squad etc return !unitSquad || (unitSquad->getPriority() < squad.getPriority()); } Squad & SquadData::getSquad(const std::string & squadName) { UAB_ASSERT_WARNING(squadExists(squadName), "Trying to access squad that doesn't exist: %s", squadName); return m_squads[squadName]; } ================================================ FILE: UAlbertaBot/Source/SquadData.h ================================================ #pragma once #include "Common.h" #include "Squad.h" namespace UAlbertaBot { class SquadData { std::map m_squads; void updateAllSquads(); void verifySquadUniqueMembership(); public: SquadData(); void update(); void clearSquadData(); void assignUnitToSquad(BWAPI::Unit unit, Squad & squad); void addSquad(const std::string & squadName, const Squad & squad); void removeSquad(const std::string & squadName); void drawSquadInformation(int x, int y); bool canAssignUnitToSquad(BWAPI::Unit unit, const Squad & squad) const; bool squadExists(const std::string & squadName); bool unitIsInSquad(BWAPI::Unit unit) const; const Squad * getUnitSquad(BWAPI::Unit unit) const; Squad * getUnitSquad(BWAPI::Unit unit); Squad & getSquad(const std::string & squadName); const std::map & getSquads() const; }; } ================================================ FILE: UAlbertaBot/Source/SquadOrder.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { namespace SquadOrderTypes { enum { None, Idle, Attack, Defend, Regroup, Drop, SquadOrderTypes }; } class SquadOrder { size_t m_type = SquadOrderTypes::None; int m_radius = 0; BWAPI::Position m_position; std::string m_status; public: SquadOrder() { } SquadOrder(int type, BWAPI::Position position, int radius, std::string status = "Default") : m_type(type) , m_position(position) , m_radius(radius) , m_status(status) { } const std::string & getStatus() const { return m_status; } const BWAPI::Position & getPosition() const { return m_position; } const int getRadius() const { return m_radius; } const size_t getType() const { return m_type; } }; } ================================================ FILE: UAlbertaBot/Source/StarDraftMap.hpp ================================================ #pragma once #include "Grid.hpp" #include #include namespace UAlbertaBot { namespace TileType { enum { Unwalkable = 'U', Walk = 'W', BuildAll = 'B', NoDepot = 'D', Mineral = 'M', Gas = 'G', Neutral = 'N' }; } struct Tile { size_t x = 0, y = 0; }; class StarDraftMap { Grid m_buildTiles; Grid m_walkTiles; std::vector m_minerals; std::vector m_geysers; std::vector m_startTiles; inline bool isWalkable(char tile) const noexcept { return (tile == TileType::Walk) || (tile == TileType::BuildAll) || (tile == TileType::NoDepot); } inline bool canBuild(char tile) const noexcept { return tile == (TileType::BuildAll) || (tile == TileType::NoDepot); } inline bool canBuildDepot(char tile) const noexcept { return tile == TileType::BuildAll; } public: StarDraftMap() {} StarDraftMap(const std::string & path) { load(path); } StarDraftMap(size_t width, size_t height) : m_buildTiles(width, height, 0) , m_walkTiles(width*4, height*4, false) { } inline void set(size_t x, size_t y, char val) { m_buildTiles.set(x, y, val); if (val == TileType::Mineral) { m_minerals.push_back({x, y}); } else if (val == TileType::Gas) { m_geysers.push_back({x, y}); } } inline void setWalk(size_t x, size_t y, bool val) { m_walkTiles.set(x, y, val); } inline void addStartTile(size_t x, size_t y) { m_startTiles.push_back({x, y}); } inline size_t width() const { return m_buildTiles.width(); } inline size_t height() const { return m_buildTiles.height(); } inline char get(size_t x, size_t y) const { return m_buildTiles.get(x, y); } inline char getWalk(size_t x, size_t y) const { return m_walkTiles.get(x, y); } inline bool isWalkable(size_t x, size_t y) const { return isWalkable(get(x, y)); } inline bool canBuild(size_t x, size_t y) const { return canBuild(get(x,y)); } inline bool canBuildDepot(size_t x, size_t y) const { return canBuildDepot(get(x,y)); } inline const std::vector & startTiles() const { return m_startTiles; } inline void load(const std::string & path) { std::ifstream fin(path); size_t w, h, n, sx, sy; char c; // first line is width height fin >> w >> h; m_buildTiles = Grid(w, h, 0); m_walkTiles = Grid(4*w, 4*h, 0); // next line is the start tile locations fin >> n; for (size_t i=0; i> sx >> sy; m_startTiles.push_back({sx, sy}); } // followed by the int values in the grid for (size_t y=0; y < m_buildTiles.height(); y++) { for (size_t x=0; x < m_buildTiles.width(); x++) { fin >> c; m_buildTiles.set(x, y, c); } } // followed by the walk tiles for (size_t y=0; y < m_walkTiles.height(); y++) { for (size_t x=0; x < m_walkTiles.width(); x++) { fin >> c; m_walkTiles.set(x, y, c); } } } inline void save(const std::string & path) const { std::ofstream fout(path); // first line is width height fout << m_buildTiles.width() << " " << m_buildTiles.height() << "\n"; // next line is the start tile locations fout << m_startTiles.size(); for (auto & tile : m_startTiles) { fout << " " << tile.x << " " << tile.y; } fout << "\n"; // followed by the int values in the grid for (size_t y=0; yself()->getRace()) , m_enemyRace(BWAPI::Broodwar->enemy()->getRace()) , m_emptyBuildOrder(BWAPI::Broodwar->self()->getRace()) { } const int StrategyManager::getScore(BWAPI::Player player) const { return player->getBuildingScore() + player->getKillScore() + player->getRazingScore() + player->getUnitScore(); } const BuildOrder & StrategyManager::getOpeningBookBuildOrder() const { auto buildOrderIt = m_strategies.find(Config::Strategy::StrategyName); // look for the build order in the build order map if (buildOrderIt != std::end(m_strategies)) { return (*buildOrderIt).second.m_buildOrder; } else { UAB_ASSERT_WARNING(false, "Strategy not found: %s, returning empty initial build order", Config::Strategy::StrategyName.c_str()); return m_emptyBuildOrder; } } const bool StrategyManager::shouldExpandNow() const { // if there is no place to expand to, we can't expand if (Global::Bases().getNextExpansion(BWAPI::Broodwar->self()) == BWAPI::TilePositions::None) { BWAPI::Broodwar->printf("No valid expansion location"); return false; } size_t numDepots = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Command_Center) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Nexus) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hatchery) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive); int frame = BWAPI::Broodwar->getFrameCount(); int minute = frame / (24*60); // if we have a ton of idle workers then we need a new expansion if (Global::Workers().getNumIdleWorkers() > 10) { return true; } // if we have a ridiculous stockpile of minerals, expand if (BWAPI::Broodwar->self()->minerals() > 3000) { return true; } // we will make expansion N after array[N] minutes have passed std::vector expansionTimes ={5, 10, 20, 30, 40 , 50}; for (size_t i(0); i < expansionTimes.size(); ++i) { if (numDepots < (i+2) && minute > expansionTimes[i]) { return true; } } return false; } void StrategyManager::addStrategy(const std::string & name, Strategy & strategy) { m_strategies[name] = strategy; } const MetaPairVector StrategyManager::getBuildOrderGoal() { BWAPI::Race myRace = BWAPI::Broodwar->self()->getRace(); if (myRace == BWAPI::Races::Protoss) { return getProtossBuildOrderGoal(); } else if (myRace == BWAPI::Races::Terran) { return getTerranBuildOrderGoal(); } else if (myRace == BWAPI::Races::Zerg) { return getZergBuildOrderGoal(); } return MetaPairVector(); } const MetaPairVector StrategyManager::getProtossBuildOrderGoal() const { // the goal to return MetaPairVector goal; int numZealots = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Zealot); int numPylons = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Pylon); int numDragoons = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Dragoon); int numProbes = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Probe); int numNexusCompleted = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Nexus); int numNexusAll = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Nexus); int numCyber = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Cybernetics_Core); int numCannon = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Photon_Cannon); int numScout = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Corsair); int numReaver = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Reaver); int numDarkTeplar = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar); if (Config::Strategy::StrategyName == "Protoss_ZealotRush") { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 8)); // once we have a 2nd nexus start making dragoons if (numNexusAll >= 2) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 4)); } } else if (Config::Strategy::StrategyName == "Protoss_DragoonRush") { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 6)); } else if (Config::Strategy::StrategyName == "Protoss_Drop") { if (numZealots == 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 4)); goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Shuttle, 1)); } else { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, numZealots + 8)); } } else if (Config::Strategy::StrategyName == "Protoss_DTRush") { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, numDarkTeplar + 2)); // if we have a 2nd nexus then get some goons out if (numNexusAll >= 2) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, numDragoons + 4)); } } else { UAB_ASSERT_WARNING(false, "Unknown Protoss Strategy Name: %s", Config::Strategy::StrategyName.c_str()); } // if we have 3 nexus, make an observer if (numNexusCompleted >= 3) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } // add observer to the goal if the enemy has cloaked units if (Global::Info().enemyHasCloakedUnits()) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Observatory) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } // if we want to expand, insert a nexus into the build order if (shouldExpandNow()) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); } return goal; } const MetaPairVector StrategyManager::getTerranBuildOrderGoal() const { // the goal to return std::vector goal; int numWorkers = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_SCV); int numCC = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Command_Center); int numMarines = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Marine); int numMedics = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Medic); int numWraith = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Wraith); int numVultures = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Vulture); int numGoliath = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Goliath); int numTanks = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode); int numBay = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Terran_Engineering_Bay); if (Config::Strategy::StrategyName == "Terran_MarineRush") { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Marine, numMarines + 8)); if (numMarines > 5) { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Engineering_Bay, 1)); } } else if (Config::Strategy::StrategyName == "Terran_4RaxMarines") { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Marine, numMarines + 8)); } else if (Config::Strategy::StrategyName == "Terran_VultureRush") { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Vulture, numVultures + 8)); if (numVultures > 8) { goal.push_back(std::pair(BWAPI::TechTypes::Tank_Siege_Mode, 1)); goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode, 4)); } } else if (Config::Strategy::StrategyName == "Terran_TankPush") { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode, 6)); goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Goliath, numGoliath + 6)); goal.push_back(std::pair(BWAPI::TechTypes::Tank_Siege_Mode, 1)); } else { BWAPI::Broodwar->printf("Warning: No build order goal for Terran Strategy: %s", Config::Strategy::StrategyName.c_str()); } if (shouldExpandNow()) { goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Command_Center, numCC + 1)); goal.push_back(std::pair(BWAPI::UnitTypes::Terran_SCV, numWorkers + 10)); } return goal; } const MetaPairVector StrategyManager::getZergBuildOrderGoal() const { // the goal to return std::vector goal; int numWorkers = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Drone); int numCC = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hatchery) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Lair) + UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hive); int numMutas = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Mutalisk); int numDrones = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Drone); int zerglings = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Zergling); int numHydras = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk); int numScourge = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Scourge); int numGuardians = UnitUtil::GetAllUnitCount(BWAPI::UnitTypes::Zerg_Guardian); int mutasWanted = numMutas + 6; int hydrasWanted = numHydras + 6; if (Config::Strategy::StrategyName == "Zerg_ZerglingRush") { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Zergling, zerglings + 6)); } else if (Config::Strategy::StrategyName == "Zerg_2HatchHydra") { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 8)); goal.push_back(std::pair(BWAPI::UpgradeTypes::Grooved_Spines, 1)); goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4)); } else if (Config::Strategy::StrategyName == "Zerg_3HatchMuta") { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 12)); goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4)); } else if (Config::Strategy::StrategyName == "Zerg_3HatchScourge") { if (numScourge > 40) { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Hydralisk, numHydras + 12)); } else { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Scourge, numScourge + 12)); } goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Drone, numDrones + 4)); } if (shouldExpandNow()) { goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Hatchery, numCC + 1)); goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Drone, numWorkers + 10)); } return goal; } void StrategyManager::readResults() { if (!Config::Modules::UsingStrategyIO) { return; } std::string enemyName = BWAPI::Broodwar->enemy()->getName(); std::replace(enemyName.begin(), enemyName.end(), ' ', '_'); std::string enemyResultsFile = Config::Strategy::ReadDir + enemyName + ".txt"; std::string strategyName; int wins = 0; int losses = 0; FILE *file = fopen (enemyResultsFile.c_str(), "r"); if (file != nullptr) { char line[4096]; /* or other suitable maximum line size */ while (fgets (line, sizeof line, file) != nullptr) /* read a line */ { std::stringstream ss(line); ss >> strategyName; ss >> wins; ss >> losses; //BWAPI::Broodwar->printf("Results Found: %s %d %d", strategyName.c_str(), wins, losses); if (m_strategies.find(strategyName) == m_strategies.end()) { //BWAPI::Broodwar->printf("Warning: Results file has unknown Strategy: %s", strategyName.c_str()); } else { m_strategies[strategyName].m_wins = wins; m_strategies[strategyName].m_losses = losses; } } fclose (file); } else { //BWAPI::Broodwar->printf("No results file found: %s", enemyResultsFile.c_str()); } } void StrategyManager::writeResults() { if (!Config::Modules::UsingStrategyIO) { return; } std::string enemyName = BWAPI::Broodwar->enemy()->getName(); std::replace(enemyName.begin(), enemyName.end(), ' ', '_'); std::string enemyResultsFile = Config::Strategy::WriteDir + enemyName + ".txt"; std::stringstream ss; for (auto & kv : m_strategies) { const Strategy & strategy = kv.second; ss << strategy.m_name << " " << strategy.m_wins << " " << strategy.m_losses << "\n"; } Logger::LogOverwriteToFile(enemyResultsFile, ss.str()); } void StrategyManager::onEnd(const bool isWinner) { if (!Config::Modules::UsingStrategyIO) { return; } if (isWinner) { m_strategies[Config::Strategy::StrategyName].m_wins++; } else { m_strategies[Config::Strategy::StrategyName].m_losses++; } writeResults(); } void StrategyManager::setLearnedStrategy() { // we are currently not using this functionality for the competition so turn it off return; if (!Config::Modules::UsingStrategyIO) { return; } const std::string & strategyName = Config::Strategy::StrategyName; Strategy & currentStrategy = m_strategies[strategyName]; int totalGamesPlayed = 0; int strategyGamesPlayed = currentStrategy.m_wins + currentStrategy.m_losses; double winRate = strategyGamesPlayed > 0 ? currentStrategy.m_wins / static_cast(strategyGamesPlayed) : 0; // if we are using an enemy specific strategy if (Config::Strategy::FoundEnemySpecificStrategy) { return; } // if our win rate with the current strategy is super high don't explore at all // also we're pretty confident in our base strategies so don't change if insufficient games have been played if (strategyGamesPlayed < 5 || (strategyGamesPlayed > 0 && winRate > 0.49)) { BWAPI::Broodwar->printf("Still using default strategy"); return; } // get the total number of games played so far with this race for (auto & kv : m_strategies) { Strategy & strategy = kv.second; if (strategy.m_race == BWAPI::Broodwar->self()->getRace()) { totalGamesPlayed += strategy.m_wins + strategy.m_losses; } } // calculate the UCB value and store the highest double C = 0.5; std::string bestUCBStrategy; double bestUCBStrategyVal = std::numeric_limits::lowest(); for (auto & kv : m_strategies) { Strategy & strategy = kv.second; if (strategy.m_race != BWAPI::Broodwar->self()->getRace()) { continue; } int sGamesPlayed = strategy.m_wins + strategy.m_losses; double sWinRate = sGamesPlayed > 0 ? currentStrategy.m_wins / static_cast(strategyGamesPlayed) : 0; double ucbVal = C * sqrt(log((double)totalGamesPlayed / sGamesPlayed)); double val = sWinRate + ucbVal; if (val > bestUCBStrategyVal) { bestUCBStrategy = strategy.m_name; bestUCBStrategyVal = val; } } Config::Strategy::StrategyName = bestUCBStrategy; } ================================================ FILE: UAlbertaBot/Source/StrategyManager.h ================================================ #pragma once #include "Common.h" #include "BuildOrder.h" namespace UAlbertaBot { struct Strategy { std::string m_name = "None"; BWAPI::Race m_race = BWAPI::Races::None; int m_wins = 0; int m_losses = 0; BuildOrder m_buildOrder; Strategy() { } Strategy(const std::string & name, const BWAPI::Race & race, const BuildOrder & buildOrder) : m_name(name) , m_race(race) , m_wins(0) , m_losses(0) , m_buildOrder(buildOrder) { } }; class StrategyManager { friend class Global; StrategyManager(); BWAPI::Race m_selfRace; BWAPI::Race m_enemyRace; std::map m_strategies; int m_totalGamesPlayed = 0; BuildOrder m_emptyBuildOrder; void writeResults(); const int getScore(BWAPI::Player player) const; const bool shouldExpandNow() const; const MetaPairVector getProtossBuildOrderGoal() const; const MetaPairVector getTerranBuildOrderGoal() const; const MetaPairVector getZergBuildOrderGoal() const; public: void onEnd(const bool isWinner); void addStrategy(const std::string & name, Strategy & strategy); void setLearnedStrategy(); void readResults(); const MetaPairVector getBuildOrderGoal(); const BuildOrder & getOpeningBookBuildOrder() const; }; } ================================================ FILE: UAlbertaBot/Source/TankManager.cpp ================================================ #include "TankManager.h" #include "UnitUtil.h" #include "Micro.h" using namespace UAlbertaBot; TankManager::TankManager() { } void TankManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & tanks = getUnits(); // figure out targets BWAPI::Unitset tankTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(tankTargets, tankTargets.end()), [](BWAPI::Unit u) { return u->isVisible() && !u->isFlying(); }); int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32; bool haveSiege = BWAPI::Broodwar->self()->hasResearched(BWAPI::TechTypes::Tank_Siege_Mode); // for each zealot for (auto & tank : tanks) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); bool tankNearChokepoint = false; // TODO: chokepoint // if the order is to attack or defend if (m_order.getType() == SquadOrderTypes::Attack || m_order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!tankTargets.empty()) { // find the best target for this zealot BWAPI::Unit target = getTarget(tank, tankTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(tank->getPosition(), tank->getTargetPosition(), BWAPI::Colors::Purple); } // if we are within siege range, siege up if (tank->getDistance(target) < siegeTankRange && tank->canSiege() && !tankNearChokepoint) { tank->siege(); } // otherwise unsiege and move in else if ((!target || tank->getDistance(target) > siegeTankRange) && tank->canUnsiege()) { tank->unsiege(); } // if we're in siege mode just attack the target if (tank->isSieged()) { Micro::SmartAttackUnit(tank, target); } // if we're not in siege mode kite the target else { Micro::SmartKiteTarget(tank, target); } } // if there are no targets else { // if we're not near the order position if (tank->getDistance(m_order.getPosition()) > 100) { if (tank->canUnsiege()) { tank->unsiege(); } else { // move to it Micro::SmartAttackMove(tank, m_order.getPosition()); } } } } } } // get a target for the zealot to attack BWAPI::Unit TankManager::getTarget(BWAPI::Unit tank, const BWAPI::Unitset & targets) { int bestPriorityDistance = 1000000; int bestPriority = 0; double bestLTD = 0; BWAPI::Unit bestTargetThreatInRange = nullptr; double bestTargetThreatInRangeLTD = 0; int highPriority = 0; double closestDist = std::numeric_limits::infinity(); BWAPI::Unit closestTarget = nullptr; int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32; BWAPI::Unitset targetsInSiegeRange; for (auto & target : targets) { if (target->getDistance(tank) < siegeTankRange && UnitUtil::CanAttack(tank, target)) { targetsInSiegeRange.insert(target); } } const BWAPI::Unitset & newTargets = targetsInSiegeRange.empty() ? targets : targetsInSiegeRange; // check first for units that are in range of our attack that can cause damage // choose the highest priority one from them at the lowest health for (const auto & target : newTargets) { if (!UnitUtil::CanAttack(tank, target)) { continue; } double distance = tank->getDistance(target); double LTD = UnitUtil::CalculateLTD(target, tank); int priority = getAttackPriority(tank, target); bool targetIsThreat = LTD > 0; BWAPI::Broodwar->drawTextMap(target->getPosition(), "%d", priority); if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist)) { closestDist = distance; highPriority = priority; closestTarget = target; } } if (bestTargetThreatInRange) { return bestTargetThreatInRange; } return closestTarget; } // get the attack priority of a type in relation to a zergling int TankManager::getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target) { BWAPI::UnitType rangedType = rangedUnit->getType(); BWAPI::UnitType targetType = target->getType(); bool isThreat = rangedType.isFlyer() ? targetType.airWeapon() != BWAPI::WeaponTypes::None : targetType.groundWeapon() != BWAPI::WeaponTypes::None; if (target->getType().isWorker()) { isThreat = false; } if (target->getType() == BWAPI::UnitTypes::Zerg_Larva || target->getType() == BWAPI::UnitTypes::Zerg_Egg) { return 0; } // if the target is building something near our base something is fishy BWAPI::Position ourBasePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); if (target->getType().isWorker() && (target->isConstructing() || target->isRepairing()) && target->getDistance(ourBasePosition) < 1200) { return 100; } if (target->getType().isBuilding() && (target->isCompleted() || target->isBeingConstructed()) && target->getDistance(ourBasePosition) < 1200) { return 90; } // highest priority is something that can attack us or aid in combat if (targetType == BWAPI::UnitTypes::Terran_Bunker || isThreat) { return 11; } // next priority is worker else if (targetType.isWorker()) { return 9; } // next is special buildings else if (targetType == BWAPI::UnitTypes::Zerg_Spawning_Pool) { return 5; } // next is special buildings else if (targetType == BWAPI::UnitTypes::Protoss_Pylon) { return 5; } // next is buildings that cost gas else if (targetType.gasPrice() > 0) { return 4; } else if (targetType.mineralPrice() > 0) { return 3; } // then everything else else { return 1; } } BWAPI::Unit TankManager::closestrangedUnit(BWAPI::Unit target, std::set & rangedUnitsToAssign) { double minDistance = 0; BWAPI::Unit closest = nullptr; for (auto & rangedUnit : rangedUnitsToAssign) { double distance = rangedUnit->getDistance(target); if (!closest || distance < minDistance) { minDistance = distance; closest = rangedUnit; } } return closest; } ================================================ FILE: UAlbertaBot/Source/TankManager.h ================================================ #pragma once #include #include "MicroManager.h" namespace UAlbertaBot { class TankManager : public MicroManager { public: TankManager(); void executeMicro(const BWAPI::Unitset & targets); int getAttackPriority(BWAPI::Unit rangedUnit, BWAPI::Unit target); BWAPI::Unit getTarget(BWAPI::Unit rangedUnit, const BWAPI::Unitset & targets); BWAPI::Unit closestrangedUnit(BWAPI::Unit target, std::set & rangedUnitsToAssign); }; } ================================================ FILE: UAlbertaBot/Source/TimerManager.cpp ================================================ #include "TimerManager.h" #include "Config.h" using namespace UAlbertaBot; TimerManager::TimerManager() : m_timers(std::vector(NumTypes)) , m_barWidth(40) { m_timerNames.push_back("Total"); m_timerNames.push_back("Worker"); m_timerNames.push_back("Production"); m_timerNames.push_back("Building"); m_timerNames.push_back("Combat"); m_timerNames.push_back("Scout"); m_timerNames.push_back("UnitInfo"); m_timerNames.push_back("MapGrid"); m_timerNames.push_back("MapTools"); m_timerNames.push_back("Search"); } void TimerManager::startTimer(const TimerManager::Type t) { m_timers[t].start(); } void TimerManager::stopTimer(const TimerManager::Type t) { m_timers[t].stop(); } double TimerManager::getTotalElapsed() { return m_timers[0].getElapsedTimeInMilliSec(); } void TimerManager::displayTimers(int x, int y) { if (!Config::Debug::DrawModuleTimers) { return; } BWAPI::Broodwar->drawBoxScreen(x-5, y-5, x+110+m_barWidth, y+5+(10*m_timers.size()), BWAPI::Colors::Black, true); int yskip = 0; double total = m_timers[0].getElapsedTimeInMilliSec(); for (size_t i(0); i 55) { BWAPI::Broodwar->printf("Timer Debug: %s %lf", m_timerNames[i].c_str(), elapsed); } int width = (int)((elapsed == 0) ? 0 : (m_barWidth * (elapsed / total))); BWAPI::Broodwar->drawTextScreen(x, y+yskip-3, "\x04 %s", m_timerNames[i].c_str()); BWAPI::Broodwar->drawBoxScreen(x+60, y+yskip, x+60+width+1, y+yskip+8, BWAPI::Colors::White); BWAPI::Broodwar->drawTextScreen(x+70+m_barWidth, y+yskip-3, "%.4lf", elapsed); yskip += 10; } } ================================================ FILE: UAlbertaBot/Source/TimerManager.h ================================================ #pragma once #include "Common.h" #include "../../BOSS/source/Timer.hpp" namespace UAlbertaBot { class TimerManager { std::vector m_timers; std::vector m_timerNames; int m_barWidth = 0; public: enum Type { All, Worker, Production, Building, Combat, Scout, InformationManager, MapGrid, MapTools, Search, NumTypes }; TimerManager(); void startTimer(const TimerManager::Type t); void stopTimer(const TimerManager::Type t); void displayTimers(int x, int y); double getTotalElapsed(); }; } ================================================ FILE: UAlbertaBot/Source/TransportManager.cpp ================================================ #include "TransportManager.h" #include "BaseLocationManager.h" #include "Global.h" #include "Micro.h" #include "MapTools.h" using namespace UAlbertaBot; TransportManager::TransportManager() { } void TransportManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & transportUnits = getUnits(); if (transportUnits.empty()) { return; } } void TransportManager::calculateMapEdgeVertices() { auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); if (!enemyBaseLocation) { return; } const BWAPI::Position basePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); const std::vector & closestTobase = Global::Map().getClosestTilesTo(basePosition); std::set unsortedVertices; int minX = std::numeric_limits::max(); int minY = minX; int maxX = std::numeric_limits::min(); int maxY = maxX; //compute mins and maxs for (auto &tile : closestTobase) { if (tile.x > maxX) maxX = tile.x; else if (tile.x < minX) minX = tile.x; if (tile.y > maxY) maxY = tile.y; else if (tile.y < minY) minY = tile.y; } m_minCorner = BWAPI::Position(minX, minY) * 32 + BWAPI::Position(16, 16); m_maxCorner = BWAPI::Position(maxX, maxY) * 32 + BWAPI::Position(16, 16); //add all(some) edge tiles! for (int x = minX; x <= maxX; x += 5) { unsortedVertices.insert(BWAPI::Position(x, minY) * 32 + BWAPI::Position(16, 16)); unsortedVertices.insert(BWAPI::Position(x, maxY) * 32 + BWAPI::Position(16, 16)); } for (int y = minY; y <= maxY; y += 5) { unsortedVertices.insert(BWAPI::Position(minX, y) * 32 + BWAPI::Position(16, 16)); unsortedVertices.insert(BWAPI::Position(maxX, y) * 32 + BWAPI::Position(16, 16)); } std::vector sortedVertices; BWAPI::Position current = *unsortedVertices.begin(); m_mapEdgeVertices.push_back(current); unsortedVertices.erase(current); // while we still have unsorted vertices left, find the closest one remaining to current while (!unsortedVertices.empty()) { double bestDist = 1000000; BWAPI::Position bestPos; for (const BWAPI::Position & pos : unsortedVertices) { double dist = pos.getDistance(current); if (dist < bestDist) { bestDist = dist; bestPos = pos; } } current = bestPos; sortedVertices.push_back(bestPos); unsortedVertices.erase(bestPos); } m_mapEdgeVertices = sortedVertices; } void TransportManager::drawTransportInformation(int x = 0, int y = 0) { if (!Config::Debug::DrawUnitTargetInfo) { return; } for (size_t i(0); i < m_mapEdgeVertices.size(); ++i) { BWAPI::Broodwar->drawCircleMap(m_mapEdgeVertices[i], 4, BWAPI::Colors::Green, false); BWAPI::Broodwar->drawTextMap(m_mapEdgeVertices[i], "%d", i); } } void TransportManager::update() { if (!m_transportShip && getUnits().size() > 0) { m_transportShip = *getUnits().begin(); } // calculate enemy region vertices if we haven't yet if (m_mapEdgeVertices.empty()) { calculateMapEdgeVertices(); } moveTroops(); moveTransport(); drawTransportInformation(); } void TransportManager::moveTransport() { if (!m_transportShip || !m_transportShip->exists() || !(m_transportShip->getHitPoints() > 0)) { return; } // If I didn't finish unloading the troops, wait BWAPI::UnitCommand currentCommand(m_transportShip->getLastCommand()); if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All || currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All_Position) && m_transportShip->getLoadedUnits().size() > 0) { return; } if (m_to.isValid() && m_from.isValid()) { followPerimeter(m_to, m_from); } else { followPerimeter(); } } void TransportManager::moveTroops() { if (!m_transportShip || !m_transportShip->exists() || !(m_transportShip->getHitPoints() > 0)) { return; } //unload zealots if close enough or dying int transportHP = m_transportShip->getHitPoints() + m_transportShip->getShields(); auto enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); if (enemyBaseLocation && (m_transportShip->getDistance(enemyBaseLocation->getPosition()) < 300 || transportHP < 100) && m_transportShip->canUnloadAtPosition(m_transportShip->getPosition())) { //unload troops //and return? // get the unit's current command BWAPI::UnitCommand currentCommand(m_transportShip->getLastCommand()); // if we've already told this unit to unload, wait if (currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All || currentCommand.getType() == BWAPI::UnitCommandTypes::Unload_All_Position) { return; } //else unload m_transportShip->unloadAll(m_transportShip->getPosition()); } } void TransportManager::followPerimeter(int clockwise) { BWAPI::Position goTo = getFleePosition(clockwise); if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(goTo, 5, BWAPI::Colors::Red, true); } Micro::SmartMove(m_transportShip, goTo); } void TransportManager::followPerimeter(BWAPI::Position to, BWAPI::Position from) { static int following = 0; if (following) { followPerimeter(following); return; } //assume we're near FROM! if (m_transportShip->getDistance(from) < 50 && m_waypoints.empty()) { //compute waypoints std::pair wpIDX = findSafePath(to, from); bool valid = (wpIDX.first > -1 && wpIDX.second > -1); UAB_ASSERT_WARNING(valid, "waypoints not valid! (transport mgr)"); m_waypoints.push_back(m_mapEdgeVertices[wpIDX.first]); m_waypoints.push_back(m_mapEdgeVertices[wpIDX.second]); BWAPI::Broodwar->printf("WAYPOINTS: [%d] - [%d]", wpIDX.first, wpIDX.second); Micro::SmartMove(m_transportShip, m_waypoints[0]); } else if (m_waypoints.size() > 1 && m_transportShip->getDistance(m_waypoints[0]) < 100) { BWAPI::Broodwar->printf("FOLLOW PERIMETER TO SECOND WAYPOINT!"); //follow perimeter to second waypoint! //clockwise or counterclockwise? int closestPolygonIndex = getClosestVertexIndex(m_transportShip); UAB_ASSERT_WARNING(closestPolygonIndex != -1, "Couldn't find a closest vertex"); if (m_mapEdgeVertices[(closestPolygonIndex + 1) % m_mapEdgeVertices.size()].getApproxDistance(m_waypoints[1]) < m_mapEdgeVertices[(closestPolygonIndex - 1) % m_mapEdgeVertices.size()].getApproxDistance(m_waypoints[1])) { BWAPI::Broodwar->printf("FOLLOW clockwise"); following = 1; followPerimeter(following); } else { BWAPI::Broodwar->printf("FOLLOW counter clockwise"); following = -1; followPerimeter(following); } } else if (m_waypoints.size() > 1 && m_transportShip->getDistance(m_waypoints[1]) < 50) { //if close to second waypoint, go to destination! following = 0; Micro::SmartMove(m_transportShip, to); } } int TransportManager::getClosestVertexIndex(BWAPI::UnitInterface * unit) { int closestIndex = -1; double closestDistance = 10000000; for (size_t i(0); i < m_mapEdgeVertices.size(); ++i) { double dist = unit->getDistance(m_mapEdgeVertices[i]); if (dist < closestDistance) { closestDistance = dist; closestIndex = i; } } return closestIndex; } int TransportManager::getClosestVertexIndex(BWAPI::Position p) { int closestIndex = -1; double closestDistance = 10000000; for (size_t i(0); i < m_mapEdgeVertices.size(); ++i) { double dist = p.getApproxDistance(m_mapEdgeVertices[i]); if (dist < closestDistance) { closestDistance = dist; closestIndex = i; } } return closestIndex; } std::pair TransportManager::findSafePath(BWAPI::Position to, BWAPI::Position from) { BWAPI::Broodwar->printf("FROM: [%d,%d]", from.x, from.y); BWAPI::Broodwar->printf("TO: [%d,%d]", to.x, to.y); //closest map edge point to destination int endPolygonIndex = getClosestVertexIndex(to); //BWAPI::Broodwar->printf("end indx: [%d]", endPolygonIndex); UAB_ASSERT_WARNING(endPolygonIndex != -1, "Couldn't find a closest vertex"); BWAPI::Position enemyEdge = m_mapEdgeVertices[endPolygonIndex]; auto * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); BWAPI::Position enemyPosition = enemyBaseLocation->getPosition(); //find the projections on the 4 edges UAB_ASSERT_WARNING((m_minCorner.isValid() && m_maxCorner.isValid()), "Map corners should have been set! (transport mgr)"); std::vector p; p.push_back(BWAPI::Position(from.x, m_minCorner.y)); p.push_back(BWAPI::Position(from.x, m_maxCorner.y)); p.push_back(BWAPI::Position(m_minCorner.x, from.y)); p.push_back(BWAPI::Position(m_maxCorner.x, from.y)); int d1 = p[0].getApproxDistance(enemyPosition); int d2 = p[1].getApproxDistance(enemyPosition); int d3 = p[2].getApproxDistance(enemyPosition); int d4 = p[3].getApproxDistance(enemyPosition); //have to choose the two points that are not max or min (the sides!) int maxIndex = (d1 > d2 ? d1 : d2) > (d3 > d4 ? d3 : d4) ? (d1 > d2 ? 0 : 1) : (d3 > d4 ? 2 : 3); int minIndex = (d1 < d2 ? d1 : d2) < (d3 < d4 ? d3 : d4) ? (d1 < d2 ? 0 : 1) : (d3 < d4 ? 2 : 3); if (maxIndex > minIndex) { p.erase(p.begin() + maxIndex); p.erase(p.begin() + minIndex); } else { p.erase(p.begin() + minIndex); p.erase(p.begin() + maxIndex); } //get the one that works best from the two. BWAPI::Position waypoint = (enemyEdge.getApproxDistance(p[0]) < enemyEdge.getApproxDistance(p[1])) ? p[0] : p[1]; int startPolygonIndex = getClosestVertexIndex(waypoint); return std::pair(startPolygonIndex, endPolygonIndex); } BWAPI::Position TransportManager::getFleePosition(int clockwise) { UAB_ASSERT_WARNING(!m_mapEdgeVertices.empty(), "We should have a transport route!"); // if this is the first flee, we will not have a previous perimeter index if (m_currentRegionVertexIndex == -1) { // so return the closest position in the polygon int closestPolygonIndex = getClosestVertexIndex(m_transportShip); UAB_ASSERT_WARNING(closestPolygonIndex != -1, "Couldn't find a closest vertex"); if (closestPolygonIndex == -1) { return BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); } else { // set the current index so we know how to iterate if we are still fleeing later m_currentRegionVertexIndex = closestPolygonIndex; return m_mapEdgeVertices[closestPolygonIndex]; } } // if we are still fleeing from the previous frame, get the next location if we are close enough else { double distanceFromCurrentVertex = m_mapEdgeVertices[m_currentRegionVertexIndex].getDistance(m_transportShip->getPosition()); // keep going to the next vertex in the perimeter until we get to one we're far enough from to issue another move command while (distanceFromCurrentVertex < 128*2) { m_currentRegionVertexIndex = (m_currentRegionVertexIndex + clockwise*1) % m_mapEdgeVertices.size(); distanceFromCurrentVertex = m_mapEdgeVertices[m_currentRegionVertexIndex].getDistance(m_transportShip->getPosition()); } return m_mapEdgeVertices[m_currentRegionVertexIndex]; } } void TransportManager::setTransportShip(BWAPI::UnitInterface * unit) { m_transportShip = unit; } void TransportManager::setFrom(BWAPI::Position from) { if (from.isValid()) { m_from = from; } } void TransportManager::setTo(BWAPI::Position to) { if (to.isValid()) { m_to = to; } } ================================================ FILE: UAlbertaBot/Source/TransportManager.h ================================================ #pragma once #include #include "MicroManager.h" namespace UAlbertaBot { class MicroManager; class TransportManager : public MicroManager { BWAPI::UnitInterface* m_transportShip = nullptr; BWAPI::Position m_minCorner = {-1, -1}; BWAPI::Position m_maxCorner = {-1, -1}; BWAPI::Position m_to = {-1, -1}; BWAPI::Position m_from = {-1, -1}; int m_currentRegionVertexIndex = -1; std::vector m_waypoints; std::vector m_mapEdgeVertices; void calculateMapEdgeVertices(); void drawTransportInformation(int x, int y); void moveTransport(); void moveTroops(); void followPerimeter(int clockwise=1); void followPerimeter(BWAPI::Position to, BWAPI::Position from); int getClosestVertexIndex(BWAPI::UnitInterface * unit); int getClosestVertexIndex(BWAPI::Position p); BWAPI::Position getFleePosition(int clockwise=1); std::pair findSafePath(BWAPI::Position from, BWAPI::Position to); public: TransportManager(); void executeMicro(const BWAPI::Unitset & targets); void update(); void setTransportShip(BWAPI::UnitInterface * unit); void setFrom(BWAPI::Position from); void setTo(BWAPI::Position to); }; } ================================================ FILE: UAlbertaBot/Source/UABAssert.cpp ================================================ #include "Common.h" #include "UABAssert.h" #include "Config.h" #include "Logger.h" using namespace UAlbertaBot; namespace UAlbertaBot { namespace Assert { std::string lastErrorMessage; const std::string currentDateTime() { time_t now = time(0); struct tm tstruct; char buf[80]; //tstruct = *localtime(&now); localtime_s(&tstruct, &now); strftime(buf, sizeof(buf), "%Y-%m-%d_%X", &tstruct); return buf; } void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...) { char messageBuffer[1024] = ""; if (msg != nullptr) { va_list args; va_start(args, msg); //vsprintf(messageBuffer, msg, args); vsnprintf_s(messageBuffer, 1024, msg, args); va_end(args); } std::stringstream ss; ss << std::endl; ss << "!Assert: " << condition << std::endl; ss << "File: " << file << std::endl; ss << "Message: " << messageBuffer << std::endl; ss << "Line: " << line << std::endl; ss << "Time: " << currentDateTime() << std::endl; lastErrorMessage = messageBuffer; std::cerr << ss.str(); BWAPI::Broodwar->printf("%s", ss.str().c_str()); if (Config::Debug::LogAssertToErrorFile) { Logger::LogAppendToFile(Config::Debug::ErrorLogFilename, ss.str()); } } } } ================================================ FILE: UAlbertaBot/Source/UABAssert.h ================================================ #pragma once #include #include #include "Logger.h" #include #include #include #include #define UAB_BREAK #define UAB_ASSERT_ALL #ifdef UAB_ASSERT_ALL #define UAB_ASSERT(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ UAlbertaBot::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ UAB_BREAK \ } \ } while(0) #define UAB_ASSERT_WARNING(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ UAlbertaBot::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), ##__VA_ARGS__); \ } \ } while(0) #else #define UAB_ASSERT(cond, msg, ...) #endif namespace UAlbertaBot { namespace Assert { void ShutDown(); extern std::string lastErrorMessage; const std::string currentDateTime(); void ReportFailure(const char * condition, const char * file, int line, const char * msg, ...); } } ================================================ FILE: UAlbertaBot/Source/UAlbertaBotModule.cpp ================================================ /* +----------------------------------------------------------------------+ | UAlbertaBot | +----------------------------------------------------------------------+ | University of Alberta - AIIDE StarCraft Competition | +----------------------------------------------------------------------+ | | +----------------------------------------------------------------------+ | Author: David Churchill | +----------------------------------------------------------------------+ */ #include "Common.h" #include "UAlbertaBotModule.h" #include "JSONTools.h" #include "ParseUtils.h" #include "UnitUtil.h" #include "Global.h" #include "StrategyManager.h" #include "MapTools.h" using namespace UAlbertaBot; UAlbertaBotModule::UAlbertaBotModule() { Global::GameStart(); } // This gets called when the bot starts! void UAlbertaBotModule::onStart() { // Parse the bot's configuration file if it has one, change this file path to where your config file is // Any relative path name will be relative to Starcraft installation folder ParseUtils::ParseConfigFile(Config::ConfigFile::ConfigFileLocation); // Set our BWAPI options here BWAPI::Broodwar->setLocalSpeed(Config::BWAPIOptions::SetLocalSpeed); BWAPI::Broodwar->setFrameSkip(Config::BWAPIOptions::SetFrameSkip); if (Config::BWAPIOptions::EnableCompleteMapInformation) { BWAPI::Broodwar->enableFlag(BWAPI::Flag::CompleteMapInformation); } if (Config::BWAPIOptions::EnableUserInput) { BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); } if (Config::BotInfo::PrintInfoOnStart) { BWAPI::Broodwar->printf("Hello! I am %s, written by %s", Config::BotInfo::BotName.c_str(), Config::BotInfo::Authors.c_str()); } // Call BWTA to read and analyze the current map if (Config::Modules::UsingGameCommander) { if (Config::Modules::UsingStrategyIO) { Global::Strategy().readResults(); Global::Strategy().setLearnedStrategy(); } } //Global::Map().saveMapToFile("map.txt"); } void UAlbertaBotModule::onEnd(bool isWinner) { if (Config::Modules::UsingGameCommander) { Global::Strategy().onEnd(isWinner); } } void UAlbertaBotModule::onFrame() { if (BWAPI::Broodwar->getFrameCount() > 100000) { BWAPI::Broodwar->restartGame(); } const char red = '\x08'; const char green = '\x07'; const char white = '\x04'; if (!Config::ConfigFile::ConfigFileFound) { BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge); BWAPI::Broodwar->drawTextScreen(10, 5, "%c%s Config File Not Found", red, Config::BotInfo::BotName.c_str()); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default); BWAPI::Broodwar->drawTextScreen(10, 30, "%c%s will not run without its configuration file", white, Config::BotInfo::BotName.c_str()); BWAPI::Broodwar->drawTextScreen(10, 45, "%cCheck that the file below exists. Incomplete paths are relative to Starcraft directory", white); BWAPI::Broodwar->drawTextScreen(10, 60, "%cYou can change this file location in Config::ConfigFile::ConfigFileLocation", white); BWAPI::Broodwar->drawTextScreen(10, 75, "%cFile Not Found (or is empty): %c %s", white, green, Config::ConfigFile::ConfigFileLocation.c_str()); return; } else if (!Config::ConfigFile::ConfigFileParsed) { BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge); BWAPI::Broodwar->drawTextScreen(10, 5, "%c%s Config File Parse Error", red, Config::BotInfo::BotName.c_str()); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default); BWAPI::Broodwar->drawTextScreen(10, 30, "%c%s will not run without a properly formatted configuration file", white, Config::BotInfo::BotName.c_str()); BWAPI::Broodwar->drawTextScreen(10, 45, "%cThe configuration file was found, but could not be parsed. Check that it is valid JSON", white); BWAPI::Broodwar->drawTextScreen(10, 60, "%cFile Not Parsed: %c %s", white, green, Config::ConfigFile::ConfigFileLocation.c_str()); return; } if (Config::Modules::UsingGameCommander) { m_gameCommander.update(); } if (Config::Modules::UsingAutoObserver) { m_autoObserver.onFrame(); } } void UAlbertaBotModule::onUnitDestroy(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitDestroy(unit); } } void UAlbertaBotModule::onUnitMorph(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitMorph(unit); } } void UAlbertaBotModule::onSendText(std::string text) { ParseUtils::ParseTextCommand(text); } void UAlbertaBotModule::onUnitCreate(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitCreate(unit); } } void UAlbertaBotModule::onUnitComplete(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitComplete(unit); } } void UAlbertaBotModule::onUnitShow(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitShow(unit); } } void UAlbertaBotModule::onUnitHide(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitHide(unit); } } void UAlbertaBotModule::onUnitRenegade(BWAPI::Unit unit) { if (Config::Modules::UsingGameCommander) { m_gameCommander.onUnitRenegade(unit); } } ================================================ FILE: UAlbertaBot/Source/UAlbertaBotModule.h ================================================ #pragma once #include "Common.h" #include "GameCommander.h" #include "AutoObserver.h" namespace UAlbertaBot { class UAlbertaBotModule { GameCommander m_gameCommander; AutoObserver m_autoObserver; public: UAlbertaBotModule(); void onStart(); void onFrame(); void onEnd(bool isWinner); void onUnitDestroy(BWAPI::Unit unit); void onUnitMorph(BWAPI::Unit unit); void onSendText(std::string text); void onUnitCreate(BWAPI::Unit unit); void onUnitComplete(BWAPI::Unit unit); void onUnitShow(BWAPI::Unit unit); void onUnitHide(BWAPI::Unit unit); void onUnitRenegade(BWAPI::Unit unit); }; } ================================================ FILE: UAlbertaBot/Source/UnitData.cpp ================================================ #include "Common.h" #include "UnitData.h" using namespace UAlbertaBot; UnitData::UnitData() : mineralsLost(0) , gasLost(0) { int maxTypeID(0); for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes()) { maxTypeID = maxTypeID > t.getID() ? maxTypeID : t.getID(); } numDeadUnits = std::vector(maxTypeID + 1, 0); numUnits = std::vector(maxTypeID + 1, 0); } void UnitData::updateUnit(BWAPI::Unit unit) { if (!unit) { return; } bool firstSeen = false; auto & it = unitMap.find(unit); if (it == unitMap.end()) { firstSeen = true; unitMap[unit] = UnitInfo(); } UnitInfo & ui = unitMap[unit]; ui.unit = unit; ui.player = unit->getPlayer(); ui.lastPosition = unit->getPosition(); ui.lastHealth = unit->getHitPoints(); ui.lastShields = unit->getShields(); ui.unitID = unit->getID(); ui.type = unit->getType(); ui.completed = unit->isCompleted(); if (firstSeen) { numUnits[unit->getType().getID()]++; } } void UnitData::removeUnit(BWAPI::Unit unit) { if (!unit) { return; } mineralsLost += unit->getType().mineralPrice(); gasLost += unit->getType().gasPrice(); numUnits[unit->getType().getID()]--; numDeadUnits[unit->getType().getID()]++; unitMap.erase(unit); } void UnitData::removeBadUnits() { for (auto iter(unitMap.begin()); iter != unitMap.end();) { if (badUnitInfo(iter->second)) { numUnits[iter->second.type.getID()]--; iter = unitMap.erase(iter); } else { iter++; } } } const bool UnitData::badUnitInfo(const UnitInfo & ui) const { if (!ui.unit) { return false; } // Cull away any refineries/assimilators/extractors that were destroyed and reverted to vespene geysers if (ui.unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser) { return true; } // If the unit is a building and we can currently see its position and it is not there if (ui.type.isBuilding() && BWAPI::Broodwar->isVisible(ui.lastPosition.x/32, ui.lastPosition.y/32) && !ui.unit->isVisible()) { return true; } return false; } int UnitData::getGasLost() const { return gasLost; } int UnitData::getMineralsLost() const { return mineralsLost; } int UnitData::getNumUnits(BWAPI::UnitType t) const { return numUnits[t.getID()]; } int UnitData::getNumDeadUnits(BWAPI::UnitType t) const { return numDeadUnits[t.getID()]; } const std::map & UnitData::getUnits() const { return unitMap; } ================================================ FILE: UAlbertaBot/Source/UnitData.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { struct UnitInfo { // we need to store all of this data because if the unit is not visible, we // can't reference it from the unit pointer int unitID = 0; int lastHealth = 0; int lastShields = 0; BWAPI::Player player = nullptr; BWAPI::Unit unit; BWAPI::Position lastPosition = BWAPI::Positions::None; BWAPI::UnitType type = BWAPI::UnitTypes::None; bool completed = false; UnitInfo() { } const bool operator == (BWAPI::Unit unit) const { return unitID == unit->getID(); } const bool operator == (const UnitInfo & rhs) const { return (unitID == rhs.unitID); } const bool operator < (const UnitInfo & rhs) const { return (unitID < rhs.unitID); } }; typedef std::vector UnitInfoVector; typedef std::map UIMap; class UnitData { UIMap unitMap; std::vector numDeadUnits; std::vector numUnits; int mineralsLost = 0; int gasLost = 0; const bool badUnitInfo(const UnitInfo & ui) const; public: UnitData(); void updateUnit(BWAPI::Unit unit); void removeUnit(BWAPI::Unit unit); void removeBadUnits(); int getGasLost() const; int getMineralsLost() const; int getNumUnits(BWAPI::UnitType t) const; int getNumDeadUnits(BWAPI::UnitType t) const; const std::map & getUnits() const; }; } ================================================ FILE: UAlbertaBot/Source/UnitInfoManager.cpp ================================================ #include "UnitInfoManager.h" #include "Util.h" #include "CCBot.h" #include "Unit.h" #include UnitInfoManager::UnitInfoManager(CCBot & bot) : m_bot(bot) { } void UnitInfoManager::onStart() { } void UnitInfoManager::onFrame() { updateUnitInfo(); drawUnitInformation(100, 100); drawSelectedUnitDebugInfo(); } void UnitInfoManager::updateUnitInfo() { m_units[Players::Self].clear(); m_units[Players::Enemy].clear(); m_units[Players::Neutral].clear(); for (auto & unit : m_bot.GetUnits()) { updateUnit(unit); m_units[unit.getPlayer()].push_back(unit); } // remove bad enemy units m_unitData[Players::Self].removeBadUnits(); m_unitData[Players::Enemy].removeBadUnits(); m_unitData[Players::Neutral].removeBadUnits(); } const std::map & UnitInfoManager::getUnitInfoMap(CCPlayer player) const { return getUnitData(player).getUnitInfoMap(); } const std::vector & UnitInfoManager::getUnits(CCPlayer player) const { BOT_ASSERT(m_units.find(player) != m_units.end(), "Couldn't find player units: %d", player); return m_units.at(player); } //static std::string GetAbilityText(sc2::AbilityID ability_id) { // std::string str; // str += sc2::AbilityTypeToName(ability_id); // str += " ("; // str += std::to_string(uint32_t(ability_id)); // str += ")"; // return str; //} void UnitInfoManager::drawSelectedUnitDebugInfo() { //#ifdef SC2API // const sc2::Unit * unit; // for (auto u : m_bot.Observation()->GetUnits()) // { // if (u->is_selected && u->alliance == sc2::Unit::Self) { // unit = u; // break; // } // } // // if (!unit) { return; } // // auto query = m_bot.Query(); // auto abilities = m_bot.Observation()->GetAbilityData(); // // std::string debug_txt; // debug_txt = UnitTypeToName(unit->unit_type); // if (debug_txt.length() < 1) // { // debug_txt = "(Unknown name)"; // assert(0); // } // debug_txt += " (" + std::to_string(unit->unit_type) + ")"; // // sc2::AvailableAbilities available_abilities = query->GetAbilitiesForUnit(unit); // if (available_abilities.abilities.size() < 1) // { // std::cout << "No abilities available for this unit" << std::endl; // } // else // { // for (const sc2::AvailableAbility & available_ability : available_abilities.abilities) // { // if (available_ability.ability_id >= abilities.size()) { continue; } // // const sc2::AbilityData & ability = abilities[available_ability.ability_id]; // // debug_txt += GetAbilityText(ability.ability_id) + "\n"; // } // } // m_bot.Map().drawText(unit->pos, debug_txt, CCColor(0, 255, 0)); // // // Show the direction of the unit. // sc2::Point3D p1; // Use this to show target distance. // { // const float length = 5.0f; // sc2::Point3D p0 = unit->pos; // p0.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly. // p1 = unit->pos; // assert(unit->facing >= 0.0f && unit->facing < 6.29f); // p1.x += length * std::cos(unit->facing); // p1.y += length * std::sin(unit->facing); // m_bot.Map().drawLine(p0, p1, CCColor(255, 255, 0)); // } // // // Box around the unit. // { // sc2::Point3D p_min = unit->pos; // p_min.x -= 2.0f; // p_min.y -= 2.0f; // p_min.z -= 2.0f; // sc2::Point3D p_max = unit->pos; // p_max.x += 2.0f; // p_max.y += 2.0f; // p_max.z += 2.0f; // m_bot.Map().drawBox(p_min, p_max, CCColor(0, 0, 255)); // } // // // Sphere around the unit. // { // sc2::Point3D p = unit->pos; // p.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly. // m_bot.Map().drawCircle(p, 1.25f, CCColor(255, 0, 255)); // } // // // Pathing query to get the target. // bool has_target = false; // sc2::Point3D target; // std::string target_info; // for (const sc2::UnitOrder& unit_order : unit->orders) // { // // TODO: Need to determine if there is a target point, no target point, or the target is a unit/snapshot. // target.x = unit_order.target_pos.x; // target.y = unit_order.target_pos.y; // target.z = p1.z; // has_target = true; // // target_info = "Target:\n"; // if (unit_order.target_unit_tag != 0x0LL) { // target_info += "Tag: " + std::to_string(unit_order.target_unit_tag) + "\n"; // } // if (unit_order.progress != 0.0f && unit_order.progress != 1.0f) { // target_info += "Progress: " + std::to_string(unit_order.progress) + "\n"; // } // // // Perform the pathing query. // { // float distance = query->PathingDistance(unit->pos, target); // target_info += "\nPathing dist: " + std::to_string(distance); // } // // break; // } // // if (has_target) // { // sc2::Point3D p = target; // p.z += 0.1f; // Raise the line off the ground a bit so it renders more clearly. // m_bot.Map().drawCircle(target, 1.25f, CCColor(0, 0, 255)); // m_bot.Map().drawText(p1, target_info, CCColor(255, 255, 0)); // } //#endif } // passing in a unit type of 0 returns a count of all units size_t UnitInfoManager::getUnitTypeCount(CCPlayer player, UnitType type, bool completed) const { size_t count = 0; for (auto & unit : getUnits(player)) { if ((!type.isValid() || type == unit.getType()) && (!completed || unit.isCompleted())) { count++; } } return count; } void UnitInfoManager::drawUnitInformation(float x,float y) const { if (!m_bot.Config().DrawEnemyUnitInfo) { return; } std::stringstream ss; // TODO: move this to unitData //// for each unit in the queue //for (auto & kv : m_) //{ // int numUnits = m_unitData.at(Players::Self).getNumUnits(t); // int numDeadUnits = m_unitData.at(Players::Enemy).getNumDeadUnits(t); // // if there exist units in the vector // if (numUnits > 0) // { // ss << numUnits << " " << numDeadUnits << " " << sc2::UnitTypeToName(t) << "\n"; // } //} // //for (auto & kv : getUnitData(Players::Enemy).getUnitInfoMap()) //{ // m_bot.Map().drawCircle(kv.second.lastPosition, 0.5f); // m_bot.Map().drawText(kv.second.lastPosition, sc2::UnitTypeToName(kv.second.type)); //} // } void UnitInfoManager::updateUnit(const Unit & unit) { m_unitData[unit.getPlayer()].updateUnit(unit); } // is the unit valid? bool UnitInfoManager::isValidUnit(const Unit & unit) { if (!unit.isValid()) { return false; } // if it's a weird unit, don't bother if (unit.getType().isEgg() || unit.getType().isLarva()) { return false; } // if the position isn't valid throw it out if (!m_bot.Map().isValidPosition(unit.getPosition())) { return false; } // s'all good baby baby return true; } void UnitInfoManager::getNearbyForce(std::vector & unitInfo, CCPosition p, int player, float radius) const { bool hasBunker = false; // for each unit we know about for that player for (const auto & kv : getUnitData(player).getUnitInfoMap()) { const UnitInfo & ui(kv.second); // if it's a combat unit we care about // and it's finished! if (ui.type.isCombatUnit() && Util::Dist(ui.lastPosition,p) <= radius) { // add it to the vector unitInfo.push_back(ui); } } } const UnitData & UnitInfoManager::getUnitData(CCPlayer player) const { return m_unitData.find(player)->second; } ================================================ FILE: UAlbertaBot/Source/UnitInfoManager.h ================================================ #pragma once #include "Common.h" #include "UnitData.h" #include "BaseLocation.h" #include "Unit.h" class CCBot; class UnitInfoManager { CCBot & m_bot; std::map m_unitData; std::map> m_units; void updateUnit(const Unit & unit); void updateUnitInfo(); bool isValidUnit(const Unit & unit); const UnitData & getUnitData(CCPlayer player) const; void drawSelectedUnitDebugInfo(); public: UnitInfoManager(CCBot & bot); void onFrame(); void onStart(); const std::vector & getUnits(CCPlayer player) const; size_t getUnitTypeCount(CCPlayer player, UnitType type, bool completed = true) const; void getNearbyForce(std::vector & unitInfo, CCPosition p, int player, float radius) const; const std::map & getUnitInfoMap(CCPlayer player) const; //bool enemyHasCloakedUnits() const; void drawUnitInformation(float x, float y) const; }; ================================================ FILE: UAlbertaBot/Source/UnitUtil.cpp ================================================ #include "Common.h" #include "UnitUtil.h" using namespace UAlbertaBot; bool UnitUtil::IsCombatUnit(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); if (!unit) { return false; } // no workers or buildings allowed if (unit && unit->getType().isWorker() || unit->getType().isBuilding()) { return false; } // check for various types of combat units if (unit->getType().canAttack() || unit->getType() == BWAPI::UnitTypes::Terran_Medic || unit->getType() == BWAPI::UnitTypes::Protoss_High_Templar || unit->getType() == BWAPI::UnitTypes::Protoss_Observer || unit->isFlying() && unit->getType().spaceProvided() > 0) { return true; } return false; } bool UnitUtil::IsValidUnit(BWAPI::Unit unit) { if (!unit) { return false; } if (unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists() && unit->getType() != BWAPI::UnitTypes::Unknown && unit->getPosition().x != BWAPI::Positions::Unknown.x && unit->getPosition().y != BWAPI::Positions::Unknown.y) { return true; } else { return false; } } Rect UnitUtil::GetRect(BWAPI::Unit unit) { Rect r; r.x = unit->getLeft(); r.y = unit->getTop(); r.height = unit->getBottom() - unit->getTop(); r.width = unit->getLeft() - unit->getRight(); return r; } double UnitUtil::GetDistanceBetweenTwoRectangles(Rect & rect1, Rect & rect2) { Rect & mostLeft = rect1.x < rect2.x ? rect1 : rect2; Rect & mostRight = rect2.x < rect1.x ? rect1 : rect2; Rect & upper = rect1.y < rect2.y ? rect1 : rect2; Rect & lower = rect2.y < rect1.y ? rect1 : rect2; int diffX = std::max(0, mostLeft.x == mostRight.x ? 0 : mostRight.x - (mostLeft.x + mostLeft.width)); int diffY = std::max(0, upper.y == lower.y ? 0 : lower.y - (upper.y + upper.height)); return std::sqrtf(static_cast(diffX*diffX + diffY*diffY)); } bool UnitUtil::CanAttack(BWAPI::Unit attacker, BWAPI::Unit target) { return GetWeapon(attacker, target) != BWAPI::WeaponTypes::None; } bool UnitUtil::CanAttackAir(BWAPI::Unit unit) { return unit->getType().airWeapon() != BWAPI::WeaponTypes::None; } bool UnitUtil::CanAttackGround(BWAPI::Unit unit) { return unit->getType().groundWeapon() != BWAPI::WeaponTypes::None; } double UnitUtil::CalculateLTD(BWAPI::Unit attacker, BWAPI::Unit target) { BWAPI::WeaponType weapon = GetWeapon(attacker, target); if (weapon == BWAPI::WeaponTypes::None) { return 0; } return static_cast(weapon.damageAmount()) / weapon.damageCooldown(); } BWAPI::WeaponType UnitUtil::GetWeapon(BWAPI::Unit attacker, BWAPI::Unit target) { return target->isFlying() ? attacker->getType().airWeapon() : attacker->getType().groundWeapon(); } BWAPI::WeaponType UnitUtil::GetWeapon(BWAPI::UnitType attacker, BWAPI::UnitType target) { return target.isFlyer() ? attacker.airWeapon() : attacker.groundWeapon(); } int UnitUtil::GetAttackRange(BWAPI::Unit attacker, BWAPI::Unit target) { BWAPI::WeaponType weapon = GetWeapon(attacker, target); if (weapon == BWAPI::WeaponTypes::None) { return 0; } int range = weapon.maxRange(); if ((attacker->getType() == BWAPI::UnitTypes::Protoss_Dragoon) && (attacker->getPlayer() == BWAPI::Broodwar->self()) && BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge)) { range = 6 * 32; } return range; } int UnitUtil::GetAttackRange(BWAPI::UnitType attacker, BWAPI::UnitType target) { BWAPI::WeaponType weapon = GetWeapon(attacker, target); if (weapon == BWAPI::WeaponTypes::None) { return 0; } return weapon.maxRange(); } size_t UnitUtil::GetAllUnitCount(BWAPI::UnitType type) { size_t count = 0; for (const auto & unit : BWAPI::Broodwar->self()->getUnits()) { // trivial case: unit which exists matches the type if (unit->getType() == type) { count++; } // case where a zerg egg contains the unit type if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg && unit->getBuildType() == type) { count += type.isTwoUnitsInOneEgg() ? 2 : 1; } // case where a building has started constructing a unit but it doesn't yet have a unit associated with it if (unit->getRemainingTrainTime() > 0) { BWAPI::UnitType trainType = unit->getLastCommand().getUnitType(); if (trainType == type && unit->getRemainingTrainTime() == trainType.buildTime()) { count++; } } } return count; } BWAPI::Unit UnitUtil::GetClosestUnitTypeToTarget(BWAPI::UnitType type, BWAPI::Position target) { BWAPI::Unit closestUnit = nullptr; double closestDist = 100000; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == type) { double dist = unit->getDistance(target); if (!closestUnit || dist < closestDist) { closestUnit = unit; closestDist = dist; } } } return closestUnit; } ================================================ FILE: UAlbertaBot/Source/UnitUtil.h ================================================ #pragma once #include namespace UAlbertaBot { struct Rect { int x, y; int height, width; }; namespace UnitUtil { bool IsCombatUnit(BWAPI::Unit unit); bool IsValidUnit(BWAPI::Unit unit); bool CanAttackAir(BWAPI::Unit unit); bool CanAttackGround(BWAPI::Unit unit); bool CanAttack(BWAPI::Unit attacker, BWAPI::Unit target); int GetAttackRange(BWAPI::Unit attacker, BWAPI::Unit target); int GetAttackRange(BWAPI::UnitType attacker, BWAPI::UnitType target); double CalculateLTD(BWAPI::Unit attacker, BWAPI::Unit target); size_t GetAllUnitCount(BWAPI::UnitType type); BWAPI::Unit GetClosestUnitTypeToTarget(BWAPI::UnitType type, BWAPI::Position target); BWAPI::WeaponType GetWeapon(BWAPI::Unit attacker, BWAPI::Unit target); BWAPI::WeaponType GetWeapon(BWAPI::UnitType attacker, BWAPI::UnitType target); double GetDistanceBetweenTwoRectangles(Rect & rect1, Rect & rect2); Rect GetRect(BWAPI::Unit unit); }; } ================================================ FILE: UAlbertaBot/Source/WorkerData.cpp ================================================ #include "WorkerData.h" #include "Micro.h" using namespace UAlbertaBot; WorkerData::WorkerData() { for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)) { m_workersOnMineralPatch[unit] = 0; } } } void WorkerData::workerDestroyed(BWAPI::Unit unit) { if (!unit) { return; } clearPreviousJob(unit); m_workers.erase(unit); } void WorkerData::addWorker(BWAPI::Unit unit) { if (!unit) { return; } m_workers.insert(unit); m_workerJobMap[unit] = Default; } void WorkerData::addWorker(BWAPI::Unit unit, WorkerJob job, BWAPI::Unit jobUnit) { if (!unit || !jobUnit) { return; } assert(m_workers.find(unit) == m_workers.end()); m_workers.insert(unit); setWorkerJob(unit, job, jobUnit); } void WorkerData::addWorker(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType) { if (!unit) { return; } assert(m_workers.find(unit) == m_workers.end()); m_workers.insert(unit); setWorkerJob(unit, job, jobUnitType); } void WorkerData::addDepot(BWAPI::Unit unit) { if (!unit) { return; } assert(m_depots.find(unit) == m_depots.end()); m_depots.insert(unit); m_depotWorkerCount[unit] = 0; } void WorkerData::removeDepot(BWAPI::Unit unit) { if (!unit) { return; } m_depots.erase(unit); m_depotWorkerCount.erase(unit); // re-balance workers in here for (auto & worker : m_workers) { // if a worker was working at this depot if (m_workerDepotMap[worker] == unit) { setWorkerJob(worker, Idle, nullptr); } } } void WorkerData::addToMineralPatch(BWAPI::Unit unit, int num) { if (m_workersOnMineralPatch.find(unit) == m_workersOnMineralPatch.end()) { m_workersOnMineralPatch[unit] = num; } else { m_workersOnMineralPatch[unit] = m_workersOnMineralPatch[unit] + num; } } void WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::Unit jobUnit) { if (!unit) { return; } clearPreviousJob(unit); m_workerJobMap[unit] = job; if (job == Minerals) { // increase the number of workers assigned to this nexus m_depotWorkerCount[jobUnit] += 1; // set the mineral the worker is working on m_workerDepotMap[unit] = jobUnit; BWAPI::Unit mineralToMine = getMineralToMine(unit); m_workerMineralAssignment[unit] = mineralToMine; addToMineralPatch(mineralToMine, 1); // right click the mineral to start mining Micro::SmartRightClick(unit, mineralToMine); } else if (job == Gas) { // increase the count of workers assigned to this refinery m_refineryWorkerCount[jobUnit] += 1; // set the refinery the worker is working on m_workerRefineryMap[unit] = jobUnit; // right click the refinery to start harvesting Micro::SmartRightClick(unit, jobUnit); } else if (job == Repair) { // only SCVs can repair assert(unit->getType() == BWAPI::UnitTypes::Terran_SCV); // set the building the worker is to repair m_workerRepairMap[unit] = jobUnit; // start repairing if (!unit->isRepairing()) { Micro::SmartRepair(unit, jobUnit); } } else if (job == Scout) { } else if (job == Build) { BWAPI::Broodwar->printf("Setting worker job to build"); } } void WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType) { if (!unit) { return; } clearPreviousJob(unit); m_workerJobMap[unit] = job; if (job == Build) { m_workerBuildingTypeMap[unit] = jobUnitType; } } void WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, WorkerMoveData wmd) { if (!unit) { return; } clearPreviousJob(unit); m_workerJobMap[unit] = job; if (job == Move) { m_workerMoveMap[unit] = wmd; } if (m_workerJobMap[unit] != Move) { BWAPI::Broodwar->printf("Something went horribly wrong"); } } void WorkerData::clearPreviousJob(BWAPI::Unit unit) { if (!unit) { return; } WorkerJob previousJob = getWorkerJob(unit); if (previousJob == Minerals) { m_depotWorkerCount[m_workerDepotMap[unit]] -= 1; m_workerDepotMap.erase(unit); // remove a worker from this unit's assigned mineral patch addToMineralPatch(m_workerMineralAssignment[unit], -1); // erase the association from the map m_workerMineralAssignment.erase(unit); } else if (previousJob == Gas) { m_refineryWorkerCount[m_workerRefineryMap[unit]] -= 1; m_workerRefineryMap.erase(unit); } else if (previousJob == Build) { m_workerBuildingTypeMap.erase(unit); } else if (previousJob == Repair) { m_workerRepairMap.erase(unit); } else if (previousJob == Move) { m_workerMoveMap.erase(unit); } m_workerJobMap.erase(unit); } int WorkerData::getNumWorkers() const { return m_workers.size(); } int WorkerData::getNumMineralWorkers() const { size_t num = 0; for (auto & unit : m_workers) { if (m_workerJobMap.at(unit) == WorkerData::Minerals) { num++; } } return num; } int WorkerData::getNumGasWorkers() const { size_t num = 0; for (auto & unit : m_workers) { if (m_workerJobMap.at(unit) == WorkerData::Gas) { num++; } } return num; } int WorkerData::getNumIdleWorkers() const { size_t num = 0; for (auto & unit : m_workers) { if (m_workerJobMap.at(unit) == WorkerData::Idle) { num++; } } return num; } enum WorkerData::WorkerJob WorkerData::getWorkerJob(BWAPI::Unit unit) { if (!unit) { return Default; } std::map::iterator it = m_workerJobMap.find(unit); if (it != m_workerJobMap.end()) { return it->second; } return Default; } bool WorkerData::depotIsFull(BWAPI::Unit depot) { if (!depot) { return false; } int assignedWorkers = getNumAssignedWorkers(depot); int mineralsNearDepot = getMineralsNearDepot(depot); if (assignedWorkers >= mineralsNearDepot * 3) { return true; } else { return false; } } BWAPI::Unitset WorkerData::getMineralPatchesNearDepot(BWAPI::Unit depot) { // if there are minerals near the depot, add them to the set BWAPI::Unitset mineralsNearDepot; int radius = 300; for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) && unit->getDistance(depot) < radius) { mineralsNearDepot.insert(unit); } } // if we didn't find any, use the whole map if (mineralsNearDepot.empty()) { for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)) { mineralsNearDepot.insert(unit); } } } return mineralsNearDepot; } int WorkerData::getMineralsNearDepot(BWAPI::Unit depot) { if (!depot) { return 0; } int mineralsNearDepot = 0; for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) && unit->getDistance(depot) < 200) { mineralsNearDepot++; } } return mineralsNearDepot; } BWAPI::Unit WorkerData::getWorkerResource(BWAPI::Unit unit) { if (!unit) { return nullptr; } // create the iterator std::map::iterator it; // if the worker is mining, set the iterator to the mineral map if (getWorkerJob(unit) == Minerals) { it = m_workerMineralMap.find(unit); if (it != m_workerMineralMap.end()) { return it->second; } } else if (getWorkerJob(unit) == Gas) { it = m_workerRefineryMap.find(unit); if (it != m_workerRefineryMap.end()) { return it->second; } } return nullptr; } BWAPI::Unit WorkerData::getMineralToMine(BWAPI::Unit worker) { if (!worker) { return nullptr; } // get the depot associated with this unit BWAPI::Unit depot = getWorkerDepot(worker); BWAPI::Unit bestMineral = nullptr; double bestDist = 100000; double bestNumAssigned = 10000; if (depot) { BWAPI::Unitset mineralPatches = getMineralPatchesNearDepot(depot); for (auto & mineral : mineralPatches) { double dist = mineral->getDistance(depot); double numAssigned = m_workersOnMineralPatch[mineral]; if (numAssigned < bestNumAssigned) { bestMineral = mineral; bestDist = dist; bestNumAssigned = numAssigned; } else if (numAssigned == bestNumAssigned) { if (dist < bestDist) { bestMineral = mineral; bestDist = dist; bestNumAssigned = numAssigned; } } } } return bestMineral; } /* BWAPI::Unit WorkerData::getMineralToMine(BWAPI::Unit worker) { if (!worker) { return nullptr; } // get the depot associated with this unit BWAPI::Unit depot = getWorkerDepot(worker); BWAPI::Unit mineral = nullptr; double closestDist = 10000; if (depot) { BOOST_FOREACH (BWAPI::Unit unit, BWAPI::Broodwar->getAllUnits()) { if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field && unit->getResources() > 0) { double dist = unit->getDistance(depot); if (!mineral || dist < closestDist) { mineral = unit; closestDist = dist; } } } } return mineral; }*/ BWAPI::Unit WorkerData::getWorkerRepairUnit(BWAPI::Unit unit) { if (!unit) { return nullptr; } std::map::iterator it = m_workerRepairMap.find(unit); if (it != m_workerRepairMap.end()) { return it->second; } return nullptr; } BWAPI::Unit WorkerData::getWorkerDepot(BWAPI::Unit unit) { if (!unit) { return nullptr; } std::map::iterator it = m_workerDepotMap.find(unit); if (it != m_workerDepotMap.end()) { return it->second; } return nullptr; } BWAPI::UnitType WorkerData::getWorkerBuildingType(BWAPI::Unit unit) { if (!unit) { return BWAPI::UnitTypes::None; } std::map::iterator it = m_workerBuildingTypeMap.find(unit); if (it != m_workerBuildingTypeMap.end()) { return it->second; } return BWAPI::UnitTypes::None; } WorkerMoveData WorkerData::getWorkerMoveData(BWAPI::Unit unit) { std::map::iterator it = m_workerMoveMap.find(unit); assert(it != m_workerMoveMap.end()); return (it->second); } int WorkerData::getNumAssignedWorkers(BWAPI::Unit unit) { if (!unit) { return 0; } std::map::iterator it; // if the worker is mining, set the iterator to the mineral map if (unit->getType().isResourceDepot()) { it = m_depotWorkerCount.find(unit); // if there is an entry, return it if (it != m_depotWorkerCount.end()) { return it->second; } } else if (unit->getType().isRefinery()) { it = m_refineryWorkerCount.find(unit); // if there is an entry, return it if (it != m_refineryWorkerCount.end()) { return it->second; } // otherwise, we are only calling this on completed refineries, so set it else { m_refineryWorkerCount[unit] = 0; } } // when all else fails, return 0 return 0; } char WorkerData::getJobCode(BWAPI::Unit unit) { if (!unit) { return 'X'; } WorkerData::WorkerJob j = getWorkerJob(unit); if (j == WorkerData::Build) return 'B'; if (j == WorkerData::Combat) return 'C'; if (j == WorkerData::Default) return 'D'; if (j == WorkerData::Gas) return 'G'; if (j == WorkerData::Idle) return 'I'; if (j == WorkerData::Minerals) return 'M'; if (j == WorkerData::Repair) return 'R'; if (j == WorkerData::Move) return 'O'; if (j == WorkerData::Scout) return 'S'; return 'X'; } void WorkerData::drawDepotDebugInfo() { for (auto & depot : m_depots) { int x = depot->getPosition().x - 64; int y = depot->getPosition().y - 32; if (Config::Debug::DrawWorkerInfo) BWAPI::Broodwar->drawBoxMap(x-2, y-1, x+75, y+14, BWAPI::Colors::Black, true); if (Config::Debug::DrawWorkerInfo) BWAPI::Broodwar->drawTextMap(x, y, "\x04 Workers: %d", getNumAssignedWorkers(depot)); BWAPI::Unitset minerals = getMineralPatchesNearDepot(depot); for (auto & mineral : minerals) { int x = mineral->getPosition().x; int y = mineral->getPosition().y; if (m_workersOnMineralPatch.find(mineral) != m_workersOnMineralPatch.end()) { //if (Config::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawBoxMap(x-2, y-1, x+75, y+14, BWAPI::Colors::Black, true); //if (Config::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawTextMap(x, y, "\x04 Workers: %d", workersOnMineralPatch[mineral]); } } } } const BWAPI::Unitset & WorkerData::getWorkers() const { return m_workers; } ================================================ FILE: UAlbertaBot/Source/WorkerData.h ================================================ #pragma once #include "Common.h" namespace UAlbertaBot { class WorkerMoveData { public: int mineralsNeeded = 0; int gasNeeded = 0; BWAPI::Position position; WorkerMoveData(int m, int g, BWAPI::Position p) : mineralsNeeded(m) , gasNeeded(g) , position(p) { } WorkerMoveData() {} }; class WorkerData { public: enum WorkerJob { Minerals, Gas, Build, Combat, Idle, Repair, Move, Scout, Default }; private: BWAPI::Unitset m_workers; BWAPI::Unitset m_depots; std::map m_workerJobMap; std::map m_workerMineralMap; std::map m_workerDepotMap; std::map m_workerRefineryMap; std::map m_workerRepairMap; std::map m_workerMoveMap; std::map m_workerBuildingTypeMap; std::map m_depotWorkerCount; std::map m_refineryWorkerCount; std::map m_workersOnMineralPatch; std::map m_workerMineralAssignment; void clearPreviousJob(BWAPI::Unit unit); public: WorkerData(); void workerDestroyed(BWAPI::Unit unit); void addDepot(BWAPI::Unit unit); void removeDepot(BWAPI::Unit unit); void addWorker(BWAPI::Unit unit); void addWorker(BWAPI::Unit unit, WorkerJob job, BWAPI::Unit jobUnit); void addWorker(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType); void addToMineralPatch(BWAPI::Unit unit, int num); void drawDepotDebugInfo(); void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::Unit jobUnit); void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::UnitType jobUnitType); void setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, WorkerMoveData wmd); int getNumWorkers() const; int getNumMineralWorkers() const; int getNumGasWorkers() const; int getNumIdleWorkers() const; int getNumAssignedWorkers(BWAPI::Unit unit); int getMineralsNearDepot(BWAPI::Unit depot); char getJobCode(BWAPI::Unit unit); bool depotIsFull(BWAPI::Unit depot); BWAPI::Unit getMineralToMine(BWAPI::Unit worker); enum WorkerJob getWorkerJob(BWAPI::Unit unit); BWAPI::Unit getWorkerResource(BWAPI::Unit unit); BWAPI::Unit getWorkerDepot(BWAPI::Unit unit); BWAPI::Unit getWorkerRepairUnit(BWAPI::Unit unit); BWAPI::UnitType getWorkerBuildingType(BWAPI::Unit unit); WorkerMoveData getWorkerMoveData(BWAPI::Unit unit); BWAPI::Unitset getMineralPatchesNearDepot(BWAPI::Unit depot); const BWAPI::Unitset & getWorkers() const; }; } ================================================ FILE: UAlbertaBot/Source/WorkerManager.cpp ================================================ #include "Common.h" #include "WorkerManager.h" #include "Micro.h" #include "BaseLocationManager.h" #include "Global.h" #include "BuildingData.h" using namespace UAlbertaBot; WorkerManager::WorkerManager() { } void WorkerManager::onFrame() { PROFILE_FUNCTION(); updateWorkerStatus(); handleGasWorkers(); handleIdleWorkers(); handleMoveWorkers(); handleCombatWorkers(); drawResourceDebugInfo(); drawWorkerInformation(450, 20); m_workerData.drawDepotDebugInfo(); handleRepairWorkers(); } void WorkerManager::updateWorkerStatus() { PROFILE_FUNCTION(); // for each of our Workers for (auto & worker : m_workerData.getWorkers()) { if (!worker->isCompleted()) { continue; } // if it's idle if (worker->isIdle() && (m_workerData.getWorkerJob(worker) != WorkerData::Build) && (m_workerData.getWorkerJob(worker) != WorkerData::Move) && (m_workerData.getWorkerJob(worker) != WorkerData::Scout)) { m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr); } // if its job is gas if (m_workerData.getWorkerJob(worker) == WorkerData::Gas) { const BWAPI::Unit refinery = m_workerData.getWorkerResource(worker); // if the refinery doesn't exist anymore if (!refinery || !refinery->exists() || refinery->getHitPoints() <= 0) { setMineralWorker(worker); } } } } void WorkerManager::setRepairWorker(BWAPI::Unit worker, BWAPI::Unit unitToRepair) { m_workerData.setWorkerJob(worker, WorkerData::Repair, unitToRepair); } void WorkerManager::stopRepairing(BWAPI::Unit worker) { m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr); } void WorkerManager::handleGasWorkers() { // for each unit we have for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { // if that unit is a refinery if (unit->getType().isRefinery() && unit->isCompleted() && !isGasStealRefinery(unit)) { // get the number of workers currently assigned to it const int numAssigned = m_workerData.getNumAssignedWorkers(unit); // if it's less than we want it to be, fill 'er up for (int i=0; i<(Config::Macro::WorkersPerRefinery-numAssigned); ++i) { BWAPI::Unit gasWorker = getGasWorker(unit); if (gasWorker) { m_workerData.setWorkerJob(gasWorker, WorkerData::Gas, unit); } } } } } bool WorkerManager::isGasStealRefinery(BWAPI::Unit unit) { auto * enemyBaseLocation = Global::Bases().getPlayerStartingBaseLocation(BWAPI::Broodwar->enemy()); if (!enemyBaseLocation) { return false; } if (enemyBaseLocation->getGeysers().empty()) { return false; } for (auto & u : enemyBaseLocation->getGeysers()) { if (unit->getTilePosition() == u->getTilePosition()) { return true; } } return false; } void WorkerManager::handleIdleWorkers() { // for each of our workers for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); // if it is idle if (m_workerData.getWorkerJob(worker) == WorkerData::Idle) { // send it to the nearest mineral patch setMineralWorker(worker); } } } void WorkerManager::handleRepairWorkers() { if (BWAPI::Broodwar->self()->getRace() != BWAPI::Races::Terran) { return; } for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType().isBuilding() && (unit->getHitPoints() < unit->getType().maxHitPoints())) { const BWAPI::Unit repairWorker = getClosestMineralWorkerTo(unit); setRepairWorker(repairWorker, unit); break; } } } // bad micro for combat workers void WorkerManager::handleCombatWorkers() { for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); if (m_workerData.getWorkerJob(worker) == WorkerData::Combat) { BWAPI::Broodwar->drawCircleMap(worker->getPosition().x, worker->getPosition().y, 4, BWAPI::Colors::Yellow, true); const BWAPI::Unit target = getClosestEnemyUnit(worker); if (target) { Micro::SmartAttackUnit(worker, target); } } } } BWAPI::Unit WorkerManager::getClosestEnemyUnit(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); BWAPI::Unit closestUnit = nullptr; double closestDist = 10000; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { const double dist = unit->getDistance(worker); if ((dist < 400) && (!closestUnit || (dist < closestDist))) { closestUnit = unit; closestDist = dist; } } return closestUnit; } void WorkerManager::finishedWithCombatWorkers() { for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); if (m_workerData.getWorkerJob(worker) == WorkerData::Combat) { setMineralWorker(worker); } } } BWAPI::Unit WorkerManager::getClosestMineralWorkerTo(BWAPI::Unit enemyUnit) { UAB_ASSERT(enemyUnit != nullptr, "enemyUnit was null"); BWAPI::Unit closestMineralWorker = nullptr; double closestDist = 100000; if (m_previousClosestWorker) { if (m_previousClosestWorker->getHitPoints() > 0) { return m_previousClosestWorker; } } // for each of our workers for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); if (!worker) { continue; } // if it is a move worker if (m_workerData.getWorkerJob(worker) == WorkerData::Minerals) { double dist = worker->getDistance(enemyUnit); if (!closestMineralWorker || dist < closestDist) { closestMineralWorker = worker; closestDist = dist; } } } m_previousClosestWorker = closestMineralWorker; return closestMineralWorker; } BWAPI::Unit WorkerManager::getWorkerScout() { // for each of our workers for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); if (!worker) { continue; } // if it is a move worker if (m_workerData.getWorkerJob(worker) == WorkerData::Scout) { return worker; } } return nullptr; } void WorkerManager::handleMoveWorkers() { // for each of our workers for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); // if it is a move worker if (m_workerData.getWorkerJob(worker) == WorkerData::Move) { const WorkerMoveData data = m_workerData.getWorkerMoveData(worker); Micro::SmartMove(worker, data.position); } } } // set a worker to mine minerals void WorkerManager::setMineralWorker(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); // check if there is a mineral available to send the worker to BWAPI::Unit depot = getClosestDepot(unit); // if there is a valid mineral if (depot) { // update workerData with the new job m_workerData.setWorkerJob(unit, WorkerData::Minerals, depot); } else { // BWAPI::Broodwar->printf("No valid depot for mineral worker"); } } BWAPI::Unit WorkerManager::getClosestDepot(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); BWAPI::Unit closestDepot = nullptr; double closestDistance = 0; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(unit != nullptr, "Unit was null"); if (unit->getType().isResourceDepot() && (unit->isCompleted() || unit->getType() == BWAPI::UnitTypes::Zerg_Lair) && !m_workerData.depotIsFull(unit)) { const double distance = unit->getDistance(worker); if (!closestDepot || distance < closestDistance) { closestDepot = unit; closestDistance = distance; } } } return closestDepot; } // other managers that need workers call this when they're done with a unit void WorkerManager::finishedWithWorker(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); //BWAPI::Broodwar->printf("BuildingManager finished with worker %d", unit->getID()); if (m_workerData.getWorkerJob(unit) != WorkerData::Scout) { m_workerData.setWorkerJob(unit, WorkerData::Idle, nullptr); } } BWAPI::Unit WorkerManager::getGasWorker(BWAPI::Unit refinery) { UAB_ASSERT(refinery != nullptr, "Refinery was null"); BWAPI::Unit closestWorker = nullptr; double closestDistance = 0; for (auto & unit : m_workerData.getWorkers()) { UAB_ASSERT(unit != nullptr, "Unit was null"); if (m_workerData.getWorkerJob(unit) == WorkerData::Minerals) { const double distance = unit->getDistance(refinery); if (!closestWorker || distance < closestDistance) { closestWorker = unit; closestDistance = distance; } } } return closestWorker; } void WorkerManager::setBuildingWorker(BWAPI::Unit worker, Building & b) { UAB_ASSERT(worker != nullptr, "Worker was null"); m_workerData.setWorkerJob(worker, WorkerData::Build, b.type); } // gets a builder for BuildingManager to use // if setJobAsBuilder is true (default), it will be flagged as a builder unit // set 'setJobAsBuilder' to false if we just want to see which worker will build a building BWAPI::Unit WorkerManager::getBuilder(Building & b, bool setJobAsBuilder) { // variables to hold the closest worker of each type to the building BWAPI::Unit closestMovingWorker = nullptr; BWAPI::Unit closestMiningWorker = nullptr; double closestMovingWorkerDistance = 0; double closestMiningWorkerDistance = 0; // look through each worker that had moved there first for (auto & unit : m_workerData.getWorkers()) { UAB_ASSERT(unit != nullptr, "Unit was null"); // gas steal building uses scout worker if (b.isGasSteal && (m_workerData.getWorkerJob(unit) == WorkerData::Scout)) { if (setJobAsBuilder) { m_workerData.setWorkerJob(unit, WorkerData::Build, b.type); } return unit; } // mining worker check if (unit->isCompleted() && (m_workerData.getWorkerJob(unit) == WorkerData::Minerals)) { // if it is a new closest distance, set the pointer const double distance = unit->getDistance(BWAPI::Position(b.finalPosition)); if (!closestMiningWorker || distance < closestMiningWorkerDistance) { closestMiningWorker = unit; closestMiningWorkerDistance = distance; } } // moving worker check if (unit->isCompleted() && (m_workerData.getWorkerJob(unit) == WorkerData::Move)) { // if it is a new closest distance, set the pointer const double distance = unit->getDistance(BWAPI::Position(b.finalPosition)); if (!closestMovingWorker || distance < closestMovingWorkerDistance) { closestMovingWorker = unit; closestMovingWorkerDistance = distance; } } } // if we found a moving worker, use it, otherwise using a mining worker BWAPI::Unit chosenWorker = closestMovingWorker ? closestMovingWorker : closestMiningWorker; // if the worker exists (one may not have been found in rare cases) if (chosenWorker && setJobAsBuilder) { m_workerData.setWorkerJob(chosenWorker, WorkerData::Build, b.type); } // return the worker return chosenWorker; } // sets a worker as a scout void WorkerManager::setScoutWorker(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); m_workerData.setWorkerJob(worker, WorkerData::Scout, nullptr); } // gets a worker which will move to a current location BWAPI::Unit WorkerManager::getMoveWorker(BWAPI::Position p) { // set up the pointer BWAPI::Unit closestWorker = nullptr; double closestDistance = 0; // for each worker we currently have for (auto & unit : m_workerData.getWorkers()) { UAB_ASSERT(unit != nullptr, "Unit was null"); // only consider it if it's a mineral worker if (unit->isCompleted() && m_workerData.getWorkerJob(unit) == WorkerData::Minerals) { // if it is a new closest distance, set the pointer const double distance = unit->getDistance(p); if (!closestWorker || distance < closestDistance) { closestWorker = unit; closestDistance = distance; } } } // return the worker return closestWorker; } // sets a worker to move to a given location void WorkerManager::setMoveWorker(int mineralsNeeded, int gasNeeded, BWAPI::Position p) { // set up the pointer BWAPI::Unit closestWorker = nullptr; double closestDistance = 0; // for each worker we currently have for (auto & unit : m_workerData.getWorkers()) { UAB_ASSERT(unit != nullptr, "Unit was null"); // only consider it if it's a mineral worker if (unit->isCompleted() && m_workerData.getWorkerJob(unit) == WorkerData::Minerals) { // if it is a new closest distance, set the pointer const double distance = unit->getDistance(p); if (!closestWorker || distance < closestDistance) { closestWorker = unit; closestDistance = distance; } } } if (closestWorker) { //BWAPI::Broodwar->printf("Setting worker job Move for worker %d", closestWorker->getID()); m_workerData.setWorkerJob(closestWorker, WorkerData::Move, WorkerMoveData(mineralsNeeded, gasNeeded, p)); } else { //BWAPI::Broodwar->printf("Error, no worker found"); } } // will we have the required resources by the time a worker can travel a certain distance bool WorkerManager::willHaveResources(int mineralsRequired, int gasRequired, double distance) { // if we don't require anything, we will have it if (mineralsRequired <= 0 && gasRequired <= 0) { return true; } // the speed of the worker unit const double speed = BWAPI::Broodwar->self()->getRace().getWorker().topSpeed(); UAB_ASSERT(speed > 0, "Speed is negative"); // how many frames it will take us to move to the building location // add a second to account for worker getting stuck. better early than late const double framesToMove = (distance / speed) + 50; // magic numbers to predict income rates const double mineralRate = getNumMineralWorkers() * 0.045; const double gasRate = getNumGasWorkers() * 0.07; // calculate if we will have enough by the time the worker gets there if (mineralRate * framesToMove >= mineralsRequired && gasRate * framesToMove >= gasRequired) { return true; } else { return false; } } void WorkerManager::setCombatWorker(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); m_workerData.setWorkerJob(worker, WorkerData::Combat, nullptr); } void WorkerManager::onUnitMorph(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); // if something morphs into a worker, add it if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getHitPoints() >= 0) { m_workerData.addWorker(unit); } // if something morphs into a building, it was a worker? if (unit->getType().isBuilding() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getPlayer()->getRace() == BWAPI::Races::Zerg) { //BWAPI::Broodwar->printf("A Drone started building"); m_workerData.workerDestroyed(unit); } } void WorkerManager::onUnitShow(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); // add the depot if it exists if (unit->getType().isResourceDepot() && unit->getPlayer() == BWAPI::Broodwar->self()) { m_workerData.addDepot(unit); } // if something morphs into a worker, add it if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self() && unit->getHitPoints() >= 0) { //BWAPI::Broodwar->printf("A worker was shown %d", unit->getID()); m_workerData.addWorker(unit); } } void WorkerManager::rebalanceWorkers() { // for each worker for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); if (!m_workerData.getWorkerJob(worker) == WorkerData::Minerals) { continue; } BWAPI::Unit depot = m_workerData.getWorkerDepot(worker); if (depot && m_workerData.depotIsFull(depot)) { m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr); } else if (!depot) { m_workerData.setWorkerJob(worker, WorkerData::Idle, nullptr); } } } void WorkerManager::onUnitDestroy(BWAPI::Unit unit) { UAB_ASSERT(unit != nullptr, "Unit was null"); if (unit->getType().isResourceDepot() && unit->getPlayer() == BWAPI::Broodwar->self()) { m_workerData.removeDepot(unit); } if (unit->getType().isWorker() && unit->getPlayer() == BWAPI::Broodwar->self()) { m_workerData.workerDestroyed(unit); } if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) { rebalanceWorkers(); } } void WorkerManager::drawResourceDebugInfo() { if (!Config::Debug::DrawResourceInfo) { return; } for (auto & worker : m_workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); const char job = m_workerData.getJobCode(worker); const BWAPI::Position pos = worker->getTargetPosition(); BWAPI::Broodwar->drawTextMap(worker->getPosition().x, worker->getPosition().y - 5, "\x07%c", job); BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, pos.x, pos.y, BWAPI::Colors::Cyan); const BWAPI::Unit depot = m_workerData.getWorkerDepot(worker); if (depot) { BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, depot->getPosition().x, depot->getPosition().y, BWAPI::Colors::Orange); } } } void WorkerManager::drawWorkerInformation(int x, int y) { if (!Config::Debug::DrawWorkerInfo) { return; } BWAPI::Broodwar->drawTextScreen(x, y, "\x04 Workers %d", m_workerData.getNumMineralWorkers()); BWAPI::Broodwar->drawTextScreen(x, y+20, "\x04 UnitID"); BWAPI::Broodwar->drawTextScreen(x+50, y+20, "\x04 State"); int yspace = 0; for (auto & unit : m_workerData.getWorkers()) { UAB_ASSERT(unit != nullptr, "Worker was null"); BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), "\x03 %d", unit->getID()); BWAPI::Broodwar->drawTextScreen(x+50, y+40+((yspace++)*10), "\x03 %c", m_workerData.getJobCode(unit)); } } bool WorkerManager::isFree(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); return m_workerData.getWorkerJob(worker) == WorkerData::Minerals || m_workerData.getWorkerJob(worker) == WorkerData::Idle; } bool WorkerManager::isWorkerScout(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); return (m_workerData.getWorkerJob(worker) == WorkerData::Scout); } bool WorkerManager::isBuilder(BWAPI::Unit worker) { UAB_ASSERT(worker != nullptr, "Worker was null"); return (m_workerData.getWorkerJob(worker) == WorkerData::Build); } int WorkerManager::getNumMineralWorkers() { return m_workerData.getNumMineralWorkers(); } int WorkerManager::getNumIdleWorkers() { return m_workerData.getNumIdleWorkers(); } int WorkerManager::getNumGasWorkers() { return m_workerData.getNumGasWorkers(); } ================================================ FILE: UAlbertaBot/Source/WorkerManager.h ================================================ #pragma once #include #include "WorkerData.h" namespace UAlbertaBot { class Building; class WorkerManager { friend class Global; WorkerData m_workerData; BWAPI::Unit m_previousClosestWorker = nullptr; void setMineralWorker(BWAPI::Unit unit); bool isGasStealRefinery(BWAPI::Unit unit); void handleIdleWorkers(); void handleGasWorkers(); void handleMoveWorkers(); void handleCombatWorkers(); void handleRepairWorkers(); WorkerManager(); public: void onFrame(); void onUnitDestroy(BWAPI::Unit unit); void onUnitMorph(BWAPI::Unit unit); void onUnitShow(BWAPI::Unit unit); void finishedWithWorker(BWAPI::Unit unit); void finishedWithCombatWorkers(); void drawResourceDebugInfo(); void updateWorkerStatus(); void drawWorkerInformation(int x, int y); int getNumMineralWorkers(); int getNumGasWorkers(); int getNumIdleWorkers(); void setScoutWorker(BWAPI::Unit worker); bool isWorkerScout(BWAPI::Unit worker); bool isFree(BWAPI::Unit worker); bool isBuilder(BWAPI::Unit worker); BWAPI::Unit getBuilder(Building & b, bool setJobAsBuilder = true); BWAPI::Unit getMoveWorker(BWAPI::Position p); BWAPI::Unit getClosestDepot(BWAPI::Unit worker); BWAPI::Unit getGasWorker(BWAPI::Unit refinery); BWAPI::Unit getClosestEnemyUnit(BWAPI::Unit worker); BWAPI::Unit getClosestMineralWorkerTo(BWAPI::Unit enemyUnit); BWAPI::Unit getWorkerScout(); void setBuildingWorker(BWAPI::Unit worker, Building & b); void setRepairWorker(BWAPI::Unit worker, BWAPI::Unit unitToRepair); void stopRepairing(BWAPI::Unit worker); void setMoveWorker(int m, int g, BWAPI::Position p); void setCombatWorker(BWAPI::Unit worker); bool willHaveResources(int mineralsRequired, int gasRequired, double distance); void rebalanceWorkers(); }; } ================================================ FILE: UAlbertaBot/Source/main.cpp ================================================ #include #include #include "UAlbertaBotModule.h" #include #include #include #include "Global.h" #include "../../SparCraft/source/SparCraft.h" #include "../../BOSS/source/BOSS.h" using namespace BWAPI; using namespace UAlbertaBot; void UAlbertaBot_BWAPIReconnect() { while (!BWAPIClient.connect()) { std::this_thread::sleep_for(std::chrono::milliseconds{ 1000 }); } } void UAlbertaBot_PlayGame() { PROFILE_FUNCTION(); UAlbertaBotModule bot; // The main game loop, which continues while we are connected to BWAPI and in a game while (BWAPI::BWAPIClient.isConnected() && BWAPI::Broodwar->isInGame()) { // Handle each of the events that happened on this frame of the game for (const BWAPI::Event & e : BWAPI::Broodwar->getEvents()) { switch (e.getType()) { case BWAPI::EventType::MatchStart: { bot.onStart(); break; } case BWAPI::EventType::MatchFrame: { bot.onFrame(); break; } case BWAPI::EventType::MatchEnd: { bot.onEnd(e.isWinner()); break; } case BWAPI::EventType::UnitShow: { bot.onUnitShow(e.getUnit()); break; } case BWAPI::EventType::UnitHide: { bot.onUnitHide(e.getUnit()); break; } case BWAPI::EventType::UnitCreate: { bot.onUnitCreate(e.getUnit()); break; } case BWAPI::EventType::UnitMorph: { bot.onUnitMorph(e.getUnit()); break; } case BWAPI::EventType::UnitDestroy: { bot.onUnitDestroy(e.getUnit()); break; } case BWAPI::EventType::UnitRenegade: { bot.onUnitRenegade(e.getUnit()); break; } case BWAPI::EventType::UnitComplete: { bot.onUnitComplete(e.getUnit()); break; } case BWAPI::EventType::SendText: { bot.onSendText(e.getText()); break; } } } BWAPI::BWAPIClient.update(); if (!BWAPI::BWAPIClient.isConnected()) { std::cout << "Disconnected\n"; break; } } std::cout << "Game Over\n"; } int main(int argc, char * argv[]) { PROFILE_FUNCTION(); bool exitIfStarcraftShutdown = true; std::cout << "UAlbertaBot - David Churchill\n"; std::cout << "https://github.com/davechurchill/ualbertabot\n\n"; std::cout << "Compiled on " << __DATE__ << " @ " << __TIME__ << "\n\n"; // Initialize SparCraft, the combat simulation package SparCraft::init(); // Initialize BOSS, the Build Order Search System BOSS::init(); size_t gameCount = 0; while (true) { // if we are not currently connected to BWAPI, try to reconnect if (!BWAPI::BWAPIClient.isConnected()) { UAlbertaBot_BWAPIReconnect(); } // if we have connected to BWAPI while (BWAPI::BWAPIClient.isConnected()) { // wait for the game to start until the game starts std::cout << "Waiting for game start\n"; while (BWAPI::BWAPIClient.isConnected() && !BWAPI::Broodwar->isInGame()) { BWAPI::BWAPIClient.update(); } // Check to see if Starcraft shut down somehow if (BWAPI::BroodwarPtr == nullptr) { break; } // If we are successfully in a game, call the module to play the game if (BWAPI::Broodwar->isInGame()) { std::cout << "Playing game " << gameCount++ << " on map " << BWAPI::Broodwar->mapFileName() << "\n"; UAlbertaBot_PlayGame(); } } if (exitIfStarcraftShutdown && !BWAPI::BWAPIClient.isConnected()) { return 0; } } return 0; } ================================================ FILE: UAlbertaBot/Source/rapidjson/allocators.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Allocator /*! \class rapidjson::Allocator \brief Concept for allocating, resizing and freeing memory block. Note that Malloc() and Realloc() are non-static but Free() is static. So if an allocator need to support Free(), it needs to put its pointer in the header of memory block. \code concept Allocator { static const bool kNeedFree; //!< Whether this allocator needs to call Free(). // Allocate a memory block. // \param size of the memory block in bytes. // \returns pointer to the memory block. void* Malloc(size_t size); // Resize a memory block. // \param originalPtr The pointer to current memory block. Null pointer is permitted. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) // \param newSize the new size in bytes. void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // Free a memory block. // \param pointer to the memory block. Null pointer is permitted. static void Free(void *ptr); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // CrtAllocator //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. \note implements Allocator concept */ class CrtAllocator { public: static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. return std::malloc(size); else return NULL; // standardize to returning NULL. } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; if (newSize == 0) { std::free(originalPtr); return NULL; } return std::realloc(originalPtr, newSize); } static void Free(void *ptr) { std::free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// // MemoryPoolAllocator //! Default memory allocator used by the parser and DOM. /*! This allocator allocate memory blocks from pre-allocated memory chunks. It does not free memory blocks. And Realloc() only allocate new memory. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. User may also supply a buffer as the first chunk. If the user-buffer is full then additional chunks are allocated by BaseAllocator. The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \note implements Allocator concept */ template class MemoryPoolAllocator { public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { } //! Constructor with user-supplied buffer. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. The user buffer will not be deallocated when this allocator is destructed. \param buffer User supplied buffer. \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); chunkHead_ = reinterpret_cast(buffer); chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->size = 0; chunkHead_->next = 0; } //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ ~MemoryPoolAllocator() { Clear(); RAPIDJSON_DELETE(ownBaseAllocator_); } //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { while (chunkHead_ && chunkHead_ != userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } if (chunkHead_ && chunkHead_ == userBuffer_) chunkHead_->size = 0; // Clear user buffer } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ size_t Capacity() const { size_t capacity = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) capacity += c->capacity; return capacity; } //! Computes the memory blocks allocated. /*! \return total used bytes. */ size_t Size() const { size_t size = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size += c->size; return size; } //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { if (!size) return NULL; size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; chunkHead_->size += size; return buffer; } //! Resizes a memory block (concept Allocator) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { if (originalPtr == 0) return Malloc(newSize); if (newSize == 0) return NULL; // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast(newSize - originalSize); increment = RAPIDJSON_ALIGN(increment); if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; return originalPtr; } } // Realloc process: allocate and copy memory, do not free original buffer. void* newBuffer = Malloc(newSize); RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. if (originalSize) std::memcpy(newBuffer, originalPtr, originalSize); return newBuffer; } //! Frees a memory block (concept Allocator) static void Free(void *ptr) { (void)ptr; } // Do nothing private: //! Copy constructor is not permitted. MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; //! Copy assignment operator is not permitted. MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. */ void AddChunk(size_t capacity) { if (!baseAllocator_) ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity)); chunk->capacity = capacity; chunk->size = 0; chunk->next = chunkHead_; chunkHead_ = chunk; } static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. */ struct ChunkHeader { size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t size; //!< Current size of allocated memory in bytes. ChunkHeader *next; //!< Next chunk in the linked list. }; ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. void *userBuffer_; //!< User supplied buffer. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ENCODINGS_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/document.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ /*! \file document.h */ #include "reader.h" #include "internal/meta.h" #include "internal/strfunc.h" #include // placement new #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #elif defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_HAS_STDSTRING #ifndef RAPIDJSON_HAS_STDSTRING #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation #else #define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default #endif /*! \def RAPIDJSON_HAS_STDSTRING \ingroup RAPIDJSON_CONFIG \brief Enable RapidJSON support for \c std::string By defining this preprocessor symbol to \c 1, several convenience functions for using \ref rapidjson::GenericValue with \c std::string are enabled, especially for construction and comparison. \hideinitializer */ #endif // !defined(RAPIDJSON_HAS_STDSTRING) #if RAPIDJSON_HAS_STDSTRING #include #endif // RAPIDJSON_HAS_STDSTRING #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::iterator, std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. template class GenericValue; //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. https://code.google.com/p/rapidjson/issues/detail?id=64 */ template struct GenericMember { GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. }; /////////////////////////////////////////////////////////////////////////////// // GenericMemberIterator #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! \tparam Const Is this a constant iterator? \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. This class implements a Random Access Iterator for GenericMember elements of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. \note This iterator implementation is mainly intended to avoid implicit conversions from iterator values to \c NULL, e.g. from GenericValue::FindMember. \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a pointer-based implementation, if your platform doesn't provide the C++ header. \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template class GenericMemberIterator : public std::iterator >::Type> { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef std::iterator BaseType; public: //! Iterator type itself typedef GenericMemberIterator Iterator; //! Constant iterator type typedef GenericMemberIterator ConstIterator; //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; //! Pointer to (const) GenericMember typedef typename BaseType::pointer Pointer; //! Reference to (const) GenericMember typedef typename BaseType::reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) typedef typename BaseType::difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. \note All operations, except for comparisons, are undefined on such values. */ GenericMemberIterator() : ptr_() {} //! Iterator conversions to more const /*! \param it (Non-const) iterator to copy from Allows the creation of an iterator from another GenericMemberIterator that is "less const". Especially, creating a non-constant iterator from a constant iterator are disabled: \li const -> non-const (not ok) \li const -> const (ok) \li non-const -> const (ok) \li non-const -> non-const (ok) \note If the \c Const template parameter is already \c false, this constructor effectively defines a regular copy-constructor. Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} //! @name stepping //@{ Iterator& operator++(){ ++ptr_; return *this; } Iterator& operator--(){ --ptr_; return *this; } Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } //@} //! @name increment/decrement //@{ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } //@} //! @name relations //@{ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } //@} //! @name dereference //@{ Reference operator*() const { return *ptr_; } Pointer operator->() const { return ptr_; } Reference operator[](DifferenceType n) const { return ptr_[n]; } //@} //! Distance DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } private: //! Internal constructor from plain pointer explicit GenericMemberIterator(Pointer p) : ptr_(p) {} Pointer ptr_; //!< raw pointer }; #else // RAPIDJSON_NOMEMBERITERATORCLASS // class-based member iterator implementation disabled, use plain pointers template struct GenericMemberIterator; //! non-const GenericMemberIterator template struct GenericMemberIterator { //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template struct GenericMemberIterator { //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; #endif // RAPIDJSON_NOMEMBERITERATORCLASS /////////////////////////////////////////////////////////////////////////////// // GenericStringRef //! Reference to a constant string (not taking a copy) /*! \tparam CharType character type of the string This helper class is used to automatically infer constant string references for string literals, especially from \c const \b (!) character arrays. The main use is for creating JSON string values without copying the source string via an \ref Allocator. This requires that the referenced string pointers have a sufficient lifetime, which exceeds the lifetime of the associated GenericValue. \b Example \code Value v("foo"); // ok, no need to copy & calculate length const char foo[] = "foo"; v.SetString(foo); // ok const char* bar = foo; // Value x(bar); // not ok, can't rely on bar's lifetime Value x(StringRef(bar)); // lifetime explicitly guaranteed by user Value y(StringRef(bar, 3)); // ok, explicitly pass length \endcode \see StringRef, GenericValue::SetString */ template struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than \ref StringRef(const CharType*) by inferring the string \ref length from the array length, and also supports strings containing null characters. \tparam N length of the string, automatically inferred \param str Constant character array, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note Constant complexity. \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ template GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. \see StringRef(const CharType*) \param str Constant character pointer, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ explicit GenericStringRef(const CharType* str) : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } //! Create constant string reference from pointer and length /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ GenericStringRef(const CharType* str, SizeType len) : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } const Ch* const s; //!< plain CharType pointer const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: //! Disallow copy-assignment GenericStringRef operator=(const GenericStringRef&); //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; }; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType Character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ template inline GenericStringRef StringRef(const CharType* str) { return GenericStringRef(str, internal::StrLen(str)); } //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. This version has better performance with supplied length, and also supports string containing null characters. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param length The length of source string. \return GenericStringRef string reference object \relatesalso GenericStringRef */ template inline GenericStringRef StringRef(const CharType* str, size_t length) { return GenericStringRef(str, SizeType(length)); } #if RAPIDJSON_HAS_STDSTRING //! Mark a string object as constant string /*! Mark a string object (e.g. \c std::string) as a "string literal". This function can be used to avoid copying a string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ template inline GenericStringRef StringRef(const std::basic_string& str) { return GenericStringRef(str.data(), SizeType(str.size())); } #endif /////////////////////////////////////////////////////////////////////////////// // GenericValue type traits namespace internal { template struct IsGenericValueImpl : FalseType {}; // select candidates according to nested encoding and allocator types template struct IsGenericValueImpl::Type, typename Void::Type> : IsBaseOf, T>::Type {}; // helper to match arbitrary GenericValue instantiations, including derived classes template struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // GenericValue //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! A JSON value can be one of 7 types. This class is a variant type supporting these types. Use the Value if UTF8 and default allocator \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ template > class GenericValue { public: //! Name-value pair in an object. typedef GenericMember Member; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericStringRef StringRefType; //!< Reference to a constant string typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) { rhs.flags_ = kNullFlag; // give up contents } #endif private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); public: //! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \param type Type of the value. \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { static const unsigned defaultFlags[7] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; RAPIDJSON_ASSERT(type <= kNumberType); flags_ = defaultFlags[type]; // Use ShortString to store empty string. if (type == kStringType) data_.ss.SetLength(0); } //! Explicit copy constructor (with allocator) /*! Creates a copy of a Value by using the given Allocator \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). \see CopyFrom() */ template< typename SourceAllocator > GenericValue(const GenericValue& rhs, Allocator & allocator); //! Constructor for boolean value. /*! \param b Boolean value \note This constructor is limited to \em real boolean values and rejects implicitly converted types like arbitrary pointers. Use an explicit cast to \c bool, if you want to construct a boolean JSON value in such cases. */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif : data_(), flags_(b ? kTrueFlag : kFalseFlag) { // safe-guard against failing SFINAE RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); } //! Constructor for int value. explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) { data_.n.i64 = i; if (i >= 0) flags_ |= kUintFlag | kUint64Flag; } //! Constructor for unsigned value. explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) { data_.n.u64 = u; if (!(u & 0x80000000)) flags_ |= kIntFlag | kInt64Flag; } //! Constructor for int64_t value. explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) { data_.n.i64 = i64; if (i64 >= 0) { flags_ |= kNumberUint64Flag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) flags_ |= kUintFlag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) flags_ |= kIntFlag; } else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) flags_ |= kIntFlag; } //! Constructor for uint64_t value. explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { data_.n.u64 = u64; if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) flags_ |= kInt64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) flags_ |= kUintFlag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) flags_ |= kIntFlag; } //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); } //! Constructor for constant string (i.e. do not make a copy of string) explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue(const std::basic_string& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } #endif //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(flags_) { case kArrayFlag: for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) v->~GenericValue(); Allocator::Free(data_.a.elements); break; case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); Allocator::Free(data_.o.members); break; case kCopyStringFlag: Allocator::Free(const_cast(data_.s.str)); break; default: break; // Do nothing for other types. } } } //@} //!@name Assignment operators //@{ //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { RAPIDJSON_ASSERT(this != &rhs); this->~GenericValue(); RawAssign(rhs); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { return *this = rhs.Move(); } #endif //! Assignment of constant string reference (no copy) /*! \param str Constant string reference to be assigned \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. \see GenericStringRef, operator=(T) */ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { GenericValue s(str); return *this = s; } //! Assignment with primitive types. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value The value to be assigned. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref SetString(const Ch*, Allocator&) (for copying) or \ref StringRef() (to explicitly mark the pointer as constant) instead. All other pointer types would implicitly convert to \c bool, use \ref SetBool() instead. */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; } //! Deep-copy assignment from Value /*! Assigns a \b copy of the Value to the current Value object \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying */ template GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); this->~GenericValue(); new (this) GenericValue(rhs, allocator); return *this; } //! Exchange the contents of this value with those of other. /*! \param other Another value. \note Constant complexity. */ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { GenericValue temp; temp.RawAssign(*this); RawAssign(other); other.RawAssign(temp); return *this; } //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@} //!@name Equal-to and not-equal-to operators //@{ //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. \note Linear time complexity (number of all values in the subtree and total lengths of all strings). */ template bool operator==(const GenericValue& rhs) const { typedef GenericValue RhsType; if (GetType() != rhs.GetType()) return false; switch (GetType()) { case kObjectType: // Warning: O(n^2) inner-loop if (data_.o.size != rhs.data_.o.size) return false; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) return false; } return true; case kArrayType: if (data_.a.size != rhs.data_.a.size) return false; for (SizeType i = 0; i < data_.a.size; i++) if ((*this)[i] != rhs[i]) return false; return true; case kStringType: return StringEqual(rhs); case kNumberType: if (IsDouble() || rhs.IsDouble()) { double a = GetDouble(); // May convert from integer to double. double b = rhs.GetDouble(); // Ditto return a >= b && a <= b; // Prevent -Wfloat-equal } else return data_.n.u64 == rhs.data_.n.u64; default: // kTrueType, kFalseType, kNullType return true; } } //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } #if RAPIDJSON_HAS_STDSTRING //! Equal-to operator with string object /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } #endif //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } //! Not-equal-to operator /*! \return !(*this == rhs) */ template bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } //! Not-equal-to operator with const C-string pointer bool operator!=(const Ch* rhs) const { return !(*this == rhs); } //! Not-equal-to operator with arbitrary types /*! \return !(*this == rhs) */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } //! Not-Equal-to operator with arbitrary types (symmetric version) /*! \return !(rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type //@{ Type GetType() const { return static_cast(flags_ & kTypeMask); } bool IsNull() const { return flags_ == kNullFlag; } bool IsFalse() const { return flags_ == kFalseFlag; } bool IsTrue() const { return flags_ == kTrueFlag; } bool IsBool() const { return (flags_ & kBoolFlag) != 0; } bool IsObject() const { return flags_ == kObjectFlag; } bool IsArray() const { return flags_ == kArrayFlag; } bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } bool IsInt() const { return (flags_ & kIntFlag) != 0; } bool IsUint() const { return (flags_ & kUintFlag) != 0; } bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } bool IsString() const { return (flags_ & kStringFlag) != 0; } //@} //!@name Null //@{ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } //@} //!@name Bool //@{ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } //@} //!@name Object //@{ //! Set this value as an empty object. /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. Since 0.2, if the name is not correct, it will assert. If user is unsure whether a member exists, user should use HasMember() first. A better approach is to use FindMember(). \note Linear time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { GenericValue n(StringRef(name)); return (*this)[n]; } template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam SourceAllocator Allocator of the \c name value \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). And it can also handle strings with embedded null characters. \note Linear time complexity. */ template GenericValue& operator[](const GenericValue& name) { MemberIterator member = FindMember(name); if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note static GenericValue NullValue; return NullValue; } } template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } #if RAPIDJSON_HAS_STDSTRING //! Get a value from an object associated with name (string object). GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif //! Const member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } //! Check whether a member exists in the object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } #if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } #endif //! Check whether a member exists in the object with GenericValue name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ template bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } //! Find member by name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ MemberIterator FindMember(const Ch* name) { GenericValue n(StringRef(name)); return FindMember(n); } ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } //! Find member by name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ template MemberIterator FindMember(const GenericValue& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); MemberIterator member = MemberBegin(); for ( ; member != MemberEnd(); ++member) if (name.StringEqual(member->name)) break; return member; } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } #if RAPIDJSON_HAS_STDSTRING //! Find member by string object name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). */ MemberIterator FindMember(const std::basic_string& name) { return FindMember(StringRef(name)); } ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(StringRef(name)); } #endif //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c name and \c value will be transferred to this object on success. \pre IsObject() && name.IsString() \post name.IsNull() && value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); Object& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; o.members = reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))); } else { SizeType oldCapacity = o.capacity; o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 o.members = reinterpret_cast(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); } } o.members[o.size].name.RawAssign(name); o.members[o.size].value.RawAssign(value); o.size++; return *this; } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Add a string object as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } #endif //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A string value as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(GenericValue& name, T value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Add a member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c value will be transferred to this object on success. \pre IsObject() \post value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A constant string reference as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Remove all members in the object. /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. \note Linear time complexity. */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); data_.o.size = 0; } //! Remove a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Linear time complexity. */ bool RemoveMember(const Ch* name) { GenericValue n(StringRef(name)); return RemoveMember(n); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif template bool RemoveMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { RemoveMember(m); return true; } else return false; } //! Remove a member in object by iterator. /*! \param m member iterator (obtained by FindMember() or MemberBegin()). \return the new iterator after removal. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Constant time complexity. */ MemberIterator RemoveMember(MemberIterator m) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(data_.o.members != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); MemberIterator last(data_.o.members + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) { // Move the last one to this place *m = *last; } else { // Only one left, just destroy m->~Member(); } --data_.o.size; return m; } //! Remove a member from an object by iterator. /*! \param pos iterator to the member to remove \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() \return Iterator following the removed element. If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. \note This function preserves the relative order of the remaining object members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator pos) { return EraseMember(pos, pos +1); } //! Remove members in the range [first, last) from an object. /*! \param first iterator to the first member to remove \param last iterator following the last member to remove \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() \return Iterator following the last removed element. \note This function preserves the relative order of the remaining object members. \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(data_.o.members != 0); RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); data_.o.size -= (last - first); return pos; } //! Erase a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note Linear time complexity. */ bool EraseMember(const Ch* name) { GenericValue n(StringRef(name)); return EraseMember(n); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } #endif template bool EraseMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { EraseMember(m); return true; } else return false; } //@} //!@name Array //@{ //! Set this value as an empty array. /*! \post IsArray == true */ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } //! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. \note Linear time complexity. */ void Clear() { RAPIDJSON_ASSERT(IsArray()); for (SizeType i = 0; i < data_.a.size; ++i) data_.a.elements[i].~GenericValue(); data_.a.size = 0; } //! Get an element from array by index. /*! \pre IsArray() == true \param index Zero-based index of element. \see operator[](T*) */ GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); return data_.a.elements[index]; } const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } //! Element iterator /*! \pre IsArray() == true */ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast(*this).Begin(); } //! Constant \em past-the-end element iterator /*! \pre IsArray() == true */ ConstValueIterator End() const { return const_cast(*this).End(); } //! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note Linear time complexity. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); data_.a.capacity = newCapacity; } return *this; } //! Append a GenericValue at the end of the array. /*! \param value Value to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \post value.IsNull() == true \return The value itself for fluent API. \note The ownership of \c value will be transferred to this array on success. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); data_.a.elements[data_.a.size++].RawAssign(value); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { return PushBack(value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Append a constant string reference at the end of the array. /*! \param value Constant string reference to be appended. \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. \see GenericStringRef */ GenericValue& PushBack(StringRefType value, Allocator& allocator) { return (*this).template PushBack(value, allocator); } //! Append a primitive value at the end of the array. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value Value of primitive type T to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref PushBack(GenericValue&, Allocator&) or \ref PushBack(StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); } //! Remove the last element in the array. /*! \note Constant time complexity. */ GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); data_.a.elements[--data_.a.size].~GenericValue(); return *this; } //! Remove an element of array by iterator. /*! \param pos iterator to the element to remove \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1); } //! Remove elements in the range [first, last) of the array. /*! \param first iterator to the first element to remove \param last iterator following the last element to remove \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() \return Iterator following the last removed element. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(data_.a.size > 0); RAPIDJSON_ASSERT(data_.a.elements != 0); RAPIDJSON_ASSERT(first >= Begin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); data_.a.size -= (last - first); return pos; } //@} //!@name Number //@{ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } //@} //!@name String //@{ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string pointer. \param length The length of source string, excluding the trailing null terminator. \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == length \see SetString(StringRefType) */ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } //! Set this value as a string without copying source string. /*! \param s source string reference \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == s.length */ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } //! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string. \param length The length of source string, excluding the trailing null terminator. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } #endif //@} //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. It can also be used to deep clone this value via GenericDocument, which is also a Handler. \tparam Handler type of handler. \param handler An object implementing concept Handler. */ template bool Accept(Handler& handler) const { switch(GetType()) { case kNullType: return handler.Null(); case kFalseType: return handler.Bool(false); case kTrueType: return handler.Bool(true); case kObjectType: if (!handler.StartObject()) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) return false; if (!m->value.Accept(handler)) return false; } return handler.EndObject(data_.o.size); case kArrayType: if (!handler.StartArray()) return false; for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) if (!v->Accept(handler)) return false; return handler.EndArray(data_.a.size); case kStringType: return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); default: RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); else if (IsUint64()) return handler.Uint64(data_.n.u64); else return handler.Double(data_.n.d); } } private: template friend class GenericValue; template friend class GenericDocument; enum { kBoolFlag = 0x100, kNumberFlag = 0x200, kIntFlag = 0x400, kUintFlag = 0x800, kInt64Flag = 0x1000, kUint64Flag = 0x2000, kDoubleFlag = 0x4000, kStringFlag = 0x100000, kCopyFlag = 0x200000, kInlineStrFlag = 0x400000, // Initial flags of different types. kNullFlag = kNullType, kTrueFlag = kTrueType | kBoolFlag, kFalseFlag = kFalseType | kBoolFlag, kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, kConstStringFlag = kStringType | kStringFlag, kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler }; static const SizeType kDefaultArrayCapacity = 16; static const SizeType kDefaultObjectCapacity = 16; struct String { const Ch* str; SizeType length; unsigned hashcode; //!< reserved }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars // (excluding the terminating zero) and store a value to determine the length of the contained // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode // inline (for `UTF8`-encoded strings). struct ShortString { enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; inline static bool Usable(SizeType len) { return (MaxSize >= len); } inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; }i; struct U { unsigned u; char padding2[4]; }u; #else struct I { char padding[4]; int i; }i; struct U { char padding2[4]; unsigned u; }u; #endif int64_t i64; uint64_t u64; double d; }; // 8 bytes struct Object { Member* members; SizeType size; SizeType capacity; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode struct Array { GenericValue* elements; SizeType size; SizeType capacity; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; ShortString ss; Number n; Object o; Array a; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { flags_ = kArrayFlag; if (count) { data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); } else data_.a.elements = NULL; data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { flags_ = kObjectFlag; if (count) { data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); std::memcpy(data_.o.members, members, count * sizeof(Member)); } else data_.o.members = NULL; data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { flags_ = kConstStringFlag; data_.s.str = s; data_.s.length = s.length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(StringRefType s, Allocator& allocator) { Ch* str = NULL; if(ShortString::Usable(s.length)) { flags_ = kShortStringFlag; data_.ss.SetLength(s.length); str = data_.ss.str; } else { flags_ = kCopyStringFlag; data_.s.length = s.length; str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); data_.s.str = str; } std::memcpy(str, s, s.length * sizeof(Ch)); str[s.length] = '\0'; } //! Assignment without calling destructor void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; flags_ = rhs.flags_; rhs.flags_ = kNullFlag; } template bool StringEqual(const GenericValue& rhs) const { RAPIDJSON_ASSERT(IsString()); RAPIDJSON_ASSERT(rhs.IsString()); const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); if(len1 != len2) { return false; } const Ch* const str1 = GetString(); const Ch* const str2 = rhs.GetString(); if(str1 == str2) { return true; } // fast path for constant string return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); } Data data_; unsigned flags_; }; //! GenericValue with UTF8 encoding typedef GenericValue > Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument //! A document for parsing JSON text as DOM. /*! \note implements Handler concept \tparam Encoding Encoding for both parsing and string storage. \tparam Allocator Allocator for allocating memory for the DOM \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ template , typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. \param type Mandatory type of object to create. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); } //! Constructor /*! Creates an empty document which type is Null. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT : ValueType(std::move(rhs)), allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(std::move(rhs.stack_)), parseResult_(rhs.parseResult_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); } #endif ~GenericDocument() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT { // The cast to ValueType is necessary here, because otherwise it would // attempt to call GenericValue's templated assignment operator. ValueType::operator=(std::forward(rhs)); // Calling the destructor here would prematurely call stack_'s destructor Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = std::move(rhs.stack_); parseResult_ = rhs.parseResult_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); return *this; } #endif //!@name Parse from stream //!@{ //! Parse JSON text from an input stream (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam SourceEncoding Encoding of input stream \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { ValueType::SetNull(); // Remove existing root if exist GenericReader reader(&stack_.GetAllocator()); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. } return *this; } //! Parse JSON text from an input stream /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //!@} //!@name Parse in-place from mutable string //!@{ //! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseInsitu(Ch* str) { GenericInsituStringStream s(str); return ParseStream(s); } //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) /*! \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ GenericDocument& ParseInsitu(Ch* str) { return ParseInsitu(str); } //!@} //!@name Parse from read-only string //!@{ //! Parse JSON text from a read-only string (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \tparam SourceEncoding Transcoding from input Encoding \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); } //! Parse JSON text from a read-only string /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const Ch* str) { return Parse(str); } //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) /*! \param str Read-only zero-terminated string to be parsed. */ GenericDocument& Parse(const Ch* str) { return Parse(str); } //!@} //!@name Handling parse errors //!@{ //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseError() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } //!@} //! Get the allocator of this document. Allocator& GetAllocator() { return *allocator_; } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} ~ClearStackOnExit() { d_.ClearStack(); } private: ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); GenericDocument& d_; }; // callers of the following private Handler functions template friend class GenericReader; // for parsing template friend class GenericValue; // for deep copying // Implementation of Handler bool Null() { new (stack_.template Push()) ValueType(); return true; } bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); return true; } bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); return true; } bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } bool EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop(elementCount); stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); return true; } private: //! Prohibit copying GenericDocument(const GenericDocument&); //! Prohibit assignment GenericDocument& operator=(const GenericDocument&); void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) (stack_.template Pop(1))->~ValueType(); else stack_.Clear(); stack_.ShrinkToFit(); } void Destroy() { RAPIDJSON_DELETE(ownAllocator_); } static const size_t kDefaultStackCapacity = 1024; Allocator* allocator_; Allocator* ownAllocator_; internal::Stack stack_; ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; // defined here due to the dependency on GenericDocument template template inline GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) { switch (rhs.GetType()) { case kObjectType: case kArrayType: { // perform deep copy via SAX Handler GenericDocument d(&allocator); rhs.Accept(d); RawAssign(*d.stack_.template Pop(1)); } break; case kStringType: if (rhs.flags_ == kConstStringFlag) { flags_ = rhs.flags_; data_ = *reinterpret_cast(&rhs.data_); } else { SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); } break; default: // kNumberType, kTrueType, kFalseType, kNullType flags_ = rhs.flags_; data_ = *reinterpret_cast(&rhs.data_); } } RAPIDJSON_NAMESPACE_END #if defined(_MSC_VER) || defined(__GNUC__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_DOCUMENT_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/encodedstream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ #include "rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam InputByteStream Type of input byte stream. For example, FileReadStream. */ template class EncodedInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedInputStream(InputByteStream& is) : is_(is) { current_ = Encoding::TakeBOM(is_); } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); InputByteStream& is_; Ch current_; }; //! Output byte stream wrapper with statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. */ template class EncodedOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { if (putBOM) Encoding::PutBOM(os_); } void Put(Ch c) { Encoding::Put(os_, c); } void Flush() { os_.Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); } Ch Take() { RAPIDJSON_ASSERT(false); } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedOutputStream(const EncodedOutputStream&); EncodedOutputStream& operator=(const EncodedOutputStream&); OutputByteStream& os_; }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x //! Input stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for reading. \tparam InputByteStream type of input byte stream to be wrapped. */ template class AutoUTFInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param is input stream to be wrapped. \param type UTF encoding type if it is not detected from the stream. */ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; current_ = takeFunc_(*is_); } UTFType GetType() const { return type_; } bool HasBOM() const { return hasBOM_; } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } size_t Tell() const { return is_->Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFInputStream(const AutoUTFInputStream&); AutoUTFInputStream& operator=(const AutoUTFInputStream&); // Detect encoding type with BOM or RFC 4627 void DetectType() { // BOM (Byte Order Mark): // 00 00 FE FF UTF-32BE // FF FE 00 00 UTF-32LE // FE FF UTF-16BE // FF FE UTF-16LE // EF BB BF UTF-8 const unsigned char* c = (const unsigned char *)is_->Peek4(); if (!c) return; unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); hasBOM_ = false; if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } // RFC 4627: Section 3 // "Since the first two characters of a JSON text will always be ASCII // characters [RFC0020], it is possible to determine whether an octet // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking // at the pattern of nulls in the first four octets." // 00 00 00 xx UTF-32BE // 00 xx 00 xx UTF-16BE // xx 00 00 00 UTF-32LE // xx 00 xx 00 UTF-16LE // xx xx xx xx UTF-8 if (!hasBOM_) { unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; case 0x01: type_ = kUTF32LE; break; case 0x05: type_ = kUTF16LE; break; case 0x0F: type_ = kUTF8; break; default: break; // Use type defined by user. } } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); } typedef Ch (*TakeFunc)(InputByteStream& is); InputByteStream* is_; UTFType type_; Ch current_; TakeFunc takeFunc_; bool hasBOM_; }; //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. \tparam InputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param os output stream to be wrapped. \param type UTF encoding type. \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; if (putBOM) PutBOM(); } UTFType GetType() const { return type_; } void Put(Ch c) { putFunc_(*os_, c); } void Flush() { os_->Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); } Ch Take() { RAPIDJSON_ASSERT(false); } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFOutputStream(const AutoUTFOutputStream&); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); void PutBOM() { typedef void (*PutBOMFunc)(OutputByteStream&); static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; f[type_](*os_); } typedef void (*PutFunc)(OutputByteStream&, Ch); OutputByteStream* os_; UTFType type_; PutFunc putFunc_; }; #undef RAPIDJSON_ENCODINGS_FUNC RAPIDJSON_NAMESPACE_END #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/encodings.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_ #include "rapidjson.h" #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code #elif defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(overflow) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Encoding /*! \class rapidjson::Encoding \brief Concept for encoding of Unicode characters. \code concept Encoding { typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. enum { supportUnicode = 1 }; // or 0 if not supporting unicode //! \brief Encode a Unicode codepoint to an output stream. //! \param os Output stream. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. template static void Encode(OutputStream& os, unsigned codepoint); //! \brief Decode a Unicode codepoint from an input stream. //! \param is Input stream. //! \param codepoint Output of the unicode codepoint. //! \return true if a valid codepoint can be decoded from the stream. template static bool Decode(InputStream& is, unsigned* codepoint); //! \brief Validate one Unicode codepoint from an encoded stream. //! \param is Input stream to obtain codepoint. //! \param os Output for copying one codepoint. //! \return true if it is valid. //! \note This function just validating and copying the codepoint without actually decode it. template static bool Validate(InputStream& is, OutputStream& os); // The following functions are deal with byte streams. //! Take a character from input byte stream, skip BOM if exist. template static CharType TakeBOM(InputByteStream& is); //! Take a character from input byte stream. template static Ch Take(InputByteStream& is); //! Put BOM to output byte stream. template static void PutBOM(OutputByteStream& os); //! Put a character to output byte stream. template static void Put(OutputByteStream& os, Ch c); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // UTF8 //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 http://tools.ietf.org/html/rfc3629 \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. \note implements Encoding concept */ template struct UTF8 { typedef CharType Ch; enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) os.Put(static_cast(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } } template static bool Decode(InputStream& is, unsigned* codepoint) { #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = (unsigned char)c; return true; } unsigned char type = GetRange((unsigned char)c); *codepoint = (0xFF >> type) & (unsigned char)c; bool result = true; switch (type) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } template static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c; COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange((unsigned char)c)) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } static unsigned char GetRange(unsigned char c) { // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. static const unsigned char type[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, }; return type[c]; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); Ch c = Take(is); if ((unsigned char)c != 0xEFu) return c; c = is.Take(); if ((unsigned char)c != 0xBBu) return c; c = is.Take(); if ((unsigned char)c != 0xBFu) return c; c = is.Take(); return c; } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return is.Take(); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF16 //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 http://tools.ietf.org/html/rfc2781 \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness. */ template struct UTF16 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair os.Put(static_cast(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); os.Put((v & 0x3FF) | 0xDC00); } } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { *codepoint = c; return true; } else if (c <= 0xDBFF) { *codepoint = (c & 0x3FF) << 10; c = is.Take(); *codepoint |= (c & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } return false; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); Ch c; os.Put(c = is.Take()); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { os.Put(c = is.Take()); return c >= 0xDC00 && c <= 0xDFFF; } return false; } }; //! UTF-16 little endian encoding. template struct UTF16LE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return (unsigned short)c == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = (unsigned char)is.Take(); c |= (unsigned char)is.Take() << 8; return c; } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(0xFFu); os.Put(0xFEu); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(c & 0xFFu); os.Put((c >> 8) & 0xFFu); } }; //! UTF-16 big endian encoding. template struct UTF16BE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return (unsigned short)c == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take(); return c; } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(0xFEu); os.Put(0xFFu); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put((c >> 8) & 0xFFu); os.Put(c & 0xFFu); } }; /////////////////////////////////////////////////////////////////////////////// // UTF32 //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness. */ template struct UTF32 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(codepoint); } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c = is.Take(); *codepoint = c; return c <= 0x10FFFF; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c; os.Put(c = is.Take()); return c <= 0x10FFFF; } }; //! UTF-32 little endian enocoding. template struct UTF32LE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return (unsigned)c == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = (unsigned char)is.Take(); c |= (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take() << 16; c |= (unsigned char)is.Take() << 24; return c; } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(c & 0xFFu); os.Put((c >> 8) & 0xFFu); os.Put((c >> 16) & 0xFFu); os.Put((c >> 24) & 0xFFu); } }; //! UTF-32 big endian encoding. template struct UTF32BE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return (unsigned)c == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = (unsigned char)is.Take() << 24; c |= (unsigned char)is.Take() << 16; c |= (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take(); return c; } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put((c >> 24) & 0xFFu); os.Put((c >> 16) & 0xFFu); os.Put((c >> 8) & 0xFFu); os.Put(c & 0xFFu); } }; /////////////////////////////////////////////////////////////////////////////// // ASCII //! ASCII encoding. /*! http://en.wikipedia.org/wiki/ASCII \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. \note implements Encoding concept */ template struct ASCII { typedef CharType Ch; enum { supportUnicode = 0 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); os.Put(static_cast(codepoint & 0xFF)); } template static bool Decode(InputStream& is, unsigned* codepoint) { unsigned char c = static_cast(is.Take()); *codepoint = c; return c <= 0X7F; } template static bool Validate(InputStream& is, OutputStream& os) { unsigned char c = is.Take(); os.Put(c); return c <= 0x7F; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); Ch c = Take(is); return c; } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return is.Take(); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); (void)os; } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // AutoUTF //! Runtime-specified UTF encoding type of a stream. enum UTFType { kUTF8 = 0, //!< UTF-8. kUTF16LE = 1, //!< UTF-16 little endian. kUTF16BE = 2, //!< UTF-16 big endian. kUTF32LE = 3, //!< UTF-32 little endian. kUTF32BE = 4 //!< UTF-32 big endian. }; //! Dynamically select encoding according to stream's runtime-specified UTF encoding type. /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). */ template struct AutoUTF { typedef CharType Ch; enum { supportUnicode = 1 }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); } #undef RAPIDJSON_ENCODINGS_FUNC }; /////////////////////////////////////////////////////////////////////////////// // Transcoder //! Encoding conversion. template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::Encode(os, codepoint); return true; } //! Validate one Unicode codepoint from an encoded stream. template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { template RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) || defined(_MSV_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ENCODINGS_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/error/en.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ERROR_EN_H__ #define RAPIDJSON_ERROR_EN_H__ #include "error.h" RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. /*! \ingroup RAPIDJSON_ERRORS \param parseErrorCode Error code obtained in parsing. \return the error message. \note User can make a copy of this function for localization. Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { switch (parseErrorCode) { case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ERROR_EN_H__ ================================================ FILE: UAlbertaBot/Source/rapidjson/error/error.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H__ #include "../rapidjson.h" /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_CHARTYPE //! Character type of error messages. /*! \ingroup RAPIDJSON_ERRORS The default character type is \c char. On Windows, user can define this macro as \c TCHAR for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_CHARTYPE #define RAPIDJSON_ERROR_CHARTYPE char #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_STRING #define RAPIDJSON_ERROR_STRING(x) x #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseErrorCode //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { kParseErrorNone = 0, //!< No error. kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorValueInvalid, //!< Invalid value. kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorTermination, //!< Parsing was terminated. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. }; //! Result of parsing (wraps ParseErrorCode) /*! \ingroup RAPIDJSON_ERRORS \code Document doc; ParseResult ok = doc.Parse("[42]"); if (!ok) { fprintf(stderr, "JSON parse error: %s (%u)", GetParseError_En(ok.Code()), ok.Offset()); exit(EXIT_FAILURE); } \endcode \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } //! Conversion to \c bool, returns \c true, iff !\ref IsError(). operator bool() const { return !IsError(); } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: ParseErrorCode code_; size_t offset_; }; //! Function pointer type of GetParseError(). /*! \ingroup RAPIDJSON_ERRORS This is the prototype for \c GetParseError_X(), where \c X is a locale. User can dynamically change locale in runtime, e.g.: \code GetParseErrorFunc GetParseError = GetParseError_En; // or whatever const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ERROR_ERROR_H__ ================================================ FILE: UAlbertaBot/Source/rapidjson/filereadstream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ #include "rapidjson.h" #include RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). /*! \note implements Stream concept */ class FileReadStream { public: typedef char Ch; //!< Character type (byte). //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } Ch Peek() const { return *current_; } Ch Take() { Ch c = *current_; Read(); return c; } size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return (current_ + 4 <= bufferLast_) ? current_ : 0; } private: void Read() { if (current_ < bufferLast_) ++current_; else if (!eof_) { count_ += readCount_; readCount_ = fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; if (readCount_ < bufferSize_) { buffer_[readCount_] = '\0'; ++bufferLast_; eof_ = true; } } } std::FILE* fp_; Ch *buffer_; size_t bufferSize_; Ch *bufferLast_; Ch *current_; size_t readCount_; size_t count_; //!< Number of characters read bool eof_; }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/filewritestream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ #include "rapidjson.h" #include RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for input using fread(). /*! \note implements Stream concept */ class FileWriteStream { public: typedef char Ch; //!< Character type. Only support char. FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { RAPIDJSON_ASSERT(fp_ != 0); } void Put(char c) { if (current_ >= bufferEnd_) Flush(); *current_++ = c; } void PutN(char c, size_t n) { size_t avail = static_cast(bufferEnd_ - current_); while (n > avail) { std::memset(current_, c, avail); current_ += avail; Flush(); n -= avail; avail = static_cast(bufferEnd_ - current_); } if (n > 0) { std::memset(current_, c, n); current_ += n; } } void Flush() { if (current_ != buffer_) { fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); current_ = buffer_; } } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: // Prohibit copy constructor & assignment operator. FileWriteStream(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&); std::FILE* fp_; char *buffer_; char *bufferEnd_; char *current_; }; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(FileWriteStream& stream, char c, size_t n) { stream.PutN(c, n); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/biginteger.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_BIGINTEGER_H_ #define RAPIDJSON_BIGINTEGER_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) #include // for _umul128 #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { class BigInteger { public: typedef uint64_t Type; BigInteger(const BigInteger& rhs) : count_(rhs.count_) { std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; } BigInteger(const char* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 while (length >= kMaxDigitPerIteration) { AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); length -= kMaxDigitPerIteration; i += kMaxDigitPerIteration; } if (length > 0) AppendDecimal64(decimals + i, decimals + i + length); } BigInteger& operator=(uint64_t u) { digits_[0] = u; count_ = 1; return *this; } BigInteger& operator+=(uint64_t u) { Type backup = digits_[0]; digits_[0] += u; for (size_t i = 0; i < count_ - 1; i++) { if (digits_[i] >= backup) return *this; // no carry backup = digits_[i + 1]; digits_[i + 1] += 1; } // Last carry if (digits_[count_ - 1] < backup) PushBack(1); return *this; } BigInteger& operator*=(uint64_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { uint64_t hi; digits_[i] = MulAdd64(digits_[i], u, k, &hi); k = hi; } if (k > 0) PushBack(k); return *this; } BigInteger& operator*=(uint32_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { const uint64_t c = digits_[i] >> 32; const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t uc = u * c; const uint64_t ud = u * d; const uint64_t p0 = ud + k; const uint64_t p1 = uc + (p0 >> 32); digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); k = p1 >> 32; } if (k > 0) PushBack(k); return *this; } BigInteger& operator<<=(size_t shift) { if (IsZero() || shift == 0) return *this; size_t offset = shift / kTypeBit; size_t interShift = shift % kTypeBit; RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); count_ += offset; } else { digits_[count_] = 0; for (size_t i = count_; i > 0; i--) digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); digits_[offset] = digits_[0] << interShift; count_ += offset; if (digits_[count_]) count_++; } std::memset(digits_, 0, offset * sizeof(Type)); return *this; } bool operator==(const BigInteger& rhs) const { return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; } bool operator==(const Type rhs) const { return count_ == 1 && digits_[0] == rhs; } BigInteger& MultiplyPow5(unsigned exp) { static const uint32_t kPow5[12] = { 5, 5 * 5, 5 * 5 * 5, 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 }; if (exp == 0) return *this; for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 if (exp > 0) *this *= kPow5[exp - 1]; return *this; } // Compute absolute difference of this and rhs. // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } else { a = this; b = &rhs; ret = false; } Type borrow = 0; for (size_t i = 0; i < a->count_; i++) { Type d = a->digits_[i] - borrow; if (i < b->count_) d -= b->digits_[i]; borrow = (d > a->digits_[i]) ? 1 : 0; out->digits_[i] = d; if (d != 0) out->count_ = i + 1; } return ret; } int Compare(const BigInteger& rhs) const { if (count_ != rhs.count_) return count_ < rhs.count_ ? -1 : 1; for (size_t i = count_; i-- > 0;) if (digits_[i] != rhs.digits_[i]) return digits_[i] < rhs.digits_[i] ? -1 : 1; return 0; } size_t GetCount() const { return count_; } Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: void AppendDecimal64(const char* begin, const char* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; else { unsigned exp = static_cast(end - begin); (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u } } void PushBack(Type digit) { RAPIDJSON_ASSERT(count_ < kCapacity); digits_[count_++] = digit; } static uint64_t ParseUint64(const char* begin, const char* end) { uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); r = r * 10 + (*p - '0'); } return r; } // Assume a * b + k < 2^128 static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t low = _umul128(a, b, outHigh) + k; if (low < k) (*outHigh)++; return low; #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(a) * static_cast(b); p += k; *outHigh = static_cast(p >> 64); return static_cast(p); #else const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; x1 += (x0 >> 32); // can't give carry x1 += x2; if (x1 < x2) x3 += (static_cast(1) << 32); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t hi = x3 + (x1 >> 32); lo += k; if (lo < k) hi++; *outHigh = hi; return lo; #endif } static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kTypeBit = sizeof(Type) * 8; Type digits_[kCapacity]; size_t count_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_BIGINTEGER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/diyfp.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) #include #pragma intrinsic(_BitScanReverse64) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif struct DiyFp { DiyFp() {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} explicit DiyFp(double d) { union { double d; uint64_t u64; } u = { d }; int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); uint64_t significand = (u.u64 & kDpSignificandMask); if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; } else { f = significand; e = kDpMinExponent + 1; } } DiyFp operator-(const DiyFp& rhs) const { return DiyFp(f - rhs.f, e); } DiyFp operator*(const DiyFp& rhs) const { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t h; uint64_t l = _umul128(f, rhs.f, &h); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(f) * static_cast(rhs.f); uint64_t h = static_cast(p >> 64); uint64_t l = static_cast(p); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #else const uint64_t M32 = 0xFFFFFFFF; const uint64_t a = f >> 32; const uint64_t b = f & M32; const uint64_t c = rhs.f >> 32; const uint64_t d = rhs.f & M32; const uint64_t ac = a * c; const uint64_t bc = b * c; const uint64_t ad = a * d; const uint64_t bd = b * d; uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); tmp += 1U << 31; /// mult_round return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); #endif } DiyFp Normalize() const { #if defined(_MSC_VER) && defined(_M_AMD64) unsigned long index; _BitScanReverse64(&index, f); return DiyFp(f << (63 - index), e - (63 - index)); #elif defined(__GNUC__) && __GNUC__ >= 4 int s = __builtin_clzll(f); return DiyFp(f << s, e - s); #else DiyFp res = *this; while (!(res.f & (static_cast(1) << 63))) { res.f <<= 1; res.e--; } return res; #endif } DiyFp NormalizeBoundary() const { DiyFp res = *this; while (!(res.f & (kDpHiddenBit << 1))) { res.f <<= 1; res.e--; } res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); return res; } void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); mi.f <<= mi.e - pl.e; mi.e = pl.e; *plus = pl; *minus = mi; } double ToDouble() const { union { double d; uint64_t u64; }u; const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; } static const int kDiySignificandSize = 64; static const int kDpSignificandSize = 52; static const int kDpExponentBias = 0x3FF + kDpSignificandSize; static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias; static const int kDpDenormalExponent = -kDpExponentBias + 1; static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); uint64_t f; int e; }; inline DiyFp GetCachedPowerByIndex(size_t index) { // 10^-348, 10^-340, ..., 10^340 static const uint64_t kCachedPowers_F[] = { RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) }; static const int16_t kCachedPowers_E[] = { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast(dk); if (dk - k > 0.0) k++; unsigned index = static_cast((k >> 3) + 1); *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table return GetCachedPowerByIndex(index); } inline DiyFp GetCachedPower10(int exp, int *outExp) { unsigned index = (exp + 348) / 8; *outExp = -348 + index * 8; return GetCachedPowerByIndex(index); } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIYFP_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/dtoa.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" #include "ieee754.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer wp_w - rest > rest + ten_kappa - wp_w)) { buffer[len - 1]--; rest += ten_kappa; } } inline unsigned CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; if (n < 1000) return 3; if (n < 10000) return 4; if (n < 100000) return 5; if (n < 1000000) return 6; if (n < 10000000) return 7; if (n < 100000000) return 8; // Will not reach 10 digits in DigitGen() //if (n < 1000000000) return 9; //return 10; return 9; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { uint32_t d = 0; switch (kappa) { case 9: d = p1 / 100000000; p1 %= 100000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break; case 6: d = p1 / 100000; p1 %= 100000; break; case 5: d = p1 / 10000; p1 %= 10000; break; case 4: d = p1 / 1000; p1 %= 1000; break; case 3: d = p1 / 100; p1 %= 100; break; case 2: d = p1 / 10; p1 %= 10; break; case 1: d = p1; p1 = 0; break; default:; } if (d || *len) buffer[(*len)++] = static_cast('0' + static_cast(d)); kappa--; uint64_t tmp = (static_cast(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); return; } } // kappa = 0 for (;;) { p2 *= 10; delta *= 10; char d = static_cast(p2 >> -one.e); if (d || *len) buffer[(*len)++] = static_cast('0' + d); p2 &= one.f - 1; kappa--; if (p2 < delta) { *K += kappa; GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); return; } } } inline void Grisu2(double value, char* buffer, int* length, int* K) { const DiyFp v(value); DiyFp w_m, w_p; v.NormalizedBoundaries(&w_m, &w_p); const DiyFp c_mk = GetCachedPower(w_p.e, K); const DiyFp W = v.Normalize() * c_mk; DiyFp Wp = w_p * c_mk; DiyFp Wm = w_m * c_mk; Wm.f++; Wp.f--; DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); } inline char* WriteExponent(int K, char* buffer) { if (K < 0) { *buffer++ = '-'; K = -K; } if (K >= 100) { *buffer++ = static_cast('0' + static_cast(K / 100)); K %= 100; const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else if (K >= 10) { const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else *buffer++ = static_cast('0' + static_cast(K)); return buffer; } inline char* Prettify(char* buffer, int length, int k) { const int kk = length + k; // 10^(kk-1) <= v < 10^kk if (length <= kk && kk <= 21) { // 1234e7 -> 12340000000 for (int i = length; i < kk; i++) buffer[i] = '0'; buffer[kk] = '.'; buffer[kk + 1] = '0'; return &buffer[kk + 2]; } else if (0 < kk && kk <= 21) { // 1234e-2 -> 12.34 std::memmove(&buffer[kk + 1], &buffer[kk], length - kk); buffer[kk] = '.'; return &buffer[length + 1]; } else if (-6 < kk && kk <= 0) { // 1234e-6 -> 0.001234 const int offset = 2 - kk; std::memmove(&buffer[offset], &buffer[0], length); buffer[0] = '0'; buffer[1] = '.'; for (int i = 2; i < offset; i++) buffer[i] = '0'; return &buffer[length + offset]; } else if (length == 1) { // 1e30 buffer[1] = 'e'; return WriteExponent(kk - 1, &buffer[2]); } else { // 1234e30 -> 1.234e33 std::memmove(&buffer[2], &buffer[1], length - 1); buffer[1] = '.'; buffer[length + 1] = 'e'; return WriteExponent(kk - 1, &buffer[0 + length + 2]); } } inline char* dtoa(double value, char* buffer) { Double d(value); if (d.IsZero()) { if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else { if (value < 0) { *buffer++ = '-'; value = -value; } int length, K; Grisu2(value, buffer, &length, &K); return Prettify(buffer, length, K); } } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DTOA_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/ieee754.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_IEEE754_ #define RAPIDJSON_IEEE754_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { class Double { public: Double() {} Double(double d) : d_(d) {} Double(uint64_t u) : u_(u) {} double Value() const { return d_; } uint64_t Uint64Value() const { return u_; } double NextPositiveDouble() const { RAPIDJSON_ASSERT(!Sign()); return Double(u_ + 1).Value(); } bool Sign() const { return (u_ & kSignMask) != 0; } uint64_t Significand() const { return u_ & kSignificandMask; } int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } static unsigned EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else return order + 1074; } private: static const int kSignificandSize = 52; static const int kExponentBias = 0x3FF; static const int kDenormalExponent = 1 - kExponentBias; static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); union { double d_; uint64_t u_; }; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_IEEE754_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/itoa.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline const char* GetDigitsLut() { static const char cDigitsLut[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; return cDigitsLut; } inline char* u32toa(uint32_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else if (value < 100000000) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } else { // value = aabbbbcccc in decimal const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else *buffer++ = static_cast('0' + static_cast(a)); const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } return buffer; } inline char* i32toa(int32_t value, char* buffer) { uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u32toa(u, buffer); } inline char* u64toa(uint64_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen10 = kTen8 * 100; const uint64_t kTen11 = kTen8 * 1000; const uint64_t kTen12 = kTen8 * 10000; const uint64_t kTen13 = kTen8 * 100000; const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; if (value < kTen8) { uint32_t v = static_cast(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (v >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } } else if (value < kTen16) { const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; if (value >= kTen15) *buffer++ = cDigitsLut[d1]; if (value >= kTen14) *buffer++ = cDigitsLut[d1 + 1]; if (value >= kTen13) *buffer++ = cDigitsLut[d2]; if (value >= kTen12) *buffer++ = cDigitsLut[d2 + 1]; if (value >= kTen11) *buffer++ = cDigitsLut[d3]; if (value >= kTen10) *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; if (value >= kTen8) *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } else { const uint32_t a = static_cast(value / kTen16); // 1 to 1844 value %= kTen16; if (a < 10) *buffer++ = static_cast('0' + static_cast(a)); else if (a < 100) { const uint32_t i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else if (a < 1000) { *buffer++ = static_cast('0' + static_cast(a / 100)); const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else { const uint32_t i = (a / 100) << 1; const uint32_t j = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } return buffer; } inline char* i64toa(int64_t value, char* buffer) { uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u64toa(u, buffer); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ITOA_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/meta.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ #include "../rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif #if RAPIDJSON_HAS_CXX11_TYPETRAITS #include #endif //@cond RAPIDJSON_INTERNAL RAPIDJSON_NAMESPACE_BEGIN namespace internal { // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching template struct Void { typedef void Type; }; /////////////////////////////////////////////////////////////////////////////// // BoolType, TrueType, FalseType // template struct BoolType { static const bool Value = Cond; typedef BoolType Type; }; typedef BoolType TrueType; typedef BoolType FalseType; /////////////////////////////////////////////////////////////////////////////// // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; template struct SelectIfCond : SelectIfImpl::template Apply {}; template struct SelectIf : SelectIfCond {}; template struct AndExprCond : FalseType {}; template <> struct AndExprCond : TrueType {}; template struct OrExprCond : TrueType {}; template <> struct OrExprCond : FalseType {}; template struct BoolExpr : SelectIf::Type {}; template struct NotExpr : SelectIf::Type {}; template struct AndExpr : AndExprCond::Type {}; template struct OrExpr : OrExprCond::Type {}; /////////////////////////////////////////////////////////////////////////////// // AddConst, MaybeAddConst, RemoveConst template struct AddConst { typedef const T Type; }; template struct MaybeAddConst : SelectIfCond {}; template struct RemoveConst { typedef T Type; }; template struct RemoveConst { typedef T Type; }; /////////////////////////////////////////////////////////////////////////////// // IsSame, IsConst, IsMoreConst, IsPointer // template struct IsSame : FalseType {}; template struct IsSame : TrueType {}; template struct IsConst : FalseType {}; template struct IsConst : TrueType {}; template struct IsMoreConst : AndExpr::Type, typename RemoveConst::Type>, BoolType::Value >= IsConst::Value> >::Type {}; template struct IsPointer : FalseType {}; template struct IsPointer : TrueType {}; /////////////////////////////////////////////////////////////////////////////// // IsBaseOf // #if RAPIDJSON_HAS_CXX11_TYPETRAITS template struct IsBaseOf : BoolType< ::std::is_base_of::value> {}; #else // simplified version adopted from Boost template struct IsBaseOfImpl { RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); typedef char (&Yes)[1]; typedef char (&No) [2]; template static Yes Check(const D*, T); static No Check(const B*, int); struct Host { operator const B*() const; operator const D*(); }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; }; template struct IsBaseOf : OrExpr, BoolExpr > >::Type {}; #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS ////////////////////////////////////////////////////////////////////////// // EnableIf / DisableIf // template struct EnableIfCond { typedef T Type; }; template struct EnableIfCond { /* empty */ }; template struct DisableIfCond { typedef T Type; }; template struct DisableIfCond { /* empty */ }; template struct EnableIf : EnableIfCond {}; template struct DisableIf : DisableIfCond {}; // SFINAE helpers struct SfinaeTag {}; template struct RemoveSfinaeTag; template struct RemoveSfinaeTag { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type * = NULL #define RAPIDJSON_DISABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type * = NULL #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type } // namespace internal RAPIDJSON_NAMESPACE_END //@endcond #if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_META_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/pow10.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. \param n non-negative exponent. Must <= 308. \return 10.0^n */ inline double Pow10(int n) { static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }; RAPIDJSON_ASSERT(n >= 0 && n <= 308); return e[n]; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_POW10_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/stack.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // Stack //! A type-unsafe stack for storing different types of data. /*! \tparam Allocator Allocator for allocating stack memory. */ template class Stack { public: // Optimization note: Do not allocate memory for stack_ in constructor. // Do it lazily when first Push() -> Expand() -> Resize(). Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { RAPIDJSON_ASSERT(stackCapacity > 0); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack(Stack&& rhs) : allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(rhs.stack_), stackTop_(rhs.stackTop_), stackEnd_(rhs.stackEnd_), initialCapacity_(rhs.initialCapacity_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } #endif ~Stack() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack& operator=(Stack&& rhs) { if (&rhs != this) { Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = rhs.stack_; stackTop_ = rhs.stackTop_; stackEnd_ = rhs.stackEnd_; initialCapacity_ = rhs.initialCapacity_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } return *this; } #endif void Clear() { stackTop_ = stack_; } void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. Allocator::Free(stack_); stack_ = 0; stackTop_ = 0; stackEnd_ = 0; } else Resize(GetSize()); } // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { // Expand the stack if needed if (stackTop_ + sizeof(T) * count >= stackEnd_) Expand(count); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; } template T* Pop(size_t count) { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stackTop_ -= count * sizeof(T); return reinterpret_cast(stackTop_); } template T* Top() { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template T* Bottom() { return (T*)stack_; } Allocator& GetAllocator() { return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } private: template void Expand(size_t count) { // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. size_t newCapacity; if (stack_ == 0) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); newCapacity += (newCapacity + 1) / 2; } size_t newSize = GetSize() + sizeof(T) * count; if (newCapacity < newSize) newCapacity = newSize; Resize(newCapacity); } void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } void Destroy() { Allocator::Free(stack_); RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack } // Prohibit copy constructor & assignment operator. Stack(const Stack&); Stack& operator=(const Stack&); Allocator* allocator_; Allocator* ownAllocator_; char *stack_; char *stackTop_; char *stackEnd_; size_t initialCapacity_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STACK_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/strfunc.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom strlen() which works on different character types. /*! \tparam Ch Character type (e.g. char, wchar_t, short) \param s Null-terminated input string. \return Number of characters in the string. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template inline SizeType StrLen(const Ch* s) { const Ch* p = s; while (*p) ++p; return SizeType(p - s); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/internal/strtod.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_ #include "../rapidjson.h" #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" #include "pow10.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline double FastPath(double significand, int exp) { if (exp < -308) return 0.0; else if (exp >= 0) return significand * internal::Pow10(exp); else return significand / internal::Pow10(-exp); } inline double StrtodNormalPrecision(double d, int p) { if (p < -308) { // Prevent expSum < -308, making Pow10(p) = 0 d = FastPath(d, -308); d = FastPath(d, p + 308); } else d = FastPath(d, p); return d; } template inline T Min3(T a, T b, T c) { T m = a; if (m > b) m = b; if (m > c) m = c; return m; } inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { const Double db(b); const uint64_t bInt = db.IntegerSignificand(); const int bExp = db.IntegerExponent(); const int hExp = bExp - 1; int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; // Adjust for decimal exponent if (dExp >= 0) { dS_Exp2 += dExp; dS_Exp5 += dExp; } else { bS_Exp2 -= dExp; bS_Exp5 -= dExp; hS_Exp2 -= dExp; hS_Exp5 -= dExp; } // Adjust for binary exponent if (bExp >= 0) bS_Exp2 += bExp; else { dS_Exp2 -= bExp; hS_Exp2 -= bExp; } // Adjust for half ulp exponent if (hExp >= 0) hS_Exp2 += hExp; else { dS_Exp2 -= hExp; bS_Exp2 -= hExp; } // Remove common power of two factor from all three scaled values int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); dS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2; BigInteger dS = d; dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2; BigInteger bS(bInt); bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2; BigInteger hS(1); hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; BigInteger delta(0); dS.Difference(bS, &delta); return delta.Compare(hS); } inline bool StrtodFast(double d, int p, double* result) { // Use fast path for string-to-double conversion if possible // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ if (p > 22 && p < 22 + 16) { // Fast Path Cases In Disguise d *= internal::Pow10(p - 22); p = 22; } if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 *result = FastPath(d, p); return true; } else return false; } // Compute an approximation and see if it is within 1/2 ULP inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { uint64_t significand = 0; size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 for (; i < length; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; significand = significand * 10 + (decimals[i] - '0'); } if (i < length && decimals[i] >= '5') // Rounding significand++; size_t remaining = length - i; const unsigned kUlpShift = 3; const unsigned kUlp = 1 << kUlpShift; int error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); v = v.Normalize(); error <<= -v.e; const int dExp = (int)decimalPosition - (int)i + exp; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 }; int adjustment = dExp - actualExp - 1; RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); v = v * kPow10[adjustment]; if (length + adjustment > 19) // has more digits than decimal digits in 64-bit error += kUlp / 2; } v = v * cachedPower; error += kUlp + (error == 0 ? 0 : 1); const int oldExp = v.e; v = v.Normalize(); error <<= oldExp - v.e; const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); unsigned precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { unsigned scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; error = (error >> scaleExp) + 1 + kUlp; precisionSize -= scaleExp; } DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if (precisionBits >= halfWay + error) { rounded.f++; if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) rounded.f >>= 1; rounded.e++; } } *result = rounded.ToDouble(); return halfWay - error >= precisionBits || precisionBits >= halfWay + error; } inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { const BigInteger dInt(decimals, length); const int dExp = (int)decimalPosition - (int)length + exp; Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) return a.Value(); // within half ULP else if (cmp == 0) { // Round towards even if (a.Significand() & 1) return a.NextPositiveDouble(); else return a.Value(); } else // adjustment return a.NextPositiveDouble(); } inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); double result; if (StrtodFast(d, p, &result)) return result; // Trim leading zeros while (*decimals == '0' && length > 1) { length--; decimals++; decimalPosition--; } // Trim trailing zeros while (decimals[length - 1] == '0' && length > 1) { length--; decimalPosition--; exp++; } // Trim right-most digits const int kMaxDecimalDigit = 780; if ((int)length > kMaxDecimalDigit) { int delta = (int(length) - kMaxDecimalDigit); exp += delta; decimalPosition -= delta; length = kMaxDecimalDigit; } // If too small, underflow to zero if (int(length) + exp < -324) return 0.0; if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) return result; // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison return StrtodBigInteger(result, decimals, length, decimalPosition, exp); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STRTOD_ ================================================ FILE: UAlbertaBot/Source/rapidjson/memorybuffer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ #include "rapidjson.h" #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output byte stream. /*! This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. Differences between MemoryBuffer and StringBuffer: 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template struct GenericMemoryBuffer { typedef char Ch; // byte GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} void Put(Ch c) { *stack_.template Push() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { stack_.ShrinkToFit(); } Ch* Push(size_t count) { return stack_.template Push(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetBuffer() const { return stack_.template Bottom(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; }; typedef GenericMemoryBuffer<> MemoryBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_MEMORYBUFFER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/memorystream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. /*! This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. Differences between MemoryStream and StringStream: 1. StringStream has encoding but MemoryStream is a byte stream. 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). \note implements Stream concept */ struct MemoryStream { typedef char Ch; // byte MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } Ch Take() { return (src_ == end_) ? '\0' : *src_++; } size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return Tell() + 4 <= size_ ? src_ : 0; } const Ch* src_; //!< Current read position. const Ch* begin_; //!< Original head of the string. const Ch* end_; //!< End of stream. size_t size_; //!< Size of the stream. }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_MEMORYBUFFER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/msinttypes/inttypes.h ================================================ // ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // miloyip: VC supports inttypes.h since VC2013 #if _MSC_VER >= 1800 #include #else // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_VER >= 1800 #endif // _MSC_INTTYPES_H_ ] ================================================ FILE: UAlbertaBot/Source/rapidjson/msinttypes/stdint.h ================================================ // ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif // miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. #if _MSC_VER >= 1600 // [ #include #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 #undef INT8_C #undef INT16_C #undef INT32_C #undef INT64_C #undef UINT8_C #undef UINT16_C #undef UINT32_C #undef UINT64_C // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #else // ] _MSC_VER >= 1700 [ #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we should wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #ifdef __cplusplus extern "C" { #endif # include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_VER >= 1600 ] #endif // _MSC_STDINT_H_ ] ================================================ FILE: UAlbertaBot/Source/rapidjson/pointer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_POINTER_H_ #define RAPIDJSON_POINTER_H_ #include "document.h" #include "internal/itoa.h" RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode */ enum PointerParseErrorCode { kPointerParseErrorNone = 0, //!< The parse is successful kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' kPointerParseErrorInvalidEscape, //!< Invalid escape kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment }; /////////////////////////////////////////////////////////////////////////////// // GenericPointer //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. /*! This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" (https://tools.ietf.org/html/rfc6901). A JSON pointer is for identifying a specific value in a JSON document (GenericDocument). It can simplify coding of DOM tree manipulation, because it can access multiple-level depth of DOM tree with single API call. After it parses a string representation (e.g. "/foo/0" or URI fragment representation (e.g. "#/foo/0") into its internal representation (tokens), it can be used to resolve a specific value in multiple documents, or sub-tree of documents. Contrary to GenericValue, Pointer can be copy constructed and copy assigned. Apart from assignment, a Pointer cannot be modified after construction. Although Pointer is very convenient, please aware that constructing Pointer involves parsing and dynamic memory allocation. A special constructor with user- supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. \tparam ValueType The value type of the DOM tree. E.g. GenericValue > \tparam Allocator The allocator type for allocating memory for internal representation. \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ template class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename EncodingType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. They are resolved according to the actual value type (object or array). For token that are not numbers, or the numeric value is out of bound (greater than limits of SizeType), they are only treated as string form (i.e. the token's index will be equal to kPointerInvalidIndex). This struct is public so that user can create a Pointer without parsing and allocation, using a special constructor. */ struct Token { const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. SizeType length; //!< Length of the name. SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. }; //!@name Constructors and destructor. //@{ //! Default constructor. GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Constructor that parses a string or URI fragment representation. /*! \param source A null-terminated, string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. */ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, internal::StrLen(source)); } #if RAPIDJSON_HAS_STDSTRING //! Constructor that parses a string or URI fragment representation. /*! \param source A string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source.c_str(), source.size()); } #endif //! Constructor that parses a string or URI fragment representation, with length of the source string. /*! \param source A string or URI fragment representation of JSON pointer. \param length Length of source. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Slightly faster than the overload without length. */ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, length); } //! Constructor with user-supplied tokens. /*! This constructor let user supplies const array of tokens. This prevents the parsing process and eliminates allocation. This is preferred for memory constrained environments. \param tokens An constant array of tokens representing the JSON pointer. \param tokenCount Number of tokens. \b Example \code #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } #define INDEX(i) { #i, sizeof(#i) - 1, i } static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); // Equivalent to static const Pointer p("/foo/123"); #undef NAME #undef INDEX \endcode */ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } //! Destructor. ~GenericPointer() { if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. Allocator::Free(tokens_); RAPIDJSON_DELETE(ownAllocator_); } //! Assignment operator. GenericPointer& operator=(const GenericPointer& rhs) { if (this != &rhs) { // Do not delete ownAllcator if (nameBuffer_) Allocator::Free(tokens_); tokenCount_ = rhs.tokenCount_; parseErrorOffset_ = rhs.parseErrorOffset_; parseErrorCode_ = rhs.parseErrorCode_; if (rhs.nameBuffer_) CopyFromRaw(rhs); // Normally parsed tokens. else { tokens_ = rhs.tokens_; // User supplied const tokens. nameBuffer_ = 0; } } return *this; } //@} //!@name Append token //@{ //! Append a token and return a new Pointer /*! \param token Token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Token& token, Allocator* allocator = 0) const { GenericPointer r; r.allocator_ = allocator; Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); r.tokens_[tokenCount_].name = p; r.tokens_[tokenCount_].length = token.length; r.tokens_[tokenCount_].index = token.index; return r; } //! Append a name token with length, and return a new Pointer /*! \param name Name to be appended. \param length Length of name. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { Token token = { name, length, kPointerInvalidIndex }; return Append(token, allocator); } //! Append a name token without length, and return a new Pointer /*! \param name Name (const Ch*) to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { return Append(name, StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Append a name token, and return a new Pointer /*! \param name Name to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { return Append(name.c_str(), static_cast(name.size()), allocator); } #endif //! Append a index token, and return a new Pointer /*! \param index Index to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer; buffer[length] = '\0'; if (sizeof(Ch) == 1) { Token token = { (Ch*)buffer, length, index }; return Append(token, allocator); } else { Ch name[21]; for (size_t i = 0; i <= length; i++) name[i] = buffer[i]; Token token = { name, length, index }; return Append(token, allocator); } } //! Append a token by value, and return a new Pointer /*! \param value Value (either Uint or String) to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { if (token.IsString()) return Append(token.GetString(), token.GetStringLength(), allocator); else { RAPIDJSON_ASSERT(token.IsUint64()); RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); return Append(static_cast(token.GetUint64()), allocator); } } //!@name Handling Parse Error //@{ //! Check whether this is a valid pointer. bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } //! Get the parsing error offset in code unit. size_t GetParseErrorOffset() const { return parseErrorOffset_; } //! Get the parsing error code. PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } //@} //!@name Tokens //@{ //! Get the token array (const version only). const Token* GetTokens() const { return tokens_; } //! Get the number of tokens. size_t GetTokenCount() const { return tokenCount_; } //@} //!@name Equality/inequality operators //@{ //! Equality operator. /*! \note When any pointers are invalid, always returns false. */ bool operator==(const GenericPointer& rhs) const { if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) return false; for (size_t i = 0; i < tokenCount_; i++) { if (tokens_[i].index != rhs.tokens_[i].index || tokens_[i].length != rhs.tokens_[i].length || (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) { return false; } } return true; } //! Inequality operator. /*! \note When any pointers are invalid, always returns true. */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } //@} //!@name Stringify //@{ //! Stringify the pointer into string representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { return Stringify(os); } //! Stringify the pointer into URI fragment representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool StringifyUriFragment(OutputStream& os) const { return Stringify(os); } //@} //!@name Create value //@{ //! Create a value in a subtree. /*! If the value is not exist, it creates all parent values and a JSON Null value. So it always succeed and return the newly created or existing value. Remind that it may change types of parents according to tokens, so it potentially removes previously stored values. For example, if a document was an array, and "/foo" is used to create a value, then the document will be changed to an object, and all existing array elements are lost. \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created (a JSON Null value), or already exists value. */ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { v->PushBack(Value().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } else { if (t->index == kPointerInvalidIndex) { // must be object name if (!v->IsObject()) v->SetObject(); // Change to Object } else { // object name or array index if (!v->IsArray() && !v->IsObject()) v->SetArray(); // Change to Array } if (v->IsArray()) { if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) v->PushBack(Value().Move(), allocator); exist = false; } v = &((*v)[t->index]); } else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator); v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end exist = false; } else v = &m->value; } } } if (alreadyExist) *alreadyExist = exist; return *v; } //! Creates a value in a document. /*! \param document A document to be resolved. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ template ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { return Create(document, document.GetAllocator(), alreadyExist); } //@} //!@name Query value //@{ //! Query a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ ValueType* Get(ValueType& root) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) return 0; v = &m->value; } break; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) return 0; v = &((*v)[t->index]); break; default: return 0; } } return v; } //! Query a const value in a const subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ const ValueType* Get(const ValueType& root) const { return Get(const_cast(root)); } //@} //!@name Query a value with default //@{ //! Query a value in a subtree with default value. /*! Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. So that this function always succeed. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param defaultValue Default value to be cloned if the value was not exists. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif //! Query a value in a subtree with default primitive value. /*! \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); } //! Query a value in a document with default value. template ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //! Query a value in a document with default null-terminated string. template ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #endif //! Query a value in a document with default primitive value. /*! \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(GenericDocument& document, T defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //@} //!@name Set a value //@{ //! Set a value in a subtree, with move semantics. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be set. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = value; } //! Set a value in a subtree, with copy semantics. ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).CopyFrom(value, allocator); } //! Set a null-terminated string in a subtree. ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Set a std::basic_string in a subtree. ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #endif //! Set a primitive value in a subtree. /*! \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value).Move(); } //! Set a value in a document, with move semantics. template ValueType& Set(GenericDocument& document, ValueType& value) const { return Create(document) = value; } //! Set a value in a document, with copy semantics. template ValueType& Set(GenericDocument& document, const ValueType& value) const { return Create(document).CopyFrom(value, document.GetAllocator()); } //! Set a null-terminated string in a document. template ValueType& Set(GenericDocument& document, const Ch* value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Sets a std::basic_string in a document. template ValueType& Set(GenericDocument& document, const std::basic_string& value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #endif //! Set a primitive value in a document. /*! \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(GenericDocument& document, T value) const { return Create(document) = value; } //@} //!@name Swap a value //@{ //! Swap a value with a value in a subtree. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be swapped. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).Swap(value); } //! Swap a value with a value in a document. template ValueType& Swap(GenericDocument& document, ValueType& value) const { return Create(document).Swap(value); } //@} //! Erase a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Whether the resolved value is found and erased. \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. */ bool Erase(ValueType& root) const { RAPIDJSON_ASSERT(IsValid()); if (tokenCount_ == 0) // Cannot erase the root return false; ValueType* v = &root; const Token* last = tokens_ + (tokenCount_ - 1); for (const Token *t = tokens_; t != last; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) return false; v = &m->value; } break; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) return false; v = &((*v)[t->index]); break; default: return false; } } switch (v->GetType()) { case kObjectType: return v->EraseMember(GenericStringRef(last->name, last->length)); case kArrayType: if (last->index == kPointerInvalidIndex || last->index >= v->Size()) return false; v->Erase(v->Begin() + last->index); return true; default: return false; } } private: //! Clone the content from rhs to this. /*! \param rhs Source pointer. \param extraToken Extra tokens to be allocated. \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. \return Start of non-occupied name buffer, for storing extra names. */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) nameBufferSize += t->length; tokenCount_ = rhs.tokenCount_ + extraToken; tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); // Adjust pointers to name buffer std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) t->name += diff; return nameBuffer_ + nameBufferSize; } //! Check whether a character should be percent-encoded. /*! According to RFC 3986 2.3 Unreserved Characters. \param c The character (code unit) to be tested. */ bool NeedPercentEncode(Ch c) const { return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); } //! Parse a JSON String or its URI fragment representation into tokens. /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); RAPIDJSON_ASSERT(tokens_ == 0); // Create own allocator if user did not supply. if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); // Count number of '/' as tokenCount tokenCount_ = 0; for (const Ch* s = source; s != source + length; s++) if (*s == '/') tokenCount_++; Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); size_t i = 0; // Detect if it is a URI fragment bool uriFragment = false; if (source[i] == '#') { uriFragment = true; i++; } if (i != length && source[i] != '/') { parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; goto error; } while (i < length) { RAPIDJSON_ASSERT(source[i] == '/'); i++; // consumes '/' token->name = name; bool isNumber = true; while (i < length && source[i] != '/') { Ch c = source[i]; if (uriFragment) { // Decoding percent-encoding for URI fragment if (c == '%') { PercentDecodeStream is(&source[i], source + length); GenericInsituStringStream os(name); Ch* begin = os.PutBegin(); if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; goto error; } size_t len = os.PutEnd(begin); i += is.Tell() - 1; if (len == 1) c = *name; else { name += len; isNumber = false; i++; continue; } } else if (NeedPercentEncode(c)) { parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; goto error; } } i++; // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { c = source[i]; if (c == '0') c = '~'; else if (c == '1') c = '/'; else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } i++; } else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } } // First check for index: all of characters are digit if (c < '0' || c > '9') isNumber = false; *name++ = c; } token->length = name - token->name; if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator // Second check for index: more than one digit cannot have leading zero if (isNumber && token->length > 1 && token->name[0] == '0') isNumber = false; // String to SizeType conversion SizeType n = 0; if (isNumber) { for (size_t j = 0; j < token->length; j++) { SizeType m = n * 10 + static_cast(token->name[j] - '0'); if (m < n) { // overflow detection isNumber = false; break; } n = m; } } token->index = isNumber ? n : kPointerInvalidIndex; token++; } RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer parseErrorCode_ = kPointerParseErrorNone; return; error: Allocator::Free(tokens_); nameBuffer_ = 0; tokens_ = 0; tokenCount_ = 0; parseErrorOffset_ = i; return; } //! Stringify to string or URI fragment representation. /*! \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. \tparam OutputStream type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { RAPIDJSON_ASSERT(IsValid()); if (uriFragment) os.Put('#'); for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { os.Put('/'); for (size_t j = 0; j < t->length; j++) { Ch c = t->name[j]; if (c == '~') { os.Put('~'); os.Put('0'); } else if (c == '/') { os.Put('~'); os.Put('1'); } else if (uriFragment && NeedPercentEncode(c)) { // Transcode to UTF8 sequence GenericStringStream source(&t->name[j]); PercentEncodeStream target(os); if (!Transcoder >().Validate(source, target)) return false; j += source.Tell() - 1; } else os.Put(c); } } return true; } //! A helper stream for decoding a percent-encoded sequence into code unit. /*! This stream decodes %XY triplet into code unit (0-255). If it encounters invalid characters, it sets output code unit as 0 and mark invalid, and to be checked by IsValid(). */ class PercentDecodeStream { public: //! Constructor /*! \param source Start of the stream \param end Past-the-end of the stream. */ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} Ch Take() { if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet valid_ = false; return 0; } src_++; Ch c = 0; for (int j = 0; j < 2; j++) { c <<= 4; Ch h = *src_; if (h >= '0' && h <= '9') c += h - '0'; else if (h >= 'A' && h <= 'F') c += h - 'A' + 10; else if (h >= 'a' && h <= 'f') c += h - 'a' + 10; else { valid_ = false; return 0; } src_++; } return c; } size_t Tell() const { return src_ - head_; } bool IsValid() const { return valid_; } private: const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. const Ch* end_; //!< Past-the-end position. bool valid_; //!< Whether the parsing is valid. }; //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. template class PercentEncodeStream { public: PercentEncodeStream(OutputStream& os) : os_(os) {} void Put(char c) { // UTF-8 must be byte unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); os_.Put(hexDigits[u >> 4]); os_.Put(hexDigits[u & 15]); } private: OutputStream& os_; }; Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. Allocator* ownAllocator_; //!< Allocator owned by this Pointer. Ch* nameBuffer_; //!< A buffer containing all names in tokens. Token* tokens_; //!< A list of tokens. size_t tokenCount_; //!< Number of tokens in tokens_. size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. PointerParseErrorCode parseErrorCode_; //!< Parsing error code. }; //! GenericPointer for Value (UTF-8, default allocator). typedef GenericPointer Pointer; //!@name Helper functions for GenericPointer //@{ ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { return pointer.Create(root, a); } template typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Create(root, a); } // No allocator parameter template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { return pointer.Create(document); } template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Create(document); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer) { return pointer.Get(root); } template const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer) { return pointer.Get(root); } template typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { return GenericPointer(source, N - 1).Get(root); } template const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Get(root); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } // No allocator parameter template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } // No allocator parameter template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { return pointer.Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { return pointer.Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { return GenericPointer(source, N - 1).Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { return GenericPointer(source, N - 1).Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { return GenericPointer(source, N - 1).Set(document, value); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Swap(root, value, a); } template typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Swap(root, value, a); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Swap(document, value); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Swap(document, value); } ////////////////////////////////////////////////////////////////////////////// template bool EraseValueByPointer(T& root, const GenericPointer& pointer) { return pointer.Erase(root); } template bool EraseValueByPointer(T& root, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Erase(root); } //@} RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_POINTER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/prettywriter.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif RAPIDJSON_NAMESPACE_BEGIN //! Writer with indentation and spacing. /*! \tparam OutputStream Type of ouptut os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor /*! \param os Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } /*! @name Implementation of Handler \see Handler */ //@{ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kStringType); return Base::WriteString(str, length); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); return Base::WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndObject(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; } bool StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); return Base::WriteStartArray(); } bool EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndArray(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top(); if (level->inArray) { if (level->valueCount > 0) { Base::os_->Put(','); // add comma if it is not the first element in array Base::os_->Put('\n'); } else Base::os_->Put('\n'); WriteIndent(); } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::os_->Put(','); Base::os_->Put('\n'); } else { Base::os_->Put(':'); Base::os_->Put(' '); } } else Base::os_->Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. Base::hasRoot_ = true; } } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(*Base::os_, indentChar_, count); } Ch indentChar_; unsigned indentCharCount_; private: // Prohibit copy constructor & assignment operator. PrettyWriter(const PrettyWriter&); PrettyWriter& operator=(const PrettyWriter&); }; RAPIDJSON_NAMESPACE_END #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/rapidjson.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ /*!\file rapidjson.h \brief common definitions and configuration \see RAPIDJSON_CONFIG */ /*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration \brief Configuration macros for library features Some RapidJSON features are configurable to adapt the library to a wide variety of platforms, environments and usage scenarios. Most of the features can be configured in terms of overriden or predefined preprocessor macros at compile-time. Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. \note These macros should be given on the compiler command-line (where applicable) to avoid inconsistent values when compiling different translation units of a single application. */ #include // malloc(), realloc(), free(), size_t #include // memset(), memcpy(), memmove(), memcmp() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_VERSION_STRING // // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. // //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Major version of RapidJSON in integer. */ /*! \def RAPIDJSON_MINOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Minor version of RapidJSON in integer. */ /*! \def RAPIDJSON_PATCH_VERSION \ingroup RAPIDJSON_CONFIG \brief Patch version of RapidJSON in integer. */ /*! \def RAPIDJSON_VERSION_STRING \ingroup RAPIDJSON_CONFIG \brief Version of RapidJSON in ".." string format. */ #define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 0 #define RAPIDJSON_PATCH_VERSION 2 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NAMESPACE_(BEGIN|END) /*! \def RAPIDJSON_NAMESPACE \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace In order to avoid symbol clashes and/or "One Definition Rule" errors between multiple inclusions of (different versions of) RapidJSON in a single binary, users can customize the name of the main RapidJSON namespace. In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref RAPIDJSON_NAMESPACE_END need to be defined as well: \code // in some .cpp file #define RAPIDJSON_NAMESPACE my::rapidjson #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { #define RAPIDJSON_NAMESPACE_END } } #include "rapidjson/..." \endcode \see rapidjson */ /*! \def RAPIDJSON_NAMESPACE_BEGIN \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (opening expression) \see RAPIDJSON_NAMESPACE */ /*! \def RAPIDJSON_NAMESPACE_END \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (closing expression) \see RAPIDJSON_NAMESPACE */ #ifndef RAPIDJSON_NAMESPACE #define RAPIDJSON_NAMESPACE rapidjson #endif #ifndef RAPIDJSON_NAMESPACE_BEGIN #define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { #endif #ifndef RAPIDJSON_NAMESPACE_END #define RAPIDJSON_NAMESPACE_END } #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE /*! \def RAPIDJSON_NO_INT64DEFINE \ingroup RAPIDJSON_CONFIG \brief Use external 64-bit integer types. RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types to be available at global scope. If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to prevent RapidJSON from defining its own types. */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #ifdef _MSC_VER #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else // Other compilers should have this. #include #include #endif //!@endcond #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_INT64DEFINE #endif #endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && !defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline #elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE #endif //!@endcond #endif // RAPIDJSON_FORCEINLINE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! \def RAPIDJSON_ENDIAN \ingroup RAPIDJSON_CONFIG GCC 4.6 provided macro for detecting endianness of the target machine. But other compilers may not have this. User can define RAPIDJSON_ENDIAN to either \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. Default detection implemented with reference to \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp */ #ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro # ifdef __BYTE_ORDER__ # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN // Detect with architecture macros # elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_64BIT //! Whether using 64-bit architecture #ifndef RAPIDJSON_64BIT #if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__) #define RAPIDJSON_64BIT 1 #else #define RAPIDJSON_64BIT 0 #endif #endif // RAPIDJSON_64BIT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ALIGN //! Data alignment of the machine. /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align Some machines require strict data alignment. Currently the default uses 4 bytes alignment. User can customize by defining the RAPIDJSON_ALIGN function macro., */ #ifndef RAPIDJSON_ALIGN #if RAPIDJSON_64BIT == 1 #define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u) #else #define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) #endif #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_UINT64_C2 //! Construct a 64-bit literal by a pair of 32-bit integer. /*! 64-bit literal with or without ULL suffix is prone to compiler warnings. UINT64_C() is C macro which cause compilation problems. Use this macro to define 64-bit constants by a pair of 32-bit integer. */ #ifndef RAPIDJSON_UINT64_C2 #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG \brief Enable SSE2/SSE4.2 optimization. RapidJSON supports optimized implementations for some parsing operations based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible processors. To enable these optimizations, two different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. #define RAPIDJSON_SSE42 \endcode \c RAPIDJSON_SSE42 takes precedence, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_SIZETYPEDEFINE #ifndef RAPIDJSON_NO_SIZETYPEDEFINE /*! \def RAPIDJSON_NO_SIZETYPEDEFINE \ingroup RAPIDJSON_CONFIG \brief User-provided \c SizeType definition. In order to avoid using 32-bit size types for indexing strings and arrays, define this preprocessor symbol and provide the type rapidjson::SizeType before including RapidJSON: \code #define RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { typedef ::std::size_t SizeType; } #include "rapidjson/..." \endcode \see rapidjson::SizeType */ #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_SIZETYPEDEFINE #endif RAPIDJSON_NAMESPACE_BEGIN //! Size type (for string lengths, array sizes, etc.) /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, instead of using \c size_t. Users may override the SizeType by defining \ref RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; RAPIDJSON_NAMESPACE_END #endif // always import std::size_t to rapidjson namespace RAPIDJSON_NAMESPACE_BEGIN using std::size_t; RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ASSERT //! Assertion. /*! \ingroup RAPIDJSON_CONFIG By default, rapidjson uses C \c assert() for internal assertions. User can override it by defining RAPIDJSON_ASSERT(x) macro. \note Parsing errors are handled and can be customized by the \ref RAPIDJSON_ERRORS APIs. */ #ifndef RAPIDJSON_ASSERT #include #define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT // Adopt from boost #ifndef RAPIDJSON_STATIC_ASSERT //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN2(X, Y) X##Y #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif //!@endcond /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time \param x compile-time condition \hideinitializer */ #define RAPIDJSON_STATIC_ASSERT(x) \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif /////////////////////////////////////////////////////////////////////////////// // Helpers //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) // adopted from Boost #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF #if defined(__GNUC__) #define RAPIDJSON_GNUC \ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) #endif #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_OFF(x) \ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) // push/pop support in Clang and GCC>=4.6 #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else // GCC >= 4.2, < 4.6 #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif #elif defined(_MSC_VER) // pragma (MSVC specific) #define RAPIDJSON_PRAGMA(x) __pragma(x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else #define RAPIDJSON_DIAG_OFF(x) /* ignored */ #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif // RAPIDJSON_DIAG_* /////////////////////////////////////////////////////////////////////////////// // C++11 features #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) // (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else #define RAPIDJSON_NOEXCEPT /* noexcept */ #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif //!@endcond /////////////////////////////////////////////////////////////////////////////// // new/delete #ifndef RAPIDJSON_NEW ///! customization point for global \c new #define RAPIDJSON_NEW(x) new x #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete #define RAPIDJSON_DELETE(x) delete x #endif /////////////////////////////////////////////////////////////////////////////// // Allocators and Encodings #include "allocators.h" #include "encodings.h" /*! \namespace rapidjson \brief main RapidJSON namespace \see RAPIDJSON_NAMESPACE */ RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Stream /*! \class rapidjson::Stream \brief Concept for reading and writing characters. For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). For write-only stream, only need to implement Put() and Flush(). \code concept Stream { typename Ch; //!< Character type of the stream. //! Read the current character from stream without moving the read cursor. Ch Peek() const; //! Read the current character from stream and moving the read cursor to next character. Ch Take(); //! Get the current read cursor. //! \return Number of characters read from start. size_t Tell(); //! Begin writing operation at the current read pointer. //! \return The begin writer pointer. Ch* PutBegin(); //! Write a character. void Put(Ch c); //! Flush the buffer. void Flush(); //! End the writing operation. //! \param begin The begin write pointer returned by PutBegin(). //! \return Number of characters written. size_t PutEnd(Ch* begin); } \endcode */ //! Provides additional information for stream. /*! By using traits pattern, this type provides a default configuration for stream. For custom stream, this type can be specialized for other configuration. See TEST(Reader, CustomStringStream) in readertest.cpp for example. */ template struct StreamTraits { //! Whether to make local copy of stream for optimization during parsing. /*! By default, for safety, streams do not use local copy optimization. Stream that can be copied fast should specialize this, like StreamTraits. */ enum { copyOptimization = 0 }; }; //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { for (size_t i = 0; i < n; i++) stream.Put(c); } /////////////////////////////////////////////////////////////////////////////// // StringStream //! Read-only string stream. /*! \note implements Stream concept */ template struct GenericStringStream { typedef typename Encoding::Ch Ch; GenericStringStream(const Ch *src) : src_(src), head_(src) {} Ch Peek() const { return *src_; } Ch Take() { return *src_++; } size_t Tell() const { return static_cast(src_ - head_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! String stream with UTF8 encoding. typedef GenericStringStream > StringStream; /////////////////////////////////////////////////////////////////////////////// // InsituStringStream //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. \note implements Stream concept */ template struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } Ch Take() { return *src_++; } size_t Tell() { return static_cast(src_ - head_); } // Write void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } Ch* PutBegin() { return dst_ = src_; } size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } void Flush() {} Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Pop(size_t count) { dst_ -= count; } Ch* src_; Ch* dst_; Ch* head_; }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! Insitu string stream with UTF8 encoding. typedef GenericInsituStringStream > InsituStringStream; /////////////////////////////////////////////////////////////////////////////// // Type //! Type of JSON value enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/reader.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ /*! \file reader.h */ #include "rapidjson.h" #include "encodings.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_NOTHING /* deliberately empty */ #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ if (HasParseError()) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) //!@endcond /*! \def RAPIDJSON_PARSE_ERROR_NORETURN \ingroup RAPIDJSON_ERRORS \brief Macro to indicate a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) This macros can be used as a customization point for the internal error handling mechanism of RapidJSON. A common usage model is to throw an exception instead of requiring the caller to explicitly check the \ref rapidjson::GenericReader::Parse's return value: \code #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ throw ParseException(parseErrorCode, #parseErrorCode, offset) #include // std::runtime_error #include "rapidjson/error/error.h" // rapidjson::ParseResult struct ParseException : std::runtime_error, rapidjson::ParseResult { ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) : std::runtime_error(msg), ParseResult(code, offset) {} }; #include "rapidjson/reader.h" \endcode \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse */ #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ SetParseError(parseErrorCode, offset); \ RAPIDJSON_MULTILINEMACRO_END #endif /*! \def RAPIDJSON_PARSE_ERROR \ingroup RAPIDJSON_ERRORS \brief (Internal) macro to indicate and handle a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. \see RAPIDJSON_PARSE_ERROR_NORETURN \hideinitializer */ #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ RAPIDJSON_MULTILINEMACRO_END #endif #include "error/error.h" // ParseErrorCode, ParseResult RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag /*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. User can define this as any \c ParseFlag combinations. */ #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS #define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream */ enum ParseFlag { kParseNoFlags = 0, //!< No flags are set. kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// // Handler /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { typename Ch; bool Null(); bool Bool(bool b); bool Int(int i); bool Uint(unsigned i); bool Int64(int64_t i); bool Uint64(uint64_t i); bool Double(double d); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType memberCount); bool StartArray(); bool EndArray(SizeType elementCount); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // BaseReaderHandler //! Default implementation of Handler. /*! This can be used as base class of any reader handler. \note implements Handler concept */ template, typename Derived = void> struct BaseReaderHandler { typedef typename Encoding::Ch Ch; typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; bool Default() { return true; } bool Null() { return static_cast(*this).Default(); } bool Bool(bool) { return static_cast(*this).Default(); } bool Int(int) { return static_cast(*this).Default(); } bool Uint(unsigned) { return static_cast(*this).Default(); } bool Int64(int64_t) { return static_cast(*this).Default(); } bool Uint64(uint64_t) { return static_cast(*this).Default(); } bool Double(double) { return static_cast(*this).Default(); } bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } bool StartObject() { return static_cast(*this).Default(); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool EndObject(SizeType) { return static_cast(*this).Default(); } bool StartArray() { return static_cast(*this).Default(); } bool EndArray(SizeType) { return static_cast(*this).Default(); } }; /////////////////////////////////////////////////////////////////////////////// // StreamLocalCopy namespace internal { template::copyOptimization> class StreamLocalCopy; //! Do copy optimization. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original), original_(original) {} ~StreamLocalCopy() { original_ = s; } Stream s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; Stream& original_; }; //! Keep reference. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original) {} Stream& s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // SkipWhitespace //! Skip the JSON white spaces in a stream. /*! \param is A input stream for skipping white spaces. \note This function has SSE2/SSE4.2 specialization. */ template void SkipWhitespace(InputStream& is) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') s.Take(); } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); for (;; p += 16) { const __m128i s = _mm_load_si128((const __m128i *)p); const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); if (r != 0) { // some of characters is non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string static const char whitespaces[4][17] = { " ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); for (;; p += 16) { const __m128i s = _mm_load_si128((const __m128i *)p); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = (unsigned short)~_mm_movemask_epi8(x); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } #endif // RAPIDJSON_SSE2 #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& is) { is.src_ = SkipWhitespace_SIMD(is.src_); } #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. /*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. It needs to allocate a stack for storing a single decoded string during non-destructive parsing. For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. */ template class GenericReader { public: typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type //! Constructor. /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { if (parseFlags & kParseIterativeFlag) return IterativeParse(is, handler); parseResult_.Clear(); ClearStackOnExit scope(*this); SkipWhitespace(is); if (is.Peek() == '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespace(is); if (is.Peek() != '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } } } return parseResult_; } //! Parse JSON text (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { return Parse(is, handler); } //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } protected: void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } private: // Prohibit copy constructor & assignment operator. GenericReader(const GenericReader&); GenericReader& operator=(const GenericReader&); void ClearStack() { stack_.Clear(); } // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericReader& r) : r_(r) {} ~ClearStackOnExit() { r_.ClearStack(); } private: GenericReader& r_; ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); }; // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' if (!handler.StartObject()) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespace(is); if (is.Peek() == '}') { is.Take(); if (!handler.EndObject(0)) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { if (is.Peek() != '"') RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespace(is); if (is.Take() != ':') RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespace(is); ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespace(is); ++memberCount; switch (is.Take()) { case ',': SkipWhitespace(is); break; case '}': if (!handler.EndObject(memberCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); } } } // Parse array: [ value, ... ] template void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' if (!handler.StartArray()) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespace(is); if (is.Peek() == ']') { is.Take(); if (!handler.EndArray(0)) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType elementCount = 0;;) { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespace(is); switch (is.Take()) { case ',': SkipWhitespace(is); break; case ']': if (!handler.EndArray(elementCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); } } } template void ParseNull(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { if (!handler.Null()) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } template void ParseTrue(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { if (!handler.Bool(true)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } template void ParseFalse(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { if (!handler.Bool(false)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is) { unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = is.Take(); codepoint <<= 4; codepoint += static_cast(c); if (c >= '0' && c <= '9') codepoint -= '0'; else if (c >= 'A' && c <= 'F') codepoint -= 'A' - 10; else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } } return codepoint; } template class StackStream { public: typedef CharType Ch; StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} RAPIDJSON_FORCEINLINE void Put(Ch c) { *stack_.template Push() = c; ++length_; } size_t Length() const { return length_; } Ch* Pop() { return stack_.template Pop(length_); } private: StackStream(const StackStream&); StackStream& operator=(const StackStream&); internal::Stack& stack_; SizeType length_; }; // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler, bool isKey = false) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream(s, s); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SizeType length = static_cast(stackStream.Length()) - 1; const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } if (!success) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse string to an output is // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. template RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 //!@endcond RAPIDJSON_ASSERT(is.Peek() == '\"'); is.Take(); // Skip '\"' for (;;) { Ch c = is.Peek(); if (c == '\\') { // Escape is.Take(); Ch e = is.Take(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { os.Put(escape[(unsigned char)e]); } else if (e == 'u') { // Unicode unsigned codepoint = ParseHex4(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair if (is.Take() != '\\' || is.Take() != 'u') RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); unsigned codepoint2 = ParseHex4(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } TEncoding::Encode(os, codepoint); } else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); } else if (c == '"') { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } else if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); else { if (parseFlags & kParseValidateEncodingFlag ? !Transcoder::Validate(is, os) : !Transcoder::Transcode(is, os)) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } } } template class NumberStream; template class NumberStream { public: NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } size_t Tell() { return is.Tell(); } size_t Length() { return 0; } const char* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); InputStream& is; }; template class NumberStream : public NumberStream { typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : NumberStream(reader, is), stackStream(reader.stack_) {} ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch TakePush() { stackStream.Put((char)Base::is.Peek()); return Base::is.Take(); } size_t Length() { return stackStream.Length(); } const char* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: StackStream stackStream; }; template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); NumberStream s(*this, copy.s); // Parse minus bool minus = false; if (s.Peek() == '-') { minus = true; s.Take(); } // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; if (s.Peek() == '0') { i = 0; s.TakePush(); } else if (s.Peek() >= '1' && s.Peek() <= '9') { i = static_cast(s.TakePush() - '0'); if (minus) while (s.Peek() >= '0' && s.Peek() <= '9') { if (i >= 214748364) { // 2^31 = 2147483648 if (i != 214748364 || s.Peek() > '8') { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (s.Peek() >= '0' && s.Peek() <= '9') { if (i >= 429496729) { // 2^32 - 1 = 4294967295 if (i != 429496729 || s.Peek() > '5') { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; double d = 0.0; if (use64bit) { if (minus) while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { d = i64; useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { d = i64; useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } // Force double for big integer if (useDouble) { while (s.Peek() >= '0' && s.Peek() <= '9') { if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); d = d * 10 + (s.TakePush() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; size_t decimalPosition; if (s.Peek() == '.') { s.Take(); decimalPosition = s.Length(); if (!(s.Peek() >= '0' && s.Peek() <= '9')) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { #if RAPIDJSON_64BIT // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { i64 = i64 * 10 + static_cast(s.TakePush() - '0'); --expFrac; if (i64 != 0) significandDigit++; } } d = (double)i64; #else // Use double to store significand in 32-bit architecture d = use64bit ? (double)i64 : (double)i; #endif useDouble = true; } while (s.Peek() >= '0' && s.Peek() <= '9') { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; if (d > 0.0) significandDigit++; } else s.TakePush(); } } else decimalPosition = s.Length(); // decimal position at the end of integer. // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (s.Peek() == 'e' || s.Peek() == 'E') { if (!useDouble) { d = use64bit ? i64 : i; useDouble = true; } s.Take(); bool expMinus = false; if (s.Peek() == '+') s.Take(); else if (s.Peek() == '-') { s.Take(); expMinus = true; } if (s.Peek() >= '0' && s.Peek() <= '9') { exp = s.Take() - '0'; if (expMinus) { while (s.Peek() >= '0' && s.Peek() <= '9') { exp = exp * 10 + (s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; while (s.Peek() >= '0' && s.Peek() <= '9') { exp = exp * 10 + (s.Take() - '0'); if (exp > maxExp) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); } } } else RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); if (expMinus) exp = -exp; } // Finish parsing, call event according to the type of number. bool cont = true; size_t length = s.Length(); const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; if (parseFlags & kParseFullPrecisionFlag) d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); else d = internal::StrtodNormalPrecision(d, p); cont = handler.Double(minus ? -d : d); } else { if (use64bit) { if (minus) cont = handler.Int64(static_cast(~i64 + 1)); else cont = handler.Uint64(i64); } else { if (minus) cont = handler.Int(static_cast(~i + 1)); else cont = handler.Uint(i); } } if (!cont) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse any JSON value template void ParseValue(InputStream& is, Handler& handler) { switch (is.Peek()) { case 'n': ParseNull (is, handler); break; case 't': ParseTrue (is, handler); break; case 'f': ParseFalse (is, handler); break; case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; default : ParseNumber(is, handler); } } // Iterative Parsing // States enum IterativeParsingState { IterativeParsingStartState = 0, IterativeParsingFinishState, IterativeParsingErrorState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state IterativeParsingValueState, cIterativeParsingStateCount }; // Tokens enum Token { LeftBracketToken = 0, RightBracketToken, LeftCurlyBracketToken, RightCurlyBracketToken, CommaToken, ColonToken, StringToken, FalseToken, TrueToken, NullToken, NumberToken, kTokenCount }; RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken #define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N // Maps from ASCII to Token static const unsigned char tokenMap[256] = { N16, // 00~0F N16, // 10~1F N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F N16, // 40~4F N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF }; #undef N #undef N16 //!@endcond if (sizeof(Ch) == 1 || unsigned(c) < 256) return (Token)tokenMap[(unsigned char)c]; else return NumberToken; } RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { // Start { IterativeParsingArrayInitialState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingValueState, // String IterativeParsingValueState, // False IterativeParsingValueState, // True IterativeParsingValueState, // Null IterativeParsingValueState // Number }, // Finish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Error(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ObjectInitial { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberKey { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingKeyValueDelimiterState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // KeyValueDelimiter { IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberValueState, // String IterativeParsingMemberValueState, // False IterativeParsingMemberValueState, // True IterativeParsingMemberValueState, // Null IterativeParsingMemberValueState // Number }, // MemberValue { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingMemberDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberDelimiter { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ArrayInitial { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // Element { IterativeParsingErrorState, // Left bracket IterativeParsingArrayFinishState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingElementDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // ArrayFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Single Value (sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState } }; // End of G return (IterativeParsingState)G[state][token]; } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // May return a new state on state pop. template RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { (void)token; switch (dst) { case IterativeParsingErrorState: return dst; case IterativeParsingObjectInitialState: case IterativeParsingArrayInitialState: { // Push the state(Element or MemeberValue) if we are nested in another array or value of member. // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. IterativeParsingState n = src; if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) n = IterativeParsingElementState; else if (src == IterativeParsingKeyValueDelimiterState) n = IterativeParsingMemberValueState; // Push current state. *stack_.template Push(1) = n; // Initialize and push the member/element count. *stack_.template Push(1) = 0; // Call handler bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return dst; } } case IterativeParsingMemberKeyState: ParseString(is, handler, true); if (HasParseError()) return IterativeParsingErrorState; else return dst; case IterativeParsingKeyValueDelimiterState: RAPIDJSON_ASSERT(token == ColonToken); is.Take(); return dst; case IterativeParsingMemberValueState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingElementState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingMemberDelimiterState: case IterativeParsingElementDelimiterState: is.Take(); // Update member/element count. *stack_.template Top() = *stack_.template Top() + 1; return dst; case IterativeParsingObjectFinishState: { // Get member count. SizeType c = *stack_.template Pop(1); // If the object is not empty, count the last member. if (src == IterativeParsingMemberValueState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndObject(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } case IterativeParsingArrayFinishState: { // Get element count. SizeType c = *stack_.template Pop(1); // If the array is not empty, count the last element. if (src == IterativeParsingElementState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndArray(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } default: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. // The IterativeParsingStartState is not enumerated in this switch-case. // It is impossible for that case. And it can be caught by following assertion. // The IterativeParsingFinishState is not enumerated in this switch-case either. // It is a "derivative" state which cannot triggered from Predict() directly. // Therefore it cannot happen here. And it can be caught by following assertion. RAPIDJSON_ASSERT(dst == IterativeParsingValueState); // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return IterativeParsingFinishState; } } template void HandleError(IterativeParsingState src, InputStream& is) { if (HasParseError()) { // Error flag has been set. return; } switch (src) { case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); } } template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; SkipWhitespace(is); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); if (d == IterativeParsingErrorState) { HandleError(state, is); break; } state = d; // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; SkipWhitespace(is); } // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_READER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/stringbuffer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ #include "rapidjson.h" #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. /*! \tparam Encoding Encoding of the stream. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template class GenericStringBuffer { public: typedef typename Encoding::Ch Ch; GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { if (&rhs != this) stack_ = std::move(rhs.stack_); return *this; } #endif void Put(Ch c) { *stack_.template Push() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.ShrinkToFit(); stack_.template Pop(1); } Ch* Push(size_t count) { return stack_.template Push(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.template Pop(1); return stack_.template Bottom(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; private: // Prohibit copy constructor & assignment operator. GenericStringBuffer(const GenericStringBuffer&); GenericStringBuffer& operator=(const GenericStringBuffer&); }; //! String buffer with UTF8 encoding typedef GenericStringBuffer > StringBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { std::memset(stream.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STRINGBUFFER_H_ ================================================ FILE: UAlbertaBot/Source/rapidjson/writer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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 RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ #include "rapidjson.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" #include "internal/itoa.h" #include "stringbuffer.h" #include // placement new #if RAPIDJSON_HAS_STDSTRING #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif RAPIDJSON_NAMESPACE_BEGIN //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output os. User may programmatically calls the functions of a writer to generate JSON text. On the other side, a writer can also be passed to objects that generates events, for example Reader::Parse() and Document::Accept(). \tparam OutputStream Type of output stream. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> class Writer { public: typedef typename SourceEncoding::Ch Ch; //! Constructor /*! \param os Output stream. \param stackAllocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {} explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, in order to make a Writer object reusable for output multiple JSONs. \param os New output stream. \code Writer writer(os1); writer.StartObject(); // ... writer.EndObject(); writer.Reset(os2); writer.StartObject(); // ... writer.EndObject(); \endcode */ void Reset(OutputStream& os) { os_ = &os; hasRoot_ = false; level_stack_.Clear(); } //! Checks whether the output is a complete JSON. /*! A complete JSON has a complete root object or array. */ bool IsComplete() const { return hasRoot_ && level_stack_.Empty(); } /*!@name Implementation of Handler \see Handler */ //@{ bool Null() { Prefix(kNullType); return WriteNull(); } bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } //! Writes the given \c double value to the stream /*! \param d The value to be written. \return Whether it is succeed. */ bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; Prefix(kStringType); return WriteString(str, length); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { Prefix(kObjectType); new (level_stack_.template Push()) Level(false); return WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); level_stack_.template Pop(1); bool ret = WriteEndObject(); if (level_stack_.Empty()) // end of json text os_->Flush(); return ret; } bool StartArray() { Prefix(kArrayType); new (level_stack_.template Push()) Level(true); return WriteStartArray(); } bool EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); bool ret = WriteEndArray(); if (level_stack_.Empty()) // end of json text os_->Flush(); return ret; } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} protected: //! Information for each nested level struct Level { Level(bool inArray_) : valueCount(0), inArray(inArray_) {} size_t valueCount; //!< number of values in this level bool inArray; //!< true if in array, otherwise in object }; static const size_t kDefaultLevelDepth = 32; bool WriteNull() { os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; } bool WriteBool(bool b) { if (b) { os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); } else { os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); } return true; } bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); for (const char* p = buffer; p != end; ++p) os_->Put(*p); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); for (const char* p = buffer; p != end; ++p) os_->Put(*p); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); for (const char* p = buffer; p != end; ++p) os_->Put(*p); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); for (char* p = buffer; p != end; ++p) os_->Put(*p); return true; } bool WriteDouble(double d) { char buffer[25]; char* end = internal::dtoa(d, buffer); for (char* p = buffer; p != end; ++p) os_->Put(*p); return true; } bool WriteString(const Ch* str, SizeType length) { static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 Z16, Z16, // 30~4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 }; os_->Put('\"'); GenericStringStream is(str); while (is.Tell() < length) { const Ch c = is.Peek(); if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { // Unicode escaping unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; os_->Put('\\'); os_->Put('u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { os_->Put(hexDigits[(codepoint >> 12) & 15]); os_->Put(hexDigits[(codepoint >> 8) & 15]); os_->Put(hexDigits[(codepoint >> 4) & 15]); os_->Put(hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; os_->Put(hexDigits[(lead >> 12) & 15]); os_->Put(hexDigits[(lead >> 8) & 15]); os_->Put(hexDigits[(lead >> 4) & 15]); os_->Put(hexDigits[(lead ) & 15]); os_->Put('\\'); os_->Put('u'); os_->Put(hexDigits[(trail >> 12) & 15]); os_->Put(hexDigits[(trail >> 8) & 15]); os_->Put(hexDigits[(trail >> 4) & 15]); os_->Put(hexDigits[(trail ) & 15]); } } else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { is.Take(); os_->Put('\\'); os_->Put(escape[(unsigned char)c]); if (escape[(unsigned char)c] == 'u') { os_->Put('0'); os_->Put('0'); os_->Put(hexDigits[(unsigned char)c >> 4]); os_->Put(hexDigits[(unsigned char)c & 0xF]); } } else if (!Transcoder::Transcode(is, *os_)) return false; } os_->Put('\"'); return true; } bool WriteStartObject() { os_->Put('{'); return true; } bool WriteEndObject() { os_->Put('}'); return true; } bool WriteStartArray() { os_->Put('['); return true; } bool WriteEndArray() { os_->Put(']'); return true; } void Prefix(Type type) { (void)type; if (level_stack_.GetSize() != 0) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) os_->Put(','); // add comma if it is not the first element in array else // in object os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. hasRoot_ = true; } } OutputStream* os_; internal::Stack level_stack_; bool hasRoot_; private: // Prohibit copy constructor & assignment operator. Writer(const Writer&); Writer& operator=(const Writer&); }; // Full specialization for StringStream to prevent memory copying template<> inline bool Writer::WriteInt(int i) { char *buffer = os_->Push(11); const char* end = internal::i32toa(i, buffer); os_->Pop(11 - (end - buffer)); return true; } template<> inline bool Writer::WriteUint(unsigned u) { char *buffer = os_->Push(10); const char* end = internal::u32toa(u, buffer); os_->Pop(10 - (end - buffer)); return true; } template<> inline bool Writer::WriteInt64(int64_t i64) { char *buffer = os_->Push(21); const char* end = internal::i64toa(i64, buffer); os_->Pop(21 - (end - buffer)); return true; } template<> inline bool Writer::WriteUint64(uint64_t u) { char *buffer = os_->Push(20); const char* end = internal::u64toa(u, buffer); os_->Pop(20 - (end - buffer)); return true; } template<> inline bool Writer::WriteDouble(double d) { char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer); os_->Pop(25 - (end - buffer)); return true; } RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: UAlbertaBot/Source/research/CombatData.cpp ================================================ #include "CombatData.h" CombatUnitData::CombatUnitData() : _unit(NULL) , _phase(CombatUnitData::NONE) , _enteredReady(0) , _enteredAttacking(0) , _enteredReloading(0) , _waitCommandGiven(0) { } CombatUnitData::CombatUnitData(BWAPI::Unit * unit) : _unit(unit) , _phase(CombatUnitData::NONE) , _enteredReady(0) , _enteredAttacking(0) , _enteredReloading(0) , _waitCommandGiven(0) { } const bool CombatUnitData::isWaiting() const { return (getPhase() == RELOADING) && (_waitCommandGiven > _enteredReloading); } const int CombatUnitData::getPhase() const { return _phase; } void CombatUnitData::waitCommand() { _waitCommandGiven = BWAPI::Broodwar->getFrameCount(); } void CombatUnitData::update() { int currentFrame = BWAPI::Broodwar->getFrameCount(); if (_phase == NONE) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } else { _phase = RELOADING; _enteredReloading = currentFrame; } } else if (_phase == READY) { if (_unit->isAttackFrame() || _unit->isStartingAttack()) { _phase = ATTACKING; _enteredAttacking = currentFrame; } } else if (_phase == ATTACKING) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } else if (!_unit->isAttackFrame() || ((currentFrame - _enteredAttacking) > Search::StarcraftData::getAttackFrames(_unit->getType()).first)) { _phase = RELOADING; _enteredReloading = currentFrame; } } else if (_phase == RELOADING) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } } } CombatData::CombatData() {} CombatUnitData & CombatData::getUnitData(BWAPI::Unit * unit) { return map[unit]; } void CombatData::updateUnit(BWAPI::Unit * unit) { // if it's not in our map, add a default entry if (!exists(unit)) { addUnit(unit); } getUnitData(unit).update(); } void CombatData::addUnit(BWAPI::Unit * unit) { map[unit] = CombatUnitData(unit); } void CombatData::removeUnit(BWAPI::Unit * unit) { map.erase(unit); } bool CombatData::exists(BWAPI::Unit * unit) const { return map.find(unit) != map.end(); } bool CombatData::commandWillInterruptAttack(BWAPI::Unit * unit) { const CombatUnitData & unitData(getUnitData(unit)); if (unitData.getPhase() == CombatUnitData::ATTACKING) { return true; } BWAPI::Broodwar->drawTextScreen(20, 20, "ATTACK PASS!"); return false; } bool CombatData::canIssueAttackCommand(BWAPI::Unit * attacker, BWAPI::Unit * target) { BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); BWAPI::UnitCommandType commandType = currentCommand.getType(); // if we have already given a command this frame, don't issue another one //if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - attacker->getLastCommandFrame() <= 7) //{ // drawDebugPlate(attacker, "A FRAME"); // return false; //} // if the last command given was an attack command if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit) { // if the target is the same as the current one, we don't need to switch if (currentCommand.getTarget() == target) { drawDebugPlate(attacker, "SAME"); return false; } } return true; //return !commandWillInterruptAttack(attacker); } bool CombatData::canIssueMoveCommand(BWAPI::Unit * unit, BWAPI::Position & position) { BWAPI::UnitCommand currentCommand(unit->getLastCommand()); BWAPI::UnitCommandType commandType = currentCommand.getType(); int threshold = 5; // if we have already given a command this frame, don't issue another one //if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() <= 7) //{ // drawDebugPlate(unit, "M FRAME"); // return false; //} if (getUnitData(unit).isWaiting()) { drawDebugPlate(unit, "WAIT"); return false; } // if the last command given was an attack command if (currentCommand.type == BWAPI::UnitCommandTypes::Move) { if (!unit->isMoving()) { return true; } else { return unit->getDistance(position) < 28; } } return !commandWillInterruptAttack(unit); } bool CombatData::canIssueStopCommand(BWAPI::Unit * unit) { // if the last move was attacking a unit do nothing if (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit) { return false; } return !commandWillInterruptAttack(unit); } const std::pair CombatData::getUnitCooldown(BWAPI::Unit * unit, MicroSearch::Unit & u) const { int attackCooldown(0); int moveCooldown(0); BWAPI::UnitCommand lastCommand = unit->getLastCommand(); int lastCommandFrame = unit->getLastCommandFrame(); int currentFrame = BWAPI::Broodwar->getFrameCount(); int framesSinceCommand = currentFrame - lastCommandFrame; if ((unit->getType() == BWAPI::UnitTypes::Protoss_Dragoon) && (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit)) { // dragoons are one of only 2 unit types whose attack can be canceled by the in-game targeter being called too early so // this hack makes up for that by taking it's stop-delay into account attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-Search::StarcraftData::getAttackFrames(unit->getType()).first); } else { attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-2); } // if the last attack was an attack command if (lastCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit) { moveCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, u.attackInitFrameTime() - framesSinceCommand); //BWAPI::Broodwar->drawTextScreen(100,100, "%d, %d", attackCooldown-currentFrame, moveCooldown-currentFrame); } // if the last command was a move command else if (lastCommand.getType() == BWAPI::UnitCommandTypes::Move) { moveCooldown = currentFrame; } if (moveCooldown - BWAPI::Broodwar->getFrameCount() < 4 || unit->isMoving()) { moveCooldown = currentFrame; } moveCooldown = std::min(moveCooldown, attackCooldown); return std::pair(attackCooldown, moveCooldown); } void CombatData::drawDebugPlate(BWAPI::Unit * unit, char * string) { BWAPI::Broodwar->drawBoxMap(unit->getPosition().x()-15, unit->getPosition().y()-10, unit->getPosition().x() + 10, unit->getPosition().y(), BWAPI::Colors::Black, true); BWAPI::Broodwar->drawTextMap(unit->getPosition().x()-15, unit->getPosition().y()-10, string); } void CombatData::waitCommand(BWAPI::Unit * unit) { getUnitData(unit).waitCommand(); } ================================================ FILE: UAlbertaBot/Source/research/CombatData.h ================================================ #pragma once #include "Common.h" #include "BWAPI.h" #include "GameCommander.h" #include "..\..\AdversarialSearch\source\Timer.h" #include "..\..\AdversarialSearch\source\GameState.h" #include "..\..\AdversarialSearch\source\Player.h" #include "..\..\AdversarialSearch\source\TranspositionTable.h" #include class CombatUnitData { BWAPI::Unit * _unit; int _phase, _enteredReady, _enteredAttacking, _enteredReloading, _waitCommandGiven; public: enum { NONE, READY, ATTACKING, RELOADING }; CombatUnitData(); CombatUnitData(BWAPI::Unit * unit); void update(); void waitCommand(); void attackCommand(); const bool isWaiting() const; const int getPhase() const; }; class CombatData { std::map map; CombatUnitData & getUnitData(BWAPI::Unit * unit); public: CombatData(); void updateUnit(BWAPI::Unit * unit); void addUnit(BWAPI::Unit * unit); void removeUnit(BWAPI::Unit * unit); void drawDebugPlate(BWAPI::Unit * unit, char * string); bool exists(BWAPI::Unit * unit) const; bool commandWillInterruptAttack(BWAPI::Unit * unit); bool canIssueAttackCommand(BWAPI::Unit * attacker, BWAPI::Unit * target); bool canIssueMoveCommand(BWAPI::Unit * unit, BWAPI::Position & position); bool canIssueStopCommand(BWAPI::Unit * unit); int attackAnimStartTime(BWAPI::Unit * unit); void waitCommand(BWAPI::Unit * unit); void attackCommand(BWAPI::Unit * unit); const std::pair getUnitCooldown(BWAPI::Unit * unit, MicroSearch::Unit & u) const; }; ================================================ FILE: UAlbertaBot/Source/research/GameHistory.hpp ================================================ #pragma once #include "BWAPI.h" #include #include #include class UnitFrameData { BWAPI::UnitType m_type; BWAPI::Position m_pos; BWAPI::Order m_order; BWAPI::Position m_orderPos; int m_id = 0; int m_player = 0; int m_hp = 0; int m_shields= 0; int m_energy = 0; double m_angle = 0; public: UnitFrameData(BWAPI::Unit unit) : m_type (unit->getType()) , m_pos (unit->getPosition()) , m_order (unit->getOrder()) , m_orderPos (unit->getOrderTargetPosition()) , m_id (unit->getID()) , m_player (unit->getPlayer()->getID()) , m_hp (unit->getHitPoints()) , m_shields (unit->getShields()) , m_energy (unit->getEnergy()) , m_angle (unit->getAngle()) { } void writeToFile(std::ofstream & fout) const { fout << m_player << " "; // 1 byte fout << m_type.getID() << " "; // 1 byte fout << m_id << " "; // 2 byte fout << m_hp << " "; // 2 byte fout << m_shields << " "; // 2 byte fout << m_pos.x << " "; // 2 byte fout << m_pos.y << " "; // 2 byte } }; class GameFrame { int m_frame = 0; std::vector m_units; public: GameFrame() : m_frame(BWAPI::Broodwar->getFrameCount()) { for (const BWAPI::Unit & unit : BWAPI::Broodwar->getAllUnits()) { if (unit->getPlayer()->getID() != -1) { m_units.push_back(UnitFrameData(unit)); } } } int getFrame() const { return m_frame; } void writeToFile(std::ofstream & fout) const { fout << "f " << m_frame << "\n"; for (const auto & unit : m_units) { unit.writeToFile(fout); fout << "\n"; } } }; class GameMap { int m_width = 0; int m_height = 0; std::vector m_walkable; public: GameMap() : m_width(BWAPI::Broodwar->mapWidth() * 4) , m_height(BWAPI::Broodwar->mapHeight() * 4) , m_walkable(BWAPI::Broodwar->mapHeight() * BWAPI::Broodwar->mapWidth() * 16, 0) { for (int h(0); h < m_height; ++h) { for (int w(0); w < m_width; ++w) { m_walkable[h*w + w] = BWAPI::Broodwar->isWalkable(h, w); } } } void writeToFile(std::ofstream & fout) const { } }; class GameHistory { GameMap m_map; std::vector m_frames; int m_frameSkip = 0; public: GameHistory() { } void setFrameSkip(int frames) { m_frameSkip = frames; } void onFrame() { if (m_frames.empty() || (BWAPI::Broodwar->getFrameCount() - m_frames.back().getFrame() >= m_frameSkip)) { m_frames.push_back(GameFrame()); } } void writeToFile(const std::string & filename) const { std::ofstream fout(filename); for (const auto & frame : m_frames) { frame.writeToFile(fout); } fout.close(); } }; ================================================ FILE: UAlbertaBot/Source/research/HardCodedInfo.cpp ================================================ /*#include "Common.h" #include "BWAPI.h" #include "HardCodedInfo.h" // gotta keep c++ static happy HardCodedInfo * HardCodedInfo::Instance() = NULL; // constructor HardCodedInfo::HardCodedInfo() { setChokeDefendLocations(); } // get an instance of this HardCodedInfo * HardCodedInfo::Instance() { // if the instance doesn't exist, create it if (!HardCodedInfo::Instance()) { HardCodedInfo::Instance() = new HardCodedInfo(); } return HardCodedInfo::Instance(); } void HardCodedInfo::setChokeDefendLocations() { // (2)Benzene.scx ---- af618ea3ed8a8926ca7b17619eebcb9126f0d8b1 mainChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"] = std::vector(); mainChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"].push_back(BWAPI::Position(3334, 953)); mainChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"].push_back(BWAPI::Position(741, 2614)); naturalChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"] = std::vector(); naturalChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"].push_back(BWAPI::Position(3683, 1530)); naturalChokes["af618ea3ed8a8926ca7b17619eebcb9126f0d8b1"].push_back(BWAPI::Position(368, 1994)); // (2)Destination.scx ---- 4e24f217d2fe4dbfa6799bc57f74d8dc939d425b mainChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"] = std::vector(); mainChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"].push_back(BWAPI::Position(1417, 3752)); mainChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"].push_back(BWAPI::Position(1610, 311)); naturalChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"] = std::vector(); naturalChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"].push_back(BWAPI::Position(1049, 3274)); naturalChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"].push_back(BWAPI::Position(2015, 805)); //mainChokes["4e24f217d2fe4dbfa6799bc57f74d8dc939d425b"].push_back(BWAPI::Position(, )); // (2)Heartbreak Ridge.scx ---- 6f8da3c3cc8d08d9cf882700efa049280aedca8c mainChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"] = std::vector(); mainChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"].push_back(BWAPI::Position(3635, 1387)); mainChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"].push_back(BWAPI::Position(439, 1752)); naturalChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"] = std::vector(); naturalChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"].push_back(BWAPI::Position(3336, 859)); naturalChokes["6f8da3c3cc8d08d9cf882700efa049280aedca8c"].push_back(BWAPI::Position(694, 2234)); // (3)Aztec.scx ---- ba2fc0ed637e4ec91cc70424335b3c13e131b75a mainChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"] = std::vector(); mainChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(3158, 481)); mainChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(3049, 3589)); mainChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(522, 1865)); naturalChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"] = std::vector(); naturalChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(3158, 481)); naturalChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(3049, 3589)); naturalChokes["ba2fc0ed637e4ec91cc70424335b3c13e131b75a"].push_back(BWAPI::Position(522, 1865)); // (3)Tau Cross.scx ---- 9bfc271360fa5bab3707a29e1326b84d0ff58911 mainChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"] = std::vector(); mainChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(274, 894)); mainChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(3825, 1134)); mainChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(2219, 3677)); naturalChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"] = std::vector(); naturalChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(891, 591)); naturalChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(3406, 1392)); naturalChokes["9bfc271360fa5bab3707a29e1326b84d0ff58911"].push_back(BWAPI::Position(1675, 3419)); // (4)Andromeda.scx ---- 1e983eb6bcfa02ef7d75bd572cb59ad3aab49285 mainChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"] = std::vector(); mainChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(3716, 1023)); mainChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(346, 1031)); mainChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(338, 3026)); mainChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(3690, 3041)); naturalChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"] = std::vector(); naturalChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(3028, 1052)); naturalChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(1004, 1034)); naturalChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(914, 3101)); naturalChokes["1e983eb6bcfa02ef7d75bd572cb59ad3aab49285"].push_back(BWAPI::Position(3075, 3064)); // (4)Circuit Breaker.scx ---- 450a792de0e544b51af5de578061cb8a2f020f32 mainChokes["450a792de0e544b51af5de578061cb8a2f020f32"] = std::vector(); mainChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(3948, 797)); mainChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(143, 800)); mainChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(171, 3285)); mainChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(3906, 3289)); naturalChokes["450a792de0e544b51af5de578061cb8a2f020f32"] = std::vector(); naturalChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(3489, 1115)); naturalChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(589, 1113)); naturalChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(602, 3005)); naturalChokes["450a792de0e544b51af5de578061cb8a2f020f32"].push_back(BWAPI::Position(3487, 3008)); // (4)Empire of the Sun.scm ---- a220d93efdf05a439b83546a579953c63c863ca7 mainChokes["a220d93efdf05a439b83546a579953c63c863ca7"] = std::vector(); mainChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(3325, 3831)); mainChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(3344, 304)); mainChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(738, 287)); mainChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(753, 3815)); naturalChokes["a220d93efdf05a439b83546a579953c63c863ca7"] = std::vector(); naturalChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(2945, 3547)); naturalChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(2927, 487)); naturalChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(1128, 522)); naturalChokes["a220d93efdf05a439b83546a579953c63c863ca7"].push_back(BWAPI::Position(1143, 3507)); // (4)Fortress.scx ---- 83320e505f35c65324e93510ce2eafbaa71c9aa1 mainChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"] = std::vector(); mainChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(1810, 3863)); mainChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(3667, 2181)); mainChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(397, 1904)); mainChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(2188, 249)); naturalChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"] = std::vector(); naturalChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(1559, 3612)); naturalChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(3471, 2477)); naturalChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(583, 1628)); naturalChokes["83320e505f35c65324e93510ce2eafbaa71c9aa1"].push_back(BWAPI::Position(2492, 506)); // (4)Python.scx ---- de2ada75fbc741cfa261ee467bf6416b10f9e301 mainChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"] = std::vector(); mainChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(2064, 114)); mainChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(2001, 3957)); mainChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(3874, 1812)); mainChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(156, 2262)); naturalChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"] = std::vector(); naturalChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(1803, 607)); naturalChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(2218, 3553)); naturalChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(3391, 2047)); naturalChokes["de2ada75fbc741cfa261ee467bf6416b10f9e301"].push_back(BWAPI::Position(618, 2058)); } BWAPI::Position HardCodedInfo::getChokepoint(ChokeType type, BWAPI::Player * player) { // get and assert we know where this player is BWTA::BaseLocation * mainBaseLocation = BWTA::getStartLocation(player); assert(mainBaseLocation); // get the position of the main base BWAPI::Position mainBasePosition = mainBaseLocation->getPosition(); // find the closest main choke point to this location double closestDist = 10000; BWAPI::Position closestPos(10000,10000); std::vector & chokes = (type == MAIN_CHOKE) ? mainChokes[BWAPI::Broodwar->mapHash()] : naturalChokes[BWAPI::Broodwar->mapHash()]; BOOST_FOREACH (BWAPI::Position p, chokes) { double dist = p.getDistance(mainBasePosition); if (dist < closestDist) { closestDist = dist; closestPos = p; } } assert(closestPos.isValid()); return closestPos; } void HardCodedInfo::drawChokePoints() { BOOST_FOREACH(BWAPI::Position p, mainChokes[BWAPI::Broodwar->mapHash()]) { if (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(p.x(), p.y(), 10, BWAPI::Colors::Purple, true); } BOOST_FOREACH(BWAPI::Position p, naturalChokes[BWAPI::Broodwar->mapHash()]) { if (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(p.x(), p.y(), 10, BWAPI::Colors::Purple, true); } }*/ ================================================ FILE: UAlbertaBot/Source/research/HardCodedInfo.h ================================================ /*#pragma once #include "Common.h" #include "BWTA.h" #include class HardCodedInfo { std::ofstream logStream; std::string logFile; HardCodedInfo(); static HardCodedInfo * instance; void setChokeDefendLocations(); std::map> mainChokes; std::map> naturalChokes; public: enum ChokeType {MAIN_CHOKE, NATURAL_CHOKE, CHOKE_TYPES}; static HardCodedInfo * Instance; void drawChokePoints(); BWAPI::Position getChokepoint(ChokeType type, BWAPI::Player * player); }; */ ================================================ FILE: UAlbertaBot/Source/research/MapGrid.cpp ================================================ #include "Common.h" #include "MapGrid.h" #include "Global.h" using namespace UAlbertaBot; MapGrid::MapGrid() { mapWidth = BWAPI::Broodwar->mapWidth()*32; mapHeight = BWAPI::Broodwar->mapHeight()*32; cellSize = Config::Tools::MAP_GRID_SIZE; cols = (mapWidth + cellSize - 1) / cellSize; rows = (mapHeight + cellSize - 1) / cellSize; cells = std::vector(rows * cols); lastUpdated = 0; calculateCellCenters(); } BWAPI::Position MapGrid::getNaturalExpansion() { return naturalExpansion; } BWAPI::Position MapGrid::getLeastExplored() { int minSeen = 1000000; double minSeenDist = 0; int leastRow(0), leastCol(0); for (int r=0; rself()->getStartLocation())) > 0) { continue; } BWAPI::Position home(BWAPI::Broodwar->self()->getStartLocation()); double dist = home.getDistance(getCellByIndex(r, c).center); int lastVisited = getCellByIndex(r, c).timeLastVisited; if (lastVisited < minSeen || ((lastVisited == minSeen) && (dist > minSeenDist))) { leastRow = r; leastCol = c; minSeen = getCellByIndex(r, c).timeLastVisited; minSeenDist = dist; } } } return getCellCenter(leastRow, leastCol); } void MapGrid::calculateCellCenters() { PROFILE_FUNCTION(); for (int r=0; r < rows; ++r) { for (int c=0; c < cols; ++c) { GridCell & cell = getCellByIndex(r,c); int centerX = (c * cellSize) + (cellSize / 2); int centerY = (r * cellSize) + (cellSize / 2); // if the x position goes past the end of the map if (centerX > mapWidth) { // when did the last cell start int lastCellStart = c * cellSize; // how wide did we go int tooWide = mapWidth - lastCellStart; // go half the distance between the last start and how wide we were centerX = lastCellStart + (tooWide / 2); } else if (centerX == mapWidth) { centerX -= 50; } if (centerY > mapHeight) { // when did the last cell start int lastCellStart = r * cellSize; // how wide did we go int tooHigh = mapHeight - lastCellStart; // go half the distance between the last start and how wide we were centerY = lastCellStart + (tooHigh / 2); } else if (centerY == mapHeight) { centerY -= 50; } cell.center = BWAPI::Position(centerX, centerY); assert(cell.center.isValid()); } } } BWAPI::Position MapGrid::getCellCenter(int row, int col) { return getCellByIndex(row, col).center; } // clear the vectors in the grid void MapGrid::clearGrid() { for (size_t i(0); idrawLineMap(i*cellSize, 0, i*cellSize, mapHeight, BWAPI::Colors::Blue); } for (int j=0; jdrawLineMap(0, j*cellSize, mapWidth, j*cellSize, BWAPI::Colors::Blue); } for (int r=0; r < rows; ++r) { for (int c=0; c < cols; ++c) { GridCell & cell = getCellByIndex(r,c); BWAPI::Broodwar->drawTextMap(cell.center.x, cell.center.y, "Last Seen %d", cell.timeLastVisited); BWAPI::Broodwar->drawTextMap(cell.center.x, cell.center.y+10, "Row/Col (%d, %d)", r, c); } } } // clear the grid clearGrid(); //BWAPI::Broodwar->printf("MapGrid info: WH(%d, %d) CS(%d) RC(%d, %d) C(%d)", mapWidth, mapHeight, cellSize, rows, cols, cells.size()); // add our units to the appropriate cell for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { getCell(unit).ourUnits.insert(unit); getCell(unit).timeLastVisited = BWAPI::Broodwar->getFrameCount(); } // add enemy units to the appropriate cell for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getHitPoints() > 0) { getCell(unit).oppUnits.insert(unit); getCell(unit).timeLastOpponentSeen = BWAPI::Broodwar->getFrameCount(); } } } void MapGrid::GetUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits) { const int x0(std::max( (center.x - radius) / cellSize, 0)); const int x1(std::min( (center.x + radius) / cellSize, cols-1)); const int y0(std::max( (center.y - radius) / cellSize, 0)); const int y1(std::min( (center.y + radius) / cellSize, rows-1)); const int radiusSq(radius * radius); for(int y(y0); y<=y1; ++y) { for(int x(x0); x<=x1; ++x) { int row = y; int col = x; GridCell & cell(getCellByIndex(row,col)); if(ourUnits) { for (auto & unit : cell.ourUnits) { BWAPI::Position d(unit->getPosition() - center); if(d.x * d.x + d.y * d.y <= radiusSq) { if (!units.contains(unit)) { units.insert(unit); } } } } if(oppUnits) { for (auto & unit : cell.oppUnits) if (unit->getType() != BWAPI::UnitTypes::Unknown && unit->isVisible()) { BWAPI::Position d(unit->getPosition() - center); if(d.x * d.x + d.y * d.y <= radiusSq) { if (!units.contains(unit)) { units.insert(unit); } } } } } } } ================================================ FILE: UAlbertaBot/Source/research/MapGrid.h ================================================ #pragma once #include #include "MicroManager.h" namespace UAlbertaBot { class GridCell { public: int timeLastVisited; int timeLastOpponentSeen; BWAPI::Unitset ourUnits; BWAPI::Unitset oppUnits; BWAPI::Position center; GridCell() : timeLastVisited(0) , timeLastOpponentSeen(0) { } }; class MapGrid { friend class Global; MapGrid(); int cellSize; int mapWidth, mapHeight; int rows, cols; int lastUpdated; std::vector cells; void calculateCellCenters(); void clearGrid(); BWAPI::Position getCellCenter(int x, int y); BWAPI::Position naturalExpansion; public: void update(); void GetUnits(BWAPI::Unitset & units, BWAPI::Position center, int radius, bool ourUnits, bool oppUnits); BWAPI::Position getLeastExplored(); BWAPI::Position getNaturalExpansion(); GridCell & getCellByIndex(int r, int c) { return cells[r*cols + c]; } GridCell & getCell(BWAPI::Position pos) { return getCellByIndex(pos.y / cellSize, pos.x / cellSize); } GridCell & getCell(BWAPI::Unit unit) { return getCell(unit->getPosition()); } }; } ================================================ FILE: UAlbertaBot/Source/research/combatpredictor/CombatPredictor.cpp ================================================ #include "CombatPredictor.h" using namespace UAlbertaBot; Combat::Combat(std::vector & ou, std::vector &eu, bool meOBS, bool oppOBS) { ourCombatUnits.clear(); enemyCombatUnits.clear(); HP.clear(); combatTime.clear(); unitTypes.clear(); unitIDS.clear(); std::vector startHp; forceFinish = false; I_have_Observers = meOBS; bothInvisUnits = false; if (ou.size() < 1 || eu.size() < 1) // NOT VALID { finished = true; return; } for (auto u : ou) { int t = u->getType(); int id = u->getID(); int hp = (u->getHitPoints() + u->getShields()); ourCombatUnits.push_back(u); startHp.push_back(u->getHitPoints() + u->getShields()); //special case for DTs, 61 - visible, 74 - invisible if (t == 61 && !oppOBS) { unitTypes.push_back(t + 13); bothInvisUnits = true; } else unitTypes.push_back(t); unitIDS.push_back(id); } unitTypes.push_back(-1); bool dtFlag = false; for (auto u : eu) { enemyCombatUnits.push_back(u); //special case for DTs if (u.type == 61 && !meOBS) { int hp_last = u.lastHealth; if (hp_last < 1) //if I saw it before keep the hp otherwise max hp for DT hp_last = 120; startHp.push_back(hp_last); unitTypes.push_back(u.type+13); dtFlag = true; } else { startHp.push_back(u.lastHealth); unitTypes.push_back(u.type); } unitIDS.push_back(u.unitID); } HP.push_back(startHp); combatStartTime = BWAPI::Broodwar->getFrameCount(); combatTime.push_back(0); finished = false; if (!dtFlag) bothInvisUnits = false; ID = CombatPredictor::Instance().combatID; CombatPredictor::Instance().combatID += 1; } bool Combat::isOneSideDead() { bool meDead = true; for (auto u : ourCombatUnits) { if (u->getHitPoints() + u->getShields() > 0) { meDead = false; break; } } if (meDead) return true; bool himDead = true; for (auto u : enemyCombatUnits) { int hp = CombatPredictor::Instance().observedHPs[u.unitID]; //if (search != temp.end() && search->second.lastHealth > 0) if (hp > 0) { himDead = false; break; } } return himDead; } void Combat::update() { int const elapsedTime = BWAPI::Broodwar->getFrameCount() - combatStartTime; bool process = false; //need to check if one of the players //has no units left if (isOneSideDead()) { //need to finish battle and log it off! process = true; forceFinish = true; } if (process || forceFinish) { //save new hp values combatTime.push_back(elapsedTime); std::vector startHp; //for me, already have pointers for (auto u : ourCombatUnits) { startHp.push_back(u->getHitPoints() + u->getShields()); } //for enemy, need to look in information manager for (auto u : enemyCombatUnits) { int hp = CombatPredictor::Instance().observedHPs[u.unitID]; //special case for invisible DTs if (u.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !I_have_Observers) { if (hp < 1) //if I saw it before keep the hp otherwise max hp for DT hp = 120; } startHp.push_back(hp); } HP.push_back(startHp); } if ((elapsedTime > 801) || forceFinish ) //finish fight, flush to disk { std::ostringstream oss; int id = ID; //CombatPredictor::Instance().combatID; //I don't want extremely short fights ... int total_startHP = std::accumulate(HP[0].begin(), HP[0].end(), 0); int total_endHP = std::accumulate(HP.back().begin(), HP.back().end(), 0); //if either 100hp damage total or 20% of inital hp int difHP = std::abs(total_endHP - total_startHP); if ((difHP < 100 && difHP*5 < total_startHP )|| bothInvisUnits) { //SHORT battle, don't log oss << defWriteFolder << "s_battle_" << CombatPredictor::Instance().getSuffix() << "_" << id << ".txt"; writeToFile(oss.str(),false); } else { //PROPER battle oss << defWriteFolder << "battle_" << CombatPredictor::Instance().getSuffix() << "_" << id << ".txt"; writeToFile(oss.str(),true); } finished = true; } } void CombatPredictor::addCombat(Combat &c) { observedIDs; bool reinforcements = false; for (auto id : c.unitIDS) { UAB_ASSERT(id < 2000, "Too many units !!!"); if (!observedIDs[id]) //not observed, need to end previous battles - REINFORCEMENTS { reinforcements = true; observedIDs[id] = 1; //break; } } if (!reinforcements) //add combat //combats.push_back(c); // OR MAYBE NOT ADD COMBAT, IRRELEVANT? ; else { //need to finish all previous combats for (unsigned int i = 0; i < combats.size(); i++) { if (!combats[i].isFinished()) { //force update, and finish combats[i].forceFinish = true; combats[i].update(); } } //then add new combat combats.push_back(c); } } void Combat::writeToFile(std::string filename, bool valid4Train) { //this is the debug file std::ofstream logStream(filename); logStream << "Frame: " << combatStartTime << std::endl; logStream << "Unit Types: "; int otherPlayerIDX = 0, j = 0; for (int i : unitTypes) { if (i < 0) { logStream << " | "; otherPlayerIDX = j; } else logStream << i << " "; j++; } logStream << std::endl; logStream << " Unit IDs: "; j = 0; for (int i : unitIDS) { if (j == otherPlayerIDX) logStream << " | " << i << " "; else logStream << i << " "; j++; } logStream << std::endl; logStream << "-------------------------------" << std::endl; //write frame| HPs int i = 0; for (auto h : HP) { logStream << combatTime[i++] << " | "; for (auto u : h) logStream << u << " "; logStream << std::endl; } logStream.flush(); logStream.close(); if (valid4Train) { //this is the MATLAB training file (accumulator) std::ofstream trainStream(defWriteFolder + "train_" + CombatPredictor::Instance().getSuffix() + ".txt", std::ofstream::app); int counter = 0; trainStream << 0 << " " << combatTime.back() << " "; counter += 2; //write initial conditions bool p1 = true; for (unsigned int i = 0; i < unitTypes.size(); i++) { if (unitTypes[i] < 0) //switch players { p1 = false; } else { if (p1) trainStream << unitTypes[i] << " " << (HP[0])[i] << " "; if (!p1) trainStream << unitTypes[i] + MAX_UNIT_TYPES << " " << (HP[0])[i - 1] << " "; counter += 2; } } //need to add -1s to keep length to 150, easier for matlab to read while (counter++ < 150) trainStream << -1 << " "; trainStream << std::endl; //write result counter = 0; trainStream << 0 << " " << combatTime.back() << " "; counter += 2; p1 = true; for (unsigned int i = 0; i < unitTypes.size(); i++) { if (unitTypes[i] < 0) //switch players { p1 = false; } else { if (p1) trainStream << unitTypes[i] << " " << (HP.back())[i] << " "; if (!p1) trainStream << unitTypes[i] + MAX_UNIT_TYPES << " " << (HP.back())[i - 1] << " "; counter += 2; } } //need to add -1s to keep length to 150, easier for matlab to read while (counter++ < 150) trainStream << -1 << " "; trainStream << std::endl; trainStream.flush(); trainStream.close(); //write down results to compare % acccuracy std::ofstream resultStream(defWriteFolder + "results_" + CombatPredictor::Instance().getSuffix() + ".txt", std::ofstream::app); std::pair ltd = LTD2(); if (ltd.first > ltd.second *1.1) // P1 win resultStream << SparcraftPrediction << " " << MATLAB_Prediction << " " << 1 << " " << ltd.first / (ltd.second + 0.01) << std::endl; else if (ltd.second > ltd.first * 1.1) // P2 win resultStream << SparcraftPrediction << " " << MATLAB_Prediction << " " << -1 << " " << ltd.second / (ltd.first + 0.01) << std::endl; resultStream.flush(); resultStream.close(); } } std::pair Combat::LTD2() { bool p1 = true; float LTD_p1 = 0; float LTD_p2 = 0; float currentSum = 0; //float totalSum = 0; for (unsigned int i = 0; i < unitTypes.size(); i++) { if (unitTypes[i] < 0) //switch players { p1 = false; LTD_p1 = currentSum; currentSum = 0; } else { if (p1) { BWAPI::UnitType t = BWAPI::UnitType(unitTypes[i]); float dpf = CombatPredictor::Instance().dpf(t); currentSum += sqrtf((float)(HP.back())[i]) * dpf; } if (!p1) { BWAPI::UnitType t = BWAPI::UnitType(unitTypes[i]); float dpf = CombatPredictor::Instance().dpf(t); currentSum += sqrtf((float)(HP.back())[i-1]) * dpf; } } } LTD_p2 = currentSum; return std::pair(LTD_p1, LTD_p2); } CombatPredictor::CombatPredictor() { } CombatPredictor & CombatPredictor::Instance() { static CombatPredictor instance; return instance; } const float CombatPredictor::dpf(BWAPI::UnitType &ut) { float damage = BWAPI::UnitTypes::Protoss_Zealot ? 2 * (float)ut.groundWeapon().damageAmount() : (float)ut.groundWeapon().damageAmount(); float attackCooldown = (float)ut.groundWeapon().damageCooldown(); return (float)std::max(0.0f, damage / (attackCooldown + 1)); } void CombatPredictor::initUnitList() { std::srand((unsigned int)std::time(0)); uniqSuffix = BWAPI::Broodwar->enemy()->getName() + "_" + std::to_string(rand() % 1000); auto set = BWAPI::UnitTypes::allUnitTypes(); int len = set.size(); //pre-allocate memory //no more than 256 different unit types in StarCraft MaxHP.resize(256, 0); observedIDs.resize(2000, 0); observedHPs.resize(2000, -1); std::ofstream logStream(defWriteFolder +"predictorInit.txt"); for (auto type : set) { int maxHP = type.maxHitPoints() + type.maxShields(); int ID = type.getID(); logStream << ID << " " //<< type.getName() << " " << maxHP << " " << dpf(type)*maxHP << std::endl; //save the info MaxHP[ID] = maxHP; } logStream.flush(); logStream.close(); Sfeatures.clear(); SfA.clear(); SfB.clear(); //READ FEATURES std::string enemyFeatures = "f_" + BWAPI::Broodwar->enemy()->getName() + ".txt"; std::string enemyFile(defReadFolder + enemyFeatures); std::ifstream features; // (defReadFolder + enemyFeatures); features.open(enemyFile); if (features.is_open() && features.good()) { CombatPredictor::Instance().vsTrainedOpp = true; } else { //default features //std::ifstream features(defReadFolder + "features.txt"); features.open(defReadFolder + "f_default.txt"); UAB_ASSERT(features.is_open() && features.good(), "Couldn't open file %sf_default.txt", defReadFolder.c_str()); CombatPredictor::Instance().vsTrainedOpp = false; } if (features.is_open() && features.good()) { // read away std::string line; while (getline(features, line)) { double d = std::stod(line); Sfeatures.push_back(d); } features.close(); int nrS = Sfeatures.size() / 2; SfA = std::vector(&Sfeatures[0], &Sfeatures[nrS - 1]); SfB = std::vector(&Sfeatures[nrS], &Sfeatures[nrS * 2 - 1]); } } const SparCraft::ScoreType CombatPredictor::predictCombat(const HLUnitData &myUnits, const HLUnitData &oppUnits) { bool I_haveOBS = false; bool He_hasOBS = false; int nrA = 0; int nrB = 0; double sumA = 0.0; double sumB = 0.0; for (auto &iter : oppUnits.getUnits()) { const UnitInfo & ui(iter.second); if (ui.completed && ui.type.isDetector()) He_hasOBS = true; } for(auto &iter: myUnits.getUnits()) { const UnitInfo & ui(iter.second); if (ui.completed && ui.type.isDetector()) I_haveOBS = true; if (ui.completed && (ui.type.canAttack() || ui.type.isWorker() || ui.type.isDetector() || ui.type == BWAPI::UnitTypes::Terran_Medic || ui.type == BWAPI::UnitTypes::Protoss_Reaver || ui.type == BWAPI::UnitTypes::Terran_Bunker)) { if (ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !He_hasOBS) //invisible DT, unit ID 74 sumA += SfA[74] * ui.lastHealth / MaxHP[74]; else //visible DT or something else sumA += SfA[ui.type] * ui.lastHealth / MaxHP[ui.type]; nrA += 1; } } for(auto &iter: oppUnits.getUnits()) { const UnitInfo & ui(iter.second); if (ui.completed && (ui.type.canAttack() || ui.type.isWorker() || ui.type.isDetector() || ui.type == BWAPI::UnitTypes::Terran_Medic || ui.type == BWAPI::UnitTypes::Protoss_Reaver || ui.type == BWAPI::UnitTypes::Terran_Bunker)) { if (ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar && !He_hasOBS) //invisible DT { //TODO: make sure ui.lastHealth is not 0 for invisible DTs UAB_ASSERT(ui.lastHealth > 0, "Invisible DT has HP zero ?!"); sumB += SfB[74] * ui.lastHealth / MaxHP[74]; } else //visible DT or something else sumB += SfB[ui.type] * ui.lastHealth / MaxHP[ui.type]; nrB += 1; } } return (int)((pow(nrA, power - 1)*sumA - pow(nrB, power - 1)*sumB)*100.0); } SparCraft::ScoreType CombatPredictor::predictCombat(std::vector> &ArmyA, std::vector> &ArmyB) { int nrA = 0; int nrB = 0; double sumA = 0.0; double sumB = 0.0; for (auto p : ArmyA) { //p.first = ID of unit //p.secont = current HP+shielcs of unit sumA += SfA[p.first] * p.second / MaxHP[p.first]; nrA += 1; } for (auto p : ArmyB) { //p.first = ID of unit //p.secont = current HP+shielcs of unit sumB += SfB[p.first] * p.second / MaxHP[p.first]; nrB += 1; } return (int) ((pow(nrA, power - 1)*sumA - pow(nrB, power - 1)*sumB)*10.0); //convert to LTD2 ? for now it only matters if > 0 or < 0, so no need. } ================================================ FILE: UAlbertaBot/Source/research/combatpredictor/CombatPredictor.h ================================================ #pragma once #include "Common.h" #include "MapGrid.h" #include "HLUnitData.h" #ifdef USING_VISUALIZATION_LIBRARIES #include "Visualizer.h" #endif #include "..\..\SparCraft\source\GameState.h" #include "..\..\SparCraft\source\Game.h" #include "..\..\SparCraft\source\Unit.h" #include "..\..\SparCraft\source\AllPlayers.h" #include "InformationManager.h" #include namespace UAlbertaBot { const int MAX_UNIT_TYPES = 234 ; //TODO: double check const std::string defWriteFolder = "bwapi-data/write/"; const std::string defReadFolder = "bwapi-data/"; class Combat { std::vector ourCombatUnits; std::vector enemyCombatUnits; std::vector unitTypes; std::vector > HP; int combatStartTime; std::vector combatTime; bool finished; bool bothInvisUnits; int ID; bool I_have_Observers; public: int SparcraftPrediction; int MATLAB_Prediction; bool forceFinish; std::vector unitIDS; Combat(std::vector & ou, std::vector &eu, bool meOBS, bool oppOBS); void update(); void writeToFile(std::string filename, bool valid4train); bool isFinished(){ return finished; } bool isOneSideDead(); std::pair LTD2(); }; class CombatPredictor { double power = 1.52; std::vector Sfeatures; std::vector SfA; std::vector SfB; std::vector MaxHP; std::vector observedIDs; std::string uniqSuffix; public: bool vsTrainedOpp = false; int combatID = 0; std::vector combats; std::vector observedHPs; CombatPredictor(); static CombatPredictor & Instance(); void initUnitList(); std::string getSuffix(){ return uniqSuffix; }; const float CombatPredictor::dpf(BWAPI::UnitType &ut); const SparCraft::ScoreType predictCombat(const HLUnitData &myUnits, const HLUnitData &oppUnits); //predict combat, for each army need {ID, current HP+shields} x each unit SparCraft::ScoreType predictCombat(std::vector> &ArmyA, std::vector> &ArmyB); void updateFeatures(int afterHowManyNewBattles); void retrainMATLAB_model(); void addCombat(Combat &c); }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLCombatCommander.cpp ================================================ #include "HLCombatCommander.h" using namespace UAlbertaBot; HLCombatCommander::HLCombatCommander(){ } HLCombatCommander::~HLCombatCommander() { } void HLCombatCommander::update(std::set combatUnits) { //if (squadUpdateFrame()) //{ // // clear all squad data // squadData.clearSquadData(); // // give back combat workers to worker manager // WorkerManager::Instance().finishedWithCombatWorkers(); // for (auto& s : HLSearch::Instance().getSquads(combatUnits)){ // squadData.addSquad(s); // } //} //squadData.update(); combatCommander.update(combatUnits); } bool HLCombatCommander::squadUpdateFrame() const { return BWAPI::Broodwar->getFrameCount() % 24 == 0; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLCombatCommander.h ================================================ #pragma once #include "Common.h" #include "Squad.h" #include "HLSearch.h" #include "SquadData.h" #include "CombatCommander.h" namespace UAlbertaBot { class HLCombatCommander { SquadData squadData; CombatCommander combatCommander; public: HLCombatCommander(); ~HLCombatCommander(); void update(std::set combatUnits); bool squadUpdateFrame() const; }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLManager.cpp ================================================ #include "HLManager.h" #include "base/ProductionManager.h" using namespace UAlbertaBot; HLManager::HLManager() { BWAPI::Broodwar->printf("High Level Manager Instantiated"); Logger::LogAppendToFile(UAB_LOGFILE, "State size: %d", sizeof(HLState)); } HLManager::~HLManager() { } HLManager & HLManager::Instance() { static HLManager instance; return instance; } void HLManager::update() { //static bool firstRun = true; //static int frame = 0; //if ((firstRun && !ProductionManager::Instance().runningOpeningBook()) // ||(!firstRun && (++frame%2000==0))) //{ // firstRun = false; static int cumulativeSearchTime = 0; if (cumulativeSearchTime>39000) { BWAPI::Broodwar->printf("Too much time searching, skipping HL search"); Logger::LogAppendToFile(UAB_LOGFILE, "\nToo much time searching, skipping HL search"); cumulativeSearchTime+= _search.search(0, 0, 0); return; } else if (cumulativeSearchTime > 36000) { BWAPI::Broodwar->printf("Too much time searching, short HL search: %d[ms]", 42000 - cumulativeSearchTime); Logger::LogAppendToFile(UAB_LOGFILE, "\nToo much time searching, short HL search: %d[ms]", 42000 - cumulativeSearchTime); cumulativeSearchTime+=_search.search(42000 - cumulativeSearchTime, 10000, 40); } else { cumulativeSearchTime+=_search.search(6000, 10000, 40); } auto move = _search.getBestMove(); StrategyManager::Instance().setCurrentStrategy(move.getStrategy(),move.getChoices()); BWAPI::Broodwar->printf("Setting move %s\n", move.toString().c_str()); Logger::LogAppendToFile(UAB_LOGFILE, "Setting move %s\n", move.toString().c_str()); // ProductionManager::Instance().purgeQueue(); //} } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLManager.h ================================================ #pragma once #include "Common.h" #include "Squad.h" #include "HLSearch.h" #include "ScoutManager.h" namespace UAlbertaBot { class HLManager { //ScoutManager scoutManager; HLManager(); ~HLManager(); HLSearch _search; public: static HLManager & Instance(); void update(); //void update( // std::set combatUnits, // std::set scoutUnits, // std::set workerUnits); }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLSearch.cpp ================================================ #include "HLSearch.h" #include "../../BOSS/source/BOSS.h" using namespace UAlbertaBot; HLSearch::HLSearch() :_tt(20000), _cache(20000), _bestMove(StrategyManager::ProtossHighLevelSearch) { } HLSearch::~HLSearch() { } long long HLSearch::search(double timeLimit, int frameLimit, int maxHeight) { _stats.clear(); _stats.startTimer(); _timeUp = false; _timeLimitMs = timeLimit; HLState state(BWAPI::Broodwar, BWAPI::Broodwar->self(), BWAPI::Broodwar->enemy()); int currentEval = state.evaluate(BWAPI::Broodwar->self()->getID()); Logger::LogAppendToFile(UAB_LOGFILE, "\n\nStarting search at frame %d, static eval: %d\n", BWAPI::Broodwar->getFrameCount(), currentEval); //if (currentEval > 150 || currentEval < -200) //{ // Logger::LogAppendToFile(UAB_LOGFILE, "Game seems decided, skipping HL search\n"); // return _stats.getRunningTimeMilliSecs(); //} _minFrame = 1000000; Logger::LogAppendToFile(UAB_LOGFILE, _stats.header() + " score\tbest move\tmin frame\tmax frame\n"); //for (int height = 2; height <= maxHeight && !_timeUp; height += 2) //{ int height = maxHeight; for (int frames = 2000; frames <= frameLimit && !_timeUp; frames += 2000) { _maxFrame = 0; int prevFrame = _minFrame; _minFrame = 1000000; int score = alphaBeta(state, 0, height, state.currentFrame() + frames, BWAPI::Broodwar->self()->getID(), HLMove(), MIN_SCORE, MAX_SCORE); Logger::LogAppendToFile(UAB_LOGFILE, _stats.toString()); Logger::LogAppendToFile(UAB_LOGFILE, " %d %s %d %d\n", score, _bestMove.toString().c_str(), _minFrame - state.currentFrame(), _maxFrame - state.currentFrame()); if (prevFrame == _minFrame || (_minFrame - state.currentFrame()) > frameLimit) { break; } } return _stats.getRunningTimeMilliSecs(); } int HLSearch::alphaBeta(const HLState& state, int depth, int height, int frameLimit, int turn, const HLMove &firstSideMove, int alpha, int beta) { _stats.incNodeCount(); if (firstSideMove.isEmpty() && (height <=0 || state.currentFrame() >= frameLimit || state.gameOver())){ if (state.currentFrame() < _minFrame) { _minFrame = state.currentFrame(); } if (state.currentFrame() > _maxFrame) { _maxFrame = state.currentFrame(); } return state.evaluate(turn); } if (_stats.getNodeCount() % 10 && _stats.getRunningTimeMilliSecs() > _timeLimitMs) { _timeUp = true; } int score = MIN_SCORE; int al = alpha; HLMove bestMove; int i = 0; HLMove ttBest; if (firstSideMove.isEmpty()) { _stats.incTTquery(); const HLEntry &e = _tt.lookup(state); if (e._hash == state.getHash()) { _stats.incTTfound(); ttBest = e._bestMove; } } else { _stats.incTTquery(); const HLEntry &e = _tt.lookup(state, depth,firstSideMove); if (e._hash == state.getHash(depth, firstSideMove)) { _stats.incTTfound(); ttBest = e._bestMove; } } ////todo: use value to return or at least shrink alpha-beta window? auto &moves = state.getMoves(turn); UAB_ASSERT(moves.size() != 0, "No moves generated at depth %d", depth); if (!ttBest.isEmpty()) { auto it=std::find(moves.begin(), moves.end(), ttBest); UAB_ASSERT(it != moves.end(), "Couldn't find best move among valid moves"); if (it != moves.end()) { std::iter_swap(it, moves.begin()); } } //std::sort(moves.begin(), moves.end(), [this, &state, depth](const HLMove &m1, const HLMove &m2) //{ // _stats.incTTquery(); // const HLEntry &e1 = _tt.lookup(state, depth, m1); // if (e1._hash != state.getHash(depth, m1)) // { // return false; // } // _stats.incTTfound(); // _stats.incTTquery(); // const HLEntry &e2 = _tt.lookup(state, depth, m2); // if (e2._hash != state.getHash(depth, m2)) // { // return true; // } // _stats.incTTfound(); // return e1._value > e2._value; //}); for (auto it = moves.begin(); it != moves.end() && !_timeUp;it++){ auto m = *it; //Logger::LogAppendToFile(UAB_LOGFILE, "Searching depth %d, move %s, move %s\n", depth, firstSideMove.toString().c_str(), m.toString().c_str()); int value; if (firstSideMove.isEmpty()){ value = alphaBeta(state, depth + 1, height - 1, frameLimit, 1 - turn, m, -beta, -al); } else{ //Logger::LogAppendToFile(UAB_LOGFILE, "Start frame: %d\n", newState.currentFrame()); std::array < HLMove, 2 > movePair; if (turn == 1){ movePair = std::array < HLMove, 2 > { {firstSideMove, m} }; } else{//move for player 1 first movePair = std::array < HLMove, 2 > { {m, firstSideMove} }; } //Logger::LogAppendToFile(UAB_LOGFILE, "Turn %d depth %d Checking moves: %s %s hash: %u\n", turn, depth, // firstSideMove.toString().c_str(), m.toString().c_str(), state.getHash(depth,movePair)); try { _stats.incCacheQuery(); const auto &entry = _cache.lookup(state, depth, movePair); if (entry._hash == state.getHash(depth, movePair))//found { _stats.incCacheFound(); //Logger::LogAppendToFile(UAB_LOGFILE, "Moves "+ firstSideMove.toString() + m.toString()+" matches\n"); //Logger::LogAppendToFile(UAB_LOGFILE, " hashes: %u %u\n", entry._hash, entry._state.getHash()); if (state.currentFrame() == entry._state.currentFrame()){//didn't progress //Logger::LogAppendToFile(UAB_LOGFILE, "No progress (cached)"); continue; } value = alphaBeta(entry._state, depth + 1, height - 1, frameLimit, 1 - turn, HLMove(), -beta, -al); } else { HLState newState(state); newState.applyAndForward(depth, frameLimit-newState.currentFrame(), movePair); if (state.currentFrame() == newState.currentFrame()){//didn't progress //Logger::LogAppendToFile(UAB_LOGFILE, "No progress"); continue; } _stats.addFwd(newState.currentFrame() - state.currentFrame()); _cache.store(state, depth, movePair, newState); value = alphaBeta(newState, depth + 1, height - 1, frameLimit, 1 - turn, HLMove(), -beta, -al); } } catch (const BOSS::Assert::BOSSException &){ //Logger::LogAppendToFile(UAB_LOGFILE, "No Legal build order"); continue;//couldn't find legal build order, skip } } i++; if (value > score){ score = value; bestMove = m; if (value > alpha){ al = value; if (al >= beta){ break; } } } //break;//temporary, let's only check 1 move wide } if (!_timeUp) { _stats.addBF(i); if (firstSideMove.isEmpty()) { _tt.store(state, bestMove, score, alpha, beta, height); } else { _tt.store(state, depth, firstSideMove, bestMove, score, alpha, beta, height); } } if (depth == 0){ if (!bestMove.isEmpty()) { _bestMove = bestMove; } else if (height == 2)//only use default move if first ID iteration { //_bestMove = HLMove(StrategyManager::ProtossHighLevelSearch); Logger::LogAppendToFile(UAB_LOGFILE, "Couldn't find a strategy, using default\n"); } } return score; } HLMove HLSearch::getBestMove() { return _bestMove; } //std::vector HLSearch::getSquads(const std::set & combatUnits) //{ // auto searchSquads = _bestMove.getSquads(); // std::set unitsToAdd(combatUnits.begin(),combatUnits.end()); // // //remove non combat units // for (auto &s : searchSquads){ // for (unsigned int i = 0; i < s.getUnits().size();i++){ // auto &u = s.getUnits()[i]; // if (combatUnits.count(u) == 0){//if unit is not combat, remove it from squad // s.removeUnit(u); // i--; // } // else{//unit already assigned // unitsToAdd.erase(u); // } // } // } // // //assign remaining units // for (auto &u : unitsToAdd){ // bool assigned=false; // for (auto &s : searchSquads){ // if (u->getRegion() == s.getRegion()){ // s.addUnit(u); // assigned = true; // break; // } // } // if (!assigned){//create new squad // std::vector unit(1, u); // searchSquads.push_back(HLSquad(unit, SquadOrder())); // } // } // // std::vector squads(searchSquads.size()); // //transform HLSquad into Squad // std::transform(searchSquads.begin(), searchSquads.end(), squads.begin(), // [](const HLSquad &s){return static_cast(s); }); // // return squads; //} ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLSearch.h ================================================ #pragma once #include "Common.h" #include "Squad.h" #include "HLState.h" #include "HLStatistics.h" #include "HLTranspositionTable.h" namespace UAlbertaBot { const static int MIN_SCORE = std::numeric_limits::min() + 1, MAX_SCORE = std::numeric_limits::max() - 1; class HLSearch { //std::list > _strategicPV;//frame,strategy //std::list > _tacticalPV;//frame,squad //todo:switch these to priority_queues? HLStatistics _stats; HLMove _bestMove; //saved by the search int alphaBeta(const HLState& state, int depth, int height, int frameLimit, int turn, const HLMove &firstSideMove, int alpha, int beta); //void uct(const HLState &state, int playouts); //const int _defaultStrategy = 0; HLTranspositionTable _tt; HLCacheTable _cache; bool _timeUp; int _timeLimitMs; int _maxFrame,_minFrame; public: HLSearch(const UAlbertaBot::HLSearch &) = delete; HLSearch(); ~HLSearch(); long long search(double timeLimit, int frameLimit, int maxHeight); //std::vector getSquads(const std::set & combatUnits);//get Squads and orders //std::set getScouts(); HLMove getBestMove(); }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLSquad.cpp ================================================ #include "HLSquad.h" using namespace UAlbertaBot; HLSquadOrder::HLSquadOrder() : _type(None) { } HLSquadOrder::HLSquadOrder(OrderType type, BWTA::Region* target) : _type(type) , _target(target) { } HLSquad::HLSquad(const std::vector & units, BWTA::Region *region) : _currentRegion(region), _framesTravelled(0), //_units(units.begin(),units.end()), _order(), _speed(std::min_element(units.begin(), units.end(), [](const UnitInfo &u1, const UnitInfo &u2) { return u1.type.topSpeed() < u2.type.topSpeed(); })->type.topSpeed()), _strengthCalculated(false) { for (const auto &unit : units) { _units[unit.unitID] = unit; } UAB_ASSERT(_currentRegion != NULL, "Current region is null!"); } void HLSquad::addUnit(const UnitInfo &unit) { _speed = std::min(_speed, unit.type.topSpeed()); _strengthCalculated = false; _units[unit.unitID]=unit; } int HLSquad::travel(int frames) { _framesTravelled += frames; if (!_path.empty()) { int framesToNext; while (!_path.empty() && (_framesTravelled > (framesToNext = _currentRegion->getCenter().getDistance(_path.front()->getCenter()) / _speed))) { _currentRegion = _path.front(); UAB_ASSERT(_currentRegion != NULL, "Current region is null!"); _path.pop_front(); _framesTravelled -= framesToNext; } } if (_path.empty())//reached destination { int remainingFrames = _framesTravelled; _framesTravelled = 0; return remainingFrames; } return 0; } void HLSquad::order(HLSquadOrder order) { if (order._type == HLSquadOrder::Attack || order._type == HLSquadOrder::Defend) { UAB_ASSERT(_currentRegion != NULL, "Current region is null!"); _path = getPath(_currentRegion, order._target); } else if (order._type ==HLSquadOrder::None) { _path.clear(); } _order = order; _framesTravelled = 0; } int HLSquad::getStrength() const { if (!_strengthCalculated) { calculateStrength(); } return _strength; } int HLSquad::getGroundStrength() const { if (!_strengthCalculated) { calculateStrength(); } return _groundStrength; } int HLSquad::getAntiAirStrength() const { if (!_strengthCalculated) { calculateStrength(); } return _antiAirStrength; } int HLSquad::getFlyingStrength() const { if (!_strengthCalculated) { calculateStrength(); } return _flyingStrength; } void HLSquad::calculateStrength() const { _groundStrength = _flyingStrength = _antiAirStrength = _strength = 0; for (auto u : _units) { if (u.second.type.airWeapon() != BWAPI::WeaponTypes::None) { _antiAirStrength++; } if (u.second.type.groundWeapon() != BWAPI::WeaponTypes::None) { _groundStrength++; } if (u.second.type.airWeapon() != BWAPI::WeaponTypes::None || u.second.type.groundWeapon() != BWAPI::WeaponTypes::None) { if (u.second.isFlyer()) { _flyingStrength++; } _strength++; } } } //class Node{ // const BWTA::Region* region; // int gscore, hscore; //public: // int f_score() const{ return gscore + hscore; } // int g_score() const{ return gscore; } // Node(const BWTA::Region* r, int g, int h) :region(r), gscore(g), hscore(h){} // const BWTA::Region* getRegion() const{ return region; } // bool operator==(const Node &other){ return this->region == other.region; } //}; struct NodeComp{ const std::unordered_map &_g_score, &_f_score; NodeComp(const std::unordered_map &g_score, const std::unordered_map &f_score) : _g_score(g_score), _f_score(f_score){} bool operator()(BWTA::Region *r1, BWTA::Region *r2) const{ return _f_score.at(r1) < _f_score.at(r2); }; }; //namespace std{ // template<>struct hash < Node > { // size_t operator()(const Node &n){ // return std::hash()(n.getRegion()); // } // }; //} std::list reconstruct_path(const std::unordered_map &came_from, BWTA::Region *current) { std::list total_path; total_path.push_front(current); while (came_from.count(current) > 0) { current = came_from.at(current); total_path.push_front(current); } return total_path; } std::list UAlbertaBot::getPath(BWTA::Region *from, BWTA::Region *to) { //Logger::LogAppendToFile(UAB_LOGFILE, "Performing A*"); std::unordered_set closed; std::unordered_set open; std::vector open_queue; std::unordered_map came_from; std::unordered_map g_score; std::unordered_map f_score; NodeComp comp(g_score,f_score); open.insert(from); open_queue.push_back(from); g_score[from] = 0; f_score[from] = g_score[from] + from->getCenter().getApproxDistance(to->getCenter()); std::make_heap(open_queue.begin(), open_queue.end(), comp); //while openset is not empty while (!open_queue.empty()) { //current : = the node in openset having the lowest f_score[] value auto current = open_queue.front(); //if current = goal if (current == to) { return reconstruct_path(came_from, to); } // remove current from openset std::pop_heap(open_queue.begin(), open_queue.end(), comp); open_queue.pop_back(); open.erase(current); // for each neighbor in neighbor_nodes(current) for (auto n : getNeighbours(current)) { // if neighbor in closedset if (closed.find(n) != closed.end()) { continue; } //tentative_g_score: = g_score[current] + dist_between(current, neighbor) int tentative_g_score = g_score.at(current) + current->getCenter().getApproxDistance(n->getCenter()); // if neighbor not in openset or tentative_g_score < g_score[neighbor] auto stored = open.find(n); if (stored == open.end() || tentative_g_score < g_score.at(n)) { // came_from[neighbor] : = current came_from[n] = current; // g_score[neighbor] : = tentative_g_score g_score[n] = tentative_g_score; // f_score[neighbor] : = g_score[neighbor] + heuristic_cost_estimate(neighbor, goal) f_score[n] = g_score.at(n) + n->getCenter().getApproxDistance(to->getCenter()); // if neighbor not in openset if (stored == open.end()) // add neighbor to openset { open.insert(n); open_queue.push_back(n); std::push_heap(open_queue.begin(), open_queue.end(), comp); } else//value updated, need to re-sort { std::make_heap(open_queue.begin(), open_queue.end(), comp); } } } // add current to closedset closed.insert(current); } } std::unordered_set UAlbertaBot::getNeighbours(const BWTA::Region *region) { std::unordered_set neighbours; for (auto c : region->getChokepoints()) { if (c->getRegions().first != region) { neighbours.insert(c->getRegions().first); } else { neighbours.insert(c->getRegions().second); } } return neighbours; } std::string HLSquad::toString() const { std::stringstream ss; ss << "Squad at " << _currentRegion->getCenter() << ", Units: "; for (auto u : _units) { ss << u.second.type.getName() << " "; } return ss.str(); } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLSquad.h ================================================ #pragma once #include "Common.h" #include "HLUnitData.h" namespace UAlbertaBot{ class HLSquadOrder { public: enum OrderType { None, Attack, Defend, SquadOrderTypes }; OrderType _type; BWTA::Region* _target; HLSquadOrder(); HLSquadOrder(OrderType type, BWTA::Region* target); }; class HLSquad{ BWTA::Region *_currentRegion; std::list _path; int _framesTravelled; std::unordered_map _units; HLSquadOrder _order; double _speed; mutable int _groundStrength; mutable int _flyingStrength; mutable int _antiAirStrength; mutable int _strength; mutable bool _strengthCalculated; public: HLSquad(const std::vector & units, BWTA::Region *region); ~HLSquad(){}; void addUnit(const UnitInfo &unit); double getSpeed() const{ return _speed; } bool hasPath() const{ return !_path.empty(); } BWTA::Region* getNextRegion() const{ return _path.front(); } BWTA::Region* getCurrentRegion() const{ return _currentRegion; } int getTravelledTime() const{ return _framesTravelled; } int travel(int frames); int getGroundStrength() const; int getStrength() const; int getAntiAirStrength() const; int getFlyingStrength() const; void calculateStrength() const; void order(HLSquadOrder order); HLSquadOrder order() const{ return _order; } //std::vector& getUnits() { return _units; } //const std::vector& getUnits() const { return _units; } void removeUnit(const UnitInfo &unit){ _units.erase(unit.unitID); } void removeUnit(int id){ _units.erase(id); _strengthCalculated = false; } //void removeUnit(const std::unordered_set::iterator &unit){ _units.erase(unit); _strengthCalculated = false; } //void updateUnit(const UnitInfo &unit) //{ // removeUnit(unit); // addUnit(unit); //} std::unordered_map::iterator begin(){ return _units.begin(); } std::unordered_map::iterator end(){ return _units.end(); } std::unordered_map::const_iterator begin() const{ return _units.begin(); } std::unordered_map::const_iterator end() const{ return _units.end(); } UnitInfo& operator[](const int &id){ return _units[id]; } UnitInfo& at(const int &id){ return _units.at(id); } bool empty() const{ return _units.empty(); } std::string toString() const; //HLSquad(const Squad &squad);//implicit conversion //bool done();//check if order completed //BWAPI::Region getRegion() const{ return region; } //void addUnit(BWAPI::UnitInterface *u){ Squad::addUnit(u); } //bool removeUnit(BWAPI::UnitInterface *u){ return Squad::removeUnit(u); } }; std::list getPath(BWTA::Region *from, BWTA::Region *to); std::unordered_set getNeighbours(const BWTA::Region *region); } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLState.cpp ================================================ #include "HLState.h" #include #include "CombatPredictor.h" using namespace UAlbertaBot; unsigned int HLState::_zobristChoice[20][StrategyManager::NumProtossStrategies][20][10]; unsigned int HLState::_zobristStrategy[20][StrategyManager::NumProtossStrategies]; //_dummy_static_initializer _dummy; HLState::HLState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, BWAPI::PlayerInterface * enemy) { UAB_ASSERT(player->getID() < 2, "Only player ids 0 and 1 supported"); UAB_ASSERT(enemy->getID() < 2, "Only player ids 0 and 1 supported"); _state[player->getID()] = BOSS::GameState(game, player); _state[enemy->getID()] = BOSS::GameState(game, enemy); _players[player->getID()] = player; _players[enemy->getID()] = enemy; addSquads(player); addSquads(enemy); //_buildOrderIndex[0] = 0; //_buildOrderIndex[1] = 0; //TODO:change this to take UnitData as parameter _unitData[player->getID()] = HLUnitData(InformationManager::Instance().getUnitData(player),player); _unitData[enemy->getID()] = HLUnitData(InformationManager::Instance().getUnitData(enemy), player); _workerData[player->getID()] = WorkerManager::Instance().getData(); _workerData[enemy->getID()] = WorkerData(); for (auto &u : enemy->getUnits()){ if (u->getType().isWorker()){ _workerData[enemy->getID()].addWorker(u); } } //_opening[0] = false; //_opening[1] = false; //todo: assign worker jobs //3 per gas, 3 per mineral patch, 1 to build, and if scout outside nexus region static std::mt19937 rng(1);//todo:use a seed? for (int depth = 0; depth < 20; depth++){ for (int s = 0; s < StrategyManager::NumProtossStrategies; s++){ _zobristStrategy[depth][s] = rng(); for (int point = 0; point < 20; point++){ for (auto c = 0; c < 10; c++){ _zobristChoice[depth][s][point][c] = rng(); } } } } _hash = rng(); } bool HLState::isNonWorkerCombatUnit(const BWAPI::UnitInterface *unit) { //if (unit->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar) //{ // UAB_ASSERT(InformationManager::Instance().isCombatUnit(unit->getType()) // && SparCraft::System::isSupportedUnitType(unit->getType()), "Dark templar is not supported :("); //} return unit &&unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists() && unit->getType() != BWAPI::UnitTypes::Unknown && unit->getPosition().isValid() && InformationManager::Instance().isCombatUnit(unit->getType()) && SparCraft::System::isSupportedUnitType(unit->getType()); } bool HLState::isNonWorkerCombatUnit(const UnitInfo &unit) { //if (unit.type == BWAPI::UnitTypes::Protoss_Dark_Templar) //{ // UAB_ASSERT(InformationManager::Instance().isCombatUnit(unit.type) // && SparCraft::System::isSupportedUnitType(unit.type), "Dark templar is not supported :("); //} return unit.completed && unit.lastHealth > 0 && unit.type != BWAPI::UnitTypes::Unknown && unit.lastPosition.isValid() && InformationManager::Instance().isCombatUnit(unit.type) && SparCraft::System::isSupportedUnitType(unit.type); } void HLState::addSquads(const BWAPI::PlayerInterface *player) { std::unordered_map < BWTA::Region*, std::vector > units; for (auto &unit : player->getUnits()){ if (isNonWorkerCombatUnit(unit)) { try { units[BWTA::getRegion(unit->getPosition())].push_back(UnitInfo(unit)); } catch (...) { Logger::LogAppendToFile(UAB_LOGFILE, "Exception while running BWTA::getRegion(%d, %d), ignoring this unit", unit->getPosition().x, unit->getPosition().y); } } } for (auto &it : units) { if (it.first == nullptr)//skip null region { continue; } int totalDamage = 0; for (auto &unit : it.second) { totalDamage += (unit.damage(true) + unit.damage(false)); } if (totalDamage == 0)//skip squads with all observers { continue; } _squad[player->getID()].push_back(HLSquad(it.second, it.first)); } } HLState::~HLState() { } //void HLState::forwardGameState(int frames, int playerID) //{ // if (_buildOrderIndex[playerID] >= _buildOrder[playerID].size()){ // // UAB_ASSERT(BOSS::Races::GetRace(_state[playerID].getRace()) == BWAPI::Races::Protoss, "Non protoss?"); // // //get goal units // auto goalUnits = StrategyManager::Instance().getBuildOrderGoal( // _unitData[playerID], // _unitData[1 - playerID], // _workerData[playerID], // _state[playerID].getCurrentFrame(), // 0,//strategy // getRace(playerID)); // // try{ // BOSS::BuildOrderSearchGoal goal(_state[playerID].getRace()); // // for (size_t i = 0; i < goalUnits.size(); ++i) // { // MetaType type = goalUnits[i].first; // BOSS::ActionType actionType; // if (type.isUnit()) // { // actionType = type.unitType; // } // else if (type.isUpgrade()) // { // actionType = type.upgradeType; // } // else if (type.isTech()) // { // actionType = type.techType; // } // else{ // UAB_ASSERT(false, "Should have found a valid type here"); // } // goal.setGoal(actionType, goalUnits[i].second); // } // //perform search // BOSS::DFBB_BuildOrderSmartSearch smartSearch(_state[playerID].getRace()); // smartSearch.setGoal(goal); // smartSearch.setState(_state[playerID]); // smartSearch.setTimeLimit(1000); // smartSearch.search(); // // // //get build order from search // if (smartSearch.getResults().solved){ // _buildOrder[playerID] = smartSearch.getResults().buildOrder; // BWAPI::Broodwar->printf("Build order found"); // } // else{ // BOSS::NaiveBuildOrderSearch nbos(smartSearch.getParameters().initialState, smartSearch.getParameters().goal); // _buildOrder[playerID] = nbos.solve(); // BWAPI::Broodwar->printf("Build order not found, using naive"); // } // // }catch (BOSS::Assert::BOSSException &e){ // BWAPI::Broodwar->printf(e.what()); // } // } // //move forward the world, executing the build order // int remainingFrames = frames; // for (; _buildOrderIndex[playerID] < _buildOrder[playerID].size(); _buildOrderIndex[playerID]++){ // //BWAPI::Broodwar->printf("Frame: %d, next action: %s",initialState.getCurrentFrame(),order[i].getMetaName().c_str()); // int nextActionStart = _state[playerID].whenCanPerform(_buildOrder[playerID][_buildOrderIndex[playerID]]); // if (nextActionStart < remainingFrames){ // _state[playerID].doAction(_buildOrder[playerID][_buildOrderIndex[playerID]]); // remainingFrames -= nextActionStart; // } // else{ // break; // } // } // //TODO: add new units to unitdata. Create squad defending home base with new units. // //TODO: check case where the build order (preexistent or newly acquired) is too short and we need to get a second one // if (remainingFrames > 0){ // _state[playerID].fastForward(remainingFrames); // } // BWAPI::Broodwar->printf("Final Frame: %d", _state[playerID].getCurrentFrame()); // // //TODO: execute squad orders //} bool HLState::checkChoicePoint(const HLMove &move, int playerID) const { try{ StrategyManager::Instance().getBuildOrderGoal( _unitData[playerID], _unitData[1 - playerID], _workerData[playerID], currentFrame(), move.getStrategy(), getRace(playerID), move.getChoices()); } catch (const ChoicePoint &){ return true;//if some script hit an internal choice point } return false; } BOSS::BuildOrder HLState::getBuildOrder(const HLMove &move, int playerID) const { MetaPairVector goalUnits; try{ goalUnits = StrategyManager::Instance().getBuildOrderGoal( _unitData[playerID], _unitData[1 - playerID], _workerData[playerID], currentFrame(), move.getStrategy(), getRace(playerID), move.getChoices()); } catch (const ChoicePoint &){ Logger::LogAppendToFile(UAB_LOGFILE, "Hit choice point at beginning\n"); return BOSS::BuildOrder();//if some script hit an internal choice point } BOSS::BuildOrder buildOrder; BOSS::BuildOrderSearchGoal goal(_state[playerID].getRace()); for (size_t i = 0; i < goalUnits.size(); ++i) { MetaType type = goalUnits[i].first; BOSS::ActionType actionType; if (type.isUnit()) { actionType = type.unitType; } else if (type.isUpgrade()) { actionType = type.upgradeType; } else if (type.isTech()) { actionType = type.techType; } else{ UAB_ASSERT(false, "Should have found a valid type here"); } goal.setGoal(actionType, goalUnits[i].second); } BOSS::NaiveBuildOrderSearch nbos(_state[playerID], goal); buildOrder = nbos.solve(); return buildOrder; } void HLState::applyAndForward(int depth, int frames, const std::array &moves) { int forwardedFrames = 0; _hash = getHash(depth, moves); UAB_ASSERT(getRace(0) == BWAPI::Races::Protoss, "Non protoss?"); UAB_ASSERT(getRace(1) == BWAPI::Races::Protoss, "Non protoss?"); BOSS::BuildOrder buildOrder[2]; for (int playerId = 0; playerId < 2; playerId++) { if (buildOrder[playerId].empty()) { buildOrder[playerId] = getBuildOrder(moves[playerId], playerId); //Logger::LogAppendToFile(UAB_LOGFILE, "Using build order planning, size: %d\n", buildOrder[playerId].size()); } } //execute build orders unsigned int buildOrderIndex[2] = { 0, 0 }; while (buildOrderIndex[0] < buildOrder[0].size() && buildOrderIndex[1] < buildOrder[1].size()){ int nextActionStart[2]; for (int playerID = 0; playerID < 2; playerID++){ nextActionStart[playerID] = _state[playerID].whenCanPerform(buildOrder[playerID][buildOrderIndex[playerID]]); } int nextPlayer = nextActionStart[0] < nextActionStart[1] ? 0 : 1; int framesToForward = nextActionStart[nextPlayer] - _state[nextPlayer].getCurrentFrame(); if (forwardedFrames + framesToForward>frames) { framesToForward = frames - forwardedFrames; synchronizeNewUnits(0, _state[0].fastForward(_state[0].getCurrentFrame() + framesToForward)); synchronizeNewUnits(1, _state[1].fastForward(_state[1].getCurrentFrame() + framesToForward)); if (framesToForward > 0) { forwardSquads(framesToForward); } break; } forwardedFrames += framesToForward; const BOSS::ActionType& action = buildOrder[nextPlayer][buildOrderIndex[nextPlayer]++]; //Logger::LogAppendToFile(UAB_LOGFILE, "Start new unit: %s to player %d frame %d\n", action.getName().c_str(), nextPlayer, _state[nextPlayer].getCurrentFrame()); synchronizeNewUnits(nextPlayer, _state[nextPlayer].doAction(action), action); if (checkChoicePoint(moves[1 - nextPlayer], 1 - nextPlayer)) { //Logger::LogAppendToFile(UAB_LOGFILE, "Hit choice point while forwarding 1\n"); break;//if some script hit an internal choice point } if (nextActionStart[0] == nextActionStart[1]){ const BOSS::ActionType& action = buildOrder[1 - nextPlayer][buildOrderIndex[1 - nextPlayer]++]; //Logger::LogAppendToFile(UAB_LOGFILE, "Start new unit: %s to player %d frame %d\n", action.getName().c_str(), 1 - nextPlayer, _state[1 - nextPlayer].getCurrentFrame()); synchronizeNewUnits(1 - nextPlayer, _state[1 - nextPlayer].doAction(action), action); if (checkChoicePoint(moves[nextPlayer], nextPlayer)) { //Logger::LogAppendToFile(UAB_LOGFILE, "Hit choice point while forwarding 1\n"); break;;//if some script hit an internal choice point } } else{ synchronizeNewUnits(1 - nextPlayer, _state[1 - nextPlayer].fastForward(nextActionStart[nextPlayer])); } if (framesToForward > 0) { forwardSquads(framesToForward); } UAB_ASSERT(_state[0].getMinerals() >= 0, "negative minerals: " + _state[0].getMinerals()); UAB_ASSERT(_state[1].getMinerals() >= 0, "negative minerals: " + _state[1].getMinerals()); } //make sure both states are at the same frame int frameDiff = _state[0].getCurrentFrame() - _state[1].getCurrentFrame(); if (frameDiff < 0){ synchronizeNewUnits(0, _state[0].fastForward(_state[1].getCurrentFrame())); } else if (frameDiff > 0){ synchronizeNewUnits(1, _state[1].fastForward(_state[0].getCurrentFrame())); } if (std::abs(frameDiff) > 0) { forwardSquads(std::abs(frameDiff)); } //Logger::LogAppendToFile(UAB_LOGFILE, "Finished forwarding\n"); } //void HLState::doAction(int playerID, const BOSS::ActionType action){ // _state[playerID].doAction(action); // if (action.isUnit()){ // _unitData[playerID].updateUnit(); // if (action.isWorker()){ // _workerData[playerID].addWorker(); // } // } //} void HLState::synchronizeNewUnits(int playerID, const std::vector &finishedUnits) { for (auto &unit : finishedUnits){ if (unit.isUnit()){ if ((_unitData[playerID].getNumUnits(unit.getUnitType()) == _unitData[playerID].getNumCompletedUnits(unit.getUnitType())) || !_unitData[playerID].finishUnit(unit.getUnitType()))//units of this type were in progress, let's finish them {//let's add a new finished unit auto parentType = unit.getUnitType().whatBuilds().first; //BWAPI::Position pos; //for (auto temp : _unitData[playerID].getUnitVector()){//let's take the position of the first building that can build it // if (temp.type == parentType){ // pos = temp.lastPosition; // break; // } //} BWAPI::Position pos(_players[playerID]->getStartLocation());//everything spawns at the main base int newID = std::max(_unitData[playerID].highestID(), _unitData[1 - playerID].highestID()) + 1; UnitInfo newUnit(newID, _players[playerID], pos, unit.getUnitType(), true); _unitData[playerID].addUnit(newUnit); addNewUnitToSquad(newUnit); //Logger::LogAppendToFile(UAB_LOGFILE, "Added new unit: %s to player %d frame %d\n", newUnit.type.getName().c_str(), playerID, _state[playerID].getCurrentFrame()); if (unit.isWorker()){ //todo:for now we'll ignore new workers //_workerData[playerID].addWorker(); } } else{ //Logger::LogAppendToFile(UAB_LOGFILE, "Finished new unit: %s to player %d frame %d\n", unit.getName().c_str(), playerID, _state[playerID].getCurrentFrame()); } } } } void HLState::synchronizeNewUnits(int playerID, const std::vector &finishedUnits, const BOSS::ActionType &startedUnit) { if (startedUnit.isUnit()){ auto parentType = startedUnit.getUnitType().whatBuilds().first; BWAPI::Position pos(_players[playerID]->getStartLocation());//everything spawns at the main base int newID = std::max(_unitData[playerID].highestID(), _unitData[1 - playerID].highestID()) + 1; UnitInfo newUnit(newID, _players[playerID], pos, startedUnit.getUnitType(), false); _unitData[playerID].addUnit(newUnit); //Logger::LogAppendToFile(UAB_LOGFILE, "Started new unit: %s to player %d frame %d\n", newUnit.type.getName().c_str(), playerID, _state[playerID].getCurrentFrame()); if (startedUnit.isWorker()){ //todo:for now we'll ignore new workers //_workerData[playerID].addWorker(); } } synchronizeNewUnits(playerID, finishedUnits); } void HLState::synchronizeDeadUnits(const std::array,2> &units) { for (int p = 0; p < 2; p++) { for (const auto &u : units[p]) { _state[p].removeCompletedAction(BOSS::ActionType(u.type)); _unitData[p].removeUnit(u.unitID); _workerData[p].workerDestroyed(u.unit); //_squad updated previously } } } void HLState::addNewUnitToSquad(const UnitInfo &newUnit) { if (isNonWorkerCombatUnit(newUnit)) { //todo:find squad in region, or create new squad BWTA::Region *r = BWTA::getRegion(newUnit.lastPosition); bool added = false; for (auto &s : _squad[newUnit.player->getID()]) { if (s.getCurrentRegion() == r) { s.addUnit(newUnit); added = true; break; } } if (!added) { std::vector v(1,newUnit); _squad[newUnit.player->getID()].push_back(HLSquad(v, r)); } } } void HLState::assignDefenseSquads() { for (int playerId = 0; playerId < 2; playerId++) { //check if we need to defend any of our regions for ( BWTA::Region *r: _unitData[playerId].getBaseRegions()) { int enemyFlyingStrength = 0; int enemyGroundStrength = 0; for (auto &s : _squad[1 - playerId]) { if (s.getCurrentRegion() == r) { enemyFlyingStrength += s.getFlyingStrength(); enemyGroundStrength += s.getGroundStrength(); } } std::vector skip(_squad[playerId].size(),false); //assign closest squads to region to defend until we outnumber enemies while (enemyFlyingStrength > 0) { int i = getClosestUnassignedSquad(playerId, r, skip); if (i < 0)break; HLSquad &s = _squad[playerId][i]; if ((enemyFlyingStrength > 0) && (s.getAntiAirStrength() > 0)) { s.order(HLSquadOrder(HLSquadOrder::Defend, r)); enemyFlyingStrength -= s.getAntiAirStrength(); } else { skip[i] = true; } } skip = std::vector(_squad[playerId].size(), false); while (enemyGroundStrength > 0) { int i = getClosestUnassignedSquad(playerId, r, skip); if (i < 0)break; HLSquad &s = _squad[playerId][i]; if ((enemyGroundStrength > 0) && (s.getGroundStrength() > 0)) { s.order(HLSquadOrder(HLSquadOrder::Defend, r)); enemyGroundStrength -= s.getGroundStrength(); } else { skip[i] = true; } } } } } void HLState::assignAttackSquads() { for (int playerId = 0; playerId < 2; playerId++) { //if there are unassigned squads, send them to the closest enemy region try { BWTA::Region *r = getClosestBaseLocation(1 - playerId, BWTA::getStartLocation(_players[playerId])->getRegion())->getRegion(); while (1) { HLSquad &s = getUnassignedSquad(playerId); s.order(HLSquadOrder(HLSquadOrder::OrderType::Attack, r)); } } catch (...) { } } } std::vector, 2 > > HLState::getCombats() const { std::vector, 2 > > combats; for (auto r : BWTA::getRegions()) { std::vector first; for (size_t s = 0; s < _squad[0].size();s++) { if (_squad[0][s].getCurrentRegion() == r && _squad[0][s].getStrength() > 0) { first.push_back(s); } } if (!first.empty()) { std::vector second; for (size_t s = 0; s < _squad[1].size(); s++) { if (_squad[1][s].getCurrentRegion() == r && _squad[1][s].getStrength() > 0) { second.push_back(s); } } if (!second.empty()) { combats.push_back(std::array < std::vector, 2 > {{ first, second }}); } } } return combats; } void HLState::forwardCombat(const std::array,2 > &squadIndex, int frames) { if (frames < 20)//don't simulate extremely short combats { return; } CombatSimulation sim; SparCraft::GameState state; static std::random_device rd; static std::mt19937 gen(rd()); static std::uniform_int_distribution<> X(100,200); static std::uniform_int_distribution<> Y(-200, 200); for (int p = 0; p < 2; p++) { UAB_ASSERT(!squadIndex[p].empty(), "Adding no squads!"); for (size_t i = 0; i < squadIndex[p].size(); i++) { const HLSquad &squad = _squad[p][squadIndex[p][i]]; UAB_ASSERT(!squad.empty(), "Adding empty squad!"); BWAPI::Position squadPos=squad.getCurrentRegion()->getCenter(); for (auto it = squad.begin(); it != squad.end();it++) { const UnitInfo &unit = it->second; if (InformationManager::Instance().isCombatUnit(unit.type) && SparCraft::System::isSupportedUnitType(unit.type)) { try { int newX = squadPos.x + (p == 0 ? -1 : 1)*X(gen); if (newX < 0)newX = 0; int newY = squadPos.y + Y(gen); if (newY < 0)newY = 0; SparCraft::Unit u(unit.type, SparCraft::Position(newX,newY), unit.unitID, sim.getSparCraftPlayerID(unit.player), unit.lastHealth, 0, currentFrame(), currentFrame()); state.addUnitWithID(u); } catch (int e) { e = 1; Logger::LogAppendToFile(UAB_LOGFILE,"Problem Adding Unit with ID: %d", unit.unitID); } } } } } state.finishedMoving(); UAB_ASSERT(state.numUnits(SparCraft::Players::Player_One) > 0 && state.numUnits(SparCraft::Players::Player_Two) > 0, "Someone has 0 units in this battle!"); if (state.numUnits(SparCraft::Players::Player_One) <= 0 || state.numUnits(SparCraft::Players::Player_Two) <= 0) { Logger::LogAppendToFile(UAB_LOGFILE, state.toString()); for (int p = 0; p < 2; p++) { Logger::LogAppendToFile(UAB_LOGFILE, "Player %d\n", p); for (size_t i = 0; i < squadIndex[p].size(); i++) { Logger::LogAppendToFile(UAB_LOGFILE, "Squad %d\n", i); const HLSquad &squad = _squad[p][squadIndex[p][i]]; BWAPI::Position squadPos = squad.getCurrentRegion()->getCenter(); for (auto it = squad.begin(); it != squad.end(); it++) { const UnitInfo &unit = it->second; Logger::LogAppendToFile(UAB_LOGFILE, " %s", unit.type.getName().c_str()); } } } } std::array, 2> deadUnits; try { SparCraft::PlayerPtr selfNOK(new SparCraft::Player_NOKDPS(SparCraft::Players::Player_One)); SparCraft::PlayerPtr enemyNOK(new SparCraft::Player_NOKDPS(SparCraft::Players::Player_Two)); SparCraft::Game g(state, selfNOK, enemyNOK, frames); int prev = g.getState().evalLTD2(SparCraft::Players::Player_One); g.play(); UAB_ASSERT(prev!=g.getState().evalLTD2(SparCraft::Players::Player_One), "LTD2 == before and after combat! Length: %d frames\n%s",frames,state.toString()); //todo:get dead units for (int p = 0; p < 2; p++) { for (size_t i = 0; i < squadIndex[p].size(); i++) { auto it = _squad[p][squadIndex[p][i]].begin(); while (it != _squad[p][squadIndex[p][i]].end()) { int id = it->first; UnitInfo unit = it->second; it++; try{ auto &sparUnit = g.getState().getUnitByID(p, id); if (!sparUnit.isAlive()){ _squad[p][squadIndex[p][i]].removeUnit(id); deadUnits[p].push_back(unit); } else//unit alive, health might have changed { _squad[p][squadIndex[p][i]][id].lastHealth = sparUnit.currentHP(); } } catch (int){ _squad[p][squadIndex[p][i]].removeUnit(id); deadUnits[p].push_back(unit); } } } } } catch (int) { BWAPI::Broodwar->printf("SparCraft FatalError, simulateCombat() threw"); UAB_ASSERT(false, "SparCraft FatalError, simulateCombat() threw"); } synchronizeDeadUnits(deadUnits); //Logger::LogAppendToFile(UAB_LOGFILE, "Combat executed for %d frames", frames); } BWTA::BaseLocation * HLState::getClosestBaseLocation(int playerId, BWTA::Region *r) const { int min = std::numeric_limits::max(); BWTA::BaseLocation *min_base = NULL; for (auto l : BWTA::getBaseLocations()) { int d = l->getRegion()->getCenter().getApproxDistance(r->getCenter()); if (d skip) { int min = std::numeric_limits::max(), min_i = -1; for (size_t i = 0; i < _squad[playerId].size(); i++) { if (skip[i])continue; auto &s = _squad[playerId][i]; if ((s.order()._type == HLSquadOrder::None)) { int d = s.getCurrentRegion()->getCenter().getApproxDistance(r->getCenter()); if (d < min) { min = d; min_i = i; } } } return min_i; } HLSquad & HLState::getUnassignedSquad(int playerId) { for (auto &s : _squad[playerId]) { if (s.order()._type == HLSquadOrder::None) { return s; } } throw 1; } void HLState::clearOrders() { for (int playerId = 0; playerId < 2; playerId++) { for (auto &s : _squad[playerId]) { s.order(HLSquadOrder()); } } } void HLState::forwardSquads(int frames) { //delete empty squads for (int playerId = 0; playerId < 2; playerId++) { _squad[playerId].erase( std::remove_if(_squad[playerId].begin(), _squad[playerId].end(), [](const HLSquad &s){return s.empty(); }), _squad[playerId].end()); } //merge squads in same region for (int playerId = 0; playerId < 2; playerId++) { for (auto it1 = _squad[playerId].begin(); it1 != _squad[playerId].end(); it1++) { auto it2 = it1; it2++; for (; it2 != _squad[playerId].end(); it2++) { if (it1->getCurrentRegion() == it2->getCurrentRegion()) { for (auto unit : *it2) { it1->addUnit(unit.second); } _squad[playerId].erase(it2); break;//todo: this assumes only 2 squads in same region, if there are three, it will merge the first 2 only } } } } //assign orders to squads if ((currentFrame()-lastSquadUpdate)>100) { lastSquadUpdate = currentFrame(); clearOrders(); assignDefenseSquads(); assignAttackSquads(); } std::vector doneSquads[2] = { std::vector(_squad[0].size(),false), std::vector(_squad[1].size(),false) }; //execute orders //if enemy in same region or path //do combat for (auto &combat : getCombats()){ forwardCombat(combat, frames); for (int s : combat.at(0)) { doneSquads[0][s] = true; } for (int s : combat.at(1)) { doneSquads[1][s] = true; } } //move towards destination for (int playerId = 0; playerId < 2; playerId++) { for (size_t s = 0; s < doneSquads[playerId].size(); s++) { if (!doneSquads[playerId][s]) { _squad[playerId][s].travel(frames); } } } } std::vector HLState::getMoves(int playerID, int strategy, const std::unordered_map &choices) const { std::vector moves; try{ auto goalUnits = StrategyManager::Instance().getBuildOrderGoal( _unitData[playerID], _unitData[1 - playerID], _workerData[playerID], _state[playerID].getCurrentFrame(), strategy, getRace(playerID), choices); moves.push_back(HLMove(strategy, choices)); } catch (const ChoicePoint &c){ for (int option = 0; option < c._options; option++){ auto newChoices = choices; newChoices[c._point] = option; auto temp = getMoves(playerID, strategy, newChoices); moves.insert(moves.end(), temp.begin(), temp.end()); } } return moves; } std::vector HLState::getMoves(int playerID) const { std::vector moves; //if (_opening[playerID]){ // std::vector moves; // for (int s = 0; s < StrategyManager::getNumStrategies(getRace(playerID)); s++) // { // moves.push_back(HLMove(s)); // } // return moves; //} //for (int s = 0; s < StrategyManager::getNumStrategies(getRace(playerID));s++){ int s = StrategyManager::ProtossHighLevelSearch; //auto enemy = BWAPI::Broodwar->enemy(); //if (enemy->getID() == playerID) //{ // if (enemy->getName().compare("Skynet") == 0) // { // s=StrategyManager::ProtossDarkTemplar; // } // else if (enemy->getName().compare("UAlbertaBot") == 0) // { // s = StrategyManager::ProtossZealotRush; // } //} try{ auto goalUnits = StrategyManager::Instance().getBuildOrderGoal( _unitData[playerID], _unitData[1 - playerID], _workerData[playerID], _state[playerID].getCurrentFrame(), s,//strategy getRace(playerID), std::unordered_map()); moves.push_back(HLMove(s)); } catch (const ChoicePoint &c){ for (int option = 0; option < c._options; option++){ std::unordered_map choices; choices[c._point] = option; auto temp = getMoves(playerID, s, choices); moves.insert(moves.end(), temp.begin(), temp.end()); } } //} return moves; ////do nothing move //HLMove move(0); //for (const auto &s : _squad[playerID]){ // move.addSquad(s); //} //moves.push_back(move); ////merge squads move //move= HLMove(0); //if (_squad[playerID].size() > 1){ // for (int i = 0; i < _squad[playerID].size()-1; i+=2){ // move.addSquad(merge(_squad[playerID][i], _squad[playerID][i + 1])); // } // if (_squad[playerID].size() % 2 == 1){ // move.addSquad(_squad[playerID].back()); // } //} //moves.push_back(move); ////attack move, just attack first neighbouring region //move = HLMove(0); //for (auto &s : _squad[playerID]){ // BWAPI::Position pos = (*s.getUnits().front()->getRegion()->getNeighbors().begin())->getCenter(); // int radius = 1000; // s.setSquadOrder(SquadOrder(SquadOrder::Attack, pos, radius)); // move.addSquad(s); //} //moves.push_back(move); //return moves; } //HLSquad HLState::merge(const HLSquad& s1, const HLSquad &s2) //{ // auto units = s1.getUnits(); // auto units2 = s2.getUnits(); // units.insert(units.end(), units2.begin(),units2.end()); // return HLSquad(units, s1.getSquadOrder()); //} int HLState::evaluate(int playerID) const { if (Options::Modules::USING_COMBAT_PREDICTOR) { return CombatPredictor::Instance().predictCombat(_unitData[playerID], _unitData[1 - playerID]); } float sum[2] = { 0.0f, 0.0f }; float dragFactor = 0.6; for (auto &unit : _unitData[playerID].getUnits()){ if (unit.second.completed) { //if (unit.second.type==BWAPI::UnitTypes::Protoss_Dark_Templar) // sum[playerID] += 1000; sum[playerID] += sqrtf(unit.second.lastHealth) * unit.second.dpf(); // int score = unit.second.type == BWAPI::UnitTypes::Protoss_Dragoon ? unit.second.type.destroyScore() * dragFactor : unit.second.type.destroyScore(); // sum[playerID] += ((float)unit.second.lastHealth) / unit.second.type.maxHitPoints() * score; } } for (auto &unit : _unitData[1 - playerID].getUnits()){ if (unit.second.completed) { //if (unit.second.type == BWAPI::UnitTypes::Protoss_Dark_Templar) // sum[1-playerID] += 1000; sum[1-playerID] += sqrtf(unit.second.lastHealth) * unit.second.dpf(); // int score = unit.second.type == BWAPI::UnitTypes::Protoss_Dragoon ? unit.second.type.destroyScore() * dragFactor : unit.second.type.destroyScore(); // sum[1 - playerID] += ((float)unit.second.lastHealth) / unit.second.type.maxHitPoints() * score; } } return sum[playerID] - sum[1 - playerID]; } bool HLState::gameOver() const { return false; } //HLMove::HLMove(int strategy, const std::vector &squads) :_strategy(strategy), _squads(squads) //{ // //} HLMove::HLMove(int strategy, const std::unordered_map &choices) :_strategy(strategy), _choices(choices) { } HLMove::HLMove(int strategy) :_strategy(strategy) { } HLMove::HLMove() : _strategy(-1) { } //void HLMove::addSquad(const HLSquad &squad) //{ // _squads.push_back(squad); //} std::string HLMove::toString() const { std::ostringstream ss; ss << "[strat:"<<_strategy<<", "; for (auto &c : _choices){ ss << "[" << c.first << ", " << c.second << "] "; } ss << "]"; return ss.str(); } int HLState::currentFrame() const { return std::min(_state[0].getCurrentFrame(), _state[1].getCurrentFrame()); } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLState.h ================================================ #pragma once #include "Common.h" #include "../../BOSS/source/BOSS.h" #include "Squad.h" #include "HLUnitData.h" #include "HLSquad.h" #include #include namespace UAlbertaBot{ class HLMove{ int _strategy; //build order std::unordered_map _choices; //std::vector _squads; //units and their orders //int _frames; //length of the move public: //HLMove(int strategy, const std::vector &squads); HLMove(int strategy, const std::unordered_map &choices); HLMove(int strategy); HLMove(); //void addSquad(const HLSquad &squad); //const std::vector& getSquads() const{ // return _squads; //}; const std::unordered_map& getChoices() const{ return _choices; }; int getStrategy() const{ return _strategy; }; bool isEmpty() const{ return _strategy == -1; }; std::string toString() const; bool operator==(const HLMove &m) const { return _strategy == m._strategy && _choices == m._choices; } //HLMove& operator=(const HLMove &m) //{ // _strategy = m._strategy; // _choices = m._choices; // return *this; //} }; class HLState { BOSS::GameState _state[2]; //includes all we need for the economic part, includes frame std::vector _squad[2]; //combat units BWAPI::Player _players[2]; HLUnitData _unitData[2]; WorkerData _workerData[2]; static unsigned int _zobristChoice[20][StrategyManager::NumProtossStrategies][20][10];//10 depth, 5 strategies, 20 choice points, 10 choices each static unsigned int _zobristStrategy[20][StrategyManager::NumProtossStrategies]; unsigned int _hash; //bool _opening[2]; //BOSS::BuildOrder _buildOrder[2]; //int _buildOrderIndex[2]; int lastSquadUpdate=0; void addSquads(const BWAPI::PlayerInterface *player); //static HLSquad merge(const HLSquad& s1, const HLSquad &s2);//merge s2 into s1, keeps order of s1 //void forwardGameState(int frames, int playerID); void synchronizeNewUnits(int playerID, const std::vector &newUnits); void synchronizeNewUnits(int playerID, const std::vector &newUnits, const BOSS::ActionType &startedUnit); void synchronizeDeadUnits(const std::array, 2> &units); BOSS::BuildOrder getBuildOrder(const HLMove &move, int playerID) const; bool checkChoicePoint(const HLMove &move, int playerID) const; void forwardSquads(int frames); void assignDefenseSquads(); void assignAttackSquads(); void forwardCombat(const std::array, 2 > &squads, int frames); BWTA::BaseLocation * getClosestBaseLocation(int playerId, BWTA::Region *r) const; int getClosestUnassignedSquad(int playerId, const BWTA::Region *r, const std::vector skip); HLSquad & getUnassignedSquad(int playerId); void clearOrders(); std::vector, 2 > > getCombats() const; void addNewUnitToSquad(const UnitInfo &newUnit); std::vector getMoves(int playerID, int strategy, const std::unordered_map &choices) const; public: HLState(){} HLState(BWAPI::GameWrapper & game, BWAPI::PlayerInterface * player, BWAPI::PlayerInterface * enemy); ~HLState(); std::vector getChildren() const; std::vector getMoves(int playerID) const; void applyAndForward(int depth, int frames, const std::array &moves); int evaluate(int playerID) const; bool gameOver() const; friend class HLSearch; int currentFrame() const; BWAPI::Race getRace(int playerID) const{ return BOSS::Races::GetRace(_state[playerID].getRace()); }; //bool undecidedChoicePoint(int playerID, int strategy, const std::unordered_map choices) const; //void HLState::doAction(int playerID, const BOSS::ActionType action); static bool HLState::isNonWorkerCombatUnit(const BWAPI::UnitInterface *unit); static bool HLState::isNonWorkerCombatUnit(const UnitInfo &unit); unsigned int getHash(int depth, const std::array < HLMove, 2 > &moves) const { unsigned int hash = _hash; for (int p = 0; p < 2; p++) { hash ^= _zobristStrategy[depth-p][moves.at(p).getStrategy()]; for (auto c : moves.at(p).getChoices()) { hash ^= _zobristChoice[depth - p][moves.at(p).getStrategy()][c.first][c.second]; } } return hash; } unsigned int getHash(int depth, const HLMove &move) const { unsigned int hash = _hash; hash ^= _zobristStrategy[depth][move.getStrategy()]; for (auto c : move.getChoices()) { hash ^= _zobristChoice[depth][move.getStrategy()][c.first][c.second]; } return hash; } unsigned int getHash() const { return _hash; } // friend struct _dummy_static_initializer; }; //struct _dummy_static_initializer{ // _dummy_static_initializer(){ // std::mt19937 rng(1);//todo:use a seed? // for (int depth = 0; depth < 10; depth++){ // for (int s = 0; s < 5; s++){ // HLState::_zobristStrategy[depth][s] = rng(); // Logger::LogAppendToFile(UAB_LOGFILE, "\n"); // for (int point = 0; point < 20; point++){ // for (auto c = 0; c < 10; c++){ // HLState::_zobristChoice[depth][s][point][c] = rng(); // Logger::LogAppendToFile(UAB_LOGFILE, "%u ", HLState::_zobristChoice[depth][s][point][c]); // } // } // } // } // } //}; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLStatistics.cpp ================================================ #include "HLStatistics.h" using namespace UAlbertaBot; HLStatistics::~HLStatistics() { } HLStatistics::HLStatistics() { // TODO Auto-generated constructor stub clear(); } std::string HLStatistics::toString() const{ char buff[80]; sprintf_s(buff, 80, "%6.3f [%10d %.2e %5d %5d %5d %5d %5.3f %5.1f]", getRunningTimeMilliSecs() / 1000.0, getNodeCount(), getNodesSec(), getTTqueries(), getTTfound(), getCacheQueries(), getCacheFound(), getAvgBf(), getAvgFwd()); return buff; } std::string HLStatistics::header() const { return "Time nodes nodes/sec TtQ TtF CacheQ CacheF AvgBF AvgFwd"; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLStatistics.h ================================================ #pragma once #include #include namespace UAlbertaBot{ class HLStatistics { private: std::chrono::time_point startTime; int nodeCount; int TTqueries; int TTfound; int cacheQueries; int cacheFound; int branches; int searches; //int hashCol; int forwardLength; int numForwards; public: HLStatistics(); void clear(){ nodeCount = 0; TTqueries = 0; TTfound = 0; cacheQueries = 0; cacheFound = 0; branches = 0; searches = 0; forwardLength = 0; numForwards = 0; } void startTimer(){ startTime = std::chrono::high_resolution_clock::now(); } long long getRunningTimeSecs() const{ return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); } long long getRunningTimeMilliSecs() const{ return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); } void incNodeCount(){ nodeCount++; } int getNodeCount() const{ return nodeCount; } double getNodesSec() const{ return ((float)nodeCount) / getRunningTimeMilliSecs()*1000.0; } void incTTquery(){ TTqueries++; } int getTTqueries() const{ return TTqueries; } void incTTfound(){ TTfound++; } int getTTfound() const{ return TTfound; } void incCacheQuery(){ cacheQueries++; } int getCacheQueries() const{ return cacheQueries; } void incCacheFound(){ cacheFound++; } int getCacheFound() const{ return cacheFound; } void addFwd(int length){ forwardLength += length; numForwards++; } void addBF(int nodesSearched){ searches++; branches += nodesSearched; } float getAvgBf() const{ return searches>0?((float)branches) / searches:-1.0f; } float getAvgFwd() const{ return numForwards>0 ? ((float)forwardLength) / numForwards : -1.0f; } std::string toString() const; std::string header() const; ~HLStatistics(); }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLStrategyManager.cpp ================================================ #include "Common.h" #include "StrategyManager.h" using namespace UAlbertaBot; std::unordered_map > > StrategyManager::defaultStrategyChoices; // constructor StrategyManager::StrategyManager() : firstAttackSent(false) , currentStrategy(0) , selfRace(BWAPI::Broodwar->self()->getRace()) , enemyRace(BWAPI::Broodwar->enemy()->getRace()) { addStrategies(); setStrategy(); } // get an instance of this StrategyManager & StrategyManager::Instance() { static StrategyManager instance; return instance; } void StrategyManager::addStrategies() { ////protossOpeningBook[ProtossZealotRush] = "0 0 0 0 1 0 0 3 0 0 3 0 1 3 0 4 4 4 4 4 1 0 4 4 4"; // protossOpeningBook[ProtossZealotRush] = "0 0 0 0 1 0 3 3 0 0 4 1 4 4 0 4 4 0 1 4 3 0 1 0 4 0 4 4 4 4 1 0 4 4 4"; ////protossOpeningBook[ProtossZealotRush] = "0"; ////protossOpeningBook[ProtossDarkTemplar] = "0 0 0 0 1 3 0 7 5 0 0 12 3 13 0 22 22 22 22 0 1 0"; // protossOpeningBook[ProtossDarkTemplar] = "0 0 0 0 1 0 3 0 7 0 5 0 12 0 13 3 22 22 1 22 22 0 1 0"; //protossOpeningBook[ProtossDragoons] = "0 0 0 0 1 0 0 3 0 7 0 0 5 0 0 3 8 6 1 6 6 0 3 1 0 6 6 6"; //terranOpeningBook[TerranMarineRush] = "0 0 0 0 0 1 0 0 3 0 0 3 0 1 0 4 0 0 0 6"; //zergOpeningBook[ZergZerglingRush] = "0 0 0 0 0 1 0 0 0 2 3 5 0 0 0 0 0 0 1 6"; if (selfRace == BWAPI::Races::Protoss) { results = std::vector(NumProtossStrategies); if (enemyRace == BWAPI::Races::Protoss) { usableStrategies.push_back(ProtossZealotRush); usableStrategies.push_back(ProtossDarkTemplar); usableStrategies.push_back(ProtossDragoons); } else if (enemyRace == BWAPI::Races::Terran) { usableStrategies.push_back(ProtossZealotRush); usableStrategies.push_back(ProtossDarkTemplar); usableStrategies.push_back(ProtossDragoons); } else if (enemyRace == BWAPI::Races::Zerg) { usableStrategies.push_back(ProtossZealotRush); usableStrategies.push_back(ProtossDragoons); } else { BWAPI::Broodwar->printf("Enemy Race Unknown"); usableStrategies.push_back(ProtossZealotRush); usableStrategies.push_back(ProtossDragoons); } } else if (selfRace == BWAPI::Races::Terran) { results = std::vector(NumTerranStrategies); usableStrategies.push_back(TerranMarineRush); } else if (selfRace == BWAPI::Races::Zerg) { results = std::vector(NumZergStrategies); usableStrategies.push_back(ZergZerglingRush); } if (Options::Modules::USING_STRATEGY_IO) { readResults(); } } void StrategyManager::readResults() { // read in the name of the read and write directories from settings file struct stat buf; // if the file doesn't exist something is wrong so just set them to default settings if (stat(Options::FileIO::FILE_SETTINGS, &buf) == -1) { readDir = "bwapi-data/testio/read/"; writeDir = "bwapi-data/testio/write/"; } else { std::ifstream f_in(Options::FileIO::FILE_SETTINGS); getline(f_in, readDir); getline(f_in, writeDir); f_in.close(); } // the file corresponding to the enemy's previous results std::string readFile = readDir + BWAPI::Broodwar->enemy()->getName() + ".txt"; // if the file doesn't exist, set the results to zeros if (stat(readFile.c_str(), &buf) == -1) { std::fill(results.begin(), results.end(), IntPair(0,0)); } // otherwise read in the results else { std::ifstream f_in(readFile.c_str()); std::string line; getline(f_in, line); results[ProtossZealotRush].first = atoi(line.c_str()); getline(f_in, line); results[ProtossZealotRush].second = atoi(line.c_str()); getline(f_in, line); results[ProtossDarkTemplar].first = atoi(line.c_str()); getline(f_in, line); results[ProtossDarkTemplar].second = atoi(line.c_str()); getline(f_in, line); results[ProtossDragoons].first = atoi(line.c_str()); getline(f_in, line); results[ProtossDragoons].second = atoi(line.c_str()); f_in.close(); } BWAPI::Broodwar->printf("Results (%s): (%d %d) (%d %d) (%d %d)", BWAPI::Broodwar->enemy()->getName().c_str(), results[0].first, results[0].second, results[1].first, results[1].second, results[2].first, results[2].second); } void StrategyManager::writeResults() { std::string writeFile = writeDir + BWAPI::Broodwar->enemy()->getName() + ".txt"; std::ofstream f_out(writeFile.c_str()); f_out << results[ProtossZealotRush].first << "\n"; f_out << results[ProtossZealotRush].second << "\n"; f_out << results[ProtossDarkTemplar].first << "\n"; f_out << results[ProtossDarkTemplar].second << "\n"; f_out << results[ProtossDragoons].first << "\n"; f_out << results[ProtossDragoons].second << "\n"; f_out.close(); } void StrategyManager::setStrategy() { // if we are using file io to determine strategy, do so if (Options::Modules::USING_STRATEGY_IO) { double bestUCB = -1; int bestStrategyIndex = 0; // UCB requires us to try everything once before using the formula for (size_t strategyIndex(0); strategyIndex bestUCB) { bestUCB = ucb; bestStrategyIndex = strategyIndex; } } currentStrategy = usableStrategies[bestStrategyIndex]; } else if (Options::Modules::USING_HIGH_LEVEL_SEARCH) { currentStrategy = ProtossHighLevelSearch; defaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][0] = 0; defaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][1] = 0; defaultStrategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch][2] = 0; strategyChoices[BWAPI::Races::Protoss.getID()][ProtossHighLevelSearch];//to create the empty map } else { // otherwise return a random strategy std::string enemyName(BWAPI::Broodwar->enemy()->getName()); if (enemyName.compare("Skynet") == 0) { currentStrategy = ProtossDarkTemplar; } else { currentStrategy = ProtossZealotRush; } } } void StrategyManager::onEnd(const bool isWinner) { // write the win/loss data to file if we're using IO if (Options::Modules::USING_STRATEGY_IO) { // if the game ended before the tournament time limit if (BWAPI::Broodwar->getFrameCount() < Options::Tournament::GAME_END_FRAME) { if (isWinner) { results[getCurrentStrategy()].first = results[getCurrentStrategy()].first + 1; } else { results[getCurrentStrategy()].second = results[getCurrentStrategy()].second + 1; } } // otherwise game timed out so use in-game score else { if (getScore(BWAPI::Broodwar->self()) > getScore(BWAPI::Broodwar->enemy())) { results[getCurrentStrategy()].first = results[getCurrentStrategy()].first + 1; } else { results[getCurrentStrategy()].second = results[getCurrentStrategy()].second + 1; } } writeResults(); } } const double StrategyManager::getUCBValue(const size_t & strategy) const { double totalTrials(0); for (size_t s(0); sgetBuildingScore() + player->getKillScore() + player->getRazingScore() + player->getUnitScore(); } std::vector StrategyManager::getOpeningBookBuildOrder(int strategy, BWAPI::Race race) { if (race == BWAPI::Races::Protoss) { if (strategy == ProtossZealotRush) { return OpeningBuildOrders::ProtossZealotRush(); } else if (strategy == ProtossDragoons) { return OpeningBuildOrders::ProtossDragoonRush(); } else if (strategy == ProtossDarkTemplar) { return OpeningBuildOrders::ProtossDarkTemplarRush(); } else if (strategy == ProtossHighLevelSearch) { return OpeningBuildOrders::ProtossHighLevelSearch(); } } else if (race == BWAPI::Races::Terran) { if (strategy == TerranMarineRush) { return OpeningBuildOrders::TerranMarineRush(); } } else if (race == BWAPI::Races::Zerg) { if (strategy == ZergZerglingRush) { return OpeningBuildOrders::TerranMarineRush(); } } // something wrong, return the protoss one BWAPI::Broodwar->printf("Strategy not found, returning empty initial build order"); return std::vector(); } const std::vector StrategyManager::getOpeningBookBuildOrder() const { return getOpeningBookBuildOrder(currentStrategy, selfRace); } // when do we want to defend with our workers? // this function can only be called if we have no fighters to defend with const int StrategyManager::defendWithWorkers() { if (!Options::Micro::WORKER_DEFENSE) { return false; } // our home nexus position BWAPI::Position homePosition = BWTA::getStartLocation(BWAPI::Broodwar->self())->getPosition();; // enemy units near our workers int enemyUnitsNearWorkers = 0; // defense radius of nexus int defenseRadius = 300; // fill the set with the types of units we're concerned about for (BWAPI::UnitInterface * unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's a zergling or a worker we want to defend if (unit->getType() == BWAPI::UnitTypes::Zerg_Zergling) { if (unit->getDistance(homePosition) < defenseRadius) { enemyUnitsNearWorkers++; } } } // if there are enemy units near our workers, we want to defend return enemyUnitsNearWorkers; } // called by combat commander to determine whether or not to send an attack force // freeUnits are the units available to do this attack const bool StrategyManager::doAttack(const std::set & freeUnits) { int ourForceSize = (int)freeUnits.size(); int numUnitsNeededForAttack = 1; bool doAttack = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) >= 1 || ourForceSize >= numUnitsNeededForAttack; if (doAttack) { firstAttackSent = true; } return doAttack || firstAttackSent; } const bool StrategyManager::expandProtossZealotRush() const { return expandProtossZealotRush( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } bool StrategyManager::expandProtossZealotRush(const HLUnitData &unitData, const WorkerData &selfWorkerData, int frame, int frameAdjust, int zealotAdjust) { // if there is no place to expand to, we can't expand if (MapTools::Instance().getNextExpansion(unitData.player()) == BWAPI::TilePositions::None) { return false; } int numNexus = unitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus); int numZealots = unitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Zealot); // if there are more than 10 idle workers, expand if (selfWorkerData.getNumIdleWorkers() > 10) { return true; } // 2nd Nexus Conditions: // We have 12 or more zealots // It is past frame 7000 if ((numNexus < 2) && (numZealots >(12 + zealotAdjust) || frame > (9000 + frameAdjust))) { return true; } // 3nd Nexus Conditions: // We have 24 or more zealots // It is past frame 12000 if ((numNexus < 3) && (numZealots >(24 + zealotAdjust) || frame > (15000 + frameAdjust))) { return true; } if ((numNexus < 4) && (numZealots >(24 + zealotAdjust) || frame > (21000 + frameAdjust))) { return true; } if ((numNexus < 5) && (numZealots >(24 + zealotAdjust) || frame > (26000 + frameAdjust))) { return true; } if ((numNexus < 6) && (numZealots >(24 + zealotAdjust) || frame > (30000 + frameAdjust))) { return true; } return false; } const MetaPairVector StrategyManager::getBuildOrderGoal() { if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss) { if (getCurrentStrategy() == ProtossZealotRush) { return getProtossZealotRushBuildOrderGoal(); } else if (getCurrentStrategy() == ProtossDarkTemplar) { return getProtossDarkTemplarBuildOrderGoal(); } else if (getCurrentStrategy() == ProtossDragoons) { return getProtossDragoonsBuildOrderGoal(); } else if (getCurrentStrategy() == ProtossHighLevelSearch) { return getProtossHighLevelSearchBuildOrderGoal(); } // if something goes wrong, use zealot goal return getProtossZealotRushBuildOrderGoal(); } else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran) { return getTerranBuildOrderGoal(); } else { return getZergBuildOrderGoal(); } } MetaPairVector StrategyManager::getBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame, int strategy, BWAPI::Race race, const std::unordered_map &choices) { if (race == BWAPI::Races::Protoss) { switch (strategy){ case ProtossZealotRush: return getProtossZealotRushBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; case ProtossDarkTemplar: return getProtossDarkTemplarBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; case ProtossDragoons: return getProtossDragoonsBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; case ProtossHighLevelSearch: return getProtossHighLevelSearchBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame, choices, false); break; default: UAB_ASSERT(false,"Non existing Protoss strategy %d, using default", strategy); //return getProtossZealotRushBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame, choices); break; } } else if (race == BWAPI::Races::Terran){ switch (strategy){ case TerranMarineRush: return getTerranBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; default: BWAPI::Broodwar->printf("Non existing Terran strategy %d, using default", strategy); return getTerranBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; } } else if (race == BWAPI::Races::Zerg){ switch (strategy){ case ZergZerglingRush: return getZergBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; default: BWAPI::Broodwar->printf("Non existing Zerg strategy %d, using default", strategy); return getZergBuildOrderGoal(selfUnitData, enemyUnitData, selfWorkerData, frame); break; } } else{ UAB_ASSERT(false, "Unknown race when selecting strategy"); return MetaPairVector();//to silence warning } } const MetaPairVector StrategyManager::getProtossDragoonsBuildOrderGoal() const { return getProtossDragoonsBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } MetaPairVector StrategyManager::getProtossDragoonsBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame) { // the goal to return MetaPairVector goal; int numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon); int numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe); int numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus); int numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus); int numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core); int numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon); int dragoonsWanted = numDragoons > 0 ? numDragoons + 6 : 2; if (enemyUnitData.hasCloakedUnits()) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } else { if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } if (expandProtossZealotRush(selfUnitData,selfWorkerData,frame)) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); } goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted)); //goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Gateway, gatewayWanted)); //goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Probe, std::min(90, probesWanted))); return goal; } const MetaPairVector StrategyManager::getProtossDarkTemplarBuildOrderGoal() const { return getProtossDarkTemplarBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } MetaPairVector StrategyManager::getProtossDarkTemplarBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame) { // the goal to return MetaPairVector goal; int numDarkTemplar = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dark_Templar); int numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon); int numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe); int numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus); int numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus); int numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core); int numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon); int darkTemplarWanted = 4; int dragoonsWanted = numDragoons + 6; if (enemyUnitData.hasCloakedUnits()) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } if (numNexusAll >= 2 || frame > 9000) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); } if (numDragoons > 0) { goal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1)); } if (numNexusCompleted >= 3) { dragoonsWanted = numDragoons + 6; goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame)) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); } goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted)); if (numDarkTemplar < darkTemplarWanted) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, darkTemplarWanted)); } return goal; } const MetaPairVector StrategyManager::getProtossZealotRushBuildOrderGoal() const { return getProtossZealotRushBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } MetaPairVector StrategyManager::getProtossZealotRushBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame) { // the goal to return MetaPairVector goal; int numZealots = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Zealot); int numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon); int numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe); int numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus); int numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus); int numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core); int numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon); int zealotsWanted = numZealots + 8; int dragoonsWanted = numDragoons; if (enemyUnitData.hasCloakedUnits()) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } if (numNexusAll >= 2 || frame > 9000) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Assimilator, 1)); goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Cybernetics_Core, 1)); } if (numCyber > 0) { dragoonsWanted = numDragoons + 2; goal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1)); } if (numNexusCompleted >= 3) { dragoonsWanted = numDragoons + 6; goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame)) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); } goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted)); goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, zealotsWanted)); return goal; } const MetaPairVector StrategyManager::getProtossHighLevelSearchBuildOrderGoal() const { return getProtossHighLevelSearchBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount(), strategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossHighLevelSearch), true); } MetaPairVector StrategyManager::getProtossHighLevelSearchBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame, const std::unordered_map &choices, bool execution) { // the goal to return MetaPairVector goal; int numZealots = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Zealot); int numDragoons = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dragoon); int numProbes = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Probe); int numNexusCompleted = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Nexus); int numNexusAll = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Nexus); int numCyber = selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Cybernetics_Core); int numCannon = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon); int numDarkTemplar = selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Dark_Templar); int zealotsWanted = numZealots; int dragoonsWanted = numDragoons; int darkTemplarWanted = numDarkTemplar; //dragoons or zealots int choice = defaultStrategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossHighLevelSearch).at(0); if (choices.find(0) == choices.end() ) { if (!execution) { throw ChoicePoint(0, 4); } } else { choice = choices.at(0); } switch (choice){ case 0: zealotsWanted += 8; break; case 1: dragoonsWanted += 6; break; case 2: zealotsWanted += 4; dragoonsWanted += 3; break; case 3: darkTemplarWanted = 4; if (numDarkTemplar >= 3) { dragoonsWanted += 6; //darkTemplarWanted = numDarkTemplar + 1; } break; default: UAB_ASSERT(false, "Wrong choice point option"); } if (numDragoons < dragoonsWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dragoon, dragoonsWanted)); if (numZealots < zealotsWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Zealot, zealotsWanted)); if (numDarkTemplar < darkTemplarWanted) goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Dark_Templar, darkTemplarWanted)); if (enemyUnitData.hasCloakedUnits()) { if (selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Photon_Cannon) < 2) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Photon_Cannon, 2)); } if (selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) < 1) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Robotics_Facility, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Robotics_Facility) > 0 && selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Observatory) < 1) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observatory, 1)); } if (selfUnitData.getNumCompletedUnits(BWAPI::UnitTypes::Protoss_Observatory) > 0 && selfUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Observer) < 1) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } } if (numNexusAll >= 2 || frame > 9000) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Assimilator, 1)); goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Cybernetics_Core, 1)); } if ((numCyber > 0) && ((numDragoons + dragoonsWanted)>0)) { //dragoonsWanted = numDragoons + 2; goal.push_back(MetaPair(BWAPI::UpgradeTypes::Singularity_Charge, 1)); } if (numNexusCompleted >= 3) { //dragoonsWanted = numDragoons + 6; goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Observer, 1)); } if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 0, 0)) { goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); } //if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, -2, -1000)) //{ // //choice 1: expand or not // int choice = defaultStrategyChoices.at(BWAPI::Races::Protoss.getID()).at(ProtossZealotRush).at(1); // if (choices.find(1) == choices.end()) // { // if (!execution) // { // throw ChoicePoint(1, 3); // } // } // else // { // choice = choices.at(1); // } // switch (choice){ // case 0://aggressive // //if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, -2, -1000)) // //{ // goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); // //} // break; // case 1://normal // if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 0, 0)) // { // goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); // } // break; // case 2://passive // if (expandProtossZealotRush(selfUnitData, selfWorkerData, frame, 2, 1000)) // { // goal.push_back(MetaPair(BWAPI::UnitTypes::Protoss_Nexus, numNexusAll + 1)); // } // break; // default: // UAB_ASSERT(false, "Wrong choice point option"); // } //} return goal; } const MetaPairVector StrategyManager::getTerranBuildOrderGoal() const { return getTerranBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } MetaPairVector StrategyManager::getTerranBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame) { // the goal to return std::vector goal; int numMarines = selfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Marine); int numMedics = selfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Medic); int numWraith = selfUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Wraith); int marinesWanted = numMarines + 12; int medicsWanted = numMedics + 2; int wraithsWanted = numWraith + 4; goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Marine, marinesWanted)); return (const std::vector)goal; } const MetaPairVector StrategyManager::getZergBuildOrderGoal() const { return getZergBuildOrderGoal( HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->self()), BWAPI::Broodwar->self()), HLUnitData(InformationManager::Instance().getUnitData(BWAPI::Broodwar->enemy()), BWAPI::Broodwar->enemy()), WorkerManager::Instance().getData(), BWAPI::Broodwar->getFrameCount()); } MetaPairVector StrategyManager::getZergBuildOrderGoal(const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame) { // the goal to return std::vector goal; int numMutas = selfUnitData.getNumUnits(BWAPI::UnitTypes::Zerg_Mutalisk); int numHydras = selfUnitData.getNumUnits(BWAPI::UnitTypes::Zerg_Hydralisk); int mutasWanted = numMutas + 6; int hydrasWanted = numHydras + 6; goal.push_back(std::pair(BWAPI::UnitTypes::Zerg_Zergling, 4)); //goal.push_back(std::pair(BWAPI::TechTypes::Stim_Packs, 1)); //goal.push_back(std::pair(BWAPI::UnitTypes::Terran_Medic, medicsWanted)); return (const std::vector)goal; } const int StrategyManager::getCurrentStrategy() const { return currentStrategy; } void StrategyManager::setCurrentStrategy(int newStrategy, const std::unordered_map &choices) { currentStrategy = newStrategy; strategyChoices[BWAPI::Broodwar->self()->getRace().getID()][currentStrategy] = choices; } int StrategyManager::getNumStrategies(BWAPI::Race race) { if (race == BWAPI::Races::Protoss) { return NumProtossStrategies; } else if (race == BWAPI::Races::Zerg){ return NumZergStrategies; } else if (race == BWAPI::Races::Terran){ return NumTerranStrategies; } else{ UAB_ASSERT(false, "Unknown race"); } } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLStrategyManager.h ================================================ #pragma once #include "Common.h" #include "BWTA.h" #include "BuildOrderQueue.h" #include "InformationManager.h" #include "WorkerManager.h" #include #include #include "OpeningBuildOrders.h" #include "HLUnitData.h" namespace UAlbertaBot { typedef std::pair IntPair; typedef std::pair MetaPair; typedef std::vector MetaPairVector; class StrategyManager { StrategyManager(); ~StrategyManager() {} std::string readDir; std::string writeDir; std::vector results; std::vector usableStrategies; int currentStrategy; std::unordered_map > > strategyChoices;//race->strategy->choicepoint->option static std::unordered_map > > defaultStrategyChoices; BWAPI::Race selfRace; BWAPI::Race enemyRace; bool firstAttackSent; void addStrategies(); void setStrategy(); void readResults(); void writeResults(); const int getScore(BWAPI::PlayerInterface * player) const; const double getUCBValue(const size_t & strategy) const; // protoss strategy const bool expandProtossZealotRush() const; static bool expandProtossZealotRush( const HLUnitData &selfUnitData, const WorkerData &selfWorkerData, int frame, int frameAdjust = 0, int zealotAdjust = 0); const MetaPairVector getProtossZealotRushBuildOrderGoal() const; static MetaPairVector getProtossZealotRushBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame); const MetaPairVector getProtossDarkTemplarBuildOrderGoal() const; static MetaPairVector getProtossDarkTemplarBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame); const MetaPairVector getProtossDragoonsBuildOrderGoal() const; static MetaPairVector getProtossDragoonsBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame); const MetaPairVector getProtossHighLevelSearchBuildOrderGoal() const; static MetaPairVector getProtossHighLevelSearchBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame, const std::unordered_map &choices, bool useDefaultChoicesIfNeeded); const MetaPairVector getTerranBuildOrderGoal() const; static MetaPairVector getTerranBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame); const MetaPairVector getZergBuildOrderGoal() const; static MetaPairVector getZergBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame); //const MetaPairVector getProtossOpeningBook() const; //const MetaPairVector getTerranOpeningBook() const; //const MetaPairVector getZergOpeningBook() const; public: enum { ProtossZealotRush=0, ProtossDarkTemplar=1, ProtossDragoons=2, ProtossHighLevelSearch=3, NumProtossStrategies=4 }; enum { TerranMarineRush=0, NumTerranStrategies=1 }; enum { ZergZerglingRush=0, NumZergStrategies=1 }; static StrategyManager & Instance(); void onEnd(const bool isWinner); const bool regroup(int numInRadius); const bool doAttack(const std::set & freeUnits); const int defendWithWorkers(); const bool rushDetected(); const int getCurrentStrategy() const; static int getNumStrategies(BWAPI::Race race); void setCurrentStrategy(int newStrategy, const std::unordered_map &choices);//for high level search to set the strategy const MetaPairVector getBuildOrderGoal(); const std::vector getOpeningBookBuildOrder() const; static std::vector getOpeningBookBuildOrder(int strategy, BWAPI::Race race); static MetaPairVector getBuildOrderGoal( const HLUnitData &selfUnitData, const HLUnitData &enemyUnitData, const WorkerData &selfWorkerData, int frame, int strategy, BWAPI::Race race, const std::unordered_map &choices); }; struct ChoicePoint{ short _point, _options; ChoicePoint(short point, short options) :_point(point), _options(options){}; }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLTranspositionTable.cpp ================================================ #include "HLTranspositionTable.h" using namespace UAlbertaBot; HLTranspositionTable::HLTranspositionTable(int size) :_size(size), _entries(new HLEntry[size]) { } HLTranspositionTable::~HLTranspositionTable() { } void HLTranspositionTable::store(const HLState &origState, const HLMove &bestMove, int value, int alpha, int beta, int height) { unsigned int hash = origState.getHash(); _entries[hash%_size]._bestMove = bestMove; _entries[hash%_size]._hash = hash; _entries[hash%_size]._value = value; _entries[hash%_size]._height = height; if (value <= alpha){ _entries[hash%_size]._exact = false; _entries[hash%_size]._upper = true; } else if (value >= beta){ _entries[hash%_size]._exact = false; _entries[hash%_size]._upper = false; } else{ _entries[hash%_size]._exact = true; _entries[hash%_size]._upper = false; } } void HLTranspositionTable::store(const HLState &origState, int depth, const HLMove &move, const HLMove &bestMove, int value, int alpha, int beta, int height) { unsigned int hash = origState.getHash(depth, move); _entries[hash%_size]._bestMove = bestMove; _entries[hash%_size]._hash = hash; _entries[hash%_size]._value = value; _entries[hash%_size]._height = height; if (value <= alpha){ _entries[hash%_size]._exact = false; _entries[hash%_size]._upper = true; } else if (value >= beta){ _entries[hash%_size]._exact = false; _entries[hash%_size]._upper = false; } else{ _entries[hash%_size]._exact = true; _entries[hash%_size]._upper = false; } } const HLEntry& HLTranspositionTable::lookup(const HLState &state, int depth, const HLMove &move) { return _entries[state.getHash(depth, move) % _size]; } const HLEntry& HLTranspositionTable::lookup(const HLState &state) { return _entries[state.getHash() % _size]; } HLCacheTable::HLCacheTable(int size) : _size(size), _entries(new HLCacheEntry[size]) { } HLCacheTable::~HLCacheTable() { } void HLCacheTable::store(const HLState &origState, int depth, const std::array < HLMove, 2 > &movePair, const HLState &newState) { unsigned int hash = origState.getHash(depth, movePair); _entries[hash%_size]._hash = hash; _entries[hash%_size]._state = newState; } const HLCacheEntry& HLCacheTable::lookup(const HLState &state, int depth, const std::array < HLMove, 2 > &movePair) { return _entries[state.getHash(depth, movePair) % _size]; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLTranspositionTable.h ================================================ #pragma once #include "HLState.h" namespace UAlbertaBot { struct HLEntry{ HLMove _bestMove; unsigned int _hash; int _value; int _height; bool _exact; bool _upper; }; class HLTranspositionTable { int _size; std::unique_ptr _entries; public: HLTranspositionTable(int size); ~HLTranspositionTable(); void store(const HLState &origState, const HLMove &bestMove, int value, int alpha, int beta, int height); void store(const HLState &origState, int depth, const HLMove &move, const HLMove &bestMove, int value, int alpha, int beta, int height); const HLEntry& lookup(const HLState &state, int depth, const HLMove &move); const HLEntry& lookup(const HLState &state); }; struct HLCacheEntry{ HLState _state; unsigned int _hash; }; class HLCacheTable { int _size; std::unique_ptr _entries; public: HLCacheTable(int size); ~HLCacheTable(); void store(const HLState &origState, int depth, const std::array < HLMove, 2 > &movePair, const HLState &newState); const HLCacheEntry& lookup(const HLState &state, int depth, const std::array < HLMove, 2 > &movePair); }; } ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLUnitData.cpp ================================================ #include "HLUnitData.h" using namespace UAlbertaBot; HLUnitData::HLUnitData() :_highestID(-1), mineralsLost(0), gasLost(0), _player(NULL) { int maxTypeID(0); for (const BWAPI::UnitType & t : BWAPI::UnitTypes::allUnitTypes()) { maxTypeID = maxTypeID > t.getID() ? maxTypeID : t.getID(); } numDeadUnits = std::vector(maxTypeID + 1, 0); numUnits = std::vector(maxTypeID + 1, 0); numCompletedUnits = std::vector(maxTypeID + 1, 0); } HLUnitData::HLUnitData(BWAPI::Player player) :HLUnitData() { _player = player; } HLUnitData::HLUnitData(const UnitData &data, BWAPI::Player player) : HLUnitData(player) { for (auto unit : data.getUnits()){ addUnit(unit.second); } mineralsLost = data.getMineralsLost(); gasLost = data.getGasLost(); } HLUnitData::~HLUnitData() { } //virtual methods void HLUnitData::getCloakedUnits(std::set & v) const { for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.canCloak()) { v.insert(ui); } } } int HLUnitData::numCloakedUnits() const { int count = 0; for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.canCloak()) { count++; } } return count; } void HLUnitData::getDetectorUnits(std::set & v) const { for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.isDetector()) { v.insert(ui); } } } void HLUnitData::getFlyingUnits(std::set & v) const { for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.isFlyer()) { v.insert(ui); } } } bool HLUnitData::hasCloakedUnits() const { for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.canCloak()) { return true; } } return false; } bool HLUnitData::hasDetectorUnits() const { for (auto item : _unitMap) { const UnitInfo & ui(item.second); if (ui.isDetector()) { return true; } } return false; } int HLUnitData::getNumUnits(BWAPI::UnitType t) const { return numUnits[t.getID()]; } int HLUnitData::getNumCompletedUnits(BWAPI::UnitType t) const { return numCompletedUnits[t.getID()]; } int HLUnitData::getNumDeadUnits(BWAPI::UnitType t) const { return numDeadUnits[t.getID()]; } //new methods void HLUnitData::removeUnit(int id) { if (_unitMap.find(id) != _unitMap.end()){ const UnitInfo &unit = _unitMap.at(id); numDeadUnits[unit.type.getID()]++; numCompletedUnits[unit.type.getID()]--; numUnits[unit.type.getID()]--; _unitMap.erase(id); } //todo:decrease highest ID? //todo:update _baseRegions? } void HLUnitData::addUnit(const UnitInfo &unit) { if (_unitMap.find(unit.unitID) == _unitMap.end()){ _unitMap[unit.unitID] = unit; if (unit.completed){ numCompletedUnits[unit.type.getID()]++; } numUnits[unit.type.getID()]++; if (unit.unitID > _highestID){ _highestID = unit.unitID; } } else{//update info _unitMap[unit.unitID].completed = unit.completed; _unitMap[unit.unitID].lastHealth = unit.lastHealth; _unitMap[unit.unitID].lastPosition = unit.lastPosition; } if (unit.type.isBuilding()) { try { _baseRegions.insert(BWTA::getRegion(unit.lastPosition)); } catch (...) { Logger::LogAppendToFile(UAB_LOGFILE, "Exception at BWTA::getRegion(%d, %d), ignoring unit", unit.lastPosition.x, unit.lastPosition.y); } } } bool HLUnitData::finishUnit(BWAPI::UnitType type) { bool found = false; for (auto &item : _unitMap){ if (item.second.type.getID() == type.getID() && !item.second.completed){ item.second.completed = true; numCompletedUnits[type.getID()]++; found = true; break; } } UAB_ASSERT(found,"Couldn't find unit to finish: %s\n",type.getName().c_str()); return found; } //std::vector HLUnitData::getUnitVector() const //{ // std::vector v; // std::transform(_unitMap.begin(), _unitMap.end(), std::back_inserter(v), // [](const std::pair &item){ // return item.second; // }); // return v; //} ================================================ FILE: UAlbertaBot/Source/research/hlsearch/HLUnitData.h ================================================ #pragma once #include "UnitData.h" namespace UAlbertaBot{ class HLUnitData { std::vector numDeadUnits; std::vector numUnits; std::vector numCompletedUnits; int mineralsLost; int gasLost; std::unordered_map _unitMap;//id->info int _highestID; std::unordered_set _baseRegions;//regions with buildings BWAPI::Player _player; public: HLUnitData(); HLUnitData(BWAPI::Player player); HLUnitData(const UnitData &data, BWAPI::Player player); virtual ~HLUnitData(); //virtual methods void getCloakedUnits(std::set & v) const; int numCloakedUnits() const; void getDetectorUnits(std::set & v) const; void getFlyingUnits(std::set & v) const; bool hasCloakedUnits() const; bool hasDetectorUnits() const; int getNumUnits(BWAPI::UnitType t) const; int getNumCompletedUnits(BWAPI::UnitType t) const; int getNumDeadUnits(BWAPI::UnitType t) const; const std::unordered_map & getUnits() const { return _unitMap; } //new methods void removeUnit(int id); void addUnit(const UnitInfo &unit); bool finishUnit(BWAPI::UnitType type); //std::vector getUnitVector() const; int highestID() const {return _highestID;} const std::unordered_set& getBaseRegions() const { return _baseRegions; } const BWAPI::Player player() const { return _player; } }; } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/SparCraftManager.cpp ================================================ #include "SparCraftManager.h" using namespace UAlbertaBot; SparCraftManager::SparCraftManager() : gameOver(false) { SparCraft::init(); } void SparCraftManager::onStart() { SparCraft::GameState state(extractGameState()); } void SparCraftManager::update() { if (!gameOver) { // for each unit that we control, do some book keeping for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits()) { BWAPI::Broodwar->drawTextMap(unit->getPosition().x-20, unit->getPosition().y-12, "%d", unit->getID()); // if it is a combat unit if (isCombatUnit(unit)) { if (Config::Debug::DrawUnitTargetInfo && unit->getTarget()) { BWAPI::Broodwar->drawLineMap(unit->getPosition().x-2, unit->getPosition().y-2, unit->getTarget()->getPosition().x, unit->getTarget()->getPosition().y, BWAPI::Colors::White); } } } performSparCraft(); } } void SparCraftManager::getMoves(SparCraft::GameState & state, std::vector & moveVec) { const SparCraft::IDType playerID = getPlayerID(BWAPI::Broodwar->self()); SparCraft::MoveArray moves; state.generateMoves(moves, playerID); SparCraft::PlayerPtr gsPlayer(new SparCraft::Player_PortfolioGreedySearch(playerID, SparCraft::PlayerModels::NOKDPS, 1, 0, 0)); gsPlayer->getMoves(state, moves, moveVec); } void SparCraftManager::performSparCraft() { SparCraft::GameState currentState = extractGameState(); int currentFrame = BWAPI::Broodwar->getFrameCount(); for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->enemy()->getUnits()) { BWAPI::Broodwar->drawTextMap(unit->getPosition().x, unit->getPosition().y, "%d", unit->getGroundWeaponCooldown()); } // draw our units for (size_t u(0); udrawCircleMap(unit.x(), unit.y(), 5, BWAPI::Colors::Green); BWAPI::Broodwar->drawCircleMap(unit.x(), unit.y(), unit.range(), BWAPI::Colors::Grey); std::pair cooldown = getUnitCooldown(BWAPI::Broodwar->getUnit(unit.ID()), unit); BWAPI::UnitInterface* realUnit = getUnit(unit); BWAPI::Broodwar->drawTextMap(unit.x(), unit.y(), "%d (%d %d %d)", unit.ID(), cooldown.first-currentFrame, cooldown.second-currentFrame, BWAPI::Broodwar->getUnit(unit.ID())->getGroundWeaponCooldown()); BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), realUnit->getPosition().x, realUnit->getPosition().y, BWAPI::Colors::Purple); } // TODO: Check why zealots aren't being given commands // draw their units for (size_t u(0); ugetUnit(unit.ID())); //BWAPI::Broodwar->drawCircleMap(unit.x, unit.y, 5, BWAPI::Colors::Red); } // draw our moves if we are the player to move const SparCraft::IDType whoCanMove = currentState.whoCanMove(); if ((whoCanMove == SparCraft::Players::Player_One) || (whoCanMove == SparCraft::Players::Player_Both)) { // get the best move tuple from the current state //MoveTuple bestTuple = getMoveTuple(currentState, Search::PlayerModels::AlphaBeta); std::vector moveVec; getMoves(currentState, moveVec); // extract all of the moves possible from the current state SparCraft::MoveArray moves; currentState.generateMoves(moves, SparCraft::Players::Player_One); // draw the best move for each unit for (size_t u(0); udrawCircleMap(unit.x(), unit.y(), 5, BWAPI::Colors::Red); // draw the move this unit should do drawUnitMove(currentState, unit, move); drawUnitCooldown(BWAPI::Broodwar->getUnit(unit.ID())); drawUnitHP(BWAPI::Broodwar->getUnit(unit.ID())); // do the move doUnitMove(currentState, unit, move); } } } void SparCraftManager::doUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move) { SparCraft::IDType enemyPlayer = (unit.player() + 1) % 2; BWAPI::UnitInterface* u = BWAPI::Broodwar->getUnit(unit.ID()); if (move._moveType == SparCraft::UnitActionTypes::ATTACK) { BWAPI::Broodwar->drawTextMap(unit.x()+5, unit.y()+5, "A"); SparCraft::Unit & enemyUnit(currentState.getUnit(enemyPlayer, move._moveIndex)); UnitCommandManager::Instance().smartAttackUnit(u, BWAPI::Broodwar->getUnit(enemyUnit.ID())); } else if (move._moveType == SparCraft::UnitActionTypes::MOVE) { BWAPI::Broodwar->drawTextMap(unit.x()+5, unit.y()+5, "M"); SparCraft::Position pos(SparCraft::Constants::Move_Dir[move._moveIndex][0], SparCraft::Constants::Move_Dir[move._moveIndex][1]); SparCraft::Position dest(unit.x() + (pos.x() * 4*SparCraft::Constants::Move_Distance), unit.y() + (pos.y() * 4*SparCraft::Constants::Move_Distance)); UnitCommandManager::Instance().smartMove(u, BWAPI::Position(dest.x(), dest.y())); } else if (move._moveType == SparCraft::UnitActionTypes::RELOAD) { UnitCommandManager::Instance().smartReload(u); } } void SparCraftManager::drawAttackDebug() { char * trueFix = "\x07"; char * falseFix = "\x06"; for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits()) { int x = unit->getPosition().x; int y = unit->getPosition().y + 9; BWAPI::Broodwar->drawTextMap(x, y, "%s isAttacking", unit->isAttacking() ? trueFix : falseFix); BWAPI::Broodwar->drawTextMap(x, y+10, "%s isAttackFrame", unit->isAttackFrame() ? trueFix : falseFix); BWAPI::Broodwar->drawTextMap(x, y+20, "%s isMoving", unit->isMoving() ? trueFix : falseFix); } } void SparCraftManager::drawUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move) { SparCraft::IDType enemyPlayer = (unit.player() + 1) % 2; if (move._moveType == SparCraft::UnitActionTypes::ATTACK) { SparCraft::Unit & enemyUnit(currentState.getUnit(enemyPlayer,move._moveIndex)); BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), enemyUnit.x(), enemyUnit.y(), BWAPI::Colors::Cyan); } else if (move._moveType == SparCraft::UnitActionTypes::MOVE) { SparCraft::Position pos(SparCraft::Constants::Move_Dir[move._moveIndex][0], SparCraft::Constants::Move_Dir[move._moveIndex][1]); SparCraft::Position dest(unit.x() + (pos.x() * 32), unit.y() + (pos.y() * 32)); BWAPI::Broodwar->drawLineMap(unit.x(), unit.y(), dest.x(), dest.y(), BWAPI::Colors::Yellow); } } void SparCraftManager::drawUnitCooldown(BWAPI::UnitInterface* unit) { double totalCooldown = unit->getType().groundWeapon().damageCooldown(); double remainingCooldown = unit->getGroundWeaponCooldown(); double percCooldown = remainingCooldown / (totalCooldown+1); int w = 32; int h = 4; int cw = w - (int)(w * percCooldown); int ch = h; int x1 = unit->getPosition().x - w/2; int y1 = unit->getPosition().y - 16; BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + w, y1 + h, BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + cw, y1 + ch, BWAPI::Colors::Red, true); } void SparCraftManager::drawUnitHP(BWAPI::UnitInterface* unit) { double totalHP = unit->getType().maxHitPoints() + unit->getType().maxShields(); double currentHP = unit->getHitPoints() + unit->getShields(); double percHP = currentHP / (totalHP+1); int w = 32; int h = 4; int cw = (int)(w * percHP); int ch = h; int x1 = unit->getPosition().x - w/2; int y1 = unit->getPosition().y - 12; BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + w, y1 + h, BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(x1, y1, x1 + cw, y1 + ch, BWAPI::Colors::Green, true); } const SparCraft::IDType SparCraftManager::getPlayerID(BWAPI::PlayerInterface * player) const { return (player == BWAPI::Broodwar->self()) ? SparCraft::Players::Player_One : SparCraft::Players::Player_Two; } const bool SparCraftManager::isCombatUnit(BWAPI::UnitInterface* unit) const { assert(unit != NULL); // no workers or buildings allowed if (unit && unit->getType().isWorker() || unit->getType().isBuilding()) { return false; } // check for various types of combat units if (unit->getType().canAttack() || unit->getType() == BWAPI::UnitTypes::Terran_Medic || unit->getType() == BWAPI::UnitTypes::Protoss_High_Templar || unit->getType() == BWAPI::UnitTypes::Protoss_Observer) { return true; } return false; } BWAPI::UnitInterface* SparCraftManager::getUnit(SparCraft::Unit & unit) { for (BWAPI::UnitInterface* u : BWAPI::Broodwar->getAllUnits()) { if (u->getID() == unit.ID()) { return u; } } return NULL; } const std::pair SparCraftManager::getUnitCooldown(BWAPI::UnitInterface* unit, SparCraft::Unit & u) const { int attackCooldown(0); int moveCooldown(0); BWAPI::UnitCommand lastCommand = unit->getLastCommand(); int lastCommandFrame = unit->getLastCommandFrame(); int currentFrame = BWAPI::Broodwar->getFrameCount(); int framesSinceCommand = currentFrame - lastCommandFrame; if ((unit->getType() == BWAPI::UnitTypes::Protoss_Dragoon) && (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit)) { // dragoons are one of only 2 unit types whose attack can be canceled by the in-game targeter being called too early so // this hack makes up for that by taking it's stop-delay into account attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-SparCraft::AnimationFrameData::getAttackFrames(unit->getType()).first); } else { attackCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, unit->getGroundWeaponCooldown()-2); } // if the last attack was an attack command if (lastCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit) { moveCooldown = BWAPI::Broodwar->getFrameCount() + std::max(0, u.attackInitFrameTime() - framesSinceCommand); //BWAPI::Broodwar->drawTextScreen(100,100, "%d, %d", attackCooldown-currentFrame, moveCooldown-currentFrame); } // if the last command was a move command else if (lastCommand.getType() == BWAPI::UnitCommandTypes::Move) { moveCooldown = currentFrame; } if (moveCooldown - BWAPI::Broodwar->getFrameCount() < 4 || unit->isMoving()) { moveCooldown = currentFrame; } moveCooldown = std::min(moveCooldown, attackCooldown); return std::pair(attackCooldown, moveCooldown); } //Unit(const BWAPI::UnitType unitType, const Position & pos, const IDType & unitID, const IDType & playerID, // const HealthType & hp, const HealthType & energy, const TimeType & tm, const TimeType & ta); SparCraft::Unit SparCraftManager::getSparCraftUnit(const BWAPI::UnitInterface* bwapiUnit, BWAPI::GameWrapper & game) { BWAPI::UnitType type = bwapiUnit->getType(); SparCraft::Position pos = SparCraft::Position(bwapiUnit->getPosition().x, bwapiUnit->getPosition().y); SparCraft::IDType unitID = (SparCraft::IDType)bwapiUnit->getID(); SparCraft::IDType playerID = (SparCraft::IDType)getPlayerID(bwapiUnit->getPlayer()); SparCraft::HealthType health = (SparCraft::HealthType)(bwapiUnit->getHitPoints() + bwapiUnit->getShields()); SparCraft::HealthType energy = (SparCraft::HealthType)(bwapiUnit->getEnergy()); SparCraft::TimeType timeCanMove = (SparCraft::TimeType)(game->getFrameCount()); SparCraft::TimeType timeCanAtk = (SparCraft::TimeType)(game->getFrameCount() + bwapiUnit->getGroundWeaponCooldown() + bwapiUnit->getAirWeaponCooldown()); return SparCraft::Unit(type, pos, unitID, playerID, health, energy, timeCanMove, timeCanAtk); } // constructor based on a BWAPI unit, used by UAlbertaBot /*Unit::Unit(BWAPI::UnitInterface* unit, BWAPI::Game * game, const IDType & playerID, const TimeType & gameTime) : _unitType (unit->getType() == BWAPI::UnitTypes::Terran_Medic ? BWAPI::UnitTypes::Terran_Marine : unit->getType()) , _range (unit->getType().groundWeapon().maxRange() + 32) , _position (Position(unit->getPosition().x, unit->getPosition().y)) , _unitID ((IDType)unit->getID()) , _playerID (playerID) , _currentHP ((HealthType)(unit->getHitPoints() + unit->getShields())) , _currentEnergy ((HealthType)unit->getEnergy()) , _timeCanMove ((TimeType)(game->getFrameCount())) , _timeCanAttack ((TimeType)(game->getFrameCount() + unit->getGroundWeaponCooldown() + unit->getAirWeaponCooldown())) , _previousActionTime (gameTime) , _prevCurrentPosTime (0) , _previousPosition (Position(unit->getPosition().x, unit->getPosition().y)) { }*/ // get an abstract GameState object from the current BWAPI state SparCraft::GameState SparCraftManager::extractGameState() { // construct a state with the current time SparCraft::GameState state; state.setTime(BWAPI::Broodwar->getFrameCount()); // add each of our fighting units for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits()) { if (isCombatUnit(unit)) { SparCraft::Unit u = getSparCraftUnit(unit, BWAPI::Broodwar); std::pair cd = getUnitCooldown(unit, u); u.setCooldown(cd.first, cd.second); state.addUnitWithID(u); } } for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->enemy()->getUnits()) { if (isCombatUnit(unit)) { SparCraft::Unit u = getSparCraftUnit(unit, BWAPI::Broodwar); u.setCooldown(BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount() + unit->getGroundWeaponCooldown()); state.addUnitWithID(u); } } if (state.numUnits(0) == 0 && state.numUnits(1) == 0) { gameOver = true; } else if (state.numUnits(1) == 0) { gameOver = true; } else if (state.numUnits(0) == 0) { gameOver = true; } if (gameOver) { BWAPI::Broodwar->restartGame(); } state.finishedMoving(); return state; } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/SparCraftManager.h ================================================ #pragma once #include "Common.h" #include "BWAPI.h" #include "GameCommander.h" #include "UnitCommandManager.h" #include "../../SparCraft/Source/SparCraft.h" namespace UAlbertaBot { class SparCraftManager { bool gameOver; public: SparCraftManager(); SparCraft::GameState extractGameState(); const SparCraft::IDType getPlayerID(BWAPI::PlayerInterface * player) const; const bool isCombatUnit(BWAPI::UnitInterface* unit) const; void getMoves(SparCraft::GameState & state, std::vector & moveVec); void update(); void onStart(); void doUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move); void drawUnitMove(SparCraft::GameState & currentState, SparCraft::Unit & unit, SparCraft::UnitAction & move); void drawUnitCooldown(BWAPI::UnitInterface* unit); void drawUnitHP(BWAPI::UnitInterface* unit); void drawSearchResults(int x, int y); void drawAttackDebug(); void performSparCraft(); SparCraft::Unit getSparCraftUnit(const BWAPI::UnitInterface* bwapiUnit, BWAPI::GameWrapper & game); BWAPI::UnitInterface* getUnit(SparCraft::Unit & unit); const std::pair getUnitCooldown(BWAPI::UnitInterface* unit, SparCraft::Unit & u) const; }; } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/UnitCommandData.cpp ================================================ #include "UnitCommandData.h" using namespace UAlbertaBot; UnitCommandData::UnitCommandData() : _unit(NULL) , _phase(UnitCommandData::NONE) , _enteredReady(0) , _enteredAttacking(0) , _enteredReloading(0) , _waitCommandGiven(0) { } UnitCommandData::UnitCommandData(BWAPI::UnitInterface* unit) : _unit(unit) , _phase(UnitCommandData::NONE) , _enteredReady(0) , _enteredAttacking(0) , _enteredReloading(0) , _waitCommandGiven(0) { } const bool UnitCommandData::isWaiting() const { return (getPhase() == RELOADING) && (_waitCommandGiven > _enteredReloading); } const int UnitCommandData::getPhase() const { return _phase; } void UnitCommandData::waitCommand() { _waitCommandGiven = BWAPI::Broodwar->getFrameCount(); } void UnitCommandData::update() { int currentFrame = BWAPI::Broodwar->getFrameCount(); if (_phase == NONE) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } else { _phase = RELOADING; _enteredReloading = currentFrame; } } else if (_phase == READY) { if (_unit->isAttackFrame() || _unit->isStartingAttack()) { _phase = ATTACKING; _enteredAttacking = currentFrame; } } else if (_phase == ATTACKING) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } else if (!_unit->isAttackFrame() || ((currentFrame - _enteredAttacking) > SparCraft::AnimationFrameData::getAttackFrames(_unit->getType()).first)) { _phase = RELOADING; _enteredReloading = currentFrame; } } else if (_phase == RELOADING) { if (_unit->getGroundWeaponCooldown() == 0) { _phase = READY; _enteredReady = currentFrame; } } } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/UnitCommandData.h ================================================ #pragma once #include "Common.h" #include "BWAPI.h" #include "..\..\SparCraft\source\SparCraft.h" namespace UAlbertaBot { class UnitCommandData { BWAPI::UnitInterface* _unit; int _phase, _enteredReady, _enteredAttacking, _enteredReloading, _waitCommandGiven; public: enum { NONE, READY, ATTACKING, RELOADING }; UnitCommandData(); UnitCommandData(BWAPI::UnitInterface* unit); void update(); void waitCommand(); void attackCommand(); const bool isWaiting() const; const int getPhase() const; }; } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/UnitCommandManager.cpp ================================================ #include "UnitCommandManager.h" using namespace UAlbertaBot; UnitCommandManager::UnitCommandManager() {} // get an instance of this UnitCommandManager & UnitCommandManager::Instance() { static UnitCommandManager instance; return instance; } void UnitCommandManager::update() { for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType().canAttack()) { updateUnit(unit); } } } UnitCommandData & UnitCommandManager::getUnitData(BWAPI::UnitInterface* unit) { return map[unit]; } void UnitCommandManager::updateUnit(BWAPI::UnitInterface* unit) { if (!unit) { return; } // if it's not in our map, add a default entry if (!exists(unit)) { addUnit(unit); } getUnitData(unit).update(); } void UnitCommandManager::addUnit(BWAPI::UnitInterface* unit) { map[unit] = UnitCommandData(unit); } void UnitCommandManager::removeUnit(BWAPI::UnitInterface* unit) { map.erase(unit); } bool UnitCommandManager::exists(BWAPI::UnitInterface* unit) const { return map.find(unit) != map.end(); } bool UnitCommandManager::commandWillInterruptAttack(BWAPI::UnitInterface* unit) { const UnitCommandData & unitData(getUnitData(unit)); if (unitData.getPhase() == UnitCommandData::ATTACKING) { return true; } //BWAPI::Broodwar->drawTextScreen(20, 20, "ATTACK PASS!"); return false; } bool UnitCommandManager::canIssueAttackCommand(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target) { BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); BWAPI::UnitCommandType commandType = currentCommand.getType(); // if we have already given a command this frame, don't issue another one //if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - attacker->getLastCommandFrame() <= 7) //{ // drawDebugPlate(attacker, "A FRAME"); // return false; //} // if the last command given was an attack command if (currentCommand.getType() == BWAPI::UnitCommandTypes::Attack_Unit) { // if the target is the same as the current one, we don't need to switch if (currentCommand.getTarget() == target) { drawDebugPlate(attacker, "SAME"); return false; } } //return true; return !commandWillInterruptAttack(attacker); } bool UnitCommandManager::canIssueMoveCommand(BWAPI::UnitInterface* unit, BWAPI::Position & position) { BWAPI::UnitCommand currentCommand(unit->getLastCommand()); BWAPI::UnitCommandType commandType = currentCommand.getType(); int threshold = 5; // if we have already given a command this frame, don't issue another one //if (commandType != BWAPI::UnitCommandTypes::None && BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() <= 7) //{ // drawDebugPlate(unit, "M FRAME"); // return false; //} //if (getUnitData(unit).isWaiting()) //{ // drawDebugPlate(unit, "WAIT"); // return false; //} // if the last command given was an attack command if (currentCommand.type == BWAPI::UnitCommandTypes::Move) { if (!unit->isMoving()) { return true; } else { return unit->getDistance(position) < 28; } } return !commandWillInterruptAttack(unit); } bool UnitCommandManager::canIssueStopCommand(BWAPI::UnitInterface* unit) { // if the last move was attacking a unit do nothing if (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit) { return false; } return !commandWillInterruptAttack(unit); } void UnitCommandManager::drawDebugPlate(BWAPI::UnitInterface* unit, char * string) { BWAPI::Broodwar->drawBoxMap(unit->getPosition().x-15, unit->getPosition().y-10, unit->getPosition().x + 10, unit->getPosition().y, BWAPI::Colors::Black, true); BWAPI::Broodwar->drawTextMap(unit->getPosition().x-15, unit->getPosition().y-10, string); } void UnitCommandManager::drawCommandStatus(BWAPI::UnitInterface* unit) { BWAPI::UnitType type = unit->getType(); int width = type.dimensionRight(); int height = type.dimensionDown()/6; int x1 = unit->getPosition().x - width; int x2 = unit->getPosition().y + width; int y1 = unit->getPosition().y - height; int y2 = unit->getPosition().y + height; } void UnitCommandManager::waitCommand(BWAPI::UnitInterface* unit) { getUnitData(unit).waitCommand(); } void UnitCommandManager::smartReload(BWAPI::UnitInterface* unit) { assert(unit); if (!canIssueStopCommand(unit)) { return; } unit->stop(); waitCommand(unit); } void UnitCommandManager::smartAttackUnit(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target) { assert(attacker && target); if (!canIssueAttackCommand(attacker, target)) { return; } attacker->attack(target); if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(attacker->getPosition().x+3, attacker->getPosition().y+3, target->getPosition().x+3, target->getPosition().y+3, BWAPI::Colors::Red ); } } void UnitCommandManager::smartMove(BWAPI::UnitInterface* attacker, BWAPI::Position targetPosition) { assert(attacker); if (!canIssueMoveCommand(attacker, targetPosition)) { return; } attacker->move(targetPosition); if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(attacker->getPosition().x, attacker->getPosition().y, targetPosition.x, targetPosition.y, BWAPI::Colors::Orange); } } ================================================ FILE: UAlbertaBot/Source/research/sparcraft/UnitCommandManager.h ================================================ #pragma once #include "Common.h" #include "BWAPI.h" #include "UnitCommandData.h" namespace UAlbertaBot { class UnitCommandManager { std::map map; UnitCommandData & getUnitData(BWAPI::UnitInterface* unit); UnitCommandManager(); public: static UnitCommandManager & Instance(); void update(); void updateUnit(BWAPI::UnitInterface* unit); void addUnit(BWAPI::UnitInterface* unit); void removeUnit(BWAPI::UnitInterface* unit); void drawDebugPlate(BWAPI::UnitInterface* unit, char * string); void drawCommandStatus(BWAPI::UnitInterface* unit); bool exists(BWAPI::UnitInterface* unit) const; bool commandWillInterruptAttack(BWAPI::UnitInterface* unit); bool canIssueAttackCommand(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target); bool canIssueMoveCommand(BWAPI::UnitInterface* unit, BWAPI::Position & position); bool canIssueStopCommand(BWAPI::UnitInterface* unit); int attackAnimStartTime(BWAPI::UnitInterface* unit); void smartAttackUnit(BWAPI::UnitInterface* attacker, BWAPI::UnitInterface* target); void smartMove(BWAPI::UnitInterface* attacker, BWAPI::Position targetPosition); void smartReload(BWAPI::UnitInterface* unit); void waitCommand(BWAPI::UnitInterface* unit); void attackCommand(BWAPI::UnitInterface* unit); }; } ================================================ FILE: UAlbertaBot/Source/research/visualizer/Display.cpp ================================================ #include "Common.h" #include "Display.h" #include #include using namespace BWAPI; #ifdef USE_SDL #include #include Display::Display() : windowSizeX(640), windowSizeY(480), bl(false), br(false), bu(false), bd(false) { if(SDL_Init(SDL_INIT_VIDEO) != 0) { throw std::runtime_error("Unable to initialise SDL"); } } Display::~Display() { SDL_Quit(); } void Display::OnStart() { mapWidth = Broodwar->mapWidth(); mapHeight = Broodwar->mapHeight(); mapPixelWidth = mapWidth * 32; mapPixelHeight = mapHeight * 32; const BWAPI::Position position(Broodwar->self()->getStartLocation()); cameraX = position.x() - windowSizeX / 2; cameraY = position.y() - windowSizeY / 2; SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_SetVideoMode(windowSizeX, windowSizeY, 32, SDL_OPENGL); } void Display::OnFrame() { // Handle input events HandleEvents(); // Render the frame glClear(GL_COLOR_BUFFER_BIT); RenderMainMap(); RenderMinimap(); SDL_GL_SwapBuffers(); } void Display::HandleEvents() { // Handle SDL events SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_KEYDOWN: case SDL_KEYUP: { const bool pressed(event.key.state == SDL_PRESSED); switch(event.key.keysym.sym) { case SDLK_LEFT: bl = pressed; break; case SDLK_RIGHT: br = pressed; break; case SDLK_UP: bu = pressed; break; case SDLK_DOWN: bd = pressed; break; } } break; case SDL_QUIT: throw std::runtime_error("The user is a quitter"); break; } } // Move the camera const int cameraSpeed(128); if(bl) cameraX -= cameraSpeed; if(br) cameraX += cameraSpeed; if(bu) cameraY -= cameraSpeed; if(bd) cameraY += cameraSpeed; cameraX = std::max(0, std::min(cameraX, mapPixelWidth-windowSizeX)); cameraY = std::max(0, std::min(cameraY, mapPixelHeight-windowSizeY)); } void Display::RenderMainMap() { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0,windowSizeX,windowSizeY,0,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(static_cast(-cameraX),static_cast(-cameraY),0); const int vx0(cameraX), vx1(cameraX+windowSizeX); const int vy0(cameraY), vy1(cameraY+windowSizeY); RenderTerrain( std::max(vx0>>3,0), std::max(vy0>>3,0), std::min((vx1>>3) + 1, mapWidth*4), std::min((vy1>>3) + 1, mapHeight*4)); RenderTerrainAnalysis(); RenderUnits(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); } void Display::RenderMinimap() { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0,windowSizeX,0,windowSizeY,-1,1); glBegin(GL_QUADS); glVertex2i(0,0); glVertex2i(mapWidth+1,0); glVertex2i(mapWidth+1,mapHeight+1); glVertex2i(0,mapHeight+1); glEnd(); glLoadIdentity(); glOrtho(0,mapPixelWidth,mapPixelHeight,0,-1,1); glViewport(0,0,mapWidth,mapHeight); RenderTerrain(0,0,mapWidth*4,mapHeight*4); RenderUnits(); // Render outline around viewport on minimap { const int vpx0(cameraX), vpx1(vpx0 + windowSizeX); const int vpy0(cameraY), vpy1(vpy0 + windowSizeY); glBegin(GL_LINE_STRIP); glColor3f(1,1,1); glVertex2i(vpx0,vpy0); glVertex2i(vpx1,vpy0); glVertex2i(vpx1,vpy1); glVertex2i(vpx0,vpy1); glVertex2i(vpx0,vpy0); glEnd(); } glPopMatrix(); glPopAttrib(); } void Display::RenderTerrain(int wx0, int wy0, int wx1, int wy1) const { glBegin(GL_QUADS); for(int y(wy0); ygetPolygon()); for(size_t i(0); igetChokepoints()) { const Position & v0(choke->getSides().first); const Position & v1(choke->getSides().second); glVertex2i(v0.x(), v0.y()); glVertex2i(v1.x(), v1.y()); } } glEnd(); } void Display::RenderUnits() const { static const float3 factionColors[12] = { float3(1,0,0), float3(0,0,1), float3(0,1,0.5f), float3(0.5f,0,1), float3(1,0.5f,0), float3(0.5f,0.25f,0), float3(1,1,1), float3(1,1,0), float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,1,1) }; glBegin(GL_QUADS); BOOST_FOREACH(Unit * unit, Broodwar->getAllUnits()) { const UnitType type(unit->getType()); const int x0(unit->getPosition().x() - type.dimensionLeft()); const int x1(unit->getPosition().x() + type.dimensionRight()); const int y0(unit->getPosition().y() - type.dimensionUp()); const int y1(unit->getPosition().y() + type.dimensionDown()); glColor3fv(factionColors[unit->getPlayer()->getID()]); glVertex2i(x0,y0); glVertex2i(x1,y0); glVertex2i(x1,y1); glVertex2i(x0,y1); } glEnd(); } float3 Display::GetWalkTileColor(int x, int y) const { // Unexplored areas return black const TilePosition pos(x/4,y/4); if(!Broodwar->isExplored(pos)) { return 0; } // Basic terrain color float3 color(0.2f); if(Broodwar->isWalkable(x,y)) { color = 0.4f + Broodwar->getGroundHeight(x,y) * 0.2f; if(!Broodwar->isBuildable(pos)) { color *= float3(1,0.5f,0.5f); } } // Adjust for creep if(Broodwar->hasCreep(pos)) { color = float3(0.2f,0,0.3f); } // Adjust for fog of war if(!Broodwar->isVisible(pos)) { color /= 2; } return color; } #else Display::Display() {} Display::~Display() {} void Display::OnStart() {} void Display::OnFrame() {} #endif ================================================ FILE: UAlbertaBot/Source/research/visualizer/Display.h ================================================ #ifndef DISPLAY_H #define DISPLAY_H struct float3 { float x,y,z; float3() {} float3(float f) : x(f), y(f), z(f) {} float3(float x, float y, float z) : x(x), y(y), z(z) {} operator const float * () const { return &x; } float3 operator + (const float3 & v) const { return float3(x+v.x,y+v.y,z+v.z); } float3 operator - (const float3 & v) const { return float3(x-v.x,y-v.y,z-v.z); } float3 operator * (const float3 & v) const { return float3(x*v.x,y*v.y,z*v.z); } float3 operator / (const float3 & v) const { return float3(x/v.x,y/v.y,z/v.z); } operator float * () { return &x; } const float3 & operator += (const float3 & v) { x+=v.x; y+=v.y; z+=v.z; return *this; } const float3 & operator -= (const float3 & v) { x-=v.x; y-=v.y; z-=v.z; return *this; } const float3 & operator *= (const float3 & v) { x*=v.x; y*=v.y; z*=v.z; return *this; } const float3 & operator /= (const float3 & v) { x/=v.x; y/=v.y; z/=v.z; return *this; } }; class Display { int windowSizeX; int windowSizeY; int cameraX; int cameraY; int mapWidth; int mapHeight; int mapPixelWidth; int mapPixelHeight; bool bl,br,bd,bu; void HandleEvents(); void RenderMainMap(); void RenderMinimap(); void RenderTerrain(int wx0, int wy0, int wx1, int wy1) const; void RenderTerrainAnalysis() const; void RenderUnits() const; float3 GetWalkTileColor(int x, int y) const; public: Display(); ~Display(); void OnStart(); void OnFrame(); }; #endif ================================================ FILE: UAlbertaBot/Source/research/visualizer/EnhancedInterface.hpp ================================================ #pragma once #include #include #include "BWAPI.h" namespace UAlbertaBot { class ControlGroupData { std::map> keyMap; public: ControlGroupData() {} ~ControlGroupData() {} void update() { } void onUnitDestroy(BWAPI::UnitInterface* unit) { typedef std::map> mapType; for (mapType::value_type & t : keyMap) { t.second.erase(unit); } } // sets control group to only selected units void newControlGroup(BWAPI::Key k) { BWAPI::Broodwar->printf("New control group %d", k-BWAPI::K_0); keyMap[k] = std::set(); for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->getSelectedUnits()) { if (unit->getPlayer() == BWAPI::Broodwar->self()) { keyMap[k].insert(unit); } } } void addToControlGroup(BWAPI::Key k) { BWAPI::Broodwar->printf("Add to control group %d", k-BWAPI::K_0); if (!controlGroupExists(k)) { keyMap[k] = std::set(); } for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->getSelectedUnits()) { if (unit->getPlayer() == BWAPI::Broodwar->self()) { keyMap[k].insert(unit); } } } bool controlGroupExists(BWAPI::Key k) { return keyMap.find(k) != keyMap.end(); } std::set * getControlGroupUnits(BWAPI::Key k) { if (!controlGroupExists(k)) { keyMap[k] = std::set(); } return &keyMap[k]; } }; class EnhancedInterface { int lastKeyEvent; int lastControlGroup; std::vector keys; ControlGroupData data; std::set * selectedUnits; public: EnhancedInterface() : lastKeyEvent(0) , lastControlGroup(0) , selectedUnits(NULL) { // numbers keys.push_back(BWAPI::K_0); keys.push_back(BWAPI::K_1); keys.push_back(BWAPI::K_2); keys.push_back(BWAPI::K_3); keys.push_back(BWAPI::K_4); keys.push_back(BWAPI::K_5); keys.push_back(BWAPI::K_6); keys.push_back(BWAPI::K_7); keys.push_back(BWAPI::K_8); keys.push_back(BWAPI::K_9); // letters keys.push_back(BWAPI::K_A); keys.push_back(BWAPI::K_B); keys.push_back(BWAPI::K_C); keys.push_back(BWAPI::K_D); keys.push_back(BWAPI::K_E); keys.push_back(BWAPI::K_F); keys.push_back(BWAPI::K_G); keys.push_back(BWAPI::K_H); keys.push_back(BWAPI::K_I); keys.push_back(BWAPI::K_J); keys.push_back(BWAPI::K_K); keys.push_back(BWAPI::K_L); keys.push_back(BWAPI::K_M); keys.push_back(BWAPI::K_N); keys.push_back(BWAPI::K_O); keys.push_back(BWAPI::K_P); keys.push_back(BWAPI::K_Q); keys.push_back(BWAPI::K_R); keys.push_back(BWAPI::K_S); keys.push_back(BWAPI::K_T); keys.push_back(BWAPI::K_U); keys.push_back(BWAPI::K_V); keys.push_back(BWAPI::K_W); keys.push_back(BWAPI::K_X); keys.push_back(BWAPI::K_Y); keys.push_back(BWAPI::K_Z); } ~EnhancedInterface() {} void onUnitDestroy(BWAPI::UnitInterface* unit) { data.onUnitDestroy(unit); } void update() { data.update(); processKeyboardEvents(); processMouseEvents(); if (selectedUnits) { drawSelectedUnits(175,275); } } void processKeyboardEvents() { for (BWAPI::Key k : keys) { if (BWAPI::Broodwar->getKeyState(k)) { keyboardEvent(k); } } } void processMouseEvents() { if (BWAPI::Broodwar->getMouseState(BWAPI::M_RIGHT)) { mouseEvent(BWAPI::M_RIGHT); } } void mouseEvent(BWAPI::MouseButton m) { int mouseMapX = BWAPI::Broodwar->getMousePosition().x + BWAPI::Broodwar->getScreenPosition().x; int mouseMapY = BWAPI::Broodwar->getMousePosition().y + BWAPI::Broodwar->getScreenPosition().y; if (m == BWAPI::M_RIGHT) { if (selectedUnits) { for (BWAPI::UnitInterface* unit : *selectedUnits) { unit->rightClick(BWAPI::Position(mouseMapX, mouseMapY)); } } } } void keyboardEvent(BWAPI::Key k) { if (!validKeyEvent()) { return; } bool control = BWAPI::Broodwar->getKeyState(BWAPI::K_CONTROL); bool shift = BWAPI::Broodwar->getKeyState(BWAPI::K_SHIFT); std::string prefix = std::string("") + (control ? "CTRL + " : "") + (shift ? "SHIFT + " : ""); //BWAPI::Broodwar->printf("Key Pressed: %s %d", prefix.c_str(), k); switch (k) { case BWAPI::K_D : Options::Debug::DRAW_DEBUG_INTERFACE = false; break; } if (k >= BWAPI::K_0 && k <= BWAPI::K_9) { if (shift && control) { data.newControlGroup(k); selectedUnits = data.getControlGroupUnits(k); lastControlGroup = k; } else if (control) { data.addToControlGroup(k); selectedUnits = data.getControlGroupUnits(k); lastControlGroup = k; } else { selectedUnits = data.getControlGroupUnits(k); lastControlGroup = k; } } lastKeyEvent = BWAPI::Broodwar->getFrameCount(); } bool validKeyEvent() { return (BWAPI::Broodwar->getFrameCount() - lastKeyEvent) > 20; } void drawSelectedUnits(int x, int y) { int col = 0; int row = 0; int cols = 12; BWAPI::Broodwar->drawBoxScreen(x-5, y-15, x+10+cols*22, y+100, BWAPI::Colors::Black, true); BWAPI::Broodwar->drawTextScreen(x, y-13, "\x07%d Selected Units: Group %d", selectedUnits->size(), lastControlGroup - BWAPI::K_0); int yskip = 0; int xx = x; int yy = y; for (BWAPI::UnitInterface* unit : *selectedUnits) { xx = x + (col%cols) * 22; yy = y + (col/cols) * 26; BWAPI::Broodwar->drawCircleMap(unit->getPosition().x, unit->getPosition().y, unit->getType().dimensionLeft(), BWAPI::Colors::Green, false); if (unit->getType().isBuilding()) { BWAPI::Broodwar->drawLineMap(unit->getPosition().x, unit->getPosition().y, unit->getRallyPosition().x, unit->getRallyPosition().y, BWAPI::Colors::White); } drawUnit(unit, xx, yy); col++; } } void drawUnit(BWAPI::UnitInterface* unit, int x, int y) { int BOX_HEIGHT = 20; int BOX_WIDTH = 20; int unitHealth = unit->getHitPoints() + unit->getShields(); int maxUnitHealth = unit->getType().maxHitPoints() + unit->getType().maxShields(); char unitChar = unit->getType().getName()[8]; std::string prefixColor = "\x07"; BWAPI::Color boxColor = BWAPI::Colors::Green; if (unitHealth < maxUnitHealth / 3) { boxColor = BWAPI::Colors::Red; prefixColor = "\x08"; } else if (unitHealth < 2 * maxUnitHealth / 3) { boxColor = BWAPI::Colors::Orange; prefixColor = "\x11"; } BWAPI::Broodwar->drawBoxScreen(x, y, x + BOX_WIDTH, y + BOX_HEIGHT, BWAPI::Colors::Black, true); BWAPI::Broodwar->drawBoxScreen(x, y, x + BOX_WIDTH, y + BOX_HEIGHT, boxColor, false); BWAPI::Broodwar->drawTextScreen(x + 2, y + 1, "%s%c", prefixColor.c_str(), unitChar); BWAPI::Color statusColor = getUnitColor(unit); int SUB_BOX_HEIGHT = 5; BWAPI::Broodwar->drawBoxScreen(x, y+BOX_HEIGHT+1, x+(int)(getBoxWidth(unit)*BOX_WIDTH), y+BOX_HEIGHT+SUB_BOX_HEIGHT, statusColor, true); } BWAPI::Color getUnitColor(BWAPI::UnitInterface* unit) { if (unit->getType().isWorker()) { if (unit->isGatheringMinerals()) { return BWAPI::Colors::Cyan; } if (unit->isGatheringGas()) { return BWAPI::Colors::Green; } if (unit->isIdle()) { return BWAPI::Colors::Grey; } } if (unit->getType().isBuilding()) { if (unit->isTraining()) { return BWAPI::Colors::Grey; } return BWAPI::Colors::Black; } return BWAPI::Colors::Red; } double getBoxWidth(BWAPI::UnitInterface* unit) { if (unit->isTraining()) { return 1 - (double)unit->getRemainingTrainTime() / unit->getTrainingQueue().front().buildTime(); } return 1; } }; } ================================================ FILE: UAlbertaBot/Source/research/visualizer/ReplayVisualizer.cpp ================================================ #include "ReplayVisualizer.h" #ifdef USING_VISUALIZATION_LIBRARIES /* ReplayVisualizer::ReplayVisualizer() : map(BWAPI::Broodwar) { } void ReplayVisualizer::launchSimulation(const BWAPI::Position & center, const int & radius) { // set up the display object SparCraft::Display display(SparCraft::Display(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight())); display.OnStart(); display.LoadMapTexture(&map, 19); // extract the state from the current state of BWAPI SparCraft::GameState state; setCombatUnits(state, center, radius); state.setMap(&map); // get search player objects for us and the opponent PlayerPtr selfPlayer(getSearchPlayer(SparCraft::PlayerToMove::Alternate, SparCraft::Players::Player_One, SparCraft::EvaluationMethods::Playout, 40)); PlayerPtr enemyPlayer(SparCraft::AllPlayers::getPlayerPtr(SparCraft::Players::Player_Two, SparCraft::PlayerModels::AttackClosest)); // set up the game SparCraft::Game g(state, selfPlayer, enemyPlayer, 1000); g.disp = &display; // play the game to the end g.play(); } void ReplayVisualizer::setCombatUnits(SparCraft::GameState & state, const BWAPI::Position & center, const int radius) { int selfUnits = 0; BOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getPlayer(1)->getUnits()) { bool inRadius = unit->getDistance(center) < radius; if (selfUnits < 8 && inRadius && isCombatUnit(unit->getType())) { selfUnits++; // FIX state.addUnit(SparCraft::Unit(unit, SparCraft::Players::Player_One, BWAPI::Broodwar->getFrameCount())); } else { // FIX state.addNeutralUnit(SparCraft::Unit(unit, SparCraft::Players::Player_One, BWAPI::Broodwar->getFrameCount())); } } int enemyUnits = 0; BOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getPlayer(0)->getUnits()) { if (enemyUnits >= 8) { break; } bool inRadius = unit->getDistance(center) < radius; if (enemyUnits < 8 && inRadius && isCombatUnit(unit->getType()) && !unit->getType().isFlyer()) { enemyUnits++; // FIX state.addUnit(SparCraft::Unit(unit,Search::Players::Player_Two, BWAPI::Broodwar->getFrameCount())); } else { // FIX state.addNeutralUnit(SparCraft::Unit(unit, Search::Players::Player_Two, BWAPI::Broodwar->getFrameCount())); } } int neutralUnits = 0; BOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getAllUnits()) { neutralUnits++; const IDType player(getPlayer(unit->getPlayer())); if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field || unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser) { // FIX state.addNeutralUnit(SparCraft::Unit(unit, Search::Players::Player_None, BWAPI::Broodwar->getFrameCount())); } } state.finishedMoving(); } bool ReplayVisualizer::isCombatUnit(BWAPI::UnitType type) const { if (type == BWAPI::UnitTypes::Zerg_Lurker || type == BWAPI::UnitTypes::Protoss_Dark_Templar) { return false; } // no workers or buildings allowed if (type.isWorker()) { return false; } // check for various types of combat units if (type.canAttack() || type == BWAPI::UnitTypes::Terran_Medic) { return true; } return false; } PlayerPtr ReplayVisualizer::getSearchPlayer(const IDType & playerToMoveMethod, const IDType & playerID, const IDType & evalMethod, const size_t & timeLimitMS) { IDType bestResponseTo = SparCraft::PlayerModels::NOKDPS; // base parameters to use in search SparCraft::AlphaBetaSearchParameters baseParameters; baseParameters.setMaxPlayer(playerID); baseParameters.setSearchMethod(SparCraft::SearchMethods::IDAlphaBeta); baseParameters.setEvalMethod(evalMethod); baseParameters.setMaxDepth(SparCraft::Constants::Max_Search_Depth); //baseParameters.setScriptMoveFirstMethod(SparCraft::PlayerModels::NOKDPS); baseParameters.setTimeLimit(timeLimitMS); // IF USING OPPONENT MODELING SET IT HERE baseParameters.setModelSimMethod(bestResponseTo); baseParameters.setPlayerModel(Search::Players::Player_Two, bestResponseTo, true); baseParameters.setPlayerToMoveMethod(playerToMoveMethod); return PlayerPtr(new MicroSearch::Player_AlphaBeta(playerID, baseParameters, MicroSearch::TTPtr(new MicroSearch::TranspositionTable()))); } const MicroSearch::Unit ReplayVisualizer::getUnit(const UnitInfo & ui, const IDType & playerID) const { BWAPI::UnitType type = ui.type; return MicroSearch::Unit(ui.type, MicroSearch::Position(ui.lastPosition.x, ui.lastPosition.y), ui.unitID, playerID, ui.lastHealth, 0, BWAPI::Broodwar->getFrameCount(), BWAPI::Broodwar->getFrameCount()); } const IDType ReplayVisualizer::getPlayer(BWAPI::UnitInterface* unit) const { return getPlayer(unit->getPlayer()); } const IDType ReplayVisualizer::getPlayer(BWAPI::PlayerInterface * player) const { if (player == BWAPI::Broodwar->self()) { return SparCraft::Players::Player_Two; } else if (player == BWAPI::Broodwar->enemy()) { return SparCraft::Players::Player_One; } return SparCraft::Players::Player_None; } */ #endif ================================================ FILE: UAlbertaBot/Source/research/visualizer/ReplayVisualizer.h ================================================ #pragma once #include "..\..\SparCraft\source\SparCraft.h" #ifdef USING_VISUALIZATION_LIBRARIES #include #include "InformationManager.h" #include "MapGrid.h" namespace UAlbertaBot { class ReplayVisualizer { SparCraft::Map map; const IDType getPlayer(BWAPI::UnitInterface* unit) const; const IDType getPlayer(BWAPI::PlayerInterface * player) const; void setCombatUnits(SparCraft::GameState & s, const BWAPI::Position & center, const int radius); const SparCraft::Unit getUnit(const UnitInfo & ui, const IDType & playerID) const; bool isCombatUnit(BWAPI::UnitType type) const; SparCraft::PlayerPtr getSearchPlayer(const IDType & playerToMoveMethod, const IDType & playerID, const IDType & evalMethod, const size_t & timeLimitMS); public: ReplayVisualizer(); void ReplayVisualizer::launchSimulation(const BWAPI::Position & pos, const int & radius); }; } #endif ================================================ FILE: UAlbertaBot/Source/research/visualizer/Visualizer.cpp ================================================ #include "Visualizer.h" #ifdef USING_VISUALIZATION_LIBRARIES Visualizer & Visualizer::Instance() { static Visualizer instance; return instance; } Visualizer::Visualizer() : display(SparCraft::Display(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight())) { map = SparCraft::Map(BWAPI::Broodwar); map.write("C:\\test.txt"); display.OnStart(); display.LoadMapTexture(&map, 19); } void Visualizer::setBWAPIState() { SparCraft::GameState state; state.setMap(&map); BOOST_FOREACH (BWAPI::UnitInterface* unit, BWAPI::Broodwar->getAllUnits()) { const IDType player(getPlayer(unit->getPlayer())); if (player == SparCraft::Players::Player_One || player == SparCraft::Players::Player_Two) { // FIX state.addUnit(SparCraft::Unit(unit, player, BWAPI::Broodwar->getFrameCount())); } else { if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field || unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser) { // FIX state.addNeutralUnit(SparCraft::Unit(unit, SparCraft::Players::Player_None, BWAPI::Broodwar->getFrameCount())); } } } setState(state); } void Visualizer::setState(const SparCraft::GameState & state) { display.SetState(state); } void Visualizer::onFrame() { display.OnFrame(); } const IDType Visualizer::getPlayer(BWAPI::UnitInterface* unit) const { return getPlayer(unit->getPlayer()); } const IDType Visualizer::getPlayer(BWAPI::PlayerInterface * player) const { if (player == BWAPI::Broodwar->self()) { return SparCraft::Players::Player_One; } else if (player == BWAPI::Broodwar->enemy()) { return SparCraft::Players::Player_Two; } return SparCraft::Players::Player_None; } #endif ================================================ FILE: UAlbertaBot/Source/research/visualizer/Visualizer.h ================================================ #pragma once #include "..\..\SparCraft\source\SparCraft.h" #ifdef USING_VISUALIZATION_LIBRARIES #include namespace UAlbertaBot { class Visualizer { Visualizer(); Visualizer(int mapWidth, int mapHeight, int cellSize); SparCraft::Display display; SparCraft::GameState state; SparCraft::Map map; const IDType getPlayer(BWAPI::UnitInterface* unit) const; const IDType getPlayer(BWAPI::PlayerInterface * player) const; public: // yay for singletons! static Visualizer & Instance(); void setBWAPIState(); void setState(const SparCraft::GameState & state); void onFrame(); }; } #endif ================================================ FILE: UAlbertaBot/Source/stardraft/BaseBorderFinder.hpp ================================================ #pragma once #include "Grid2D.hpp" #include "StarDraftMap.hpp" #include #include // a base is just a rectangle encompassing some portion of the map // if translated back to BWAPI, just add all the resources in the rectabgle struct BaseBorder { int left = std::numeric_limits::max(); int right = std::numeric_limits::min(); int top = std::numeric_limits::max(); int bottom = std::numeric_limits::min(); bool contains(int x, int y) const { return (x >= left) && (x <= right) && (y >= top) && (y <= bottom); } }; struct Cluster { std::vector minerals; std::vector gas; std::vector allResources; }; class BaseBorderFinder { struct Direction { char x = 0, y = 0; }; const StarDraftMap * m_map = nullptr; std::vector m_baseBorders; Grid2D m_resourceDist; Grid2D m_resourceClusterLabels; int m_maxDepth = 5; int m_ops = 0; std::vector m_stack; std::vector m_actions = { {0,1}, {0,-1}, {1,0}, {-1,0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} }; std::vector m_resourceClusters; void resourceDistanceBFS(int x, int y) { m_stack.clear(); m_stack.push_back({x, y}); m_resourceDist.set(x, y, 0); // iterate until the current pointer meets the end for (size_t i = 0; i < m_stack.size(); i++) { // get a copy of the cell and its distance to avoid future lookups Tile tile = m_stack[i]; int dist = m_resourceDist.get(tile.x, tile.y); // if we've gone far enough away, stop if (dist == m_maxDepth) { return; } // look out in each direction for (size_t a = 0; a < m_actions.size(); a++) { // calculate the child cell Tile next ={tile.x + m_actions[a].x, tile.y + m_actions[a].y}; // if this child is a valid cell we can do stuff with it if (m_map->isValid(next.x, next.y) && m_map->isWalkable(next.x, next.y)) { // save the distance to the next cell to avoid another lookup auto nval = m_resourceDist.get(next.x, next.y); // if we haven't seen this cell before if (nval == -1) { // add it to the stack and set the distance m_stack.emplace_back(next); m_ops++; m_resourceDist.set(next.x, next.y, dist + 1); } } } } } // this will form a cluster of resource tiles by BFSing from x,y // x, y will be a resource tile of unassigned cluster Cluster resourceClusterFormationBFS(int x, int y, int clusterNumber) { m_stack.clear(); m_stack.push_back({x, y}); // the vector of resource tiles for this cluster Cluster cluster; // iterate until the current pointer meets the end for (size_t i = 0; i < m_stack.size(); i++) { // get a copy of the cell and its distance to avoid future lookups Tile tile = m_stack[i]; if (m_map->isMineral(tile.x, tile.y)) { cluster.minerals.push_back(tile); } if (m_map->isGas(tile.x, tile.y)) { cluster.gas.push_back(tile); } if (m_map->isResource(tile.x, tile.y)) { cluster.allResources.push_back(tile); } // look out in each direction for (size_t a = 0; a < m_actions.size(); a++) { // calculate the child cell Tile next ={tile.x + m_actions[a].x, tile.y + m_actions[a].y}; // test the child tile for validity if (m_map->isValid(next.x, next.y) && // if this child is a valid cell m_resourceDist.get(next.x, next.y) != -1 && // and it has a valid distance m_resourceClusterLabels.get(next.x, next.y) == -1) // and it hasn't been given a cluster yet { // mark this tile as being part of this cluster m_resourceClusterLabels.set(next.x, next.y, clusterNumber); m_stack.emplace_back(next); m_ops++; } } } return cluster; } public: BaseBorderFinder() { m_stack.reserve(1024); } BaseBorderFinder(const StarDraftMap & map) : m_map(&map) { m_stack.reserve(1024); computeBases(map); } void computeBases(const StarDraftMap & map) { m_map = ↦ m_baseBorders ={}; m_resourceDist = Grid2D(m_map->width(), m_map->height(), -1); m_resourceClusterLabels = Grid2D(m_map->width(), m_map->height(), -1); // Step 1. BFS outward from resources for (auto resourceTile : m_map->resourceTiles()) { resourceDistanceBFS(resourceTile.x, resourceTile.y); } // Step 2. Label each resource cluster int clusterNumber = 0; for (auto resourceTile : m_map->resourceTiles()) { // if this tile has already been clustered skip it if (m_resourceClusterLabels.get(resourceTile.x, resourceTile.y) != -1) { continue; } // perform the BFS on this un-clustered resource tile to assign it a cluster number m_resourceClusters.push_back(resourceClusterFormationBFS(resourceTile.x, resourceTile.y, clusterNumber++)); } // Step 3. Form Base objects out of each cluster, if they are valid for (auto & cluster : m_resourceClusters) { // if there aren't enough resources in the cluster, it won't be a base if (cluster.minerals.size() < 4) { continue; } BaseBorder border; for (auto tile : cluster.allResources) { border.left = std::min(border.left, tile.x); border.right = std::max(border.right, tile.x); border.top = std::min(border.top, tile.y); border.bottom = std::max(border.bottom, tile.y); } m_baseBorders.push_back(border); } } const Grid2D & getResourceDist() const { return m_resourceDist; } const Grid2D & getClusterLabels() const { return m_resourceClusterLabels; } const std::vector & getBaseBorders() const { return m_baseBorders; } }; ================================================ FILE: UAlbertaBot/Source/stardraft/Grid2D.hpp ================================================ #pragma once #include #include template class Grid2D { size_t m_width = 0; size_t m_height = 0; std::vector> m_grid; public: Grid2D() {} Grid2D(size_t width, size_t height, T val) : m_width(width) , m_height(height) , m_grid(width, std::vector(height, val)) { } T& get(size_t x, size_t y) { return m_grid[x][y]; } T& get(int x, int y) { return m_grid[x][y]; } const T& get(size_t x, size_t y) const { return m_grid[x][y]; } const T& get(int x, int y) const { return m_grid[x][y]; } void set(size_t x, size_t y, T val) { m_grid[x][y] = val; } void set(int x, int y, T val) { m_grid[x][y] = val; } size_t width() const { return m_width; } size_t height() const { return m_height; } }; ================================================ FILE: UAlbertaBot/Source/stardraft/StarDraft.h ================================================ #pragma once #include "StarDraftMap.hpp" #include "BaseBorderFinder.hpp" ================================================ FILE: UAlbertaBot/Source/stardraft/StarDraftMap.hpp ================================================ #pragma once #include "Grid2D.hpp" #include #include namespace TileType { enum { Unwalkable = 'U', Walk = 'W', BuildAll = 'B', NoDepot = 'D', Mineral = 'M', Gas = 'G', Neutral = 'N' }; } struct Tile { int x = 0, y = 0; }; class StarDraftMap { Grid2D m_buildTiles; Grid2D m_walkTiles; std::vector m_mineralTiles; std::vector m_gasTiles; std::vector m_resourceTiles; std::vector m_startTiles; inline bool isWalkable(char tile) const noexcept { return (tile == TileType::Walk) || (tile == TileType::BuildAll) || (tile == TileType::NoDepot); } inline bool canBuild(char tile) const noexcept { return tile == (TileType::BuildAll) || (tile == TileType::NoDepot); } inline bool canBuildDepot(char tile) const noexcept { return tile == TileType::BuildAll; } public: StarDraftMap() {} StarDraftMap(const std::string & path) { load(path); } StarDraftMap(size_t width, size_t height) : m_buildTiles(width, height, 0) , m_walkTiles(width*4, height*4, false) { } inline bool isValid(int x, int y) const { return (x >= 0) && (x < (int)m_buildTiles.width()) && (y >= 0) && (y < (int)m_buildTiles.height()); } inline void set(int x, int y, char val) { m_buildTiles.set(x, y, val); if (val == TileType::Mineral) { m_mineralTiles.push_back({x, y}); m_resourceTiles.push_back({x, y}); } else if (val == TileType::Gas) { m_gasTiles.push_back({x, y}); m_resourceTiles.push_back({x, y}); } } inline void setWalk(int x, int y, bool val) { m_walkTiles.set(x, y, val); } inline void addStartTile(int x, int y) { m_startTiles.push_back({x, y}); } inline bool isMineral(int x, int y) const { return get(x, y) == 'M'; } inline bool isGas(int x, int y) const { return get(x, y) == 'G'; } inline bool isResource(int x, int y) const { return isMineral(x,y) || isGas(x,y); } inline size_t width() const { return m_buildTiles.width(); } inline size_t height() const { return m_buildTiles.height(); } inline char get(int x, int y) const { return m_buildTiles.get(x, y); } inline char getWalk(int x, int y) const { return m_walkTiles.get(x, y); } inline bool isWalkable(int x, int y) const { return isWalkable(get(x, y)); } inline bool canBuild(int x, int y) const { return canBuild(get(x,y)); } inline bool canBuildDepot(int x, int y) const { return canBuildDepot(get(x,y)); } inline const std::vector & startTiles() const { return m_startTiles; } inline const std::vector & mineralTiles() const { return m_mineralTiles; } inline const std::vector & gasTiles() const { return m_gasTiles; } inline const std::vector & resourceTiles() const { return m_resourceTiles; } inline void load(const std::string & path) { std::ifstream fin(path); int w, h, n, sx, sy; char c; // first line is width height fin >> w >> h; m_buildTiles = Grid2D(w, h, 0); m_walkTiles = Grid2D(4*w, 4*h, 0); // next line is the start tile locations fin >> n; for (int i=0; i> sx >> sy; m_startTiles.push_back({sx, sy}); } // followed by the int values in the grid for (size_t y=0; y < m_buildTiles.height(); y++) { for (size_t x=0; x < m_buildTiles.width(); x++) { fin >> c; set(x, y, c); } } // followed by the walk tiles for (size_t y=0; y < m_walkTiles.height(); y++) { for (size_t x=0; x < m_walkTiles.width(); x++) { fin >> c; m_walkTiles.set(x, y, c); } } } inline void save(const std::string & path) const { std::ofstream fout(path); // first line is width height fout << m_buildTiles.width() << " " << m_buildTiles.height() << "\n"; // next line is the start tile locations fout << m_startTiles.size(); for (auto & tile : m_startTiles) { fout << " " << tile.x << " " << tile.y; } fout << "\n"; // followed by the int values in the grid for (size_t y=0; y Debug Win32 Release Win32 StarterBot {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7} ExampleAIModule Win32Proj Application false NotSet true v142 Application Unicode v142 false <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)\..\bin\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ true $(SolutionDir)\..\bin\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ true false AllRules.ruleset BasicDesignGuidelineRules.ruleset false false $(ProjectName)_d false Disabled ../BOSS/source;../SparCraft/source;../source;$(BWTA_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue false true $(BWAPI_DIR)/Debug/BWAPILIB.lib;$(BWAPI_DIR)/Debug/BWAPIClient.lib;%(AdditionalDependencies) true Console MachineX86 /ignore:4099 %(AdditionalOptions) MaxSpeed true $(BWAPI_DIR)/include;$(BWTA_DIR)/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 None Speed AnySuitable false true true 4996 stdcpp17 true $(BWAPI_DIR)/Release/BWAPILIB.lib;$(BWAPI_DIR)/Release/BWAPIClient.lib;%(AdditionalDependencies) false Console true true MachineX86 false /ignore:4099 %(AdditionalOptions) No UseLinkTimeCodeGeneration ================================================ FILE: UAlbertaBot/VisualStudio/StarterBot.vcxproj.filters ================================================  ================================================ FILE: UAlbertaBot/VisualStudio/UAlbertaBot.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UAlbertaBot", "UAlbertaBot.vcxproj", "{2E63AE74-758A-4607-9DE4-D28E814A6E13}" ProjectSection(ProjectDependencies) = postProject {66236439-5968-4756-B2E7-8A29BEA99078} = {66236439-5968-4756-B2E7-8A29BEA99078} {9F8709E3-AC4F-45F2-8105-4A99D8E2A127} = {9F8709E3-AC4F-45F2-8105-4A99D8E2A127} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SparCraft", "..\..\SparCraft\VisualStudio\SparCraft.vcxproj", "{66236439-5968-4756-B2E7-8A29BEA99078}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BOSS", "..\..\BOSS\VisualStudio\BOSS.vcxproj", "{9F8709E3-AC4F-45F2-8105-4A99D8E2A127}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StarterBot", "StarterBot.vcxproj", "{B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Itanium = Debug|Itanium Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Itanium = Release|Itanium Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Itanium.ActiveCfg = Debug|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Win32.ActiveCfg = Debug|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|Win32.Build.0 = Debug|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Debug|x64.ActiveCfg = Debug|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Itanium.ActiveCfg = Release|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Win32.ActiveCfg = Release|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|Win32.Build.0 = Release|Win32 {2E63AE74-758A-4607-9DE4-D28E814A6E13}.Release|x64.ActiveCfg = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Itanium.ActiveCfg = Debug|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.ActiveCfg = Debug|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|Win32.Build.0 = Debug|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.ActiveCfg = Debug|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Debug|x64.Build.0 = Debug|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|Itanium.ActiveCfg = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.ActiveCfg = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|Win32.Build.0 = Release|Win32 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.ActiveCfg = Release|x64 {66236439-5968-4756-B2E7-8A29BEA99078}.Release|x64.Build.0 = Release|x64 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Itanium.ActiveCfg = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.ActiveCfg = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|Win32.Build.0 = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Debug|x64.ActiveCfg = Debug|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Itanium.ActiveCfg = Release|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.ActiveCfg = Release|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|Win32.Build.0 = Release|Win32 {9F8709E3-AC4F-45F2-8105-4A99D8E2A127}.Release|x64.ActiveCfg = Release|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Itanium.ActiveCfg = Debug|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Win32.ActiveCfg = Debug|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|Win32.Build.0 = Debug|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Debug|x64.ActiveCfg = Debug|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Itanium.ActiveCfg = Release|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Win32.ActiveCfg = Release|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|Win32.Build.0 = Release|Win32 {B2D2AD6C-D98B-42D0-8E4B-3C79D9DB27B7}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E6A802E3-72DC-4E90-8C2C-FD125D583E39} EndGlobalSection EndGlobal ================================================ FILE: UAlbertaBot/VisualStudio/UAlbertaBot.vcxproj ================================================  Debug Win32 Release Win32 UAlbertaBot {2E63AE74-758A-4607-9DE4-D28E814A6E13} ExampleAIModule Win32Proj Application false NotSet true v142 Application Unicode v142 false <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)\..\bin\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ true $(SolutionDir)\..\bin\ $(SolutionDir)\$(Configuration)\$(ProjectName)\ true false AllRules.ruleset BasicDesignGuidelineRules.ruleset false false $(ProjectName)_d Disabled ../BOSS/source;../SparCraft/source;../source;$(BWTA_DIR)/include;$(BWAPI_DIR)/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue false true $(BWAPI_DIR)/Debug/BWAPILIB.lib;$(BWAPI_DIR)/Debug/BWAPIClient.lib;$(Configuration)/SparCraft/SparCraft_d.lib;../../BOSS/bin/BOSS_d.lib;%(AdditionalDependencies) true Console MachineX86 /ignore:4099 %(AdditionalOptions) Full true ../BOSS/source;../SparCraft/source;../source;$(BWAPI_DIR)/include;$(BWTA_DIR)/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXAMPLEAIMODULE_EXPORTS;NOMINMAX;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase Speed AnySuitable false true true 4996 true $(BWAPI_DIR)/Release/BWAPILIB.lib;$(BWAPI_DIR)/Release/BWAPIClient.lib;$(Configuration)/SparCraft/SparCraft.lib;../../BOSS/bin/BOSS.lib;%(AdditionalDependencies) true Console true true MachineX86 true /ignore:4099 %(AdditionalOptions) ================================================ FILE: UAlbertaBot/VisualStudio/UAlbertaBot.vcxproj.filters ================================================  {59599488-4576-44ab-8522-7d65a6425e15} {8e8c1957-bc1d-4bc8-90b0-95beab19d8a9} {a78e9ab8-4a81-4640-b6eb-f1eed3e4b1af} {849d54bf-a76a-4425-8399-099fbe0360c4} micro micro common common macro macro macro macro macro common util util util util util macro macro micro micro macro macro macro util util util util util util micro micro micro micro micro micro micro micro micro macro macro micro common common micro macro macro macro macro macro common util util util util util macro macro micro micro micro macro macro macro util util util util util util util util micro micro micro micro micro micro micro micro micro macro macro ================================================ FILE: UAlbertaBot/bin/UAlbertaBot_Config.txt ================================================ { "Bot Info" : { "BotName" : "UAlbertaBot", "Authors" : "David Churchill", "PrintInfoOnStart" : false }, "BWAPI" : { "SetLocalSpeed" : 0, "SetFrameSkip" : 0, "UserInput" : true, "CompleteMapInformation" : false }, "Micro" : { "UseSparcraftSimulation" : true, "KiteWithRangedUnits" : true, "KiteLongerRangedUnits" : ["Mutalisk", "Vulture"], "WorkersDefendRush" : true, "RetreatMeleeUnitShields" : 0, "RetreatMeleeUnitHP" : 0, "InCombatRadius" : 1000, "RegroupRadius" : 300, "UnitNearEnemyRadius" : 600 }, "Macro" : { "BOSSFrameLimit" : 160, "WorkersPerRefinery" : 3, "BuildingSpacing" : 1, "PylonSpacing" : 3 }, "Debug" : { "ErrorLogFilename" : "bwapi-data/AI/UAlbertaBot_ErrorLog.txt", "LogAssertToErrorFile" : false, "DrawGameInfo" : true, "DrawUnitHealthBars" : true, "DrawProductionInfo" : true, "DrawWalkableSectors" : false, "DrawTileInfo" : false, "DrawBuildOrderSearchInfo" : false, "DrawScoutInfo" : false, "DrawEnemyUnitInfo" : false, "DrawModuleTimers" : false, "DrawResourceInfo" : false, "DrawCombatSimInfo" : false, "DrawUnitTargetInfo" : false, "DrawBWTAInfo" : false, "DrawMapGrid" : false, "DrawSquadInfo" : false, "DrawWorkerInfo" : false, "DrawMouseCursorInfo" : false, "DrawBuildingInfo" : false, "DrawReservedBuildingTiles" : false, "DrawBOSSStateInfo" : false, "PrintModuleTimeout" : false }, "Modules" : { "UseGameCommander" : true, "UseScoutManager" : true, "UseCombatCommander" : true, "UseBuildOrderSearch" : true, "UseStrategyIO" : true, "UseAutoObserver" : false }, "Tools" : { "MapGridSize" : 320 }, "Strategy" : { "Protoss" : "Protoss_ZealotRush", "Terran" : "Terran_MarineRush", "Zerg" : "Zerg_ZerglingRush", "ScoutGasSteal" : false, "ScoutHarassEnemy" : true, "ReadDirectory" : "bwapi-data/read/", "WriteDirectory" : "bwapi-data/write/", "UseEnemySpecificStrategy" : true, "EnemySpecificStrategy" : { "BotName1" : { "Protoss" : "Protoss_ZealotRush", "Terran" : "Terran_VultureRush", "Zerg" : "Zerg_ZerglingRush" }, "BotName2" : { "Protoss" : "Protoss_DragoonRush", "Terran" : "Terran_MarineRush", "Zerg" : "Zerg_ZerglingRush" }, "LetaBot" : { "Protoss" : "Protoss_ZealotRush", "Terran" : "Terran_4RaxMarines", "Zerg" : "Zerg_ZerglingRush" } }, "Strategies" : { "Protoss_ZealotRush" : { "Race" : "Protoss", "OpeningBuildOrder" : ["Probe", "Probe", "Probe", "Probe", "Pylon", "Probe", "Gateway", "Gateway", "Probe", "Probe", "Zealot", "Pylon", "Zealot", "Zealot", "Probe", "Zealot", "Zealot", "Probe", "Pylon", "Zealot", "Gateway", "Probe", "Pylon", "Probe", "Zealot", "Probe", "Zealot", "Zealot", "Zealot", "Zealot", "Pylon", "Probe", "Zealot", "Zealot", "Zealot" ]}, "Protoss_DragoonRush" : { "Race" : "Protoss", "OpeningBuildOrder" : ["Probe", "Probe", "Probe", "Probe", "Pylon", "Probe", "Probe", "Gateway", "Probe", "Assimilator", "Probe", "Probe", "Cybernetics_Core", "Probe", "Probe", "Gateway", "Singularity_Charge", "Dragoon", "Gateway", "Pylon", "Dragoon", "Dragoon", "Probe", "Gateway", "Pylon", "Probe", "Dragoon", "Dragoon", "Dragoon"]}, "Protoss_DTRush" : { "Race" : "Protoss", "OpeningBuildOrder" : ["Probe", "Probe", "Probe", "Probe", "Pylon", "Probe", "Gateway", "Probe", "Assimilator", "Probe", "Cybernetics_Core", "Probe", "Citadel_of_Adun", "Probe", "Templar_Archives", "Gateway", "Dark_Templar", "Dark_Templar", "Pylon", "Dark_Templar", "Dark_Templar", "Probe", "Pylon", "Probe" ]}, "Protoss_Drop" : { "Race" : "Protoss", "OpeningBuildOrder" : ["Probe", "Probe", "Probe", "Probe", "Pylon", "Probe", "Probe", "Gateway", "Probe", "Assimilator", "Probe", "Probe", "Cybernetics_Core", "Probe", "Gateway", "Robotics Facility"]}, "Terran_MarineRush" : { "Race" : "Terran", "OpeningBuildOrder" : ["SCV", "SCV", "SCV", "SCV", "SCV", "Supply Depot", "SCV"]}, "Terran_TankPush" : { "Race" : "Terran", "OpeningBuildOrder" : ["SCV", "SCV", "SCV", "SCV", "SCV", "Supply Depot", "SCV", "Barracks", "Refinery", "SCV", "SCV", "SCV", "SCV", "Factory", "Factory", "SCV", "SCV", "SCV", "SCV", "Machine Shop", "Machine Shop", "Supply Depot", "Tank Siege Mode", "Siege Tank Tank Mode", "Siege Tank Tank Mode", "Siege Tank Tank Mode", "Siege Tank Tank Mode"]}, "Terran_4RaxMarines" : { "Race" : "Terran", "OpeningBuildOrder" : ["Barracks", "SCV", "SCV", "Marine", "SCV", "Marine", "Supply Depot", "Marine", "Marine", "Marine", "Marine", "Marine", "Marine"]}, "Terran_VultureRush" : { "Race" : "Terran", "OpeningBuildOrder" : ["SCV", "SCV", "SCV", "SCV", "SCV", "Supply Depot", "SCV", "SCV", "Barracks", "Refinery", "SCV", "SCV", "SCV", "SCV", "Supply Depot", "Factory", "SCV", "SCV", "SCV", "Vulture", "Vulture"]}, "Zerg_ZerglingRush" : { "Race" : "Zerg", "OpeningBuildOrder" : ["Drone", "Spawning Pool", "Zergling", "Zergling", "Zergling", "Zergling"] }, "Zerg_9Pool" : { "Race" : "Zerg", "OpeningBuildOrder" : ["Drone", "Drone", "Drone", "Drone", "Drone", "Spawning Pool", "Drone", "Extractor", "Overlord", "Drone", "Zergling", "Zergling", "Zergling", "Hydralisk Den", "Drone", "Drone", "Drone", "Drone"] }, "Zerg_2HatchHydra" : { "Race" : "Zerg", "OpeningBuildOrder" : ["Drone", "Drone", "Drone", "Drone", "Drone", "Overlord", "Drone", "Drone", "Drone", "Hatchery", "Spawning Pool", "Drone", "Extractor", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Hydralisk Den", "Drone", "Overlord", "Drone", "Drone", "Drone", "Grooved_Spines", "Hydralisk","Hydralisk","Hydralisk","Hydralisk", "Hydralisk","Hydralisk","Hydralisk","Hydralisk", "Hydralisk","Hydralisk","Hydralisk","Hydralisk", "Hatchery", "Extractor" ] }, "Zerg_3HatchMuta" : { "Race" : "Zerg", "OpeningBuildOrder" : ["Drone", "Drone", "Drone", "Drone", "Overlord", "Drone", "Drone", "Drone", "Drone", "Hatchery", "Drone", "Drone", "Spawning_Pool", "Drone", "Drone", "Extractor", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone","Lair", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Spire", "Overlord", "Drone", "Overlord", "Hatchery", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Mutalisk", "Hatchery"]}, "Zerg_3HatchScourge" : { "Race" : "Zerg", "OpeningBuildOrder" : ["Drone", "Drone", "Drone", "Drone", "Overlord", "Drone", "Drone", "Drone", "Drone", "Hatchery", "Drone", "Drone", "Spawning_Pool", "Drone", "Drone", "Extractor", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone","Lair", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Spire", "Overlord", "Drone", "Overlord", "Hatchery", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Drone", "Hatchery", "Drone", "Extractor", "Drone", "Hatchery", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Scourge", "Hatchery", "Extractor", "Extractor", "Hatchery"]} } } } ================================================ FILE: UAlbertaBot/starterbot/Grid.hpp ================================================ #pragma once #include template class Grid { size_t m_width = 0; size_t m_height = 0; std::vector> m_grid; public: Grid() {} Grid(size_t width, size_t height, T val) : m_width(width) , m_height(height) , m_grid(width, std::vector(height, val)) { } inline T & get(size_t x, size_t y) { return m_grid[x][y]; } inline const T & get(size_t x, size_t y) const { return m_grid[x][y]; } inline void set(size_t x, size_t y, T val) { m_grid[x][y] = val; } inline size_t width() const { return m_width; } inline size_t height() const { return m_height; } }; ================================================ FILE: UAlbertaBot/starterbot/MapTools.cpp ================================================ #include "MapTools.h" #include #include #include #include // constructor for MapTools MapTools::MapTools() { } void MapTools::onStart() { m_width = BWAPI::Broodwar->mapWidth(); m_height = BWAPI::Broodwar->mapHeight(); m_walkable = Grid(m_width, m_height, 1); m_buildable = Grid(m_width, m_height, 0); m_depotBuildable = Grid(m_width, m_height, 0); m_lastSeen = Grid(m_width, m_height, 0); // Set the boolean grid data from the Map for (int x(0); x < m_width; ++x) { for (int y(0); y < m_height; ++y) { m_buildable.set(x, y, canBuild(x, y)); m_depotBuildable.set(x, y, canBuild(x, y)); m_walkable.set(x, y, m_buildable.get(x,y) || canWalk(x, y)); } } // set tiles that static resources are on as unbuildable for (auto & resource : BWAPI::Broodwar->getStaticNeutralUnits()) { if (!resource->getType().isResourceContainer()) { continue; } const int tileX = resource->getTilePosition().x; const int tileY = resource->getTilePosition().y; for (int x=tileX; xgetType().tileWidth(); ++x) { for (int y=tileY; ygetType().tileHeight(); ++y) { m_buildable.set(x, y, false); // depots can't be built within 3 tiles of any resource for (int rx=-3; rx<=3; rx++) { for (int ry=-3; ry<=3; ry++) { if (!BWAPI::TilePosition(x+rx, y+ry).isValid()) { continue; } m_depotBuildable.set(x+rx, y+ry, 0); } } } } } } void MapTools::onFrame() { for (int x=0; xgetFrameCount()); } } } if (m_drawMap) { draw(); } } void MapTools::toggleDraw() { m_drawMap = !m_drawMap; } bool MapTools::isExplored(const BWAPI::TilePosition & pos) const { return isExplored(pos.x, pos.y); } bool MapTools::isExplored(const BWAPI::Position & pos) const { return isExplored(BWAPI::TilePosition(pos)); } bool MapTools::isExplored(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return BWAPI::Broodwar->isExplored(tileX, tileY); } bool MapTools::isVisible(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return BWAPI::Broodwar->isVisible(BWAPI::TilePosition(tileX, tileY)); } bool MapTools::isPowered(int tileX, int tileY) const { return BWAPI::Broodwar->hasPower(BWAPI::TilePosition(tileX, tileY)); } bool MapTools::isValidTile(int tileX, int tileY) const { return tileX >= 0 && tileY >= 0 && tileX < m_width && tileY < m_height; } bool MapTools::isValidTile(const BWAPI::TilePosition & tile) const { return isValidTile(tile.x, tile.y); } bool MapTools::isValidPosition(const BWAPI::Position & pos) const { return isValidTile(BWAPI::TilePosition(pos)); } bool MapTools::isBuildable(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_buildable.get(tileX, tileY); } bool MapTools::isBuildable(const BWAPI::TilePosition & tile) const { return isBuildable(tile.x, tile.y); } void MapTools::printMap() const { std::stringstream ss; for (int y(0); y < m_height; ++y) { for (int x(0); x < m_width; ++x) { ss << isWalkable(x, y); } ss << "\n"; } std::ofstream out("map.txt"); out << ss.str(); out.close(); } bool MapTools::isDepotBuildableTile(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_depotBuildable.get(tileX, tileY); } bool MapTools::isWalkable(int tileX, int tileY) const { if (!isValidTile(tileX, tileY)) { return false; } return m_walkable.get(tileX, tileY); } bool MapTools::isWalkable(const BWAPI::TilePosition & tile) const { return isWalkable(tile.x, tile.y); } int MapTools::width() const { return m_width; } int MapTools::height() const { return m_height; } void MapTools::drawTile(int tileX, int tileY, const BWAPI::Color & color) const { const int padding = 2; const int px = tileX*32 + padding; const int py = tileY*32 + padding; const int d = 32 - 2*padding; BWAPI::Broodwar->drawLineMap(px, py, px + d, py, color); BWAPI::Broodwar->drawLineMap(px + d, py, px + d, py + d, color); BWAPI::Broodwar->drawLineMap(px + d, py + d, px, py + d, color); BWAPI::Broodwar->drawLineMap(px, py + d, px, py, color); } bool MapTools::canWalk(int tileX, int tileY) const { for (int i=0; i<4; ++i) { for (int j=0; j<4; ++j) { if (!BWAPI::Broodwar->isWalkable(tileX*4 + i, tileY*4 + j)) { return false; } } } return true; } bool MapTools::canBuild(int tileX, int tileY) const { return BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tileX, tileY)); } void MapTools::draw() const { const BWAPI::TilePosition screen(BWAPI::Broodwar->getScreenPosition()); const int sx = screen.x; const int sy = screen.y; const int ex = sx + 20; const int ey = sy + 15; for (int x = sx; x < ex; ++x) { for (int y = sy; y < ey; y++) { const BWAPI::TilePosition tilePos(x,y); if (!tilePos.isValid()) { continue; } if (true) { BWAPI::Color color = isWalkable(x, y) ? BWAPI::Color(0, 255, 0) : BWAPI::Color(255, 0, 0); if (isWalkable(x, y) && !isBuildable(x, y)) { color = BWAPI::Color(255, 255, 0); } if (isBuildable(x, y) && !isDepotBuildableTile(x, y)) { color = BWAPI::Color(127, 255, 255); } drawTile(x, y, color); } } } const char red = '\x08'; const char green = '\x07'; const char white = '\x04'; const char yellow = '\x03'; BWAPI::Broodwar->drawBoxScreen(0, 0, 200, 100, BWAPI::Colors::Black, true); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge); BWAPI::Broodwar->drawTextScreen(10, 5, "%cMap Legend", white); BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default); BWAPI::Broodwar->drawTextScreen(10, 30, "%cRed: ", red); BWAPI::Broodwar->drawTextScreen(60, 30, "%cCan't Walk or Build", white); BWAPI::Broodwar->drawTextScreen(10, 45, "%cGreen:", green); BWAPI::Broodwar->drawTextScreen(60, 45, "%cCan Walk and Build", white); BWAPI::Broodwar->drawTextScreen(10, 60, "%cYellow:", yellow); BWAPI::Broodwar->drawTextScreen(60, 60, "%cResource Tile, Can't Build", white); BWAPI::Broodwar->drawTextScreen(10, 75, "Teal:"); BWAPI::Broodwar->drawTextScreen(60, 75, "%cCan't Build Depot", white); } ================================================ FILE: UAlbertaBot/starterbot/MapTools.h ================================================ #pragma once #include "Grid.hpp" #include #include class MapTools { Grid m_walkable; // whether a tile is buildable (includes static resources) Grid m_buildable; // whether a tile is buildable (includes static resources) Grid m_depotBuildable; // whether a depot is buildable on a tile (illegal within 3 tiles of static resource) Grid m_lastSeen; // the last time any of our units has seen this position on the map int m_width = 0; int m_height = 0; int m_frame = 0; bool m_drawMap = false; bool canBuild(int tileX, int tileY) const; bool canWalk(int tileX, int tileY) const; void printMap() const; public: MapTools(); void onStart(); void onFrame(); void draw() const; void toggleDraw(); int width() const; int height() const; bool isValidTile(int tileX, int tileY) const; bool isValidTile(const BWAPI::TilePosition & tile) const; bool isValidPosition(const BWAPI::Position & pos) const; bool isPowered(int tileX, int tileY) const; bool isExplored(int tileX, int tileY) const; bool isExplored(const BWAPI::Position & pos) const; bool isExplored(const BWAPI::TilePosition & pos) const; bool isVisible(int tileX, int tileY) const; bool isWalkable(int tileX, int tileY) const; bool isWalkable(const BWAPI::TilePosition& tile) const; bool isBuildable(int tileX, int tileY) const; bool isBuildable(const BWAPI::TilePosition& tile) const; bool isDepotBuildableTile(int tileX, int tileY) const; void drawTile(int tileX, int tileY, const BWAPI::Color & color) const; }; ================================================ FILE: UAlbertaBot/starterbot/StarterBot.cpp ================================================ #include "StarterBot.h" #include "Tools.h" #include "MapTools.h" StarterBot::StarterBot() { } // Called when the bot starts! void StarterBot::onStart() { // Set our BWAPI options here BWAPI::Broodwar->setLocalSpeed(10); BWAPI::Broodwar->setFrameSkip(0); // Enable the flag that tells BWAPI top let users enter input while bot plays BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput); // Call MapTools OnStart m_mapTools.onStart(); } // Called whenever the game ends and tells you if you won or not void StarterBot::onEnd(bool isWinner) { std::cout << "We " << (isWinner ? "won!" : "lost!") << "\n"; } // Called on each frame of the game void StarterBot::onFrame() { // Update our MapTools information m_mapTools.onFrame(); // Send our idle workers to mine minerals so they don't just stand there sendIdleWorkersToMinerals(); // Train more workers so we can gather more income trainAdditionalWorkers(); // Build more supply if we are going to run out soon buildAdditionalSupply(); // Draw unit health bars, which brood war unfortunately does not do Tools::DrawUnitHealthBars(); // Draw some relevent information to the screen to help us debug the bot drawDebugInformation(); } // Send our idle workers to mine minerals so they don't just stand there void StarterBot::sendIdleWorkersToMinerals() { // Let's send all of our starting workers to the closest mineral to them // First we need to loop over all of the units that we (BWAPI::Broodwar->self()) own const BWAPI::Unitset& myUnits = BWAPI::Broodwar->self()->getUnits(); for (auto& unit : myUnits) { // Check the unit type, if it is an idle worker, then we want to send it somewhere if (unit->getType().isWorker() && unit->isIdle()) { // Get the closest mineral to this worker unit BWAPI::Unit closestMineral = Tools::GetClosestUnitTo(unit, BWAPI::Broodwar->getMinerals()); // If a valid mineral was found, right click it with the unit in order to start harvesting if (closestMineral) { unit->rightClick(closestMineral); } } } } // Train more workers so we can gather more income void StarterBot::trainAdditionalWorkers() { const BWAPI::UnitType workerType = BWAPI::Broodwar->self()->getRace().getWorker(); const int workersWanted = 20; const int workersOwned = Tools::CountUnitsOfType(workerType, BWAPI::Broodwar->self()->getUnits()); if (workersOwned < workersWanted) { // get the unit pointer to my depot const BWAPI::Unit myDepot = Tools::GetDepot(); // if we have a valid depot unit and it's currently not training something, train a worker // there is no reason for a bot to ever use the unit queueing system, it just wastes resources if (myDepot && !myDepot->isTraining()) { myDepot->train(workerType); } } } // Build more supply if we are going to run out soon void StarterBot::buildAdditionalSupply() { // Get the amount of supply supply we currently have unused const int unusedSupply = Tools::GetTotalSupply(true) - BWAPI::Broodwar->self()->supplyUsed(); // If we have a sufficient amount of supply, we don't need to do anything if (unusedSupply >= 2) { return; } // Otherwise, we are going to build a supply provider const BWAPI::UnitType supplyProviderType = BWAPI::Broodwar->self()->getRace().getSupplyProvider(); const bool startedBuilding = Tools::BuildBuilding(supplyProviderType); if (startedBuilding) { BWAPI::Broodwar->printf("Started Building %s", supplyProviderType.getName().c_str()); } } // Draw some relevent information to the screen to help us debug the bot void StarterBot::drawDebugInformation() { BWAPI::Broodwar->drawTextScreen(BWAPI::Position(10, 10), "Hello, World!\n"); Tools::DrawUnitCommands(); Tools::DrawUnitBoundingBoxes(); } // Called whenever a unit is destroyed, with a pointer to the unit void StarterBot::onUnitDestroy(BWAPI::Unit unit) { } // Called whenever a unit is morphed, with a pointer to the unit // Zerg units morph when they turn into other units void StarterBot::onUnitMorph(BWAPI::Unit unit) { } // Called whenever a text is sent to the game by a user void StarterBot::onSendText(std::string text) { if (text == "/map") { m_mapTools.toggleDraw(); } } // Called whenever a unit is created, with a pointer to the destroyed unit // Units are created in buildings like barracks before they are visible, // so this will trigger when you issue the build command for most units void StarterBot::onUnitCreate(BWAPI::Unit unit) { } // Called whenever a unit finished construction, with a pointer to the unit void StarterBot::onUnitComplete(BWAPI::Unit unit) { } // Called whenever a unit appears, with a pointer to the destroyed unit // This is usually triggered when units appear from fog of war and become visible void StarterBot::onUnitShow(BWAPI::Unit unit) { } // Called whenever a unit gets hidden, with a pointer to the destroyed unit // This is usually triggered when units enter the fog of war and are no longer visible void StarterBot::onUnitHide(BWAPI::Unit unit) { } // Called whenever a unit switches player control // This usually happens when a dark archon takes control of a unit void StarterBot::onUnitRenegade(BWAPI::Unit unit) { } ================================================ FILE: UAlbertaBot/starterbot/StarterBot.h ================================================ #pragma once #include "MapTools.h" #include class StarterBot { MapTools m_mapTools; public: StarterBot(); // helper functions to get you started with bot programming and learn the API void sendIdleWorkersToMinerals(); void trainAdditionalWorkers(); void buildAdditionalSupply(); void drawDebugInformation(); // functions that are triggered by various BWAPI events from main.cpp void onStart(); void onFrame(); void onEnd(bool isWinner); void onUnitDestroy(BWAPI::Unit unit); void onUnitMorph(BWAPI::Unit unit); void onSendText(std::string text); void onUnitCreate(BWAPI::Unit unit); void onUnitComplete(BWAPI::Unit unit); void onUnitShow(BWAPI::Unit unit); void onUnitHide(BWAPI::Unit unit); void onUnitRenegade(BWAPI::Unit unit); }; ================================================ FILE: UAlbertaBot/starterbot/Tools.cpp ================================================ #include "Tools.h" BWAPI::Unit Tools::GetClosestUnitTo(BWAPI::Position p, const BWAPI::Unitset& units) { BWAPI::Unit closestUnit = nullptr; for (auto& u : units) { if (!closestUnit || u->getDistance(p) < u->getDistance(closestUnit)) { closestUnit = u; } } return closestUnit; } BWAPI::Unit Tools::GetClosestUnitTo(BWAPI::Unit unit, const BWAPI::Unitset& units) { if (!unit) { return nullptr; } return GetClosestUnitTo(unit->getPosition(), units); } int Tools::CountUnitsOfType(BWAPI::UnitType type, const BWAPI::Unitset& units) { int sum = 0; for (auto& unit : units) { if (unit->getType() == type) { sum++; } } return sum; } BWAPI::Unit Tools::GetUnitOfType(BWAPI::UnitType type) { // For each unit that we own for (auto& unit : BWAPI::Broodwar->self()->getUnits()) { // if the unit is of the correct type, and it actually has been constructed, return it if (unit->getType() == type && unit->isCompleted()) { return unit; } } // If we didn't find a valid unit to return, make sure we return nullptr return nullptr; } BWAPI::Unit Tools::GetDepot() { const BWAPI::UnitType depot = BWAPI::Broodwar->self()->getRace().getResourceDepot(); return GetUnitOfType(depot); } // Attempt tp construct a building of a given type bool Tools::BuildBuilding(BWAPI::UnitType type) { // Get the type of unit that is required to build the desired building BWAPI::UnitType builderType = type.whatBuilds().first; // Get a unit that we own that is of the given type so it can build // If we can't find a valid builder unit, then we have to cancel the building BWAPI::Unit builder = Tools::GetUnitOfType(builderType); if (!builder) { return false; } // Get a location that we want to build the building next to BWAPI::TilePosition desiredPos = BWAPI::Broodwar->self()->getStartLocation(); // Ask BWAPI for a building location near the desired position for the type int maxBuildRange = 64; bool buildingOnCreep = type.requiresCreep(); BWAPI::TilePosition buildPos = BWAPI::Broodwar->getBuildLocation(type, desiredPos, maxBuildRange, buildingOnCreep); return builder->build(type, buildPos); } void Tools::DrawUnitCommands() { for (auto& unit : BWAPI::Broodwar->self()->getUnits()) { const BWAPI::UnitCommand & command = unit->getLastCommand(); // If the previous command had a ground position target, draw it in red // Example: move to location on the map if (command.getTargetPosition() != BWAPI::Positions::None) { BWAPI::Broodwar->drawLineMap(unit->getPosition(), command.getTargetPosition(), BWAPI::Colors::Red); } // If the previous command had a tile position target, draw it in red // Example: build at given tile position location if (command.getTargetTilePosition() != BWAPI::TilePositions::None) { BWAPI::Broodwar->drawLineMap(unit->getPosition(), BWAPI::Position(command.getTargetTilePosition()), BWAPI::Colors::Green); } // If the previous command had a unit target, draw it in red // Example: attack unit, mine mineral, etc if (command.getTarget() != nullptr) { BWAPI::Broodwar->drawLineMap(unit->getPosition(), command.getTarget()->getPosition(), BWAPI::Colors::White); } } } void Tools::DrawUnitBoundingBoxes() { for (auto& unit : BWAPI::Broodwar->getAllUnits()) { BWAPI::Position topLeft(unit->getLeft(), unit->getTop()); BWAPI::Position bottomRight(unit->getRight(), unit->getBottom()); BWAPI::Broodwar->drawBoxMap(topLeft, bottomRight, BWAPI::Colors::White); } } void Tools::SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target) { // if there's no valid unit, ignore the command if (!unit || !target) { return; } // Don't issue a 2nd command to the unit on the same frame if (unit->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount()) { return; } // If we are issuing the same type of command with the same arguments, we can ignore it // Issuing multiple identical commands on successive frames can lead to bugs if (unit->getLastCommand().getTarget() == target) { return; } // If there's nothing left to stop us, right click! unit->rightClick(target); } int Tools::GetTotalSupply(bool inProgress) { // start the calculation by looking at our current completed supplyt int totalSupply = BWAPI::Broodwar->self()->supplyTotal(); // if we don't want to calculate the supply in progress, just return that value if (!inProgress) { return totalSupply; } // if we do care about supply in progress, check all the currently constructing units if they will add supply for (auto& unit : BWAPI::Broodwar->self()->getUnits()) { // ignore units that are fully completed if (unit->isCompleted()) { continue; } // if they are not completed, then add their supply provided to the total supply totalSupply += unit->getType().supplyProvided(); } // one last tricky case: if a unit is currently on its way to build a supply provider, add it for (auto& unit : BWAPI::Broodwar->self()->getUnits()) { // get the last command given to the unit const BWAPI::UnitCommand& command = unit->getLastCommand(); // if it's not a build command we can ignore it if (command.getType() != BWAPI::UnitCommandTypes::Build) { continue; } // add the supply amount of the unit that it's trying to build totalSupply += command.getUnitType().supplyProvided(); } return totalSupply; } void Tools::DrawUnitHealthBars() { // how far up from the unit to draw the health bar int verticalOffset = -10; // draw a health bar for each unit on the map for (auto& unit : BWAPI::Broodwar->getAllUnits()) { // determine the position and dimensions of the unit const BWAPI::Position& pos = unit->getPosition(); int left = pos.x - unit->getType().dimensionLeft(); int right = pos.x + unit->getType().dimensionRight(); int top = pos.y - unit->getType().dimensionUp(); int bottom = pos.y + unit->getType().dimensionDown(); // if it's a resource, draw the resources remaining if (unit->getType().isResourceContainer() && unit->getInitialResources() > 0) { double mineralRatio = (double)unit->getResources() / (double)unit->getInitialResources(); DrawHealthBar(unit, mineralRatio, BWAPI::Colors::Cyan, 0); } // otherwise if it's a unit, draw the hp else if (unit->getType().maxHitPoints() > 0) { double hpRatio = (double)unit->getHitPoints() / (double)unit->getType().maxHitPoints(); BWAPI::Color hpColor = BWAPI::Colors::Green; if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange; if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red; DrawHealthBar(unit, hpRatio, hpColor, 0); // if it has shields, draw those too if (unit->getType().maxShields() > 0) { double shieldRatio = (double)unit->getShields() / (double)unit->getType().maxShields(); DrawHealthBar(unit, shieldRatio, BWAPI::Colors::Blue, -3); } } } } void Tools::DrawHealthBar(BWAPI::Unit unit, double ratio, BWAPI::Color color, int yOffset) { int verticalOffset = -10; const BWAPI::Position& pos = unit->getPosition(); int left = pos.x - unit->getType().dimensionLeft(); int right = pos.x + unit->getType().dimensionRight(); int top = pos.y - unit->getType().dimensionUp(); int bottom = pos.y + unit->getType().dimensionDown(); int ratioRight = left + (int)((right - left) * ratio); int hpTop = top + yOffset + verticalOffset; int hpBottom = top + 4 + yOffset + verticalOffset; BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), color, true); BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false); int ticWidth = 3; for (int i(left); i < right - 1; i += ticWidth) { BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black); } } ================================================ FILE: UAlbertaBot/starterbot/Tools.h ================================================ #pragma once #include namespace Tools { BWAPI::Unit GetClosestUnitTo(BWAPI::Position p, const BWAPI::Unitset& units); BWAPI::Unit GetClosestUnitTo(BWAPI::Unit unit, const BWAPI::Unitset& units); int CountUnitsOfType(BWAPI::UnitType type, const BWAPI::Unitset& units); BWAPI::Unit GetUnitOfType(BWAPI::UnitType type); BWAPI::Unit GetDepot(); bool BuildBuilding(BWAPI::UnitType type); void DrawUnitBoundingBoxes(); void DrawUnitCommands(); void SmartRightClick(BWAPI::Unit unit, BWAPI::Unit target); int GetTotalSupply(bool inProgress = false); void DrawUnitHealthBars(); void DrawHealthBar(BWAPI::Unit unit, double ratio, BWAPI::Color color, int yOffset); } ================================================ FILE: UAlbertaBot/starterbot/main.cpp ================================================ #include #include #include "StarterBot.h" #include #include #include void PlayGame(); int main(int argc, char * argv[]) { size_t gameCount = 0; // if we are not currently connected to BWAPI, try to reconnect while (!BWAPI::BWAPIClient.connect()) { std::this_thread::sleep_for(std::chrono::milliseconds{ 1000 }); } // if we have connected to BWAPI while (BWAPI::BWAPIClient.isConnected()) { // the starcraft exe has connected but we need to wait for the game to start std::cout << "Waiting for game start\n"; while (BWAPI::BWAPIClient.isConnected() && !BWAPI::Broodwar->isInGame()) { BWAPI::BWAPIClient.update(); } // Check to see if Starcraft shut down somehow if (BWAPI::BroodwarPtr == nullptr) { break; } // If we are successfully in a game, call the module to play the game if (BWAPI::Broodwar->isInGame()) { std::cout << "Playing game " << gameCount++ << " on map " << BWAPI::Broodwar->mapFileName() << "\n"; PlayGame(); } } return 0; } void PlayGame() { StarterBot bot; // The main game loop, which continues while we are connected to BWAPI and in a game while (BWAPI::BWAPIClient.isConnected() && BWAPI::Broodwar->isInGame()) { // Handle each of the events that happened on this frame of the game for (const BWAPI::Event& e : BWAPI::Broodwar->getEvents()) { switch (e.getType()) { case BWAPI::EventType::MatchStart: { bot.onStart(); break; } case BWAPI::EventType::MatchFrame: { bot.onFrame(); break; } case BWAPI::EventType::MatchEnd: { bot.onEnd(e.isWinner()); break; } case BWAPI::EventType::UnitShow: { bot.onUnitShow(e.getUnit()); break; } case BWAPI::EventType::UnitHide: { bot.onUnitHide(e.getUnit()); break; } case BWAPI::EventType::UnitCreate: { bot.onUnitCreate(e.getUnit()); break; } case BWAPI::EventType::UnitMorph: { bot.onUnitMorph(e.getUnit()); break; } case BWAPI::EventType::UnitDestroy: { bot.onUnitDestroy(e.getUnit()); break; } case BWAPI::EventType::UnitRenegade: { bot.onUnitRenegade(e.getUnit()); break; } case BWAPI::EventType::UnitComplete: { bot.onUnitComplete(e.getUnit()); break; } case BWAPI::EventType::SendText: { bot.onSendText(e.getText()); break; } } } BWAPI::BWAPIClient.update(); if (!BWAPI::BWAPIClient.isConnected()) { std::cout << "Disconnected\n"; break; } } std::cout << "Game Over\n"; }