--- a/.gitignore Sat Sep 28 22:27:13 2024 +0200
+++ b/.gitignore Tue Dec 31 15:19:43 2024 +0100
@@ -32,7 +32,7 @@
misc/libphysfs/Xcode/build/
misc/libphyslayer/Xcode/build/
moc_*.cxx_parameters
-relre:^release\/
+relre:^release/
*.log
*.cmd
*.diff
--- a/CMakeLists.txt Sat Sep 28 22:27:13 2024 +0200
+++ b/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -1,9 +1,7 @@
-cmake_minimum_required(VERSION 2.6.4)
-
-project(hedgewars)
+cmake_minimum_required(VERSION 3.12.0)
#initialise cmake environment
-foreach(hwpolicy CMP0003 CMP0012 CMP0017 CMP0018)
+foreach(hwpolicy CMP0003 CMP0012 CMP0017 CMP0018 CMP0048)
if(POLICY ${hwpolicy})
cmake_policy(SET ${hwpolicy} NEW)
endif()
@@ -15,6 +13,8 @@
endif()
endforeach()
+project(hedgewars VERSION 1.1.0)
+
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules")
include(${CMAKE_MODULE_PATH}/utils.cmake)
@@ -89,14 +89,11 @@
set(FONTS_DIRS "" CACHE STRING "Additional paths to folders where required fonts can be found ( ; is separator)")
#versioning
-set(CPACK_PACKAGE_VERSION_MAJOR 1)
-set(CPACK_PACKAGE_VERSION_MINOR 1)
-set(CPACK_PACKAGE_VERSION_PATCH 0)
set(HEDGEWARS_PROTO_VER 60)
if((CMAKE_BUILD_TYPE STREQUAL "Release") OR (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
- set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+ set(HEDGEWARS_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}")
else()
- set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}-dev")
+ set(HEDGEWARS_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}-dev")
endif()
include(${CMAKE_MODULE_PATH}/revinfo.cmake)
@@ -109,7 +106,6 @@
#platform specific init code
include(${CMAKE_MODULE_PATH}/platform.cmake)
-
#when build type is not specified, assume Debug/Release according to build version information
if(CMAKE_BUILD_TYPE)
if(NOT((CMAKE_BUILD_TYPE STREQUAL "Release") OR
@@ -139,10 +135,10 @@
add_flag_append(CMAKE_CXX_FLAGS_DEBUG "/Od")
else()
add_flag_append(CMAKE_C_FLAGS "-Wall -pipe")
- add_flag_append(CMAKE_C_FLAGS_RELEASE "-O2")
+ add_flag_append(CMAKE_C_FLAGS_RELEASE "-O3")
add_flag_append(CMAKE_C_FLAGS_DEBUG "-Wextra -O0")
add_flag_append(CMAKE_CXX_FLAGS "-Wall -pipe")
- add_flag_append(CMAKE_CXX_FLAGS_RELEASE "-O2")
+ add_flag_append(CMAKE_CXX_FLAGS_RELEASE "-O3")
add_flag_append(CMAKE_CXX_FLAGS_DEBUG "-Wextra -O0")
endif()
@@ -265,9 +261,17 @@
find_package_or_disable_msg(LIBAV NOVIDEOREC "Video recording will not be built")
+
#physfs helper library
add_subdirectory(misc/libphyslayer)
+
+#rust libraries
+add_subdirectory(tools/corrosion)
+corrosion_import_crate(MANIFEST_PATH rust/lib-hwengine-future/Cargo.toml)
+corrosion_install(TARGETS hwengine_future EXPORT hwengine_future_install_target)
+install(EXPORT hwengine_future_install_target DESTINATION ${target_library_install_dir})
+
#maybe this could be merged inside hedgewars/CMakeLists.txt
if(BUILD_ENGINE_C)
#pascal to c converter
--- a/QTfrontend/CMakeLists.txt Sat Sep 28 22:27:13 2024 +0200
+++ b/QTfrontend/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -19,6 +19,7 @@
else()
find_package(SDL2_mixer 2 REQUIRED) #audio in SDLInteraction
endif()
+
include_directories(${SDL2_INCLUDE_DIRS})
include_directories(${SDL2_MIXER_INCLUDE_DIRS})
--- a/QTfrontend/model/MapModel.h Sat Sep 28 22:27:13 2024 +0200
+++ b/QTfrontend/model/MapModel.h Tue Dec 31 15:19:43 2024 +0100
@@ -46,28 +46,30 @@
Q_OBJECT
public:
- enum MapType {
- Invalid,
- GeneratedMap,
- GeneratedMaze,
- GeneratedPerlin,
- HandDrawnMap,
- MissionMap,
- StaticMap,
- FortsMap
- };
+ enum MapType {
+ Invalid,
+ GeneratedMap,
+ GeneratedMaze,
+ GeneratedPerlin,
+ HandDrawnMap,
+ MissionMap,
+ StaticMap,
+ FortsMap,
+ WfcMap
+ };
- /// a struct for holding the attributes of a map.
- struct MapInfo
- {
- MapType type; ///< The map-type
- QString name; ///< The internal name.
- QString theme; ///< The theme to be used. (can be empty)
- quint32 limit; ///< The maximum allowed number of hedgehogs.
- QString scheme; ///< Default scheme name or "locked", for mission-maps.
- QString weapons; ///< Default weaponset name or "locked", for missions-maps.
- QString desc; ///< The brief 1-2 sentence description of the mission, for mission-maps.
- bool dlc; ///< True if this map was not packaged with the game
+ /// a struct for holding the attributes of a map.
+ struct MapInfo {
+ MapType type; ///< The map-type
+ QString name; ///< The internal name.
+ QString theme; ///< The theme to be used. (can be empty)
+ quint32 limit; ///< The maximum allowed number of hedgehogs.
+ QString scheme; ///< Default scheme name or "locked", for mission-maps.
+ QString
+ weapons; ///< Default weaponset name or "locked", for missions-maps.
+ QString desc; ///< The brief 1-2 sentence description of the mission,
+ ///< for mission-maps.
+ bool dlc; ///< True if this map was not packaged with the game
};
MapModel(MapType maptype, QObject *parent = 0);
--- a/QTfrontend/net/hwmap.h Sat Sep 28 22:27:13 2024 +0200
+++ b/QTfrontend/net/hwmap.h Tue Dec 31 15:19:43 2024 +0100
@@ -26,14 +26,14 @@
#include "tcpBase.h"
-enum MapGenerator
-{
- MAPGEN_REGULAR = 0,
- MAPGEN_MAZE = 1,
- MAPGEN_PERLIN = 2,
- MAPGEN_DRAWN = 3,
- MAPGEN_FORTS = 4,
- MAPGEN_MAP = 5
+enum MapGenerator {
+ MAPGEN_REGULAR = 0,
+ MAPGEN_MAZE = 1,
+ MAPGEN_PERLIN = 2,
+ MAPGEN_DRAWN = 3,
+ MAPGEN_FORTS = 4,
+ MAPGEN_WFC = 5,
+ MAPGEN_MAP = 6,
};
class HWMap : public TCPBase
--- a/QTfrontend/ui/widget/mapContainer.cpp Sat Sep 28 22:27:13 2024 +0200
+++ b/QTfrontend/ui/widget/mapContainer.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -129,7 +129,9 @@
cType->insertItem(4, tr("Random maze"), MapModel::GeneratedMaze);
cType->insertItem(5, tr("Random perlin"), MapModel::GeneratedPerlin);
cType->insertItem(6, tr("Forts"), MapModel::FortsMap);
- connect(cType, SIGNAL(currentIndexChanged(int)), this, SLOT(mapTypeChanged(int)));
+ cType->insertItem(7, tr("WFC"), MapModel::WfcMap);
+ connect(cType, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(mapTypeChanged(int)));
m_childWidgets << cType;
/* Randomize button */
@@ -760,19 +762,23 @@
m_mapInfo.type = MapModel::FortsMap;
f = true;
break;
+ case MAPGEN_WFC:
+ m_mapInfo.type = MapModel::WfcMap;
+ f = true;
+ break;
case MAPGEN_MAP:
- switch (m_mapInfo.type)
- {
- case MapModel::GeneratedMap:
- case MapModel::GeneratedMaze:
- case MapModel::GeneratedPerlin:
- case MapModel::HandDrawnMap:
- case MapModel::FortsMap:
- m_mapInfo.type = MapModel::Invalid;
- default:
- break;
- }
- break;
+ switch (m_mapInfo.type) {
+ case MapModel::GeneratedMap:
+ case MapModel::GeneratedMaze:
+ case MapModel::GeneratedPerlin:
+ case MapModel::HandDrawnMap:
+ case MapModel::FortsMap:
+ case MapModel::WfcMap:
+ m_mapInfo.type = MapModel::Invalid;
+ default:
+ break;
+ }
+ break;
}
if(f)
@@ -948,10 +954,11 @@
case MapModel::GeneratedMap:
case MapModel::GeneratedPerlin:
case MapModel::GeneratedMaze:
- mapPreview->setWhatsThis(randomAllPrev);
- mapFeatureSize->setWhatsThis(mfsComplex);
- btnRandomize->setWhatsThis(randomAll);
- break;
+ case MapModel::WfcMap:
+ mapPreview->setWhatsThis(randomAllPrev);
+ mapFeatureSize->setWhatsThis(mfsComplex);
+ btnRandomize->setWhatsThis(randomAll);
+ break;
case MapModel::MissionMap:
case MapModel::StaticMap:
mapPreview->setWhatsThis(randomAllPrev);
@@ -1059,8 +1066,15 @@
setMapInfo(MapModel::MapInfoForts);
lblMapList->hide();
break;
+ case MapModel::WfcMap:
+ mapgen = MAPGEN_WFC;
+ setMapInfo(MapModel::MapInfoRandom);
+ lblMapList->setText(tr("Map size:"));
+ lblMapList->show();
+ generationStyles->show();
+ break;
default:
- break;
+ break;
}
// Update theme button size
--- a/hedgewars/CMakeLists.txt Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -1,10 +1,10 @@
enable_language(Pascal)
find_package(SDL2 REQUIRED CONFIG)
-find_package(SDL2_image REQUIRED CONFIG)
-find_package(SDL2_net REQUIRED CONFIG)
-find_package(SDL2_ttf REQUIRED CONFIG)
-find_package(SDL2_mixer REQUIRED CONFIG)
+find_package(SDL2_image REQUIRED)
+find_package(SDL2_net REQUIRED)
+find_package(SDL2_ttf REQUIRED)
+find_package(SDL2_mixer REQUIRED)
include(CheckLibraryExists)
include(${CMAKE_MODULE_PATH}/utils.cmake)
@@ -78,13 +78,11 @@
adler32.pas
uLandTemplates.pas
uLandTexture.pas
+ uLandGenPerlin.pas
uLandGraphics.pas
uLandPainted.pas
- uLandOutline.pas
- uLandGenMaze.pas
- uLandGenPerlin.pas
- uLandGenTemplateBased.pas
uLandUtils.pas
+ uAI2.pas
#this is where dependency tracking becomes hard
uStore.pas
@@ -189,7 +187,6 @@
list(APPEND HW_LINK_LIBS physlayer)
-
#opengl 2
IF(GL2)
add_definitions(-dGL2)
@@ -246,6 +243,6 @@
endif()
#even though not actually used, this will trigger relink if any lib changes
-target_link_libraries(hwengine ${HW_LINK_LIBS})
+target_link_libraries(hwengine ${HW_LINK_LIBS} hwengine_future)
install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}" DESTINATION ${destination_dir})
--- a/hedgewars/SDLh.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/SDLh.pas Tue Dec 31 15:19:43 2024 +0100
@@ -931,6 +931,9 @@
TLongWordArray = array[0..16383] of LongWord;
PLongWordArray = ^TLongWordArray;
+ TWordArray = array[0..16383] of Word;
+ PWordArray = ^TWordArray;
+
PSDL_Thread = Pointer;
PSDL_mutex = Pointer;
PSDL_sem = Pointer;
@@ -1033,14 +1036,14 @@
{$IFDEF WINDOWS}
TThreadFunction = function (p: pointer): Longword; stdcall;
pfnSDL_CurrentBeginThread = function (
- _Security: pointer;
+ _Security: pointer;
_StackSize: LongWord;
_StartAddress: TThreadFunction;
_ArgList: pointer;
_InitFlag: Longword;
_ThrdAddr: PLongword): PtrUInt; cdecl;
pfnSDL_CurrentEndThread = procedure (_Retval: LongInt); cdecl;
-{$ENDIF}
+{$ENDIF}
/////////////////////////////////////////////////////////////////
///////////////////// FUNCTION DEFINITIONS /////////////////////
@@ -1142,7 +1145,7 @@
procedure SDL_SetEventFilter(filter: TSDL_EventFilter); cdecl; external SDLLibName;
function SDL_ShowCursor(toggle: LongInt): LongInt; cdecl; external SDLLibName;
-procedure SDL_WarpMouse(x, y: Word); inline;
+procedure SDL_WarpMouse(x, y: Word);
function SDL_GetKeyboardState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName;
@@ -1297,7 +1300,7 @@
// for sdl2 we provide a SDL_WarpMouse() which calls the right SDL_WarpMouseInWindow() function
// this has the advantage of reducing 'uses' and 'ifdef' statements
// (SDLwindow is a private member of uStore module)
-procedure SDL_WarpMouse(x, y: Word); inline;
+procedure SDL_WarpMouse(x, y: Word);
begin
WarpMouse(x, y);
end;
@@ -1340,7 +1343,7 @@
function SDL_CreateThread(fn: Pointer; name: PChar; data: Pointer): PSDL_Thread; cdecl;
begin
SDL_CreateThread:= SDL_CreateThread(fn, name, data, nil, nil)
-end;
+end;
{$ENDIF}
end.
--- a/hedgewars/options.inc Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/options.inc Tue Dec 31 15:19:43 2024 +0100
@@ -65,6 +65,8 @@
{$DEFINE _S:=}
{$DEFINE _P:=}
+{$optimization autoInline}
+
//{$DEFINE TRACEAIACTIONS}
//{$DEFINE COUNTTICKS}
--- a/hedgewars/uAI.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uAI.pas Tue Dec 31 15:19:43 2024 +0100
@@ -32,7 +32,7 @@
uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions,
uAmmos, uTypes,
uVariables, uCommands, uUtils, uDebug, uAILandMarks,
- uGearsUtils;
+ uGearsUtils, uAI2;
var BestActions: TActions;
CanUseAmmo: array [TAmmoType] of boolean;
@@ -635,7 +635,7 @@
var scoreShown: boolean = false;
{$ENDIF}
-procedure ProcessBot;
+procedure ProcessBot_old;
const cStopThinkTime = 40;
begin
with CurrentHedgehog^ do
@@ -677,6 +677,12 @@
StopThinking:= true
end;
+
+procedure ProcessBot;
+begin
+ if true then ProcessBot_old else uAI2.ProcessBot
+end;
+
procedure initModule;
begin
StartTicks:= 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uAI2.pas Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,60 @@
+unit uAI2;
+
+interface
+
+procedure ProcessBot;
+procedure initModule;
+
+implementation
+uses uLandUtils, uFloat, uVariables, uTypes, uAmmos;
+
+{$linklib hwengine_future}
+
+type TAmmoCounts = array[TAmmoType] of Longword;
+ PAmmoCounts = ^TAmmoCounts;
+
+function create_ai(game_field: pointer): pointer; cdecl; external;
+procedure ai_clear_team(ai: pointer); cdecl; external;
+procedure ai_add_team_hedgehog(ai: pointer; x, y: real; ammo_counts: PAmmoCounts); cdecl; external;
+procedure ai_think(ai: pointer); cdecl; external;
+function ai_have_plan(): boolean; cdecl; external;
+procedure dispose_ai(ai: pointer); cdecl; external;
+
+var ai: pointer;
+
+procedure ProcessBot;
+var currHedgehogIndex, itHedgehog: Longword;
+ itAmmo: TAmmoType;
+ ammoCounts: TAmmoCounts;
+begin
+ if ai = nil then
+ begin
+ ai:= create_ai(gameField)
+ end;
+
+ ai_clear_team(ai);
+
+ currHedgehogIndex:= CurrentTeam^.CurrHedgehog;
+ itHedgehog:= currHedgehogIndex;
+ repeat
+ with CurrentTeam^.Hedgehogs[itHedgehog] do
+ if (Gear <> nil) and (Effects[heFrozen] = 0) then
+ begin
+ for itAmmo:= Low(TAmmoType) to High(TAmmoType) do
+ ammoCounts[itAmmo]:= HHHasAmmo(CurrentTeam^.Hedgehogs[itHedgehog], itAmmo);
+
+ ai_add_team_hedgehog(ai, hwFloat2float(Gear^.X), hwFloat2float(Gear^.Y), @ammoCounts)
+ end;
+ itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber;
+ until (itHedgehog = currHedgehogIndex);
+
+ ai_think(ai);
+end;
+
+procedure initModule;
+begin
+ ai:= nil
+end;
+
+end.
+
--- a/hedgewars/uAIActions.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uAIActions.pas Tue Dec 31 15:19:43 2024 +0100
@@ -120,7 +120,17 @@
{$ENDIF}
procedure AddAction(var Actions: TActions; Action: Longword; Param: LongInt; TimeDelta: Longword; X, Y: LongInt);
+var t: Longword;
begin
+if ((Action = aia_LookLeft) or (Action = aia_LookRight)) and (Actions.Count > 0) then
+ begin
+ t:= Actions.actions[Actions.Count - 1].Action;
+ if ((t = aia_LookLeft) or (t = aia_LookRight)) then
+ begin
+ dec(Actions.Count)
+ end;
+ end;
+
if Actions.Count < MAXACTIONS then
with Actions do
begin
@@ -136,16 +146,23 @@
end
end;
-procedure CheckHang(Me: PGear);
+procedure CheckHang(Me: PGear; fromLeft: boolean);
+var newX: LongInt;
begin
-if hwRound(Me^.X) <> PrevX then
+newX:= hwRound(Me^.X);
+if newX <> PrevX then
begin
- PrevX:= hwRound(Me^.X);
+ if (newX < PrevX) = fromLeft then
+ begin
+ FreeActionsList
+ end;
+
+ PrevX:= newX;
timedelta:= 0
end else
begin
inc(timedelta);
- if timedelta > 1700 then
+ if timedelta > 900 then
begin
timedelta:= 0;
FreeActionsList
@@ -186,7 +203,7 @@
end
else
begin
- CheckHang(Me);
+ CheckHang(Me, false);
exit
end;
@@ -205,7 +222,7 @@
end
else
begin
- CheckHang(Me);
+ CheckHang(Me, true);
exit
end;
aia_LookLeft: begin
--- a/hedgewars/uAIAmmoTests.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uAIAmmoTests.pas Tue Dec 31 15:19:43 2024 +0100
@@ -25,7 +25,7 @@
amtest_Rare = $00000001; // check only several positions
amtest_NoTarget = $00000002; // each pos, but no targetting
amtest_MultipleAttacks = $00000004; // test could result in multiple attacks, set AttacksNum
- amtest_NoTrackFall = $00000008; // skip fall tracing.
+ amtest_NoTrackFall = $00000008; // skip fall tracing.
amtest_LaserSight = $00000010; // supports laser sighting
amtest_NoVampiric = $00000020; // don't use vampirism with this ammo
amtest_NoInvulnerable = $00000040; // don't use invulnerable with this with ammo
@@ -151,9 +151,9 @@
);
implementation
-uses uVariables, uUtils, uGearsHandlers;
+uses uVariables, uUtils, uGearsHandlers, uLandUtils;
-function Metric(x1, y1, x2, y2: LongInt): LongInt; inline;
+function Metric(x1, y1, x2, y2: LongInt): LongInt;
begin
Metric:= abs(x1 - x2) + abs(y1 - y2)
end;
@@ -1081,7 +1081,7 @@
if ((ix and LAND_WIDTH_MASK) = 0) and ((iy and LAND_HEIGHT_MASK) = 0) then
repeat
- if Land[iy, ix] <> 0 then
+ if LandGet(iy, ix) <> 0 then
inc(d);
x:= x + vX;
y:= y + vY;
@@ -1137,7 +1137,7 @@
x:= x + vX;
y:= y + vY;
if ((trunc(x) and LAND_WIDTH_MASK) = 0)and((trunc(y) and LAND_HEIGHT_MASK) = 0)
- and (Land[trunc(y), trunc(x)] <> 0) then
+ and (LandGet(trunc(y), trunc(x)) <> 0) then
inc(d);
until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 4)
or (x < 0)
--- a/hedgewars/uAIMisc.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uAIMisc.pas Tue Dec 31 15:19:43 2024 +0100
@@ -71,20 +71,20 @@
procedure freeModule;
procedure FillTargets;
-procedure ResetTargets; inline;
-procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
+procedure ResetTargets;
+procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt);
procedure FillBonuses(isAfterAttack: boolean);
-procedure AwareOfExplosion(x, y, r: LongInt); inline;
+procedure AwareOfExplosion(x, y, r: LongInt);
function RatePlace(Gear: PGear): LongInt;
-function CheckWrap(x: real): real; inline;
-function TestColl(x, y, r: LongInt): boolean; inline;
-function TestCollHogsOrObjects(x, y, r: LongInt): boolean; inline;
-function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
-function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
+function CheckWrap(x: real): real;
+function TestColl(x, y, r: LongInt): boolean;
+function TestCollHogsOrObjects(x, y, r: LongInt): boolean;
+function TestCollExcludingObjects(x, y, r: LongInt): boolean;
+function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean;
-function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
-function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
+function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
+function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
@@ -93,8 +93,8 @@
function RateHammer(Me: PGear): LongInt;
function HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean;
-function AIrndSign(num: LongInt): LongInt; inline;
-function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; inline;
+function AIrndSign(num: LongInt): LongInt;
+function AIrndOffset(targ: TTarget; Level: LongWord): LongInt;
var ThinkingHH: PGear;
Targets: TTargets;
@@ -109,14 +109,14 @@
var dmgMod: real = 1.0;
implementation
-uses uCollisions, uVariables, uUtils, uGearsUtils, uAIAmmoTests;
+uses uCollisions, uVariables, uUtils, uGearsUtils, uAIAmmoTests, uLandUtils;
var
KnownExplosion: record
X, Y, Radius: LongInt
end = (X: 0; Y: 0; Radius: 0);
-procedure ResetTargets; inline;
+procedure ResetTargets;
var i: LongWord;
begin
if Targets.reset then
@@ -200,7 +200,7 @@
else friendlyfactor:= max(30, 300 - f * 80 div max(1,e))
end;
-procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
+procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt);
begin
if(bonuses.Count < MAXBONUS) then
begin
@@ -212,7 +212,7 @@
end;
end;
-procedure AddWalkBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
+procedure AddWalkBonus(x, y: LongInt; r: Longword; s: LongInt);
begin
if(walkbonuses.Count < MAXBONUS div 8) then
begin
@@ -334,7 +334,7 @@
end;
end;
-procedure AwareOfExplosion(x, y, r: LongInt); inline;
+procedure AwareOfExplosion(x, y, r: LongInt);
begin
KnownExplosion.X:= x;
KnownExplosion.Y:= y;
@@ -363,17 +363,17 @@
RatePlace:= rate;
end;
-function CheckWrap(x: real): real; inline;
+function CheckWrap(x: real): real;
begin
if WorldEdge = weWrap then
if (x < leftX) then
x:= x + (rightX - leftX)
- else if x > rightX then
+ else if x > rightX then
x:= x - (rightX - leftX);
CheckWrap:= x;
end;
-function CheckBounds(x, y, r: Longint): boolean; inline;
+function CheckBounds(x, y, r: Longint): boolean;
begin
CheckBounds := (((x-r) and LAND_WIDTH_MASK) = 0) and
(((x+r) and LAND_WIDTH_MASK) = 0) and
@@ -383,60 +383,60 @@
// Check for collision with anything
-function TestCollWithEverything(x, y, r: LongInt): boolean; inline;
+function TestCollWithEverything(x, y, r: LongInt): boolean;
begin
if not CheckBounds(x, y, r) then
exit(false);
- if (Land[y-r, x-r] <> 0) or
- (Land[y+r, x-r] <> 0) or
- (Land[y-r, x+r] <> 0) or
- (Land[y+r, x+r] <> 0) then
+ if (LandGet(y-r, x-r) <> 0) or
+ (LandGet(y+r, x-r) <> 0) or
+ (LandGet(y-r, x+r) <> 0) or
+ (LandGet(y+r, x+r) <> 0) then
exit(true);
TestCollWithEverything := false;
end;
// Check for collision with non-objects
-function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
+function TestCollExcludingObjects(x, y, r: LongInt): boolean;
begin
if not CheckBounds(x, y, r) then
exit(false);
- if (Land[y-r, x-r] > lfAllObjMask) or
- (Land[y+r, x-r] > lfAllObjMask) or
- (Land[y-r, x+r] > lfAllObjMask) or
- (Land[y+r, x+r] > lfAllObjMask) then
+ if (LandGet(y-r, x-r) > lfAllObjMask) or
+ (LandGet(y+r, x-r) > lfAllObjMask) or
+ (LandGet(y-r, x+r) > lfAllObjMask) or
+ (LandGet(y+r, x+r) > lfAllObjMask) then
exit(true);
TestCollExcludingObjects:= false;
end;
// Check for collision with something other than current hedgehog or crate
-function TestColl(x, y, r: LongInt): boolean; inline;
+function TestColl(x, y, r: LongInt): boolean;
begin
if not CheckBounds(x, y, r) then
exit(false);
- if (Land[y-r, x-r] and lfNotCurHogCrate <> 0) or
- (Land[y+r, x-r] and lfNotCurHogCrate <> 0) or
- (Land[y-r, x+r] and lfNotCurHogCrate <> 0) or
- (Land[y+r, x+r] and lfNotCurHogCrate <> 0) then
+ if (LandGet(y-r, x-r) and lfNotCurHogCrate <> 0) or
+ (LandGet(y+r, x-r) and lfNotCurHogCrate <> 0) or
+ (LandGet(y-r, x+r) and lfNotCurHogCrate <> 0) or
+ (LandGet(y+r, x+r) and lfNotCurHogCrate <> 0) then
exit(true);
TestColl:= false;
end;
// Check for collision with hedgehog or object
-function TestCollHogsOrObjects(x, y, r: LongInt): boolean; inline;
+function TestCollHogsOrObjects(x, y, r: LongInt): boolean;
begin
if not CheckBounds(x, y, r) then
exit(false);
- if (Land[y-r, x-r] and lfAllObjMask <> 0) or
- (Land[y+r, x-r] and lfAllObjMask <> 0) or
- (Land[y-r, x+r] and lfAllObjMask <> 0) or
- (Land[y+r, x+r] and lfAllObjMask <> 0) then
+ if (LandGet(y-r, x-r) and lfAllObjMask <> 0) or
+ (LandGet(y+r, x-r) and lfAllObjMask <> 0) or
+ (LandGet(y-r, x+r) and lfAllObjMask <> 0) or
+ (LandGet(y+r, x+r) and lfAllObjMask <> 0) then
exit(true);
TestCollHogsOrObjects:= false;
@@ -445,7 +445,7 @@
// Check for collision with something other than the given "Me" gear.
// Wrapper to test various approaches. If it works reasonably, will just replace.
// Right now, converting to hwFloat is a tad inefficient since the x/y were hwFloat to begin with...
-function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
+function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean;
var MeX, MeY: LongInt;
begin
if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then
@@ -453,7 +453,7 @@
MeX:= hwRound(Me^.X);
MeY:= hwRound(Me^.Y);
// We are still inside the hog. Skip radius test
- if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (Land[y, x] and lfObjMask = 0) then
+ if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (LandGet(y, x) and lfObjMask = 0) then
exit(false);
end;
TestCollExcludingMe:= TestCollWithEverything(x, y, r)
@@ -527,7 +527,7 @@
{ if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then
begin
- LandPixels[trunc(y), trunc(x)]:= v;
+ LandPixelGet(trunc(y), trunc(x)):= v;
UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true);
end;}
@@ -566,12 +566,12 @@
end;
end;
-function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
+function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
begin
RateExplosion:= RealRateExplosion(Me, x, y, r, 0);
ResetTargets;
end;
-function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
+function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
begin
RateExplosion:= RealRateExplosion(Me, x, y, r, Flags);
ResetTargets;
@@ -637,7 +637,7 @@
if pY - y < 0 then dY:= -dY;
if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
- (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
+ (LandGet(y+cHHRadius+2, x) and lfIndestructible <> 0) then
fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod)
else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod)
end;
@@ -831,7 +831,7 @@
((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
dX:= 0;
if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
- (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
+ (LandGet(y+cHHRadius+2, x) and lfIndestructible <> 0) then
fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod)
else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod)
end;
@@ -915,12 +915,12 @@
begin
if (WorldEdge <> weWrap) or (not (hwAbs(meX - int2hwFloat(pX)) > int2hwFloat(cSeductionDist))) then
- dX:= _50 * aiGravity * (meX - int2hwFloat(pX)) / _25
+ dX:= aiGravity * (meX - int2hwFloat(pX)) / 2
else if (not (hwAbs(meX + int2hwFloat((RightX-LeftX) - pX)) > int2hwFloat(cSeductionDist))) then
- dX:= _50 * aiGravity * (meX + (int2hwFloat((RightX-LeftX) - pX))) / _25
+ dX:= aiGravity * (meX + (int2hwFloat((RightX-LeftX) - pX))) / 2
else
- dX:= _50 * aiGravity * (meX - (int2hwFloat((RightX-LeftX) - pX))) / _25;
- dY:= -_450 * cMaxWindSpeed * 2;
+ dX:= aiGravity * (meX - (int2hwFloat((RightX-LeftX) - pX))) / 2;
+ dY:= -_900 * cMaxWindSpeed;
pXr:= pX;
@@ -1064,7 +1064,7 @@
begin
if TestCollisionYwithGear(Gear, -1) <> 0 then
if TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) = 0 then
- Gear^.Y:= Gear^.Y - int2hwFloat(2)
+ Gear^.Y:= Gear^.Y - _2
else
if TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) = 0 then
Gear^.Y:= Gear^.Y - _1;
@@ -1081,12 +1081,6 @@
end;
repeat
- {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
- begin
- LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= Gear^.Hedgehog^.Team^.Clan^.Color;
- UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true);
- end;}
-
if CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius) then
exit(false);
if (Gear^.State and gstMoving) <> 0 then
@@ -1147,12 +1141,6 @@
GoInfo.JumpType:= jmpNone;
tY:= hwRound(Gear^.Y);
repeat
- {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
- begin
- LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= random($FFFFFFFF);//Gear^.Hedgehog^.Team^.Clan^.Color;
- UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true);
- end;}
-
pX:= hwRound(Gear^.X);
pY:= hwRound(Gear^.Y);
if CheckCoordInWater(pX, pY + cHHRadius) then
@@ -1206,7 +1194,7 @@
HHJump(AltGear, jmpHJump, GoInfo);
end;
-function AIrndSign(num: LongInt): LongInt; inline;
+function AIrndSign(num: LongInt): LongInt;
begin
if random(2) = 0 then
AIrndSign:= num
@@ -1214,7 +1202,7 @@
AIrndSign:= - num
end;
-function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; inline;
+function AIrndOffset(targ: TTarget; Level: LongWord): LongInt;
begin
if Level <> 1 then exit(0);
// at present level 2 doesn't track falls on most things
--- a/hedgewars/uChat.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uChat.pas Tue Dec 31 15:19:43 2024 +0100
@@ -108,7 +108,7 @@
procedure UpdateCursorCoords(); forward;
// relevant for UTF-8 handling
-function IsFirstCharByte(c: char): boolean; inline;
+function IsFirstCharByte(c: char): boolean;
begin
// based on https://en.wikipedia.org/wiki/UTF-8#Description
IsFirstCharByte:= (byte(c) and $C0) <> $80;
--- a/hedgewars/uCollisions.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uCollisions.pas Tue Dec 31 15:19:43 2024 +0100
@@ -70,11 +70,11 @@
function CheckGearsLineCollision(Gear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
function CheckAllGearsLineCollision(SourceGear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
-function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; inline;
-function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; inline;
-function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; inline;
-procedure ClearHitOrderLeq(MinOrder: LongInt); inline;
-procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); inline;
+function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
+function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean;
+function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean;
+procedure ClearHitOrderLeq(MinOrder: LongInt);
+procedure ClearGlobalHitOrderLeq(MinOrder: LongInt);
procedure ClearHitOrder();
procedure RefillProximityCache(SourceGear: PGear; radius: LongInt);
@@ -84,16 +84,16 @@
function TestCollisionXImpl(centerX, centerY, radius, direction: LongInt; collisionMask: Word): Word;
function TestCollisionYImpl(centerX, centerY, radius, direction: LongInt; collisionMask: Word): Word;
-function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; inline;
-function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
+function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
-function TestCollisionX(Gear: PGear; Dir: LongInt): Word; inline;
-function TestCollisionY(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionX(Gear: PGear; Dir: LongInt): Word;
+function TestCollisionY(Gear: PGear; Dir: LongInt): Word;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
function TestCollisionXKickImpl(centerX, centerY, radius, direction: LongInt; collisionMask, kickMask: Word): TKickTest;
function TestCollisionYKickImpl(centerX, centerY, radius, direction: LongInt; collisionMask, kickMask: Word): TKickTest;
@@ -103,7 +103,7 @@
function TestRectangleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
-function CheckCoordInWater(X, Y: LongInt): boolean; inline;
+function CheckCoordInWater(X, Y: LongInt): boolean;
// returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45 = _0_5)
function CalcSlopeBelowGear(Gear: PGear): hwFloat;
@@ -113,7 +113,7 @@
function CheckGearsUnderSprite(Sprite: TSprite; sprX, sprY, Frame: LongInt): boolean;
implementation
-uses uConsts, uLandGraphics, uVariables, SDLh, uLandTexture, uDebug;
+uses uConsts, uLandGraphics, uVariables, SDLh, uLandTexture, uDebug, uLandUtils;
type TCollisionEntry = record
X, Y, Radius: LongInt;
@@ -159,7 +159,7 @@
end;
end;
-function CheckCoordInWater(X, Y: LongInt): boolean; inline;
+function CheckCoordInWater(X, Y: LongInt): boolean;
begin
CheckCoordInWater:= (Y > cWaterLine)
or ((WorldEdge = weSea) and ((X < leftX) or (X > rightX)));
@@ -221,7 +221,7 @@
function LineCollisionTest(oX, oY, dirX, dirY, dirNormSqr, dirNormBound: hwFloat;
width: LongInt; Gear: PGear):
- TLineCollision; inline;
+ TLineCollision;
var toCenterX, toCenterY, r,
b, bSqr, c, desc, t: hwFloat;
realT: extended;
@@ -367,12 +367,12 @@
end
end;
-function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; inline;
+function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
begin
UpdateHitOrder := UpdateHitOrderImpl(@ordera, Gear, Order);
end;
-function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; inline;
+function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean;
begin
if Global then
UpdateHitOrder := UpdateHitOrderImpl(@globalordera, Gear, Order)
@@ -380,7 +380,7 @@
UpdateHitOrder := UpdateHitOrderImpl(@ordera, Gear, Order)
end;
-function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; inline;
+function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean;
begin
UpdateGlobalHitOrder := UpdateHitOrderImpl(@globalordera, Gear, Order);
end;
@@ -408,12 +408,12 @@
end
end;
-procedure ClearHitOrderLeq(MinOrder: LongInt); inline;
+procedure ClearHitOrderLeq(MinOrder: LongInt);
begin
ClearHitOrderLeqImpl(@ordera, MinOrder);
end;
-procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); inline;
+procedure ClearGlobalHitOrderLeq(MinOrder: LongInt);
begin
ClearHitOrderLeqImpl(@globalordera, MinOrder);
end;
@@ -480,8 +480,8 @@
minY := max(centerY - radius + 1, 0);
maxY := min(centerY + radius - 1, LAND_HEIGHT - 1);
for y := minY to maxY do
- if Land[y, x] and collisionMask <> 0 then
- exit(Land[y, x] and collisionMask);
+ if LandGet(y, x) and collisionMask <> 0 then
+ exit(LandGet(y, x) and collisionMask);
end;
TestCollisionXImpl := 0;
end;
@@ -499,18 +499,18 @@
minX := max(centerX - radius + 1, 0);
maxX := min(centerX + radius - 1, LAND_WIDTH - 1);
for x := minX to maxX do
- if Land[y, x] and collisionMask <> 0 then
- exit(Land[y, x] and collisionMask);
+ if LandGet(y, x) and collisionMask <> 0 then
+ exit(LandGet(y, x) and collisionMask);
end;
TestCollisionYImpl := 0;
end;
-function TestCollisionX(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionX(Gear: PGear; Dir: LongInt): Word;
begin
TestCollisionX := TestCollisionXImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask and lfLandMask);
end;
-function TestCollisionY(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionY(Gear: PGear; Dir: LongInt): Word;
begin
TestCollisionY := TestCollisionYImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask and lfLandMask);
end;
@@ -533,19 +533,19 @@
Gear^.CollisionMask:= lfAll;
end;
-function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
begin
LegacyFixupX(Gear);
TestCollisionXwithGear:= TestCollisionXImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask);
end;
-function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; inline;
+function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
begin
LegacyFixupY(Gear);
TestCollisionYwithGear:= TestCollisionYImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask);
end;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
var collisionMask: Word;
begin
if withGear then
@@ -559,7 +559,7 @@
TestCollisionXwithXYShift := TestCollisionXImpl(hwRound(Gear^.X + ShiftX), hwRound(Gear^.Y) + ShiftY, Gear^.Radius, Dir, collisionMask)
end;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
var collisionMask: Word;
begin
if withGear then
@@ -573,12 +573,12 @@
TestCollisionYwithXYShift := TestCollisionYImpl(hwRound(Gear^.X) + ShiftX, hwRound(Gear^.Y) + ShiftY, Gear^.Radius, Dir, collisionMask)
end;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word;
begin
TestCollisionXwithXYShift:= TestCollisionXwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
end;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word;
begin
TestCollisionYwithXYShift:= TestCollisionYwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
end;
@@ -599,16 +599,16 @@
minY := max(centerY - radius + 1, 0);
maxY := min(centerY + radius - 1, LAND_HEIGHT - 1);
for y := minY to maxY do
- if Land[y, x] and collisionMask <> 0 then
+ if LandGet(y, x) and collisionMask <> 0 then
begin
TestCollisionXKickImpl.kick := false;
- TestCollisionXKickImpl.collisionMask := Land[y, x] and collisionMask;
+ TestCollisionXKickImpl.collisionMask := LandGet(y, x) and collisionMask;
exit
end
- else if Land[y, x] and kickMask <> 0 then
+ else if LandGet(y, x) and kickMask <> 0 then
begin
TestCollisionXKickImpl.kick := true;
- TestCollisionXKickImpl.collisionMask := Land[y, x] and kickMask;
+ TestCollisionXKickImpl.collisionMask := LandGet(y, x) and kickMask;
end;
end;
end;
@@ -629,16 +629,16 @@
minX := max(centerX - radius + 1, 0);
maxX := min(centerX + radius - 1, LAND_WIDTH - 1);
for x := minX to maxX do
- if Land[y, x] and collisionMask <> 0 then
+ if LandGet(y, x) and collisionMask <> 0 then
begin
TestCollisionYKickImpl.kick := false;
- TestCollisionYKickImpl.collisionMask := Land[y, x] and collisionMask;
+ TestCollisionYKickImpl.collisionMask := LandGet(y, x) and collisionMask;
exit
end
- else if Land[y, x] and kickMask <> 0 then
+ else if LandGet(y, x) and kickMask <> 0 then
begin
TestCollisionYKickImpl.kick := true;
- TestCollisionYKickImpl.collisionMask := Land[y, x] and kickMask;
+ TestCollisionYKickImpl.collisionMask := LandGet(y, x) and kickMask;
end;
end;
end;
@@ -767,7 +767,7 @@
for y := y1 to y2 do
for x := x1 to x2 do
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > TestWord) then
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y, x) > TestWord) then
exit;
TestRectangleForObstacle:= false
@@ -816,7 +816,7 @@
tmpy:= collisionY + k * my;
if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
- if (Land[tmpy,tmpx] > TestWord) then
+ if (LandGet(tmpy,tmpx) > TestWord) then
begin
// remember the index belonging to the first and last collision (if in 1st half)
if (i <> 0) then
@@ -867,7 +867,7 @@
tmpx:= ldx + k * offset[tmpo,0];
tmpy:= ldy + k * offset[tmpo,1];
if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
- and (Land[tmpy,tmpx] > TestWord) then
+ and (LandGet(tmpy,tmpx) > TestWord) then
begin
ldx:= tmpx;
ldy:= tmpy;
@@ -891,7 +891,7 @@
tmpx:= rdx + k * offset[tmpo,0];
tmpy:= rdy + k * offset[tmpo,1];
if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
- and (Land[tmpy,tmpx] > TestWord) then
+ and (LandGet(tmpy,tmpx) > TestWord) then
begin
rdx:= tmpx;
rdy:= tmpy;
@@ -934,7 +934,7 @@
i:= x + Gear^.Radius * 2 - 2;
repeat
if (x and LAND_WIDTH_MASK) = 0 then
- if Land[y, x] <> 0 then
+ if LandGet(y, x) <> 0 then
if (not isColl) or (abs(x-gx) < abs(collX-gx)) then
begin
isColl:= true;
@@ -957,7 +957,7 @@
i:= y + Gear^.Radius * 2 - 2;
repeat
if (y and LAND_HEIGHT_MASK) = 0 then
- if Land[y, x] <> 0 then
+ if LandGet(y, x) <> 0 then
if (not isColl) or (abs(y-gy) < abs(collY-gy)) then
begin
isColl:= true;
@@ -1026,7 +1026,7 @@
i:= x + Gear^.Radius * 2 - 2;
repeat
if (x and LAND_WIDTH_MASK) = 0 then
- if (Land[y, x] and lfLandMask) <> 0 then
+ if (LandGet(y, x) and lfLandMask) <> 0 then
if (not isColl) or (abs(x-gx) < abs(collX-gx)) then
begin
isColl:= true;
--- a/hedgewars/uCommandHandlers.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uCommandHandlers.pas Tue Dec 31 15:19:43 2024 +0100
@@ -587,7 +587,7 @@
if bShowAmmoMenu then
bShowAmmoMenu:= false
- else if not(CurrentTeam^.Extdriven) and ((Gear = nil) or ((Gear^.State and (gstAttacking or gstAttacked)) <> 0)
+ else if ((Gear = nil) or ((Gear^.State and (gstAttacking or gstAttacked)) <> 0)
or ((Gear^.State and gstHHDriven) = 0)) then
begin
end
--- a/hedgewars/uCommands.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uCommands.pas Tue Dec 31 15:19:43 2024 +0100
@@ -30,7 +30,7 @@
procedure freeModule;
procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean; Rand: boolean);
procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean);
-procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); inline;
+procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean);
procedure ParseCommand(CmdStr: shortstring; TrustedSource, ExternalSource: boolean);
procedure ParseTeamCommand(s: shortstring);
procedure StopMessages(Message: Longword);
@@ -76,7 +76,7 @@
end;
-procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); inline;
+procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean);
begin
ParseCommand(CmdStr, TrustedSource, false)
end;
--- a/hedgewars/uDebug.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uDebug.pas Tue Dec 31 15:19:43 2024 +0100
@@ -23,7 +23,7 @@
interface
procedure OutError(Msg: shortstring; isFatalError: boolean);
-//procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean); inline;
+//procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean);
function checkFails(Assert: boolean; Msg: shortstring; isFatal: boolean): boolean;
function SDLCheck(Assert: boolean; Msg: shortstring; isFatal: boolean): boolean;
--- a/hedgewars/uFloat.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uFloat.pas Tue Dec 31 15:19:43 2024 +0100
@@ -56,45 +56,45 @@
{$ENDIF}
// Returns an hwFloat that represents the value of integer parameter i
-function int2hwFloat (const i: LongInt) : hwFloat; inline;
-function hwFloat2Float (const i: hwFloat) : extended; inline;
+function int2hwFloat (const i: LongInt) : hwFloat;
+function hwFloat2Float (const i: hwFloat) : extended;
// The implemented operators
-operator = (const z1, z2: hwFloat) z : boolean; inline;
+operator = (const z1, z2: hwFloat) z : boolean;
{$IFDEF PAS2C}
-operator <> (const z1, z2: hwFloat) z : boolean; inline;
+operator <> (const z1, z2: hwFloat) z : boolean;
{$ENDIF}
-operator + (const z1, z2: hwFloat) z : hwFloat; inline;
-operator - (const z1, z2: hwFloat) z : hwFloat; inline;
-operator - (const z1: hwFloat) z : hwFloat; inline;
+operator + (const z1, z2: hwFloat) z : hwFloat;
+operator - (const z1, z2: hwFloat) z : hwFloat;
+operator - (const z1: hwFloat) z : hwFloat;
-operator * (const z1, z2: hwFloat) z : hwFloat; inline;
-operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
-operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
-operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
+operator * (const z1, z2: hwFloat) z : hwFloat;
+operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat;
+operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat;
+operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
-operator < (const z1, z2: hwFloat) b : boolean; inline;
-operator > (const z1, z2: hwFloat) b : boolean; inline;
+operator < (const z1, z2: hwFloat) b : boolean;
+operator > (const z1, z2: hwFloat) b : boolean;
// Various functions for hwFloat (some are inlined in the resulting code for better performance)
function cstr(const z: hwFloat): shortstring; // Returns a shortstring representations of the hwFloat.
-function hwRound(const t: hwFloat): LongInt; inline; // Does NOT really round but returns the integer representation of the hwFloat without fractional digits. (-_0_9 -> -0, _1_5 -> _1)
-function hwAbs(const t: hwFloat): hwFloat; inline; // Returns the value of t with positive sign.
-function hwSqr(const t: hwFloat): hwFloat; inline; // Returns the square value of parameter t.
-function hwSqrt1(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
-function hwSqrt(const x: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
+function hwRound(const t: hwFloat): LongInt; // Does NOT really round but returns the integer representation of the hwFloat without fractional digits. (-_0_9 -> -0, _1_5 -> _1)
+function hwAbs(const t: hwFloat): hwFloat; // Returns the value of t with positive sign.
+function hwSqr(const t: hwFloat): hwFloat; // Returns the square value of parameter t.
+function hwSqrt1(const t: hwFloat): hwFloat; // Returns the the positive square root of parameter t.
+function hwSqrt(const x: hwFloat): hwFloat; // Returns the the positive square root of parameter t.
function Distance(const dx, dy: hwFloat): hwFloat; // Returns the distance between two points in 2-dimensional space, of which the parameters are the horizontal and vertical distance.
function DistanceI(const dx, dy: LongInt): hwFloat; // Same as above for integer parameters.
function AngleSin(const Angle: Longword): hwFloat;
function AngleCos(const Angle: Longword): hwFloat;
function vector2Angle(const x, y: hwFloat): LongInt;
-function SignAs(const num, signum: hwFloat): hwFloat; inline; // Returns an hwFloat with the value of parameter num and the sign of signum.
-function hwSign(r: hwFloat): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
-function hwSignf(r: real): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
-function isZero(const z: hwFloat): boolean; inline;
+function SignAs(const num, signum: hwFloat): hwFloat; // Returns an hwFloat with the value of parameter num and the sign of signum.
+function hwSign(r: hwFloat): LongInt; // Returns an integer with value 1 and sign of parameter r.
+function hwSignf(r: real): LongInt; // Returns an integer with value 1 and sign of parameter r.
+function isZero(const z: hwFloat): boolean;
{$WARNINGS OFF}
// some hwFloat constants
@@ -181,6 +181,7 @@
_300: hwFloat = (isNegative: false; QWordValue: 4294967296 * 300);
_360: hwFloat = (isNegative: false; QWordValue: 4294967296 * 360);
_450: hwFloat = (isNegative: false; QWordValue: 4294967296 * 450);
+ _900: hwFloat = (isNegative: false; QWordValue: 4294967296 * 900);
_1000: hwFloat = (isNegative: false; QWordValue: 4294967296 * 1000);
_1024: hwFloat = (isNegative: false; QWordValue: 4294967296 * 1024);
_2048: hwFloat = (isNegative: false; QWordValue: 4294967296 * 2048);
@@ -195,33 +196,33 @@
uses uSinTable;
-function int2hwFloat (const i: LongInt) : hwFloat; inline;
+function int2hwFloat (const i: LongInt) : hwFloat;
begin
int2hwFloat.isNegative:= i < 0;
int2hwFloat.Round:= abs(i);
int2hwFloat.Frac:= 0
end;
-function hwFloat2Float (const i: hwFloat) : extended; inline;
+function hwFloat2Float (const i: hwFloat) : extended;
begin
hwFloat2Float:= i.Frac / $100000000 + i.Round;
if i.isNegative then
hwFloat2Float:= -hwFloat2Float;
end;
-operator = (const z1, z2: hwFloat) z : boolean; inline;
+operator = (const z1, z2: hwFloat) z : boolean;
begin
z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
end;
{$IFDEF PAS2C}
-operator <> (const z1, z2: hwFloat) z : boolean; inline;
+operator <> (const z1, z2: hwFloat) z : boolean;
begin
z:= (z1.isNegative <> z2.isNegative) or (z1.QWordValue <> z2.QWordValue);
end;
{$ENDIF}
-operator + (const z1, z2: hwFloat) z : hwFloat; inline;
+operator + (const z1, z2: hwFloat) z : hwFloat;
begin
if z1.isNegative = z2.isNegative then
begin
@@ -241,7 +242,7 @@
end
end;
-operator - (const z1, z2: hwFloat) z : hwFloat; inline;
+operator - (const z1, z2: hwFloat) z : hwFloat;
begin
if z1.isNegative = z2.isNegative then
if z1.QWordValue > z2.QWordValue then
@@ -261,12 +262,12 @@
end
end;
-function isZero(const z: hwFloat): boolean; inline;
+function isZero(const z: hwFloat): boolean;
begin
isZero := z.QWordValue = 0;
end;
-operator < (const z1, z2: hwFloat) b : boolean; inline;
+operator < (const z1, z2: hwFloat) b : boolean;
begin
if z1.isNegative xor z2.isNegative then
b:= z1.isNegative
@@ -277,7 +278,7 @@
b:= (z2.QWordValue < z1.QWordValue) = z1.isNegative
end;
-operator > (const z1, z2: hwFloat) b : boolean; inline;
+operator > (const z1, z2: hwFloat) b : boolean;
begin
if z1.isNegative xor z2.isNegative then
b:= z2.isNegative
@@ -288,14 +289,14 @@
b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative
end;
-operator - (const z1: hwFloat) z : hwFloat; inline;
+operator - (const z1: hwFloat) z : hwFloat;
begin
z:= z1;
z.isNegative:= not z.isNegative
end;
-operator * (const z1, z2: hwFloat) z : hwFloat; inline;
+operator * (const z1, z2: hwFloat) z : hwFloat;
begin
z.isNegative:= z1.isNegative xor z2.isNegative;
@@ -310,13 +311,13 @@
end
end;
-operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
+operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat;
begin
z.isNegative:= z1.isNegative xor (z2 < 0);
z.QWordValue:= z1.QWordValue * abs(z2)
end;
-operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
+operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat;
var t: QWord;
begin
z.isNegative:= z1.isNegative xor z2.isNegative;
@@ -337,7 +338,7 @@
end
end;
-operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
+operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
begin
z.isNegative:= z1.isNegative xor (z2 < 0);
z.QWordValue:= z1.QWordValue div abs(z2)
@@ -371,7 +372,7 @@
hwAbs.isNegative:= false
end;
-function hwSqr(const t: hwFloat): hwFloat; inline;
+function hwSqr(const t: hwFloat): hwFloat;
begin
hwSqr.isNegative:= false;
hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
--- a/hedgewars/uGearsHandlers.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsHandlers.pas Tue Dec 31 15:19:43 2024 +0100
@@ -36,13 +36,13 @@
(x: 0; y: 1),
(x: -1; y: 0));
-procedure PrevAngle(Gear: PGear; dA: LongInt); inline;
+procedure PrevAngle(Gear: PGear; dA: LongInt);
begin
inc(Gear^.WDTimer);
Gear^.Angle := (LongInt(Gear^.Angle) - dA) and 3
end;
-procedure NextAngle(Gear: PGear; dA: LongInt); inline;
+procedure NextAngle(Gear: PGear; dA: LongInt);
begin
inc(Gear^.WDTimer);
Gear^.Angle := (LongInt(Gear^.Angle) + dA) and 3
--- a/hedgewars/uGearsHandlersMess.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsHandlersMess.pas Tue Dec 31 15:19:43 2024 +0100
@@ -152,7 +152,7 @@
uses uConsts, uVariables, uVisualGearsList, uRandom, uCollisions, uGearsList, uUtils, uSound
, SDLh, uScript, uGearsHedgehog, uGearsUtils, uIO, uCaptions, uLandGraphics
, uGearsHandlers, uTextures, uRenderUtils, uAmmos, uTeams, uLandTexture
- , uStore, uAI, uStats, uLocale;
+ , uStore, uAI, uStats, uLocale, uLandUtils;
procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
var
@@ -528,7 +528,7 @@
end
else if (collV < 0) and (collH < 0) and tdX.isNegative and tdY.isNegative then
Gear^.dX.isNegative := false;
-
+
isFalling := false;
Gear^.AdvBounce := 10;
end;
@@ -884,45 +884,45 @@
else if (cGravity.isNegative) and (yy < LAND_HEIGHT-1200) then
move:=true
// Solid pixel encountered
- else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then
- begin
- lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible);
+ else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (LandGet(yy, xx) <> 0) then
+ begin
+ lf:= LandGet(yy, xx) and (lfObject or lfBasic or lfIndestructible);
if lf = 0 then lf:= lfObject;
// If there's room below keep falling
- if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then
+ if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (LandGet(yy-1, xx) = 0) then
begin
X:= X - cWindSpeed * 1600 - dX;
end
// If there's room below, on the sides, fill the gaps
- else if (((yy-1) and LAND_HEIGHT_MASK) = 0) then
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) then
begin
- if (((xx - 1) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx - 1)] = 0) then
+ if (((xx - 1) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx - 1)) = 0) then
begin
X:= X - _0_8;
Y:= oldY;
end
- else if (((xx - 2) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx - 2)] = 0) then
+ else if (((xx - 2) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx - 2)) = 0) then
begin
X:= X - _1_6;
Y:= oldY;
end
- else if (((xx + 1) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx + 1)] = 0) then
+ else if (((xx + 1) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx + 1)) = 0) then
begin
X:= X + _0_8;
Y:= oldY;
end
- else if (((xx + 2) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx + 2)] = 0) then
+ else if (((xx + 2) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx + 2)) = 0) then
begin
X:= X + _1_6;
Y:= oldY;
end else
- if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy + 1, xx] and $FF) <> 0)) then
- move:=true
- else
+ if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((LandGet(yy + 1, xx) and $FF) <> 0)) then
+ move:=true
+ else
draw:= true
end
// if there's an hog/object below do nothing
- else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy+1, xx] and $FF) <> 0))
+ else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((LandGet(yy+1, xx) and $FF) <> 0))
then move:=true
else draw:= true
end
@@ -949,7 +949,7 @@
for px:= 0 to Pred(s^.w) do
begin
lx:=xx + px; ly:=yy + py;
- if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (Land[ly, lx] and $FF = 0) then
+ if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (LandGet(ly, lx) and $FF = 0) then
begin
rx:= lx;
ry:= ly;
@@ -957,21 +957,21 @@
begin
rx:= rx div 2;ry:= ry div 2;
end;
- if Land[yy + py, xx + px] <= lfAllObjMask then
+ if LandGet(yy + py, xx + px) <= lfAllObjMask then
if gun then
begin
LandDirty[yy div 32, xx div 32]:= 1;
- if LandPixels[ry, rx] = 0 then
- Land[ly, lx]:= lfDamaged or lfObject
- else Land[ly, lx]:= lfDamaged or lfBasic
+ if LandPixelGet(ry, rx) = 0 then
+ LandSet(ly, lx, lfDamaged or lfObject)
+ else LandSet(ly, lx, lfDamaged or lfBasic)
end
- else Land[ly, lx]:= lf;
+ else LandSet(ly, lx, lf);
if gun then
- LandPixels[ry, rx]:= (Gear^.Tint shr 24 shl RShift) or
- (Gear^.Tint shr 16 and $FF shl GShift) or
- (Gear^.Tint shr 8 and $FF shl BShift) or
- (p^[px] and AMask)
- else LandPixels[ry, rx]:= addBgColor(LandPixels[ry, rx], p^[px]);
+ LandPixelSet(ry, rx, (Gear^.Tint shr 24 shl RShift) or
+ (Gear^.Tint shr 16 and $FF shl GShift) or
+ (Gear^.Tint shr 8 and $FF shl BShift) or
+ (p^[px] and AMask))
+ else LandPixelSet(ry, rx, addBgColor(LandPixelGet(ry, rx), p^[px]));
end
else allpx:= false
end;
@@ -1520,7 +1520,7 @@
if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
begin
- LandFlags:= Land[y, x];
+ LandFlags:= LandGet(y, x);
if LandFlags <> 0 then inc(Gear^.Damage);
isDigging:= (LandFlags and lfLandMask) <> 0;
end;
@@ -1762,7 +1762,7 @@
if (Gear^.Timer mod 47) = 0 then
begin
// ok. this was an attempt to turn off dust if not actually drilling land. I have no idea why it isn't working as expected
- if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y + 12, x] > 255) then
+ if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y + 12, x) > 255) then
for i:= 0 to 1 do
AddVisualGear(x - 5 + Random(10), y + 12, vgtDust);
@@ -2194,7 +2194,7 @@
// If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility)
// or hunting is disabled due to seek radius of 0 then we aren't hunting
- if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or
+ if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or
((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
(Gear^.Angle = 0) then
gear^.State:= gear^.State and (not gstChooseTarget)
@@ -3452,7 +3452,7 @@
begin
DeleteGear(Gear);
exit
- end;
+ end;
valid:= false;
@@ -4246,8 +4246,8 @@
dec(playWidth, 2);
for i:= 0 to LAND_HEIGHT - 1 do
begin
- Land[i, leftX] := 0;
- Land[i, rightX] := 0;
+ LandSet(i, leftX, 0);
+ LandSet(i, rightX, 0);
end;
end;
@@ -4255,7 +4255,7 @@
begin
dec(cWaterLine);
for i:= 0 to LAND_WIDTH - 1 do
- Land[cWaterLine, i] := 0;
+ LandSet(cWaterLine, i, 0);
SetAllToActive
end;
@@ -5039,8 +5039,8 @@
doPortalColorSwitch();
// destroy portal if ground it was attached too is gone
- if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask)
- or (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and lfBouncy <> 0)
+ if (LandGet(hwRound(Gear^.Y), hwRound(Gear^.X)) <= lfAllObjMask)
+ or (LandGet(hwRound(Gear^.Y), hwRound(Gear^.X)) and lfBouncy <> 0)
or (Gear^.Timer < 1)
or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team)
or CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then
@@ -5407,12 +5407,12 @@
ty := 0;
// avoid compiler hints
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y, x) > 255) then
begin
Gear^.State := Gear^.State or gstCollision;
Gear^.State := Gear^.State and (not gstMoving);
- if (Land[y, x] and lfBouncy <> 0)
+ if (LandGet(y, x) and lfBouncy <> 0)
or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
begin
@@ -5773,9 +5773,9 @@
if (not CheckCoordInWater(rX, rY)) or (not CheckCoordInWater(x, y)) then
begin
if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
- and (Land[y, x] <> 0) then
+ and (LandGet(y, x) <> 0) then
begin
- if ((GameFlags and gfSolidLand) <> 0) and (Land[y, x] > 255) then
+ if ((GameFlags and gfSolidLand) <> 0) and (LandGet(y, x) > 255) then
Gear^.Damage := initHealth
else if justCollided then
begin
@@ -6683,7 +6683,7 @@
ndY:= -AngleCos(HHGear^.Angle) * _4;
if (ndX <> dX) or (ndY <> dY) or (Gear^.Message and (gmUp or gmDown) <> 0) or
(((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
- (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and
+ (Target.Y and LAND_HEIGHT_MASK = 0) and ((LandGet(Target.Y, Target.X) = 0)) and
(not CheckCoordInWater(Target.X, Target.Y))) and (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*3, Gear^.Radius*3) = nil) and
(not ((WorldEdge = weBounce) and ((Target.X > rightX) or (Target.X < leftX))))) then
begin
@@ -6717,7 +6717,7 @@
else if CheckCoordInWater(Target.X, Target.Y) or
((Target.X and LAND_WIDTH_MASK = 0) and
(Target.Y and LAND_HEIGHT_MASK = 0) and
- (Land[Target.Y, Target.X] = lfIce) and
+ (LandGet(Target.Y, Target.X) = lfIce) and
((Target.Y+iceHeight+5 > cWaterLine) or
((WorldEdge = weSea) and
((Target.X+iceHeight+5 > rightX) or
@@ -6799,13 +6799,13 @@
begin
iter^.Damage:= 0;
iter^.State:= iter^.State or gstFrozen;
- if (hwRound(iter^.X) < RightX-16) and (hwRound(iter^.X) > LeftX+16) and
+ if (hwRound(iter^.X) < RightX-16) and (hwRound(iter^.X) > LeftX+16) and
(hwRound(iter^.Y) > topY+16) and (hwRound(iter^.Y) < LAND_HEIGHT-16) then
begin
AddCI(iter);
iter^.X:= int2hwFloat(min(RightX-16,max(hwRound(iter^.X), LeftX+16)));
iter^.Y:= int2hwFloat(min(LAND_HEIGHT-16,max(hwRound(iter^.Y),TopY+16)));
- ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false);
+ ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false);
iter^.State:= iter^.State or gstInvisible
end
else
@@ -6865,7 +6865,7 @@
end
else if (t > 400) and (CheckCoordInWater(gX, gY) or
(((gX and LAND_WIDTH_MASK = 0) and (gY and LAND_HEIGHT_MASK = 0))
- and (Land[gY, gX] <> 0))) then
+ and (LandGet(gY, gX) <> 0))) then
begin
Target.X:= gX;
Target.Y:= gY;
@@ -6888,7 +6888,7 @@
Target.Y:= gY;
X:= HHGear^.X;
Y:= HHGear^.Y
- end
+ end
end;
end
end;
@@ -6996,7 +6996,7 @@
tX:=Gear^.X-targ^.X;
tY:=Gear^.Y-targ^.Y;
// allow escaping - should maybe flag this too
- if (GameTicks > Gear^.FlightTime+10000) or
+ if (GameTicks > Gear^.FlightTime+10000) or
((tX.Round+tY.Round > Gear^.Angle*6) and
(hwRound(hwSqr(tX) + hwSqr(tY)) > sqr(Gear^.Angle*6))) then
targ:= nil
@@ -7005,7 +7005,7 @@
// If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility)
// or mine is inactive due to lack of gsttmpflag or hunting is disabled due to seek radius of 0
// then we aren't hunting
- if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or
+ if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or
((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
(Gear^.State and gsttmpFlag = 0) or
(Gear^.Angle = 0) then
@@ -7269,7 +7269,7 @@
MakeSentryStep := true
end
end;
-
+
function MakeSentryJump(Sentry: PGear; maxXStep, maxYStep: LongInt): Boolean;
var x, y, offsetX, offsetY, direction: LongInt;
jumpTime: hwFloat;
@@ -7322,7 +7322,7 @@
for i := 0 to count - 1 do
begin
- if (Land[hwRound(fromY), hwRound(fromX)] and mask) <> 0 then
+ if (LandGet(hwRound(fromY), hwRound(fromX)) and mask) <> 0 then
Inc(TraceAttackPath);
fromX := fromX + distX;
fromY := fromY + distY;
--- a/hedgewars/uGearsHandlersRope.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsHandlersRope.pas Tue Dec 31 15:19:43 2024 +0100
@@ -26,7 +26,7 @@
implementation
uses uConsts, uFloat, uCollisions, uVariables, uGearsList, uSound, uGearsUtils,
- uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender;
+ uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender, uLandUtils;
const
IsNilHHFatal = false;
@@ -241,7 +241,7 @@
begin
lx := hwRound(nx);
ly := hwRound(ny);
- if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] > lfAllObjMask) then
+ if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (LandGet(ly, lx) > lfAllObjMask) then
begin
tx := _1 / Distance(ropeDx, ropeDy);
// old rope pos
@@ -358,7 +358,7 @@
HHGear^.dY := HHGear^.dY * len;
end;
- haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)]) <> 0);
+ haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((LandGet(hwRound(Gear^.Y), hwRound(Gear^.X))) <> 0);
if not haveCollision then
begin
@@ -474,7 +474,7 @@
ty := _0;
while tt > _20 do
begin
- if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] > lfAllObjMask) then
+ if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (LandGet(hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)) > lfAllObjMask) then
begin
Gear^.X := Gear^.X + tx;
Gear^.Y := Gear^.Y + ty;
--- a/hedgewars/uGearsHedgehog.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsHedgehog.pas Tue Dec 31 15:19:43 2024 +0100
@@ -29,7 +29,7 @@
procedure HedgehogChAngle(HHGear: PGear);
procedure PickUp(HH, Gear: PGear);
procedure AddPickup(HH: THedgehog; ammo: TAmmoType; cnt, X, Y: LongWord);
-procedure CheckIce(Gear: PGear); inline;
+procedure CheckIce(Gear: PGear);
procedure PlayTaunt(taunt: Longword);
function HHGetTimer(Gear: PGear): LongWord;
function HHGetTimerMsg(Gear: PGear): LongWord;
@@ -1529,7 +1529,7 @@
AllInactive:= false
end;
-procedure CheckIce(Gear: PGear); inline;
+procedure CheckIce(Gear: PGear);
(*
var x,y,tx,ty: LongInt;
tdX, tdY, slope: hwFloat;
--- a/hedgewars/uGearsRender.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsRender.pas Tue Dec 31 15:19:43 2024 +0100
@@ -56,7 +56,7 @@
end;
implementation
-uses uRender, uRenderUtils, uGearsUtils, uUtils, uVariables, uAmmos, Math, uVisualGearsList;
+uses uRender, uRenderUtils, uGearsUtils, uUtils, uVariables, uAmmos, Math, uVisualGearsList, uLandUtils;
procedure DrawRopeLinesRQ(Gear: PGear);
var n: LongInt;
@@ -72,7 +72,7 @@
if (RopePoints.Count > 0) or (Gear^.Elasticity.QWordValue > 0) then
begin
EnableTexture(false);
-
+
Tint(Gear^.Tint shr 24 div 3, Gear^.Tint shr 16 and $FF div 3, Gear^.Tint shr 8 and $FF div 3, Gear^.Tint and $FF);
n:= RopePoints.Count + 2;
@@ -541,7 +541,7 @@
hy:= ty;
wraps:= 0;
inWorldBounds := ((ty and LAND_HEIGHT_MASK) or (tx and LAND_WIDTH_MASK)) = 0;
- while (inWorldBounds and ((Land[ty, tx] and lfAll) = 0)) or (not inWorldBounds) do
+ while (inWorldBounds and ((LandGet(ty, tx) and lfAll) = 0)) or (not inWorldBounds) do
begin
if wraps > cMaxLaserSightWraps then
break;
@@ -1049,7 +1049,7 @@
ty:= hwRound(Gear^.Y) + cHHRadius + 2;
if ((tx and LAND_WIDTH_MASK) = 0) and
((ty and LAND_HEIGHT_MASK) = 0) and
- (Land[ty, tx] <> 0) then
+ (LandGet(ty, tx) <> 0) then
AddVisualGear(tx - 2 + Random(4), ty - 8, vgtDust);
end;
@@ -1417,7 +1417,7 @@
DrawSpriteRotated(sprMineOn, x, y, 0, Gear^.DirAngle)
else DrawSpriteRotated(sprMineDead, x, y, 0, Gear^.DirAngle);
end;
- gtAirMine:
+ gtAirMine:
// render air mine based on its state:
// frozen
if (Gear^.State and gstFrozen <> 0) then
--- a/hedgewars/uGearsUtils.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uGearsUtils.pas Tue Dec 31 15:19:43 2024 +0100
@@ -22,7 +22,7 @@
interface
uses uTypes, uFloat;
-procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword);
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
procedure AddSplashForGear(Gear: PGear; justSkipping: boolean);
procedure AddBounceEffectForGear(Gear: PGear; imageScale: Single);
@@ -39,7 +39,7 @@
procedure CalcRotationDirAngle(Gear: PGear);
procedure ResurrectHedgehog(var gear: PGear);
-procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline;
+procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt);
procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity, deleteOnFail: boolean);
procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right, Bottom: LongInt; skipProximity, deleteOnFail: boolean);
@@ -48,8 +48,8 @@
function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear;
function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
function CheckGearDrowning(var Gear: PGear): boolean;
-procedure CheckCollision(Gear: PGear); inline;
-procedure CheckCollisionWithLand(Gear: PGear); inline;
+procedure CheckCollision(Gear: PGear);
+procedure CheckCollisionWithLand(Gear: PGear);
procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
procedure AmmoShoveCache(Ammo: PGear; Damage, Power: LongInt);
@@ -63,7 +63,7 @@
procedure SetAllToActive;
procedure SetAllHHToActive(Ice: boolean);
-procedure SetAllHHToActive(); inline;
+procedure SetAllHHToActive();
function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
function GetUtility(Hedgehog: PHedgehog): TAmmoType;
@@ -84,9 +84,9 @@
uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug,
uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
- uGearsHedgehog;
+ uGearsHedgehog, uLandUtils;
-procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword);
begin
doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF);
end;
@@ -873,7 +873,7 @@
begin
if (y and LAND_HEIGHT_MASK) = 0 then
for i:= max(x - r, 0) to min(x + r, LAND_WIDTH - 1) do
- if (Land[y, i] and mask <> 0) and (Land[y, i] and antimask = 0) then
+ if (LandGet(y, i) and mask <> 0) and (LandGet(y, i) and antimask = 0) then
begin
inc(count);
if count = c then
@@ -895,8 +895,8 @@
begin
for i:= r - c + 2 to r do
begin
- if (Land[y, x - i] and mask <> 0) then inc(cnt);
- if (Land[y, x + i] and mask <> 0) then inc(cnt);
+ if (LandGet(y, x - i) and mask <> 0) then inc(cnt);
+ if (LandGet(y, x + i) and mask <> 0) then inc(cnt);
if cnt >= c then
begin
@@ -925,12 +925,12 @@
NoGearsToAvoid:= true
end;
-procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline;
+procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt);
begin
FindPlace(Gear, withFall, Left, Right, false, true);
end;
-procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); inline;
+procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
begin
FindPlace(Gear, withFall, Left, Right, skipProximity, true);
end;
@@ -965,7 +965,7 @@
repeat
if GetRandom(2) = 0 then dir:= -1 else dir:= 1;
x:= max(LAND_WIDTH div 2048, LongInt(GetRandom(Delta)));
- if dir = 1 then x:= Left + x else x:= Right - x;
+ if dir = 1 then x:= Left + x else x:= Right - x;
repeat
cnt:= 0;
y:= min(1024, topY) - Gear^.Radius shl 1;
@@ -984,7 +984,7 @@
until (y >= Bottom) or
(ignoreOverlap and
(CountLand(x, y, Gear^.Radius - 1, 1, lfAll, 0) <> 0)) or
- (not ignoreOverlap and
+ (not ignoreOverlap and
(CountLand(x, y, Gear^.Radius - 1, 1, lfLandMask, 0) <> 0));
if (y - sy > Gear^.Radius * 2) and (y < Bottom)
@@ -1172,7 +1172,7 @@
CheckGearNear := CheckGearNearImpl(Kind, Gear^.X, Gear^.Y, rX, rY, Gear);
end;
-procedure CheckCollision(Gear: PGear); inline;
+procedure CheckCollision(Gear: PGear);
begin
if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0)
or (TestCollisionYwithGear(Gear, hwSign(Gear^.dY)) <> 0) then
@@ -1181,7 +1181,7 @@
Gear^.State := Gear^.State and (not gstCollision)
end;
-procedure CheckCollisionWithLand(Gear: PGear); inline;
+procedure CheckCollisionWithLand(Gear: PGear);
begin
if (TestCollisionX(Gear, hwSign(Gear^.dX)) <> 0)
or (TestCollisionY(Gear, hwSign(Gear^.dY)) <> 0) then
@@ -1413,8 +1413,8 @@
gtFirePunch, gtKamikaze, gtWhip, gtShover])
and (((Ammo^.Data <> nil) and (PGear(Ammo^.Data) = Gear))
or (not UpdateHitOrder(
- Gear,
- Ammo^.WDTimer,
+ Gear,
+ Ammo^.WDTimer,
(Ammo^.Kind = gtMinigunBullet) and (Ammo^.Pos <> 0)))) then
continue;
@@ -1502,10 +1502,10 @@
else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
begin
if (Ammo^.Kind in [gtMinigunBullet]) then
- begin
+ begin
Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_01;
Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_01
- end
+ end
else
begin
Gear^.dX:= Ammo^.dX * Power * _0_01;
@@ -1591,7 +1591,7 @@
end
end;
-procedure SetAllHHToActive; inline;
+procedure SetAllHHToActive;
begin
SetAllHHToActive(true)
end;
--- a/hedgewars/uInputHandler.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uInputHandler.pas Tue Dec 31 15:19:43 2024 +0100
@@ -25,7 +25,7 @@
procedure initModule;
procedure freeModule;
-function KeyNameToCode(name: shortstring): LongInt; inline;
+function KeyNameToCode(name: shortstring): LongInt;
function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
function KeyBindToCode(bind: shortstring): LongInt;
@@ -36,7 +36,7 @@
procedure ProcessMouseMotion(xrel, yrel: LongInt);
//procedure ProcessMouseWheel(x, y: LongInt);
procedure ProcessMouseWheel(y: LongInt);
-procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
+procedure ProcessKey(event: TSDL_KeyboardEvent);
procedure ProcessKey(code: LongInt; KeyDown: boolean);
{$IFDEF USE_AM_NUMCOLUMN}
@@ -84,7 +84,7 @@
//ControllerHats: array[0..5] of array[0..19] of Byte;
//ControllerButtons: array[0..5] of array[0..19] of Byte;
-function KeyNameToCode(name: shortstring): LongInt; inline;
+function KeyNameToCode(name: shortstring): LongInt;
begin
KeyNameToCode:= KeyNameToCode(name, '');
end;
@@ -294,7 +294,7 @@
end
end;
-procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
+procedure ProcessKey(event: TSDL_KeyboardEvent);
var code: LongInt;
begin
// TODO
--- a/hedgewars/uLand.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLand.pas Tue Dec 31 15:19:43 2024 +0100
@@ -32,19 +32,18 @@
implementation
uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture,
uVariables, uUtils, uCommands, adler32, uDebug, uLandPainted, uTextures,
- uLandGenMaze, uPhysFSLayer, uScript, uLandGenPerlin,
- uLandGenTemplateBased, uLandUtils, uRenderUtils;
+ uPhysFSLayer, uScript, uLandGenPerlin,
+ uLandUtils, uRenderUtils;
var digest: shortstring;
maskOnly: boolean;
-
procedure PrettifyLandAlpha();
begin
if (cReducedQuality and rqBlurryLand) <> 0 then
- PrettifyAlpha2D(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2)
+ PrettifyAlpha2D(LAND_HEIGHT div 2, LAND_WIDTH div 2)
else
- PrettifyAlpha2D(LandPixels, LAND_HEIGHT, LAND_WIDTH);
+ PrettifyAlpha2D(LAND_HEIGHT, LAND_WIDTH);
end;
procedure DrawBorderFromImage(Surface: PSDL_Surface);
@@ -64,18 +63,18 @@
begin
yd:= LAND_HEIGHT - 1;
repeat
- while (yd > 0) and ((Land[yd, x] and targetMask) = 0) do dec(yd);
+ while (yd > 0) and ((LandGet(yd, x) and targetMask) = 0) do dec(yd);
if (yd < 0) then
yd:= 0;
- while (yd < LAND_HEIGHT) and ((Land[yd, x] and targetMask) <> 0) do
+ while (yd < LAND_HEIGHT) and ((LandGet(yd, x) and targetMask) <> 0) do
inc(yd);
dec(yd);
yu:= yd;
- while (yu > 0 ) and ((Land[yu, x] and targetMask) <> 0) do dec(yu);
- while (yu < yd ) and ((Land[yu, x] and targetMask) = 0) do inc(yu);
+ while (yu > 0 ) and ((LandGet(yu, x) and targetMask) <> 0) do dec(yu);
+ while (yu < yd ) and ((LandGet(yu, x) and targetMask) = 0) do inc(yu);
if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then
copyToXYFromRect(tmpsurf, Surface, x mod tmpsurf^.w, 16, 1, 16, x, yd - 15);
@@ -100,7 +99,7 @@
for x:= 0 to LAND_WIDTH - 1 do
for y:= 0 to LAND_HEIGHT - 1 do
- if Land[y, x] = 0 then
+ if LandGet(y, x) = 0 then
if s < y then
begin
for i:= max(s, y - 8) to y - 1 do
@@ -108,9 +107,9 @@
if ((x + i) and 16) = 0 then c:= c1 else c:= c2;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[i, x]:= c
+ LandPixelSet(i, x, c)
else
- LandPixels[i div 2, x div 2]:= c
+ LandPixelSet(i div 2, x div 2, c)
end;
s:= LAND_HEIGHT
end
@@ -123,9 +122,9 @@
if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[y, x]:= c
+ LandPixelSet(y, x, c)
else
- LandPixels[y div 2, x div 2]:= c
+ LandPixelSet(y div 2, x div 2, c)
end;
end;
@@ -134,7 +133,7 @@
for y:= 0 to LAND_HEIGHT - 1 do
for x:= 0 to LAND_WIDTH - 1 do
- if Land[y, x] = 0 then
+ if LandGet(y, x) = 0 then
if s < x then
begin
for i:= max(s, x - 8) to x - 1 do
@@ -142,9 +141,9 @@
if ((y + i) and 16) = 0 then c:= c1 else c:= c2;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[y, i]:= c
+ LandPixelSet(y, i, c)
else
- LandPixels[y div 2, i div 2]:= c
+ LandPixelSet(y div 2, i div 2, c)
end;
s:= LAND_WIDTH
end
@@ -157,9 +156,9 @@
if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[y, x]:= c
+ LandPixelSet(y, x, c)
else
- LandPixels[y div 2, x div 2]:= c
+ LandPixelSet(y div 2, x div 2, c)
end;
end
end;
@@ -356,15 +355,15 @@
uLandPainted.Draw;
end;
-function SelectTemplate: LongInt;
+function SelectTemplate: shortstring;
var l: LongInt;
begin
- SelectTemplate:= 0;
+ SelectTemplate:= '';
if (cReducedQuality and rqLowRes) <> 0 then
- SelectTemplate:= SmallTemplates[getrandom(Succ(High(SmallTemplates)))]
+ SelectTemplate:= 'small'
else
begin
- if cTemplateFilter = 0 then
+ if (cTemplateFilter = 0) and (cMapGen <> mgMaze) then
begin
l:= getRandom(GroupedTemplatesCount);
repeat
@@ -374,22 +373,35 @@
end
else getRandom(1);
- case cTemplateFilter of
- 0: OutError('Error selecting TemplateFilter. Ask unC0Rr about what you did wrong', true);
- 1: SelectTemplate:= SmallTemplates[getrandom(TemplateCounts[cTemplateFilter])];
- 2: SelectTemplate:= MediumTemplates[getrandom(TemplateCounts[cTemplateFilter])];
- 3: SelectTemplate:= LargeTemplates[getrandom(TemplateCounts[cTemplateFilter])];
- 4: SelectTemplate:= CavernTemplates[getrandom(TemplateCounts[cTemplateFilter])];
- 5: SelectTemplate:= WackyTemplates[getrandom(TemplateCounts[cTemplateFilter])];
- // For lua only!
- 6: begin
- SelectTemplate:= min(LuaTemplateNumber,High(EdgeTemplates));
- GetRandom(2) // burn 1
- end
- end
+ case cMapGen of
+ mgMaze:
+ case cTemplateFilter of
+ 0: SelectTemplate:= 'small_tunnels';
+ 1: SelectTemplate:= 'medium_tunnels';
+ 2: SelectTemplate:= 'large_tunnels';
+ 3: SelectTemplate:= 'small_islands';
+ 4: SelectTemplate:= 'medium_islands';
+ 5: SelectTemplate:= 'large_islands';
+ else OutError('Error selecting TemplateFilter', true);
+ end
+ else
+ case cTemplateFilter of
+ 1: SelectTemplate:= 'small';
+ 2: SelectTemplate:= 'medium';
+ 3: SelectTemplate:= 'large';
+ 4: SelectTemplate:= 'cavern';
+ 5: SelectTemplate:= 'wacky';
+ // For lua only!
+ 6: begin
+ SelectTemplate:= 'small';
+ GetRandom(2) // burn 1
+ end
+ else OutError('Error selecting TemplateFilter', true);
+ end
+ end
end;
- WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter));
+ WriteLnToConsole('Using template filter '+SelectTemplate);
end;
procedure LandSurface2LandPixels(Surface: PSDL_Surface);
@@ -405,11 +417,11 @@
for y:= 0 to LAND_HEIGHT - 1 do
begin
for x:= 0 to LAND_WIDTH - 1 do
- if Land[y, x] <> 0 then
+ if LandGet(y, x) <> 0 then
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[y, x]:= p^[x]// or AMask
+ LandPixelSet(y, x, p^[x])// or AMask
else
- LandPixels[y div 2, x div 2]:= p^[x];
+ LandPixelSet(y div 2, x div 2, p^[x]);
p:= PLongwordArray(@(p^[Surface^.pitch div 4]));
end;
@@ -439,38 +451,38 @@
for x:= LongWord(leftX+2) to LongWord(rightX-2) do
for y:= LongWord(topY+2) to LAND_HEIGHT-3 do
- if (Land[y, x] = 0) and
- (((Land[y, x-1] = lfBasic) and ((Land[y+1,x] = lfBasic)) or (Land[y-1,x] = lfBasic)) or
- ((Land[y, x+1] = lfBasic) and ((Land[y-1,x] = lfBasic) or (Land[y+1,x] = lfBasic)))) then
+ if (LandGet(y, x) = 0) and
+ (((LandGet(y, x-1) = lfBasic) and ((LandGet(y+1,x) = lfBasic)) or (LandGet(y-1,x) = lfBasic)) or
+ ((LandGet(y, x+1) = lfBasic) and ((LandGet(y-1,x) = lfBasic) or (LandGet(y+1,x) = lfBasic)))) then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
- if (Land[y, x-1] = lfBasic) and (LandPixels[y, x-1] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y, x-1]
+ if (LandGet(y, x-1) = lfBasic) and (LandPixelGet(y, x-1) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y, x-1))
- else if (Land[y, x+1] = lfBasic) and (LandPixels[y, x+1] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y, x+1]
+ else if (LandGet(y, x+1) = lfBasic) and (LandPixelGet(y, x+1) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y, x+1))
- else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1, x] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y-1, x]
+ else if (LandGet(y-1, x) = lfBasic) and (LandPixelGet(y-1, x) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y-1, x))
- else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1, x] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y+1, x];
+ else if (LandGet(y+1, x) = lfBasic) and (LandPixelGet(y+1, x) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y+1, x));
- if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
- LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (128 shl AShift)
+ if (((LandPixelGet(y,x) and AMask) shr AShift) > 10) then
+ LandPixelSet(y, x, (LandPixelGet(y,x) and (not AMask)) or (128 shl AShift))
end;
- Land[y,x]:= lfObject
+ LandSet(y, x, lfObject)
end
- else if (Land[y, x] = 0) and
- (((Land[y, x-1] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y+2,x] = lfBasic)) or
- ((Land[y, x-1] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y-2,x] = lfBasic)) or
- ((Land[y, x+1] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y+2,x] = lfBasic)) or
- ((Land[y, x+1] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y-2,x] = lfBasic)) or
- ((Land[y+1, x] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
- ((Land[y-1, x] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
- ((Land[y+1, x] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic)) or
- ((Land[y-1, x] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic))) then
+ else if (LandGet(y, x) = 0) and
+ (((LandGet(y, x-1) = lfBasic) and (LandGet(y+1,x-1) = lfBasic) and (LandGet(y+2,x) = lfBasic)) or
+ ((LandGet(y, x-1) = lfBasic) and (LandGet(y-1,x-1) = lfBasic) and (LandGet(y-2,x) = lfBasic)) or
+ ((LandGet(y, x+1) = lfBasic) and (LandGet(y+1,x+1) = lfBasic) and (LandGet(y+2,x) = lfBasic)) or
+ ((LandGet(y, x+1) = lfBasic) and (LandGet(y-1,x+1) = lfBasic) and (LandGet(y-2,x) = lfBasic)) or
+ ((LandGet(y+1, x) = lfBasic) and (LandGet(y+1,x+1) = lfBasic) and (LandGet(y,x+2) = lfBasic)) or
+ ((LandGet(y-1, x) = lfBasic) and (LandGet(y-1,x+1) = lfBasic) and (LandGet(y,x+2) = lfBasic)) or
+ ((LandGet(y+1, x) = lfBasic) and (LandGet(y+1,x-1) = lfBasic) and (LandGet(y,x-2) = lfBasic)) or
+ ((LandGet(y-1, x) = lfBasic) and (LandGet(y-1,x-1) = lfBasic) and (LandGet(y,x-2) = lfBasic))) then
begin
@@ -478,22 +490,22 @@
begin
- if (Land[y, x-1] = lfBasic) and (LandPixels[y,x-1] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y, x-1]
+ if (LandGet(y, x-1) = lfBasic) and (LandPixelGet(y,x-1) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y, x-1))
- else if (Land[y, x+1] = lfBasic) and (LandPixels[y,x+1] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y, x+1]
+ else if (LandGet(y, x+1) = lfBasic) and (LandPixelGet(y,x+1) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y, x+1))
- else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1,x] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y+1, x]
+ else if (LandGet(y+1, x) = lfBasic) and (LandPixelGet(y+1,x) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y+1, x))
- else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1,x] and AMask <> 0) then
- LandPixels[y, x]:= LandPixels[y-1, x];
+ else if (LandGet(y-1, x) = lfBasic) and (LandPixelGet(y-1,x) and AMask <> 0) then
+ LandPixelSet(y, x, LandPixelGet(y-1, x));
- if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
- LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (64 shl AShift)
+ if (((LandPixelGet(y,x) and AMask) shr AShift) > 10) then
+ LandPixelSet(y, x, (LandPixelGet(y,x) and (not AMask)) or (64 shl AShift))
end;
- Land[y,x]:= lfObject
+ LandSet(y, x, lfObject)
end;
AddProgress();
@@ -527,8 +539,8 @@
begin
if (y <= wbm) and ((x - w1) mod (bmWidth * 2) >= bmWidth) then
continue;
- Land[y,x]:= lfBasic;
- Land[y,lastX-x]:= lfBasic;
+ LandSet(y, x, lfBasic);
+ LandSet(y, lastX - x, lfBasic);
end;
end;
@@ -545,8 +557,8 @@
// align battlement on inner edge, because real outer edge could be offscreen
if (y <= wbm) and ((LAND_WIDTH + x - bmref) mod (bmWidth * 2) >= bmWidth) then
continue;
- Land[y,x]:= lfBasic;
- Land[y,lastX-x]:= lfBasic;
+ LandSet(y, x, lfBasic);
+ LandSet(y, lastX - x, lfBasic);
end;
end;
end;
@@ -691,7 +703,7 @@
for y:= 0 to Pred(tmpsurf^.h) do
begin
for x:= 0 to Pred(tmpsurf^.w) do
- SetLand(Land[cpY + y, cpX + x], p^[x]);
+ SetLand(cpY + y, cpX + x, p^[x]);
p:= PLongwordArray(@(p^[tmpsurf^.pitch div 4]));
end;
@@ -756,16 +768,16 @@
for x:= LongWord(leftX) to LongWord(rightX) do
begin
y:= Longword(cWaterLine) - 1 - w;
- Land[y, x]:= lfIndestructible;
+ LandSet(y, x, lfIndestructible);
if (x + y) mod 32 < 16 then
c:= AMask
else
c:= AMask or RMask or GMask; // FF00FFFF
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[y, x]:= c
+ LandPixelSet(y, x, c)
else
- LandPixels[y div 2, x div 2]:= c
+ LandPixelSet(y div 2, x div 2, c)
end
end;
@@ -794,15 +806,16 @@
begin
WriteLnToConsole('Generating land...');
case cMapGen of
- mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
- mgMaze : begin ResizeLand(4096,2048); GenMaze; end;
+ mgRandom: GenerateOutlineTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
+ mgMaze : GenerateMazeLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
mgDrawn : GenDrawnMap;
mgForts : begin GameFlags:= (GameFlags or gfDivideTeams); MakeFortsMap(); end;
+ mgWfc: GenerateWfcTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
else
OutError('Unknown mapgen', true);
end;
- if cMapGen <> mgForts then
+ if (cMapGen <> mgForts) then
GenLandSurface
end;
@@ -815,7 +828,7 @@
else
for y:= LongWord(topY) to LongWord(topY + 5) do
for x:= LongWord(leftX) to LongWord(rightX) do
- if Land[y, x] <> 0 then
+ if LandGet(y, x) <> 0 then
begin
inc(c);
if c > LongWord((LAND_WIDTH div 2)) then // avoid accidental triggering
@@ -834,13 +847,13 @@
for y:= 0 to LAND_HEIGHT - 1 do
for x:= 0 to LAND_WIDTH - 1 do
if (y < LongWord(topY)) or (x < LongWord(leftX)) or (x > LongWord(rightX)) then
- Land[y, x]:= lfIndestructible;
+ LandSet(y, x, lfIndestructible);
end
else if topY > 0 then
begin
for y:= 0 to LongWord(topY - 1) do
for x:= 0 to LAND_WIDTH - 1 do
- Land[y, x]:= lfIndestructible;
+ LandSet(y, x, lfIndestructible);
end;
// Render map border
for w:= 0 to (cBorderWidth-1) do
@@ -850,8 +863,8 @@
for y:= LongWord(topY) to LAND_HEIGHT - 1 do
begin
// set land flags
- Land[y, leftX + w]:= lfIndestructible;
- Land[y, rightX - w]:= lfIndestructible;
+ LandSet(y, leftX + w, lfIndestructible);
+ LandSet(y, rightX - w, lfIndestructible);
// paint black and yellow stripes
if (y + leftX + w) mod 32 < 16 then
@@ -865,29 +878,29 @@
if (cReducedQuality and rqBlurryLand) = 0 then
begin
- LandPixels[y, leftX + w]:= c;
- LandPixels[y, rightX - w]:= c2;
+ LandPixelSet(y, leftX + w, c);
+ LandPixelSet(y, rightX - w, c2);
end
else
begin
- LandPixels[y div 2, (leftX + w) div 2]:= c;
- LandPixels[y div 2, (rightX - w) div 2]:= c2;
+ LandPixelSet(y div 2, (leftX + w) div 2, c);
+ LandPixelSet(y div 2, (rightX - w) div 2, c2);
end;
end;
// Top border
for x:= LongWord(leftX) to LongWord(rightX) do
begin
- Land[topY + w, x]:= lfIndestructible;
+ LandSet(topY + w, x, lfIndestructible);
if (topY + x + w) mod 32 < 16 then
c:= AMask // black
else
c:= AMask or RMask or GMask; // yellow
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[topY + w, x]:= c
+ LandPixelSet(topY + w, x, c)
else
- LandPixels[(topY + w) div 2, x div 2]:= c;
+ LandPixelSet((topY + w) div 2, x div 2, c);
end;
end;
end;
@@ -915,23 +928,23 @@
for x:= LongWord(leftX) to LongWord(rightX) do
for y:= LongWord(topY) to LAND_HEIGHT-1 do
begin
- w:= LandPixels[y,x];
+ w:= LandPixelGet(y,x);
w:= round(((w shr RShift and $FF) * RGB_LUMINANCE_RED +
(w shr BShift and $FF) * RGB_LUMINANCE_GREEN +
(w shr GShift and $FF) * RGB_LUMINANCE_BLUE));
if w > 255 then
w:= 255;
- w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y,x] and AMask);
- LandPixels[y,x]:= w or (LandPixels[y, x] and AMask)
+ w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixelGet(y,x) and AMask);
+ LandPixelSet(y, x, w or (LandPixelGet(y, x) and AMask))
end
else
for x:= LongWord(leftX div 2) to LongWord(rightX div 2) do
for y:= LongWord(topY div 2) to LAND_HEIGHT-1 div 2 do
begin
- w:= LandPixels[y div 2,x div 2];
+ w:= LandPixelGet(y div 2,x div 2);
w:= ((w shr RShift and $FF) + (w shr BShift and $FF) + (w shr GShift and $FF)) div 3;
- w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y div 2,x div 2] and AMask);
- LandPixels[y,x]:= w or (LandPixels[y div 2, x div 2] and AMask)
+ w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixelGet(y div 2,x div 2) and AMask);
+ LandPixelSet(y, x, w or (LandPixelGet(y div 2, x div 2) and AMask))
end
end;
@@ -949,11 +962,12 @@
begin
WriteLnToConsole('Generating preview...');
case cMapGen of
- mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
- mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
+ mgRandom: GenerateOutlineTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
+ mgMaze: GenerateMazeLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
mgDrawn: begin GenDrawnMap; end;
mgForts: MakeFortsPreview();
+ mgWfc: GenerateWfcTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
else
OutError('Unknown mapgen', true);
end;
@@ -994,7 +1008,7 @@
for yy:= y * lh to y * lh + 7 do
for xx:= x * lw + cbit to x * lw + cbit + 7 do
if ((yy-oy) and LAND_HEIGHT_MASK = 0) and ((xx-ox) and LAND_WIDTH_MASK = 0)
- and (Land[yy-oy, xx-ox] <> 0) then
+ and (LandGet(yy-oy, xx-ox) <> 0) then
inc(t);
if t > 8 then
Preview[y, x]:= Preview[y, x] or ($80 shr bit);
@@ -1008,11 +1022,12 @@
begin
WriteLnToConsole('Generating preview...');
case cMapGen of
- mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
- mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
+ mgRandom: GenerateOutlineTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
+ mgMaze: GenerateMazeLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
mgDrawn: begin GenDrawnMap; end;
mgForts: MakeFortsPreview;
+ mgWfc: GenerateWfcTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix);
else
OutError('Unknown mapgen', true);
end;
@@ -1052,7 +1067,7 @@
for yy:= y * lh - oy to y * lh + lh - 1 - oy do
for xx:= x * lw - ox to x * lw + lw - 1 - ox do
if (yy and LAND_HEIGHT_MASK = 0) and (xx and LAND_WIDTH_MASK = 0)
- and (Land[yy, xx] <> 0) then
+ and (LandGet(yy, xx) <> 0) then
inc(t);
Preview[y, x]:= t * 255 div (lh * lw);
@@ -1074,7 +1089,7 @@
begin
landPixelDigest:= 1;
for i:= 0 to LAND_HEIGHT-1 do
- landPixelDigest:= Adler32Update(landPixelDigest, @Land[i,0], LAND_WIDTH*2);
+ landPixelDigest:= Adler32Update(landPixelDigest, LandRow(i), LAND_WIDTH*2);
s:= 'M' + IntToStr(syncedPixelDigest)+'|'+IntToStr(landPixelDigest);
ScriptSetString('LandDigest',IntToStr(landPixelDigest));
@@ -1093,21 +1108,11 @@
maskOnly:= false;
LAND_WIDTH:= 0;
LAND_HEIGHT:= 0;
-(*
- if (cReducedQuality and rqBlurryLand) = 0 then
- SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)
- else
- SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2);
-
- SetLength(Land, LAND_HEIGHT, LAND_WIDTH);
- SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
-*)
end;
procedure freeModule;
begin
- SetLength(Land, 0, 0);
- SetLength(LandPixels, 0, 0);
+ DisposeLand;
SetLength(LandDirty, 0, 0);
end;
--- a/hedgewars/uLandGenMaze.pas Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,546 +0,0 @@
-{$INCLUDE "options.inc"}
-
-unit uLandGenMaze;
-
-interface
-
-procedure GenMaze;
-
-implementation
-
-uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts, uLandGenTemplateBased, uUtils;
-
-type direction = record x, y: LongInt; end;
-const DIR_N: direction = (x: 0; y: -1);
- DIR_E: direction = (x: 1; y: 0);
- DIR_S: direction = (x: 0; y: 1);
- DIR_W: direction = (x: -1; y: 0);
-
-operator = (const a, b: direction) c: Boolean;
-begin
- c := (a.x = b.x) and (a.y = b.y);
-end;
-
-const small_cell_size = 128;
- medium_cell_size = 192;
- large_cell_size = 256;
- braidness = 10;
-
-type
- cell_t = record x,y : LongInt
- end;
-
-var x, y : LongInt;
- cellsize : LongInt; //selected by the user in the gui
- seen_cells_x, seen_cells_y : LongInt; //number of cells that can be visited by the generator, that is every second cell in x and y direction. the cells between there are walls that will be removed when we move from one cell to another
- num_edges_x, num_edges_y : LongInt; //number of resulting edges that need to be vertexificated
- num_cells_x, num_cells_y : LongInt; //actual number of cells, depending on cell size
-
-
- seen_list : array of array of LongInt;
- xwalls : array of array of Boolean;
- ywalls : array of array of Boolean;
- x_edge_list : array of array of Boolean;
- y_edge_list : array of array of Boolean;
- maze : array of array of Boolean;
-
- pa : TPixAr;
- num_vertices : LongInt;
- off_y : LongInt;
- num_steps : LongInt;
- current_step : LongInt;
-
- step_done : array of Boolean;
-
- done : Boolean;
-
-{ last_cell : array 0..3 of record x, y :LongInt ; end;
- came_from : array of array of record x, y: LongInt; end;
- came_from_pos : array of LongInt;
-}
- last_cell : array of cell_t;
- came_from : array of array of cell_t;
- came_from_pos: array of LongInt;
-
- maze_inverted : Boolean;
-
-function when_seen(x: LongInt; y: LongInt): LongInt;
-begin
-if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then
- when_seen := current_step
-else
- when_seen := seen_list[x, y];
-end;
-
-function is_x_edge(x, y: LongInt): Boolean;
-begin
-if (x < 0) or (x > num_edges_x) or (y < 0) or (y > num_cells_y) then
- is_x_edge := false
-else
- is_x_edge := x_edge_list[x, y];
-end;
-
-function is_y_edge(x, y: LongInt): Boolean;
-begin
-if (x < 0) or (x > num_cells_x) or (y < 0) or (y > num_edges_y) then
- is_y_edge := false
-else
- is_y_edge := y_edge_list[x, y];
-end;
-
-procedure see_cell;
-var dir: direction;
- tries: LongInt;
- x, y: LongInt;
- found_cell: Boolean;
- next_dir_clockwise: Boolean;
-
-begin
-x := last_cell[current_step].x;
-y := last_cell[current_step].y;
-seen_list[x, y] := current_step;
-case GetRandom(4) of
- 0: dir := DIR_N;
- 1: dir := DIR_E;
- 2: dir := DIR_S;
- 3: dir := DIR_W;
-end;
-tries := 0;
-found_cell := false;
-if getrandom(2) = 1 then
- next_dir_clockwise := true
-else
- next_dir_clockwise := false;
-
-while (tries < 5) and (not found_cell) do
-begin
- if when_seen(x + dir.x, y + dir.y) = current_step then //we are seeing ourselves, try another direction
- begin
- //we have already seen the target cell, decide if we should remove the wall anyway
- //(or put a wall there if maze_inverted, but we are not doing that right now)
- if (not maze_inverted) and (GetRandom(braidness) = 0) then
- //or just warn that inverted+braid+indestructible terrain != good idea
- begin
- case dir.x of
-
- -1:
- if x > 0 then
- ywalls[x-1, y] := false;
- 1:
- if x < seen_cells_x - 1 then
- ywalls[x, y] := false;
- end;
- case dir.y of
- -1:
- if y > 0 then
- xwalls[x, y-1] := false;
- 1:
- if y < seen_cells_y - 1 then
- xwalls[x, y] := false;
- end;
- end;
- if next_dir_clockwise then
- begin
- if dir = DIR_N then
- dir := DIR_E
- else if dir = DIR_E then
- dir := DIR_S
- else if dir = DIR_S then
- dir := DIR_W
- else
- dir := DIR_N;
- end
- else
- begin
- if dir = DIR_N then
- dir := DIR_W
- else if dir = DIR_E then
- dir := DIR_N
- else if dir = DIR_S then
- dir := DIR_E
- else
- dir := DIR_S;
- end
- end
- else if when_seen(x + dir.x, y + dir.y) = -1 then //cell was not seen yet, go there
- begin
- case dir.y of
- -1: xwalls[x, y-1] := false;
- 1: xwalls[x, y] := false;
- end;
- case dir.x of
- -1: ywalls[x-1, y] := false;
- 1: ywalls[x, y] := false;
- end;
- last_cell[current_step].x := x+dir.x;
- last_cell[current_step].y := y+dir.y;
- came_from_pos[current_step] := came_from_pos[current_step] + 1;
- came_from[current_step, came_from_pos[current_step]].x := x;
- came_from[current_step, came_from_pos[current_step]].y := y;
- found_cell := true;
- end
- else //we are seeing someone else, quit
- begin
- step_done[current_step] := true;
- found_cell := true;
- end;
-
- tries := tries + 1;
-end;
-if not found_cell then
- begin
- last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x;
- last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y;
- came_from_pos[current_step] := came_from_pos[current_step] - 1;
-
- if came_from_pos[current_step] >= 0 then
- see_cell()
-
- else
- step_done[current_step] := true;
- end;
-end;
-
-procedure add_vertex(x, y: LongInt);
-var tmp_x, tmp_y, nx, ny: LongInt;
-begin
- if x = NTPX then
- begin
- if pa.ar[num_vertices - 6].x = NTPX then
- begin
- num_vertices := num_vertices - 6;
- end
- else
- begin
- pa.ar[num_vertices].x := NTPX;
- pa.ar[num_vertices].y := 0;
- end
- end
- else
- begin
- if maze_inverted or (x mod 2 = 0) then
- tmp_x := cellsize
- else
- tmp_x := cellsize * 2 div 3;
-
- if maze_inverted or (y mod 2 = 0) then
- tmp_y := cellsize
- else
- tmp_y := cellsize * 2 div 3;
-
- nx:= (x-1)*cellsize + tmp_x;
- ny:= (y-1)*cellsize + tmp_y + off_y;
-
- if num_vertices > 2 then
- if ((pa.ar[num_vertices - 2].x = pa.ar[num_vertices - 1].x) and (pa.ar[num_vertices - 1].x = nx))
- or ((pa.ar[num_vertices - 2].y = pa.ar[num_vertices - 1].y) and (pa.ar[num_vertices - 1].y = ny))
- then
- dec(num_vertices);
-
- pa.ar[num_vertices].x := nx;
- pa.ar[num_vertices].y := ny;
- end;
-
- num_vertices := num_vertices + 1;
-end;
-
-procedure add_edge(x, y: LongInt; dir: direction);
-var i: LongInt;
-begin
-if dir = DIR_N then
- begin
- dir := DIR_W
- end
-else if dir = DIR_E then
- begin
- dir := DIR_N
- end
-else if dir = DIR_S then
- begin
- dir := DIR_E
- end
-else
- begin
- dir := DIR_S;
- end;
-
-for i := 0 to 3 do
- begin
- if dir = DIR_N then
- dir := DIR_E
- else if dir = DIR_E then
- dir := DIR_S
- else if dir = DIR_S then
- dir := DIR_W
- else
- dir := DIR_N;
-
- if (dir = DIR_N) and is_x_edge(x, y) then
- begin
- x_edge_list[x, y] := false;
- add_vertex(x+1, y);
- add_edge(x, y-1, DIR_N);
- break;
- end;
-
- if (dir = DIR_E) and is_y_edge(x+1, y) then
- begin
- y_edge_list[x+1, y] := false;
- add_vertex(x+2, y+1);
- add_edge(x+1, y, DIR_E);
- break;
- end;
-
- if (dir = DIR_S) and is_x_edge(x, y+1) then
- begin
- x_edge_list[x, y+1] := false;
- add_vertex(x+1, y+2);
- add_edge(x, y+1, DIR_S);
- break;
- end;
-
- if (dir = DIR_W) and is_y_edge(x, y) then
- begin
- y_edge_list[x, y] := false;
- add_vertex(x, y+1);
- add_edge(x-1, y, DIR_W);
- break;
- end;
- end;
-
-end;
-
-procedure GenMaze;
-var i: Longword;
-begin
-case cTemplateFilter of
- 0: begin
- cellsize := small_cell_size;
- maze_inverted := false;
- minDistance:= max(cFeatureSize*8,32);
- dabDiv:= 150;
- end;
- 1: begin
- cellsize := medium_cell_size;
- minDistance:= max(cFeatureSize*6,20);
- maze_inverted := false;
- dabDiv:= 100;
- end;
- 2: begin
- cellsize := large_cell_size;
- minDistance:= max(cFeatureSize*5,12);
- maze_inverted := false;
- dabDiv:= 90;
- end;
- 3: begin
- cellsize := small_cell_size;
- minDistance:= max(cFeatureSize*8,32);
- maze_inverted := true;
- dabDiv:= 130;
- end;
- 4: begin
- cellsize := medium_cell_size;
- minDistance:= max(cFeatureSize*6,20);
- maze_inverted := true;
- dabDiv:= 100;
- end;
- 5: begin
- cellsize := large_cell_size;
- minDistance:= max(cFeatureSize*5,12);
- maze_inverted := true;
- dabDiv:= 85;
- end;
- end;
-
-num_cells_x := LAND_WIDTH div cellsize;
-if not odd(num_cells_x) then
- num_cells_x := num_cells_x - 1; //needs to be odd
-
-num_cells_y := LAND_HEIGHT div cellsize;
-if not odd(num_cells_y) then
- num_cells_y := num_cells_y - 1;
-
-num_edges_x := num_cells_x - 1;
-num_edges_y := num_cells_y - 1;
-
-seen_cells_x := num_cells_x div 2;
-seen_cells_y := num_cells_y div 2;
-
-if maze_inverted then
- num_steps := 3 //TODO randomize, between 3 and 5?
-else
- num_steps := 1;
-
-SetLength(step_done, num_steps);
-SetLength(last_cell, num_steps);
-SetLength(came_from_pos, num_steps);
-SetLength(came_from, num_steps, num_cells_x*num_cells_y);
-
-done := false;
-
-for current_step := 0 to num_steps - 1 do
- begin
- step_done[current_step] := false;
- came_from_pos[current_step] := 0;
- end;
-
-current_step := 0;
-
-
-SetLength(seen_list, seen_cells_x, seen_cells_y);
-SetLength(xwalls, seen_cells_x, seen_cells_y - 1);
-SetLength(ywalls, seen_cells_x - 1, seen_cells_y);
-SetLength(x_edge_list, num_edges_x, num_cells_y);
-SetLength(y_edge_list, num_cells_x, num_edges_y);
-SetLength(maze, num_cells_x, num_cells_y);
-
-
-num_vertices := 0;
-
-playHeight := num_cells_y * cellsize;
-playWidth := num_cells_x * cellsize;
-off_y := LAND_HEIGHT - playHeight;
-
-for x := 0 to playWidth do
- for y := 0 to off_y - 1 do
- Land[y, x] := 0;
-
-for x := 0 to playWidth do
- for y := off_y to LAND_HEIGHT - 1 do
- Land[y, x] := lfBasic;
-
-for y := 0 to num_cells_y - 1 do
- for x := 0 to num_cells_x - 1 do
- maze[x, y] := false;
-
-for x := 0 to seen_cells_x - 1 do
- for y := 0 to seen_cells_y - 2 do
- xwalls[x, y] := true;
-
-for x := 0 to seen_cells_x - 2 do
- for y := 0 to seen_cells_y - 1 do
- ywalls[x, y] := true;
-
-for x := 0 to seen_cells_x - 1 do
- for y := 0 to seen_cells_y - 1 do
- seen_list[x, y] := -1;
-
-for x := 0 to num_edges_x - 1 do
- for y := 0 to num_cells_y - 1 do
- x_edge_list[x, y] := false;
-
-for x := 0 to num_cells_x - 1 do
- for y := 0 to num_edges_y - 1 do
- y_edge_list[x, y] := false;
-
-for current_step := 0 to num_steps-1 do
- begin
- x := GetRandom(seen_cells_x - 1) div LongWord(num_steps);
- last_cell[current_step].x := x + current_step * seen_cells_x div num_steps;
- last_cell[current_step].y := GetRandom(seen_cells_y);
-end;
-
-while not done do
- begin
- done := true;
- for current_step := 0 to num_steps-1 do
- begin
- if not step_done[current_step] then
- begin
- see_cell;
- done := false;
- end;
- end;
- end;
-
-for x := 0 to seen_cells_x - 1 do
- for y := 0 to seen_cells_y - 1 do
- if seen_list[x, y] > -1 then
- maze[(x+1)*2-1, (y+1)*2-1] := true;
-
-for x := 0 to seen_cells_x - 1 do
- for y := 0 to seen_cells_y - 2 do
- if not xwalls[x, y] then
- maze[x*2 + 1, y*2 + 2] := true;
-
-
-for x := 0 to seen_cells_x - 2 do
- for y := 0 to seen_cells_y - 1 do
- if not ywalls[x, y] then
- maze[x*2 + 2, y*2 + 1] := true;
-
-for x := 0 to num_edges_x - 1 do
- for y := 0 to num_cells_y - 1 do
- if maze[x, y] xor maze[x+1, y] then
- x_edge_list[x, y] := true
- else
- x_edge_list[x, y] := false;
-
-for x := 0 to num_cells_x - 1 do
- for y := 0 to num_edges_y - 1 do
- if maze[x, y] xor maze[x, y+1] then
- y_edge_list[x, y] := true
- else
- y_edge_list[x, y] := false;
-
-for x := 0 to num_edges_x - 1 do
- for y := 0 to num_cells_y - 1 do
- if x_edge_list[x, y] then
- begin
- x_edge_list[x, y] := false;
- add_vertex(x+1, y+1);
- add_vertex(x+1, y);
- add_edge(x, y-1, DIR_N);
- add_vertex(NTPX, 0);
- end;
-
-pa.count := num_vertices;
-
-leftX:= 0;
-rightX:= playWidth;
-topY:= off_y;
-
-// fill point
-pa.ar[pa.Count].x:= 1;
-pa.ar[pa.Count].y:= 1 + off_y;
-
-{
-for i:= 0 to pa.Count - 1 do
- begin
- system.writeln(pa.ar[i].x, ', ', pa.ar[i].y);
- end;
-}
-
-// divide while it divides
-repeat
- i:= pa.Count;
- DivideEdges(1, pa)
-until i = pa.Count;
-
-// make it smooth
-BezierizeEdge(pa, _0_2);
-
-DrawEdge(pa, 0);
-
-if maze_inverted then
- FillLand(1, 1 + off_y, 0, 0)
-else
- begin
- x := 0;
- while Land[cellsize div 2 + cellsize + off_y, x] = lfBasic do
- x := x + 1;
- while Land[cellsize div 2 + cellsize + off_y, x] = 0 do
- x := x + 1;
- FillLand(x+1, cellsize div 2 + cellsize + off_y, 0, 0);
- end;
-
-MaxHedgehogs:= 32;
-if (GameFlags and gfDisableGirders) <> 0 then
- hasGirders:= false
-else
- hasGirders := true;
-
-hasBorder := false;
-end;
-
-end.
--- a/hedgewars/uLandGenPerlin.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLandGenPerlin.pas Tue Dec 31 15:19:43 2024 +0100
@@ -9,8 +9,8 @@
uses uVariables
, uConsts
, uRandom
- , uLandOutline // FillLand
, uUtils
+ , uLandUtils
;
var p: array[0..511] of LongInt;
@@ -39,7 +39,7 @@
4086, 4088, 4089, 4091, 4092, 4092, 4093, 4094, 4094, 4095, 4095,
4095, 4095, 4095, 4095, 4095);
-function fade(t: LongInt) : LongInt; inline;
+function fade(t: LongInt) : LongInt;
var t0, t1: LongInt;
begin
t0:= fadear[t shr 8];
@@ -53,13 +53,13 @@
end;
-function lerp(t, a, b: LongInt) : LongInt; inline;
+function lerp(t, a, b: LongInt) : LongInt;
begin
lerp:= a + ((Int64(b) - a) * t shr 12)
end;
-function grad(hash, x, y: LongInt) : LongInt; inline;
+function grad(hash, x, y: LongInt) : LongInt;
var h, v, u: LongInt;
begin
h:= hash and 15;
@@ -74,7 +74,7 @@
end;
-function inoise(x, y: LongInt) : LongInt; inline;
+function inoise(x, y: LongInt) : LongInt;
const N = $10000;
var xx, yy, u, v, A, AA, AB, B, BA, BB: LongInt;
begin
@@ -205,24 +205,24 @@
}
if r < rCutoff then
- Land[y, x]:= 0
+ LandSet(y, x, 0)
else if param1 = 0 then
- Land[y, x]:= lfObjMask
+ LandSet(y, x, lfObjMask)
else
- Land[y, x]:= lfBasic
+ LandSet(y, x, lfBasic)
end;
end;
if param1 = 0 then
begin
for x:= 0 to width do
- if Land[height - 1, x] = lfObjMask then FillLand(x, height - 1, 0, lfBasic);
+ if LandGet(height - 1, x) = lfObjMask then FillLand(x, height - 1, 0, lfBasic);
// strip all lfObjMask pixels
for y:= minY to LAND_HEIGHT - 1 do
for x:= 0 to LAND_WIDTH - 1 do
- if Land[y, x] = lfObjMask then
- Land[y, x]:= 0;
+ if LandGet(y, x) = lfObjMask then
+ LandSet(y, x, 0);
end;
playWidth:= width;
--- a/hedgewars/uLandGenTemplateBased.pas Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,383 +0,0 @@
-unit uLandGenTemplateBased;
-interface
-
-uses uLandTemplates, uLandOutline;
-
-procedure GenTemplated(var Template: TEdgeTemplate);
-procedure DivideEdges(fillPointsCount: LongWord; var pa: TPixAr);
-
-var minDistance, dabDiv: LongInt; // different details size
-
-implementation
-uses {$IFDEF IPHONEOS}uTypes, {$ENDIF} uVariables, uConsts, uFloat, uLandUtils, uRandom, SDLh, math;
-
-
-procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr; fps: PPointArray);
-var i: LongInt;
-begin
- with Template do
- begin
- pa.Count:= BasePointsCount;
- for i:= 0 to pred(LongInt(pa.Count)) do
- begin
- pa.ar[i].x:= BasePoints^[i].x + LongInt(GetRandom(BasePoints^[i].w));
- if pa.ar[i].x <> NTPX then
- pa.ar[i].x:= pa.ar[i].x + ((LAND_WIDTH - Template.TemplateWidth) div 2);
- pa.ar[i].y:= BasePoints^[i].y + LongInt(GetRandom(BasePoints^[i].h)) + LAND_HEIGHT - LongInt(Template.TemplateHeight)
- end;
-
- if canMirror then
- if getrandom(2) = 0 then
- begin
- for i:= 0 to pred(BasePointsCount) do
- if pa.ar[i].x <> NTPX then
- pa.ar[i].x:= LAND_WIDTH - 1 - pa.ar[i].x;
- for i:= 0 to pred(FillPointsCount) do
- fps^[i].x:= LAND_WIDTH - 1 - fps^[i].x;
- end;
-
-(* Experiment in making this option more useful
- if ((not isNegative) and (cTemplateFilter = 4)) or
- (canFlip and (getrandom(2) = 0)) then
- begin
- for i:= 0 to pred(BasePointsCount) do
- begin
- pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y + (LAND_HEIGHT - TemplateHeight) * 2;
- if pa.ar[i].y > LAND_HEIGHT - 1 then
- pa.ar[i].y:= LAND_HEIGHT - 1;
- end;
- for i:= 0 to pred(FillPointsCount) do
- begin
- FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y + (LAND_HEIGHT - TemplateHeight) * 2;
- if FillPoints^[i].y > LAND_HEIGHT - 1 then
- FillPoints^[i].y:= LAND_HEIGHT - 1;
- end;
- end;
- end
-*)
-// template recycling. Pull these off the floor a bit
- if (not isNegative) and (cTemplateFilter = 4) then
- begin
- for i:= 0 to pred(BasePointsCount) do
- begin
- dec(pa.ar[i].y, 100);
- if pa.ar[i].y < 0 then
- pa.ar[i].y:= 0;
- end;
- for i:= 0 to pred(FillPointsCount) do
- begin
- dec(fps^[i].y, 100);
- if fps^[i].y < 0 then
- fps^[i].y:= 0;
- end;
- end;
-
- if (canFlip and (getrandom(2) = 0)) then
- begin
- for i:= 0 to pred(BasePointsCount) do
- pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y;
- for i:= 0 to pred(FillPointsCount) do
- fps^[i].y:= LAND_HEIGHT - 1 - fps^[i].y;
- end;
- end
-end;
-
-procedure FindPoint(si: LongInt; fillPointsCount: LongWord; var newPoint: TPoint; var pa: TPixAr);
-const mapBorderMargin = 40;
-var p1, p2, p4, fp, mp: TPoint;
- i, t1, t2, iy, ix, aqpb: LongInt;
- a, b, p, q: LongInt;
- dab, d, distL, distR: LongInt;
-begin
- // [p1, p2] is the segment we're trying to divide
- p1:= pa.ar[si];
- p2:= pa.ar[si + 1];
-
- if p2.x = NTPX then
- // it is segment from last to first point, so need to find first point
- begin
- i:= si - 2;
- while (i >= 0) and (pa.ar[i].x <> NTPX) do
- dec(i);
- p2:= pa.ar[i + 1]
- end;
-
- // perpendicular vector
- a:= p2.y - p1.y;
- b:= p1.x - p2.x;
- dab:= DistanceI(a, b).Round;
-
- // its middle point
- mp.x:= (p1.x + p2.x) div 2;
- mp.y:= (p1.y + p2.y) div 2;
-
- // don't process too short segments or those which are too close to map borders
- if (p1.x = NTPX)
- or (dab < minDistance * 3)
- or (mp.x < leftX + mapBorderMargin)
- or (mp.x > rightX - mapBorderMargin)
- or (mp.y < topY + mapBorderMargin)
- or (mp.y > LongInt(LAND_HEIGHT) - mapBorderMargin)
- then
- begin
- newPoint:= p1;
- exit;
- end;
-
- // find distances to map borders
- if a <> 0 then
- begin
- // left border
- iy:= (leftX + mapBorderMargin - mp.x) * b div a + mp.y;
- d:= DistanceI(mp.x - leftX - mapBorderMargin, mp.y - iy).Round;
- t1:= a * (mp.x - mapBorderMargin) + b * (mp.y - iy);
- if t1 > 0 then distL:= d else distR:= d;
-
- // right border
- iy:= (rightX - mapBorderMargin - mp.x) * b div a + mp.y;
- d:= DistanceI(mp.x - rightX + mapBorderMargin, mp.y - iy).Round;
- if t1 > 0 then distR:= d else distL:= d;
- end else
- begin
- distL:= LAND_WIDTH + LAND_HEIGHT;
- distR:= distL;
- end;
-
- if b <> 0 then
- begin
- // top border
- ix:= (topY + mapBorderMargin - mp.y) * a div b + mp.x;
- d:= DistanceI(mp.y - topY - mapBorderMargin, mp.x - ix).Round;
- t2:= b * (mp.y - mapBorderMargin) + a * (mp.x - ix);
- if t2 > 0 then distL:= min(d, distL) else distR:= min(d, distR);
-
- // bottom border
- ix:= (LAND_HEIGHT - mapBorderMargin - mp.y) * a div b + mp.x;
- d:= DistanceI(mp.y - LAND_HEIGHT + mapBorderMargin, mp.x - ix).Round;
- if t2 > 0 then distR:= min(d, distR) else distL:= min(d, distL);
- end;
-
- // now go through all other segments
- fp:= pa.ar[0];
- for i:= 0 to LongInt(pa.Count) - 2 do
- if pa.ar[i].x = NTPX then
- fp:= pa.ar[i + 1]
- else if (i <> si) then
- begin
- p4:= pa.ar[i + 1];
- if p4.x = NTPX then
- p4:= fp;
-
- // check if it intersects
- t1:= (mp.x - pa.ar[i].x) * b - a * (mp.y - pa.ar[i].y);
- t2:= (mp.x - p4.x) * b - a * (mp.y - p4.y);
-
- if (t1 > 0) <> (t2 > 0) then // yes it does, hard arith follows
- begin
- p:= p4.x - pa.ar[i].x;
- q:= p4.y - pa.ar[i].y;
- aqpb:= a * q - p * b;
-
- if (aqpb <> 0) then
- begin
- // (ix; iy) is intersection point
- iy:= (((Int64(pa.ar[i].x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(pa.ar[i].y) * p * b) div aqpb;
- if abs(b) > abs(q) then
- ix:= (iy - mp.y) * a div b + mp.x
- else
- ix:= (iy - pa.ar[i].y) * p div q + pa.ar[i].x;
-
- d:= DistanceI(mp.y - iy, mp.x - ix).Round;
- t1:= b * (mp.y - iy) + a * (mp.x - ix);
- if t1 > 0 then distL:= min(d, distL) else distR:= min(d, distR);
- end;
- end;
- end;
-
- // go through all points, including fill points
- for i:= 0 to Pred(LongInt(pa.Count + fillPointsCount)) do
- // if this point isn't on current segment
- if (si <> i) and (i <> si + 1) and (pa.ar[i].x <> NTPX) then
- begin
- // also check intersection with rays through pa.ar[i] if this point is good
- t1:= (p1.x - pa.ar[i].x) * b - a * (p1.y - pa.ar[i].y);
- t2:= (p2.x - pa.ar[i].x) * b - a * (p2.y - pa.ar[i].y);
- if (t1 > 0) <> (t2 > 0) then
- begin
- // ray from p1
- p:= pa.ar[i].x - p1.x;
- q:= pa.ar[i].y - p1.y;
- aqpb:= a * q - p * b;
-
- if (aqpb <> 0) then
- begin
- // (ix; iy) is intersection point
- iy:= (((Int64(p1.x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(p1.y) * p * b) div aqpb;
- if abs(b) > abs(q) then
- ix:= (iy - mp.y) * a div b + mp.x
- else
- ix:= (iy - p1.y) * p div q + p1.x;
-
- d:= DistanceI(mp.y - iy, mp.x - ix).Round;
- t1:= b * (mp.y - iy) + a * (mp.x - ix);
- if t1 > 0 then distL:= min(d, distL) else distR:= min(d, distR);
- end;
-
- // and ray from p2
- p:= pa.ar[i].x - p2.x;
- q:= pa.ar[i].y - p2.y;
- aqpb:= a * q - p * b;
-
- if (aqpb <> 0) then
- begin
- // (ix; iy) is intersection point
- iy:= (((Int64(p2.x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(p2.y) * p * b) div aqpb;
- if abs(b) > abs(q) then
- ix:= (iy - mp.y) * a div b + mp.x
- else
- ix:= (iy - p2.y) * p div q + p2.x;
-
- d:= DistanceI(mp.y - iy, mp.x - ix).Round;
- t2:= b * (mp.y - iy) + a * (mp.x - ix);
- if t2 > 0 then distL:= min(d, distL) else distR:= min(d, distR);
- end;
- end;
- end;
-
- // don't move new point for more than length of initial segment
- // adjust/parametrize for more flat surfaces (try values 3/4, 1/2 of dab, or even 1/4)
- d:= dab * 100 div dabDiv;
- //d:= dab * (1 + abs(cFeatureSize - 8)) div 6;
- //d:= dab * (14 + cFeatureSize) div 20;
- if distL > d then distL:= d;
- if distR > d then distR:= d;
-
- if distR + distL < minDistance * 2 + 10 then
- begin
- // limits are too narrow, just divide
- newPoint.x:= mp.x;
- newPoint.y:= mp.y;
- end
- else
- begin
- // select distance within [-distL; distR]
- d:= -distL + minDistance + LongInt(GetRandom(distR + distL - minDistance * 2));
- //d:= distR - minDistance;
- //d:= - distL + minDistance;
-
- // calculate new point
- newPoint.x:= mp.x + a * d div dab;
- newPoint.y:= mp.y + b * d div dab;
- end;
-end;
-
-procedure DivideEdges(fillPointsCount: LongWord; var pa: TPixAr);
-var i, t: LongInt;
- newPoint: TPoint;
-begin
- newPoint.x:= 0;
- newPoint.y:= 0;
- i:= 0;
-
- while i < LongInt(pa.Count) - 1 do
- begin
- FindPoint(i, fillPointsCount, newPoint, pa);
-
- if (newPoint.x <> pa.ar[i].x) or (newPoint.y <> pa.ar[i].y) then
- begin
- // point found, free a slot for it in array, don't forget to move appended fill points
- for t:= pa.Count + fillPointsCount downto i + 2 do
- pa.ar[t]:= pa.ar[t - 1];
- inc(pa.Count);
- pa.ar[i + 1]:= newPoint;
- inc(i)
- end;
- inc(i)
- end;
-end;
-
-procedure Distort2(var Template: TEdgeTemplate; fps: PPointArray; var pa: TPixAr);
-var i: Longword;
-begin
- // append fill points to ensure distortion won't move them to other side of segment
- for i:= 0 to pred(Template.FillPointsCount) do
- begin
- pa.ar[pa.Count + i].x:= fps^[i].x;
- pa.ar[pa.Count + i].y:= fps^[i].y;
- end;
-
- // divide while it divides
- repeat
- i:= pa.Count;
- DivideEdges(Template.FillPointsCount, pa)
- until i = pa.Count;
-
-{$IFDEF IPHONEOS}
- if GameType <> gmtLandPreview then
-{$ENDIF}
- // make it smooth
- BezierizeEdge(pa, _0_2);
-end;
-
-
-procedure GenTemplated(var Template: TEdgeTemplate);
-var pa: TPixAr;
- i: Longword;
- y, x: Longword;
- fps: TPointArray;
-begin
- fps:=Template.FillPoints^;
- ResizeLand(Template.TemplateWidth, Template.TemplateHeight);
- for y:= 0 to LAND_HEIGHT - 1 do
- for x:= 0 to LAND_WIDTH - 1 do
- Land[y, x]:= lfBasic;
-
- minDistance:= sqr(cFeatureSize) div 8 + 10;
- //dabDiv:= getRandom(41)+60;
- //dabDiv:= getRandom(31)+70;
- dabDiv:= getRandom(21)+100;
- MaxHedgehogs:= Template.MaxHedgehogs;
- hasGirders:= Template.hasGirders;
- playHeight:= Template.TemplateHeight;
- playWidth:= Template.TemplateWidth;
- leftX:= (LAND_WIDTH - playWidth) div 2;
- rightX:= Pred(leftX + playWidth);
- topY:= LAND_HEIGHT - playHeight;
-
- {$HINTS OFF}
- SetPoints(Template, pa, @fps);
- {$HINTS ON}
-
- Distort2(Template, @fps, pa);
-
- DrawEdge(pa, 0);
-
- with Template do
- for i:= 0 to pred(FillPointsCount) do
- with fps[i] do
- FillLand(x, y, 0, 0);
-
- DrawEdge(pa, lfBasic);
-
- // HACK: force to only cavern even if a cavern map is invertable if cTemplateFilter = 4 ?
- if (cTemplateFilter = 4)
- or (Template.canInvert and (getrandom(2) = 0))
- or (not Template.canInvert and Template.isNegative) then
- begin
- hasBorder:= true;
- for y:= 0 to LAND_HEIGHT - 1 do
- for x:= 0 to LAND_WIDTH - 1 do
- if (y < LongWord(topY)) or (x < LongWord(leftX)) or (x > LongWord(rightX)) then
- Land[y, x]:= 0
- else
- begin
- if Land[y, x] = 0 then
- Land[y, x]:= lfBasic
- else if Land[y, x] = lfBasic then
- Land[y, x]:= 0;
- end;
- end;
-end;
-
-
-end.
--- a/hedgewars/uLandGraphics.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLandGraphics.pas Tue Dec 31 15:19:43 2024 +0100
@@ -47,19 +47,19 @@
function DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword): Longword;
procedure DumpLandToLog(x, y, r: LongInt);
procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
-function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline;
-function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; inline;
-function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; inline;
+function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean;
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean;
+function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean;
function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, outOfMap, force, behind, flipHoriz, flipVert: boolean; LandFlags: Word; Tint: LongWord): boolean;
procedure EraseLandRectRaw(X, Y, width, height: LongWord);
procedure EraseLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; eraseOnLFMatch, onlyEraseLF, flipHoriz, flipVert: boolean);
function GetPlaceCollisionTex(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt): PTexture;
implementation
-uses SDLh, uLandTexture, uTextures, uVariables, uUtils, uDebug, uScript;
+uses SDLh, uLandTexture, uTextures, uVariables, uUtils, uDebug, uScript, uLandUtils;
-procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint); inline;
+procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint);
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
@@ -73,33 +73,33 @@
end;
end;
-function drawPixelBG(landX, landY, pixelX, pixelY: Longint): Longword; inline;
+function drawPixelBG(landX, landY, pixelX, pixelY: Longint): Longword;
begin
drawPixelBG := 0;
-if (Land[LandY, landX] and lfIndestructible) = 0 then
+if (LandGet(LandY, landX) and lfIndestructible) = 0 then
begin
- if ((Land[landY, landX] and lfBasic) <> 0) and (((LandPixels[pixelY, pixelX] and AMask) shr AShift) = 255) and (not disableLandBack) then
+ if ((LandGet(landY, landX) and lfBasic) <> 0) and (((LandPixelGet(pixelY, pixelX) and AMask) shr AShift) = 255) and (not disableLandBack) then
begin
- LandPixels[pixelY, pixelX]:= LandBackPixel(landX, landY);
+ LandPixelSet(pixelY, pixelX, LandBackPixel(landX, landY));
inc(drawPixelBG);
end
- else if ((Land[landY, landX] and lfObject) <> 0) or (((LandPixels[pixelY, pixelX] and AMask) shr AShift) < 255) then
- LandPixels[pixelY, pixelX]:= ExplosionBorderColorNoA
+ else if ((LandGet(landY, landX) and lfObject) <> 0) or (((LandPixelGet(pixelY, pixelX) and AMask) shr AShift) < 255) then
+ LandPixelSet(pixelY, pixelX, ExplosionBorderColorNoA)
end;
end;
-procedure drawPixelEBC(landX, landY, pixelX, pixelY: Longint); inline;
+procedure drawPixelEBC(landX, landY, pixelX, pixelY: Longint);
begin
-if (Land[landY, landX] and lfIndestructible = 0) and
- (((Land[landY, landX] and lfBasic) <> 0) or ((Land[landY, landX] and lfObject) <> 0)) then
+if (LandGet(landY, landX) and lfIndestructible = 0) and
+ (((LandGet(landY, landX) and lfBasic) <> 0) or ((LandGet(landY, landX) and lfObject) <> 0)) then
begin
- LandPixels[pixelY, pixelX]:= ExplosionBorderColor;
- Land[landY, landX]:= (Land[landY, landX] or lfDamaged) and (not lfIce);
+ LandPixelSet(pixelY, pixelX, ExplosionBorderColor);
+ LandSet(landY, landX, (LandGet(landY, landX) or lfDamaged) and (not lfIce));
LandDirty[landY div 32, landX div 32]:= 1;
end;
end;
-function isLandscapeEdge(weight:Longint):boolean; inline;
+function isLandscapeEdge(weight:Longint):boolean;
begin
isLandscapeEdge := (weight < 8) and (weight >= 2);
end;
@@ -118,7 +118,7 @@
(j > LAND_HEIGHT -1) then
exit(9);
- if Land[j, i] and lfLandMask and (not lfIce) = 0 then
+ if LandGet(j, i) and lfLandMask and (not lfIce) = 0 then
inc(r)
end;
@@ -126,7 +126,7 @@
end;
-procedure fillPixelFromIceSprite(pixelX, pixelY:Longint); inline;
+procedure fillPixelFromIceSprite(pixelX, pixelY:Longint);
var
iceSurface: PSDL_Surface;
icePixels: PLongwordArray;
@@ -136,7 +136,7 @@
// So. 3 parameters here. Ice colour, Ice opacity, and a bias on the greyscaled pixel towards lightness
iceSurface:= SpritesData[sprIceTexture].Surface;
icePixels := iceSurface^.pixels;
- w:= LandPixels[pixelY, pixelX];
+ w:= LandPixelGet(pixelY, pixelX);
if w > 0 then
begin
w:= round(((w shr RShift and $FF) * RGB_LUMINANCE_RED +
@@ -144,37 +144,37 @@
(w shr GShift and $FF) * RGB_LUMINANCE_BLUE));
if w < 128 then w:= w+128;
if w > 255 then w:= 255;
- w:= (w shl RShift) or (w shl BShift) or (w shl GShift) or (LandPixels[pixelY, pixelX] and AMask);
- LandPixels[pixelY, pixelX]:= addBgColor(w, IceColor);
- LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)])
+ w:= (w shl RShift) or (w shl BShift) or (w shl GShift) or (LandPixelGet(pixelY, pixelX) and AMask);
+ LandPixelSet(pixelY, pixelX, addBgColor(w, IceColor));
+ LandPixelSet(pixelY, pixelX, addBgColor(LandPixelGet(pixelY, pixelX), icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]))
end
else
begin
- LandPixels[pixelY, pixelX]:= IceColor and (not AMask) or $E8 shl AShift;
- LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]);
+ LandPixelSet(pixelY, pixelX, IceColor and (not AMask) or $E8 shl AShift);
+ LandPixelSet(pixelY, pixelX, addBgColor(LandPixelGet(pixelY, pixelX), icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]));
// silly workaround to avoid having to make background erasure a tadb it smarter about sea ice
- if LandPixels[pixelY, pixelX] and AMask shr AShift = 255 then
- LandPixels[pixelY, pixelX]:= LandPixels[pixelY, pixelX] and (not AMask) or 254 shl AShift;
+ if LandPixelGet(pixelY, pixelX) and AMask shr AShift = 255 then
+ LandPixelSet(pixelY, pixelX, LandPixelGet(pixelY, pixelX) and (not AMask) or 254 shl AShift);
end;
end;
-procedure DrawPixelIce(landX, landY, pixelX, pixelY: Longint); inline;
+procedure DrawPixelIce(landX, landY, pixelX, pixelY: Longint);
begin
-if ((Land[landY, landX] and lfIce) <> 0) then exit;
+if ((LandGet(landY, landX) and lfIce) <> 0) then exit;
if (pixelX < LeftX) or (pixelX > RightX) or (pixelY < TopY) then exit;
if isLandscapeEdge(getPixelWeight(landX, landY)) then
begin
- if (LandPixels[pixelY, pixelX] and AMask < 255) and (LandPixels[pixelY, pixelX] and AMask > 0) then
- LandPixels[pixelY, pixelX] := (IceEdgeColor and (not AMask)) or (LandPixels[pixelY, pixelX] and AMask)
- else if (LandPixels[pixelY, pixelX] and AMask < 255) or (Land[landY, landX] > 255) then
- LandPixels[pixelY, pixelX] := IceEdgeColor
+ if (LandPixelGet(pixelY, pixelX) and AMask < 255) and (LandPixelGet(pixelY, pixelX) and AMask > 0) then
+ LandPixelSet(pixelY, pixelX, (IceEdgeColor and (not AMask)) or (LandPixelGet(pixelY, pixelX) and AMask))
+ else if (LandPixelGet(pixelY, pixelX) and AMask < 255) or (LandGet(landY, landX) > 255) then
+ LandPixelSet(pixelY, pixelX, IceEdgeColor)
end
-else if Land[landY, landX] > 255 then
+else if LandGet(landY, landX) > 255 then
begin
fillPixelFromIceSprite(pixelX, pixelY);
end;
-if Land[landY, landX] > 255 then Land[landY, landX] := Land[landY, landX] or lfIce and (not lfDamaged);
+if LandGet(landY, landX) > 255 then LandSet(landY, landX, LandGet(landY, landX) or lfIce and (not lfDamaged));
end;
@@ -202,8 +202,8 @@
for i:= fromPix to toPix do
begin
calculatePixelsCoordinates(i, y, px, py);
- if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then
- LandPixels[py, px]:= ExplosionBorderColorNoA;
+ if ((LandGet(y, i) and lfIndestructible) = 0) and (not disableLandBack or (LandGet(y, i) > 255)) then
+ LandPixelSet(py, px, ExplosionBorderColorNoA);
end;
icePixel:
for i:= fromPix to toPix do
@@ -214,41 +214,41 @@
addNotHHObj:
for i:= fromPix to toPix do
begin
- if Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift < lfNotHHObjSize then
- Land[y, i]:= (Land[y, i] and (not lfNotHHObjMask)) or ((Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift + 1) shl lfNotHHObjShift);
+ if LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift < lfNotHHObjSize then
+ LandSet(y, i, (LandGet(y, i) and (not lfNotHHObjMask)) or ((LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift + 1) shl lfNotHHObjShift));
end;
removeNotHHObj:
for i:= fromPix to toPix do
begin
- if Land[y, i] and lfNotHHObjMask <> 0 then
- Land[y, i]:= (Land[y, i] and (not lfNotHHObjMask)) or ((Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift - 1) shl lfNotHHObjShift);
+ if LandGet(y, i) and lfNotHHObjMask <> 0 then
+ LandSet(y, i, (LandGet(y, i) and (not lfNotHHObjMask)) or ((LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift - 1) shl lfNotHHObjShift));
end;
addHH:
for i:= fromPix to toPix do
begin
- if Land[y, i] and lfHHMask < lfHHMask then
- Land[y, i]:= Land[y, i] + 1
+ if LandGet(y, i) and lfHHMask < lfHHMask then
+ LandSet(y, i, LandGet(y, i) + 1)
end;
removeHH:
for i:= fromPix to toPix do
begin
- if Land[y, i] and lfHHMask > 0 then
- Land[y, i]:= Land[y, i] - 1;
+ if LandGet(y, i) and lfHHMask > 0 then
+ LandSet(y, i, LandGet(y, i) - 1);
end;
setCurrentHog:
for i:= fromPix to toPix do
begin
- Land[y, i]:= Land[y, i] or lfCurHogCrate
+ LandSet(y, i, LandGet(y, i) or lfCurHogCrate)
end;
removeCurrentHog:
for i:= fromPix to toPix do
begin
- Land[y, i]:= Land[y, i] and lfNotCurHogCrate;
+ LandSet(y, i, LandGet(y, i) and lfNotCurHogCrate);
end;
end;
end;
-function FillLandCircleSegmentFT(x, y, dx, dy: LongInt; fill : fillType): Longword; inline;
+function FillLandCircleSegmentFT(x, y, dx, dy: LongInt; fill : fillType): Longword;
begin
FillLandCircleSegmentFT := 0;
if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
@@ -261,7 +261,7 @@
inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y - dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
end;
-function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword; inline;
+function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword;
var dx, dy, d: LongInt;
begin
dx:= 0;
@@ -323,31 +323,31 @@
if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if (Land[y + dy, i] and lfIndestructible) = 0 then
+ if (LandGet(y + dy, i) and lfIndestructible) = 0 then
begin
- if Land[y + dy, i] <> Value then inc(FillCircleLines);
- Land[y + dy, i]:= Value;
+ if LandGet(y + dy, i) <> Value then inc(FillCircleLines);
+ LandSet(y + dy, i, Value);
end;
if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if (Land[y - dy, i] and lfIndestructible) = 0 then
+ if (LandGet(y - dy, i) and lfIndestructible) = 0 then
begin
- if Land[y - dy, i] <> Value then inc(FillCircleLines);
- Land[y - dy, i]:= Value;
+ if LandGet(y - dy, i) <> Value then inc(FillCircleLines);
+ LandSet(y - dy, i, Value);
end;
if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if (Land[y + dx, i] and lfIndestructible) = 0 then
+ if (LandGet(y + dx, i) and lfIndestructible) = 0 then
begin
- if Land[y + dx, i] <> Value then inc(FillCircleLines);
- Land[y + dx, i]:= Value;
+ if LandGet(y + dx, i) <> Value then inc(FillCircleLines);
+ LandSet(y + dx, i, Value);
end;
if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if (Land[y - dx, i] and lfIndestructible) = 0 then
+ if (LandGet(y - dx, i) and lfIndestructible) = 0 then
begin
- if Land[y - dx, i] <> Value then inc(FillCircleLines);
- Land[y - dx, i]:= Value;
+ if LandGet(y - dx, i) <> Value then inc(FillCircleLines);
+ LandSet(y - dx, i, Value);
end;
end;
@@ -435,9 +435,9 @@
begin
for j := iceT to iceB do
begin
- if Land[j, i] = 0 then
+ if LandGet(j, i) = 0 then
begin
- Land[j, i] := lfIce;
+ LandSet(j, i, lfIce);
if (cReducedQuality and rqBlurryLand) = 0 then
fillPixelFromIceSprite(i, j)
else
@@ -478,7 +478,7 @@
for ty:= Max(y - Radius, 0) to Min(y + Radius, TopY) do
for tx:= Max(LeftX, ar^[i].Left - Radius) to Min(RightX, ar^[i].Right + Radius) do
begin
- if (Land[ty, tx] and lfIndestructible) = 0 then
+ if (LandGet(ty, tx) and lfIndestructible) = 0 then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
@@ -488,10 +488,10 @@
begin
by:= ty div 2; bx:= tx div 2;
end;
- if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- LandPixels[by, bx]:= LandBackPixel(tx, ty)
- else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= LandPixels[by, bx] and (not AMASK)
+ if ((LandGet(ty, tx) and lfBasic) <> 0) and (((LandPixelGet(by,bx) and AMask) shr AShift) = 255) and (not disableLandBack) then
+ LandPixelSet(by, bx, LandBackPixel(tx, ty))
+ else if ((LandGet(ty, tx) and lfObject) <> 0) or (((LandPixelGet(by,bx) and AMask) shr AShift) < 255) then
+ LandPixelSet(by, bx, LandPixelGet(by, bx) and (not AMASK))
end
end;
inc(y, dY)
@@ -504,14 +504,14 @@
begin
for ty:= Max(y - Radius, 0) to Min(y + Radius, TopY) do
for tx:= Max(LeftX, ar^[i].Left - Radius) to Min(RightX, ar^[i].Right + Radius) do
- if ((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0) then
+ if ((LandGet(ty, tx) and lfBasic) <> 0) or ((LandGet(ty, tx) and lfObject) <> 0) then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
+ LandPixelSet(ty, tx, ExplosionBorderColor)
else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor;
+ LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor);
- Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce);
+ LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce));
LandDirty[ty div 32, tx div 32]:= 1;
end;
inc(y, dY)
@@ -533,16 +533,16 @@
Y:= Y + dY;
tx:= hwRound(X);
ty:= hwRound(Y);
- if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
- or ((Land[ty, tx] and lfObject) <> 0)) then
+ if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((LandGet(ty, tx) and lfBasic) <> 0)
+ or ((LandGet(ty, tx) and lfObject) <> 0)) then
begin
- Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce);
+ LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce));
if despeckle then
LandDirty[ty div 32, tx div 32]:= 1;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
+ LandPixelSet(ty, tx, ExplosionBorderColor)
else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
+ LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor)
end
end;
end;
@@ -581,18 +581,18 @@
ty:= hwRound(Y);
if ((ty and LAND_HEIGHT_MASK) = 0)
and ((tx and LAND_WIDTH_MASK) = 0)
- and (((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0)) then
+ and (((LandGet(ty, tx) and lfBasic) <> 0) or ((LandGet(ty, tx) and lfObject) <> 0)) then
begin
- Land[ty, tx]:= Land[ty, tx] and (not lfIce);
+ LandSet(ty, tx, LandGet(ty, tx) and (not lfIce));
if despeckle then
begin
- Land[ty, tx]:= Land[ty, tx] or lfDamaged;
+ LandSet(ty, tx, LandGet(ty, tx) or lfDamaged);
LandDirty[ty div 32, tx div 32]:= 1
end;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
+ LandPixelSet(ty, tx, ExplosionBorderColor)
else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
+ LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor)
end
end;
nx:= nx - dY;
@@ -612,7 +612,7 @@
Y:= Y + dY;
tx:= hwRound(X);
ty:= hwRound(Y);
- if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and ((Land[ty, tx] and lfIndestructible) = 0) then
+ if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and ((LandGet(ty, tx) and lfIndestructible) = 0) then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
@@ -622,11 +622,11 @@
begin
by:= ty div 2; bx:= tx div 2;
end;
- if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- LandPixels[by, bx]:= LandBackPixel(tx, ty)
- else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= LandPixels[by, bx] and (not AMASK);
- Land[ty, tx]:= 0;
+ if ((LandGet(ty, tx) and lfBasic) <> 0) and (((LandPixelGet(by,bx) and AMask) shr AShift) = 255) and (not disableLandBack) then
+ LandPixelSet(by, bx, LandBackPixel(tx, ty))
+ else if ((LandGet(ty, tx) and lfObject) <> 0) or (((LandPixelGet(by,bx) and AMask) shr AShift) < 255) then
+ LandPixelSet(by, bx, LandPixelGet(by, bx) and (not AMASK));
+ LandSet(ty, tx, 0);
end
end;
DrawExplosionBorder(X, Y, dx, dy, despeckle);
@@ -644,16 +644,16 @@
Y:= Y + dY;
tx:= hwRound(X);
ty:= hwRound(Y);
- if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
- or ((Land[ty, tx] and lfObject) <> 0)) then
+ if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((LandGet(ty, tx) and lfBasic) <> 0)
+ or ((LandGet(ty, tx) and lfObject) <> 0)) then
begin
- Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce);
+ LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce));
if despeckle then
LandDirty[ty div 32, tx div 32]:= 1;
if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
+ LandPixelSet(ty, tx, ExplosionBorderColor)
else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
+ LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor)
end
end;
nx:= nx - dY;
@@ -692,7 +692,7 @@
end;
end;
-function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline;
+function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean;
var lf: Word;
begin
if indestructible then
@@ -702,12 +702,12 @@
TryPlaceOnLandSimple:= TryPlaceOnLand(cpX, cpY, Obj, Frame, doPlace, false, false, false, false, false, lf, $FFFFFFFF);
end;
-function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; inline;
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean;
begin
TryPlaceOnLand:= TryPlaceOnLand(cpX, cpY, Obj, Frame, doPlace, false, false, false, false, false, LandFlags, $FFFFFFFF);
end;
-function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; inline;
+function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean;
begin
ForcePlaceOnLand:= TryPlaceOnLand(cpX, cpY, Obj, Frame, true, false, true, behind, flipHoriz, flipVert, LandFlags, Tint)
end;
@@ -752,12 +752,12 @@
if (outOfMap and
((cpY + y) < LAND_HEIGHT) and ((cpY + y) >= 0) and
((cpX + x) < LAND_WIDTH) and ((cpX + x) >= 0) and
- ((not force) and (Land[cpY + y, cpX + x] <> 0))) or
+ ((not force) and (LandGet(cpY + y, cpX + x) <> 0))) or
(not outOfMap and
(((cpY + y) <= topY) or ((cpY + y) >= LAND_HEIGHT) or
((cpX + x) <= leftX) or ((cpX + x) >= rightX) or
- ((not force) and (Land[cpY + y, cpX + x] <> 0)))) then
+ ((not force) and (LandGet(cpY + y, cpX + x) <> 0)))) then
begin
if SDL_MustLock(Image) then
SDL_UnlockSurface(Image);
@@ -793,28 +793,28 @@
gX:= (cpX + x) div 2;
gY:= (cpY + y) div 2;
end;
- if (not behind) or (Land[cpY + y, cpX + x] and lfLandMask = 0) then
+ if (not behind) or (LandGet(cpY + y, cpX + x) and lfLandMask = 0) then
begin
- if (LandFlags and lfBasic <> 0) or
- ((LandPixels[gY, gX] and AMask shr AShift > 128) and // This test assumes lfBasic and lfObject differ only graphically
+ if (LandFlags and lfBasic <> 0) or
+ ((LandPixelGet(gY, gX) and AMask shr AShift > 128) and // This test assumes lfBasic and lfObject differ only graphically
(LandFlags and (lfObject or lfIce) = 0)) then
- Land[cpY + y, cpX + x]:= lfBasic or LandFlags
+ LandSet(cpY + y, cpX + x, lfBasic or LandFlags)
else if (LandFlags and lfIce = 0) then
- Land[cpY + y, cpX + x]:= lfObject or LandFlags
- else Land[cpY + y, cpX + x]:= LandFlags
+ LandSet(cpY + y, cpX + x, lfObject or LandFlags)
+ else LandSet(cpY + y, cpX + x, LandFlags)
end;
- if (not behind) or (LandPixels[gY, gX] = 0) then
+ if (not behind) or (LandPixelGet(gY, gX) = 0) then
begin
if tint = $FFFFFFFF then
- LandPixels[gY, gX]:= PLongword(@(p^[x * 4]))^
- else
+ LandPixelSet(gY, gX, PLongword(@(p^[x * 4]))^)
+ else
begin
pixel:= PLongword(@(p^[x * 4]))^;
- LandPixels[gY, gX]:=
+ LandPixelSet(gY, gX,
ceil((pixel shr RShift and $FF) * ((tint shr 24) / 255)) shl RShift or
ceil((pixel shr GShift and $FF) * ((tint shr 16 and $ff) / 255)) shl GShift or
ceil((pixel shr BShift and $FF) * ((tint shr 8 and $ff) / 255)) shl BShift or
- ceil((pixel shr AShift and $FF) * ((tint and $ff) / 255)) shl AShift;
+ ceil((pixel shr AShift and $FF) * ((tint and $ff) / 255)) shl AShift);
end
end
end;
@@ -847,8 +847,8 @@
for ty:= 0 to height - 1 do
for tx:= 0 to width - 1 do
begin
- LandPixels[ty, tx]:= 0;
- Land[Y + ty, X + tx]:= 0;
+ LandPixelSet(ty, tx, 0);
+ LandSet(Y + ty, X + tx, 0);
end;
end;
@@ -913,15 +913,15 @@
gX:= (cpX + x) div 2;
gY:= (cpY + y) div 2;
end;
- if (not eraseOnLFMatch or (Land[cpY + y, cpX + x] and LandFlags <> 0)) and
+ if (not eraseOnLFMatch or (LandGet(cpY + y, cpX + x) and LandFlags <> 0)) and
((PLongword(@(p^[x * 4]))^) and AMask <> 0) then
begin
if not onlyEraseLF then
begin
- LandPixels[gY, gX]:= 0;
- Land[cpY + y, cpX + x]:= 0
+ LandPixelSet(gY, gX, 0);
+ LandSet(cpY + y, cpX + x, 0)
end
- else Land[cpY + y, cpX + x]:= Land[cpY + y, cpX + x] and (not LandFlags)
+ else LandSet(cpY + y, cpX + x, LandGet(cpY + y, cpX + x) and (not LandFlags))
end
end;
p:= PByteArray(@(p^[Image^.pitch]));
@@ -990,7 +990,7 @@
for x:= 0 to Pred(w) do
if ((p^[x] and AMask) <> 0)
and (((cpY + y) < topY) or ((cpY + y) >= LAND_HEIGHT) or
- ((cpX + x) < leftX) or ((cpX + x) > rightX) or (Land[cpY + y, cpX + x] <> 0)) then
+ ((cpX + x) < leftX) or ((cpX + x) > rightX) or (LandGet(cpY + y, cpX + x) <> 0)) then
pt^[x]:= cWhiteColor
else
(pt^[x]):= cWhiteColor and (not AMask);
@@ -1028,8 +1028,8 @@
yy:= Y div 2;
end;
- pixelsweep:= (Land[Y, X] <= lfAllObjMask) and ((LandPixels[yy, xx] and AMask) <> 0);
- if (((Land[Y, X] and lfDamaged) <> 0) and ((Land[Y, X] and lfIndestructible) = 0)) or pixelsweep then
+ pixelsweep:= (LandGet(Y, X) <= lfAllObjMask) and ((LandPixelGet(yy, xx) and AMask) <> 0);
+ if (((LandGet(Y, X) and lfDamaged) <> 0) and ((LandGet(Y, X) and lfIndestructible) = 0)) or pixelsweep then
begin
c:= 0;
for i:= -1 to 1 do
@@ -1047,27 +1047,27 @@
ny:= Y div 2 + i;
nx:= X div 2 + j;
if ((ny and (LAND_HEIGHT_MASK div 2)) = 0) and ((nx and (LAND_WIDTH_MASK div 2)) = 0) then
- if (LandPixels[ny, nx] and AMASK) <> 0 then
+ if (LandPixelGet(ny, nx) and AMASK) <> 0 then
inc(c);
end
- else if (LandPixels[ny, nx] and AMASK) <> 0 then
+ else if (LandPixelGet(ny, nx) and AMASK) <> 0 then
inc(c);
end
- else if Land[ny, nx] > 255 then
+ else if LandGet(ny, nx) > 255 then
inc(c);
end
end;
if c < 4 then // 0-3 neighbours
begin
- if ((Land[Y, X] and lfBasic) <> 0) and (not disableLandBack) then
- LandPixels[yy, xx]:= LandBackPixel(X, Y)
+ if ((LandGet(Y, X) and lfBasic) <> 0) and (not disableLandBack) then
+ LandPixelSet(yy, xx, LandBackPixel(X, Y))
else
- LandPixels[yy, xx]:= LandPixels[yy, xx] and (not AMASK);
+ LandPixelSet(yy, xx, LandPixelGet(yy, xx) and (not AMASK));
if not pixelsweep then
begin
- Land[Y, X]:= 0;
+ LandSet(Y, X, 0);
exit
end
end;
@@ -1083,7 +1083,7 @@
begin
// only AA inwards
-if (Land[Y, X] and lfDamaged) = 0 then
+if (LandGet(Y, X) and lfDamaged) = 0 then
exit;
// check location
@@ -1104,9 +1104,9 @@
for nx:= X-1 to X+1 do
for ny:= Y-1 to Y+1 do
// only consider undamaged neighbors (also leads to skipping itself)
- if (Land[ny, nx] and lfDamaged) = 0 then
+ if (LandGet(ny, nx) and lfDamaged) = 0 then
begin
- pixel:= LandPixels[ny, nx];
+ pixel:= LandPixelGet(ny, nx);
inc(r, (pixel and RMask) shr RShift);
inc(g, (pixel and GMask) shr GShift);
inc(b, (pixel and BMask) shr BShift);
@@ -1132,95 +1132,95 @@
g:= g div 8;
b:= b div 8;
a:= a div 8;
-LandPixels[y,x]:= (r shl RShift) or (g shl GShift) or (b shl BShift) or (a shl AShift);
+LandPixelSet(y, x, (r shl RShift) or (g shl GShift) or (b shl BShift) or (a shl AShift));
end;
procedure Smooth_oldImpl(X, Y: LongInt);
begin
// a bit of AA for explosions
-if (Land[Y, X] = 0) and (Y > topY + 1) and
+if (LandGet(Y, X) = 0) and (Y > topY + 1) and
(Y < LAND_HEIGHT-2) and (X > leftX + 1) and (X < rightX - 1) then
begin
- if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and (((Land[y-1,x] and lfDamaged) <> 0) or ((Land[y+1,x] and lfDamaged) <> 0)))) then
+ if ((((LandGet(y, x-1) and lfDamaged) <> 0) and (((LandGet(y+1,x) and lfDamaged) <> 0)) or ((LandGet(y-1,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and (((LandGet(y-1,x) and lfDamaged) <> 0) or ((LandGet(y+1,x) and lfDamaged) <> 0)))) then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
- if ((LandPixels[y,x] and AMask) shr AShift) < 10 then
- LandPixels[y,x]:= (ExplosionBorderColor and (not AMask)) or (128 shl AShift)
+ if ((LandPixelGet(y,x) and AMask) shr AShift) < 10 then
+ LandPixelSet(y,x, (ExplosionBorderColor and (not AMask)) or (128 shl AShift))
else
- LandPixels[y,x]:=
- (((((LandPixels[y,x] and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or
- (((((LandPixels[y,x] and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or
- (((((LandPixels[y,x] and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift)
+ LandPixelSet(y,x,
+ (((((LandPixelGet(y,x) and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or
+ (((((LandPixelGet(y,x) and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or
+ (((((LandPixelGet(y,x) and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift))
end;
{
- if (Land[y, x-1] = lfObject) then
- Land[y,x]:= lfObject
- else if (Land[y, x+1] = lfObject) then
- Land[y,x]:= lfObject
+ if (LandGet(y, x-1) = lfObject) then
+ LandSet(y,x, lfObject)
+ else if (LandGet(y, x+1) = lfObject) then
+ LandSet(y,x, lfObject)
else
- Land[y,x]:= lfBasic;
+ LandSet(y,x, lfBasic);
}
end
- else if ((((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0))
- or (((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0))
- or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0))
- or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0))
- or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))
- or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))) then
+ else if ((((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0))
+ or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0))
+ or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0))
+ or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))
+ or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))) then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
begin
- if ((LandPixels[y,x] and AMask) shr AShift) < 10 then
- LandPixels[y,x]:= (ExplosionBorderColor and (not AMask)) or (64 shl AShift)
+ if ((LandPixelGet(y,x) and AMask) shr AShift) < 10 then
+ LandPixelSet(y,x, (ExplosionBorderColor and (not AMask)) or (64 shl AShift))
else
- LandPixels[y,x]:=
- (((((LandPixels[y,x] and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or
- (((((LandPixels[y,x] and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or
- (((((LandPixels[y,x] and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift)
+ LandPixelSet(y,x,
+ (((((LandPixelGet(y,x) and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or
+ (((((LandPixelGet(y,x) and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or
+ (((((LandPixelGet(y,x) and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift))
end;
{
- if (Land[y, x-1] = lfObject) then
- Land[y, x]:= lfObject
- else if (Land[y, x+1] = lfObject) then
- Land[y, x]:= lfObject
- else if (Land[y+1, x] = lfObject) then
- Land[y, x]:= lfObject
- else if (Land[y-1, x] = lfObject) then
- Land[y, x]:= lfObject
- else Land[y,x]:= lfBasic
+ if (LandGet(y, x-1) = lfObject) then
+ LandGet(y, x):= lfObject
+ else if (LandGet(y, x+1) = lfObject) then
+ LandGet(y, x):= lfObject
+ else if (LandGet(y+1, x) = lfObject) then
+ LandGet(y, x):= lfObject
+ else if (LandGet(y-1, x) = lfObject) then
+ LandGet(y, x):= lfObject
+ else LandGet(y,x):= lfBasic
}
end
end
-else if ((cReducedQuality and rqBlurryLand) = 0) and ((LandPixels[Y, X] and AMask) = AMask)
-and (Land[Y, X] and (lfDamaged or lfBasic) = lfBasic)
+else if ((cReducedQuality and rqBlurryLand) = 0) and ((LandPixelGet(Y, X) and AMask) = AMask)
+and (LandGet(Y, X) and (lfDamaged or lfBasic) = lfBasic)
and (Y > topY + 1) and (Y < LAND_HEIGHT-2) and (X > leftX + 1) and (X < rightX - 1) then
begin
- if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and (((Land[y-1,x] and lfDamaged) <> 0) or ((Land[y+1,x] and lfDamaged) <> 0)))) then
+ if ((((LandGet(y, x-1) and lfDamaged) <> 0) and (((LandGet(y+1,x) and lfDamaged) <> 0)) or ((LandGet(y-1,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and (((LandGet(y-1,x) and lfDamaged) <> 0) or ((LandGet(y+1,x) and lfDamaged) <> 0)))) then
begin
- LandPixels[y,x]:=
- (((((LandPixels[y,x] and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or
- (((((LandPixels[y,x] and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or
- (((((LandPixels[y,x] and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift)
+ LandPixelSet(y,x,
+ (((((LandPixelGet(y,x) and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or
+ (((((LandPixelGet(y,x) and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or
+ (((((LandPixelGet(y,x) and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift))
end
- else if ((((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0))
- or (((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0))
- or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0))
- or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0))
- or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0))
- or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))
- or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))) then
+ else if ((((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0))
+ or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0))
+ or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0))
+ or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0))
+ or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))
+ or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))) then
begin
- LandPixels[y,x]:=
- (((((LandPixels[y,x] and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or
- (((((LandPixels[y,x] and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or
- (((((LandPixels[y,x] and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift)
+ LandPixelSet(y,x,
+ (((((LandPixelGet(y,x) and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or
+ (((((LandPixelGet(y,x) and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or
+ (((((LandPixelGet(y,x) and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift))
end
end
end;
@@ -1308,12 +1308,12 @@
// Return true if outside of land or not the value tested, used right now for some X/Y movement that does not use normal hedgehog movement in GSHandlers.inc
-function CheckLandValue(X, Y: LongInt; LandFlag: Word): boolean; inline;
+function CheckLandValue(X, Y: LongInt; LandFlag: Word): boolean;
begin
- CheckLandValue:= ((X and LAND_WIDTH_MASK <> 0) or (Y and LAND_HEIGHT_MASK <> 0)) or ((Land[Y, X] and LandFlag) = 0)
+ CheckLandValue:= ((X and LAND_WIDTH_MASK <> 0) or (Y and LAND_HEIGHT_MASK <> 0)) or ((LandGet(Y, X) and LandFlag) = 0)
end;
-function LandBackPixel(x, y: LongInt): LongWord; inline;
+function LandBackPixel(x, y: LongInt): LongWord;
var p: PLongWordArray;
begin
if LandBackSurface = nil then
@@ -1382,30 +1382,30 @@
end;
if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then
- Land[y, x]:= Color;
+ LandSet(y, x, Color);
end
end;
-function DrawDots(x, y, xx, yy: Longint; Color: Longword): Longword; inline;
+function DrawDots(x, y, xx, yy: Longint; Color: Longword): Longword;
begin
DrawDots:= 0;
- if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (Land[y + yy, x + xx] <> Color) then
- begin inc(DrawDots); Land[y + yy, x + xx]:= Color; end;
- if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (Land[y - yy, x + xx] <> Color) then
- begin inc(DrawDots); Land[y - yy, x + xx]:= Color; end;
- if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (Land[y + yy, x - xx] <> Color) then
- begin inc(DrawDots); Land[y + yy, x - xx]:= Color; end;
- if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (Land[y - yy, x - xx] <> Color) then
- begin inc(DrawDots); Land[y - yy, x - xx]:= Color; end;
- if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (Land[y + xx, x + yy] <> Color) then
- begin inc(DrawDots); Land[y + xx, x + yy]:= Color; end;
- if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (Land[y - xx, x + yy] <> Color) then
- begin inc(DrawDots); Land[y - xx, x + yy]:= Color; end;
- if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (Land[y + xx, x - yy] <> Color) then
- begin inc(DrawDots); Land[y + xx, x - yy]:= Color; end;
- if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (Land[y - xx, x - yy] <> Color) then
- begin inc(DrawDots); Land[y - xx, x - yy]:= Color; end;
+ if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + yy, x + xx) <> Color) then
+ begin inc(DrawDots); LandSet(y + yy, x + xx, Color); end;
+ if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - yy, x + xx) <> Color) then
+ begin inc(DrawDots); LandSet(y - yy, x + xx, Color); end;
+ if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + yy, x - xx) <> Color) then
+ begin inc(DrawDots); LandSet(y + yy, x - xx, Color); end;
+ if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - yy, x - xx) <> Color) then
+ begin inc(DrawDots); LandSet(y - yy, x - xx, Color); end;
+ if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + xx, x + yy) <> Color) then
+ begin inc(DrawDots); LandSet(y + xx, x + yy, Color); end;
+ if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - xx, x + yy) <> Color) then
+ begin inc(DrawDots); LandSet(y - xx, x + yy, Color); end;
+ if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + xx, x - yy) <> Color) then
+ begin inc(DrawDots); LandSet(y + xx, x - yy, Color); end;
+ if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - xx, x - yy) <> Color) then
+ begin inc(DrawDots); LandSet(y - xx, x - yy, Color); end;
end;
function DrawLines(X1, Y1, X2, Y2, XX, YY: LongInt; color: Longword): Longword;
@@ -1512,9 +1512,9 @@
xx:= dx - r + x;
if (xx = x) and (yy = y) then
s[dx + 1]:= 'X'
- else if Land[yy, xx] > 255 then
+ else if LandGet(yy, xx) > 255 then
s[dx + 1]:= 'O'
- else if Land[yy, xx] > 0 then
+ else if LandGet(yy, xx) > 0 then
s[dx + 1]:= '*'
else
s[dx + 1]:= '.'
--- a/hedgewars/uLandObjects.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLandObjects.pas Tue Dec 31 15:19:43 2024 +0100
@@ -25,18 +25,18 @@
procedure AddObjects();
procedure FreeLandObjects();
procedure LoadThemeConfig;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface);
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word);
procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean);
procedure BlitOverlayAndGenerateCollisionInfo(cpX, cpY: Longword; Image: PSDL_Surface);
procedure BlitImageUsingMask(cpX, cpY: Longword; Image, Mask: PSDL_Surface);
procedure AddOnLandObjects(Surface: PSDL_Surface);
-procedure SetLand(var LandWord: Word; Pixel: LongWord); inline;
+procedure SetLand(y, x: LongInt; Pixel: LongWord);
implementation
uses uStore, uConsts, uConsole, uRandom, uSound
, uTypes, uVariables, uDebug, uUtils
- , uPhysFSLayer, uRenderUtils;
+ , uPhysFSLayer, uRenderUtils, uLandUtils;
const MaxRects = 512;
MAXOBJECTRECTS = 16;
@@ -84,37 +84,37 @@
ThemeObjects: TThemeObjects;
SprayObjects: TSprayObjects;
-procedure SetLand(var LandWord: Word; Pixel: LongWord); inline;
+procedure SetLand(y, x: LongInt; Pixel: LongWord);
begin
// this an if instead of masking colours to avoid confusing map creators
if ((AMask and Pixel) = 0) then
- LandWord:= 0
+ LandSet(y, x, 0)
else if (Pixel and AMask > 0) and (Pixel and RMask > 0) and (Pixel and GMask > 0) and (Pixel and BMask > 0) then // whiteish
- LandWord:= lfObject
+ LandSet(y, x, lfObject)
else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask = 0) and (Pixel and BMask = 0) then // blackish
begin
- LandWord:= lfBasic;
+ LandSet(y, x, lfBasic);
disableLandBack:= false
end
else if (Pixel and AMask > 0) and (Pixel and RMask > 0) and (Pixel and GMask = 0) and (Pixel and BMask = 0) then // reddish
- LandWord:= lfIndestructible
+ LandSet(y, x, lfIndestructible)
else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask = 0) and (Pixel and BMask > 0) then // blueish
- LandWord:= lfObject or lfIce
+ LandSet(y, x, lfObject or lfIce)
else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask > 0) and (Pixel and BMask = 0) then // greenish
- LandWord:= lfObject or lfBouncy
+ LandSet(y, x, lfObject or lfBouncy)
end;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline;
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface);
begin
BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, 0, false);
end;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word);
begin
BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, LandFlags, false);
end;
-function LerpByte(src, dst: Byte; l: LongWord): LongWord; inline;
+function LerpByte(src, dst: Byte; l: LongWord): LongWord;
begin
LerpByte:= ((255 - l) * src + l * dst) div 255;
end;
@@ -153,9 +153,9 @@
color:= p^[x];
if (cReducedQuality and rqBlurryLand) = 0 then
- pLandColor:= @LandPixels[cpY + y, cpX + x]
+ pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x])
else
- pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
+ pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]);
landColor:= pLandColor^;
alpha:= (landColor and AMask) shr AShift;
@@ -173,8 +173,8 @@
end;
- if ((color and AMask) <> 0) and (Land[cpY + y, cpX + x] <= lfAllObjMask) then
- Land[cpY + y, cpX + x]:= lfObject or LandFlags
+ if ((color and AMask) <> 0) and (LandGet(cpY + y, cpX + x) <= lfAllObjMask) then
+ LandSet(cpY + y, cpX + x, lfObject or LandFlags)
end;
p:= PLongwordArray(@(p^[Image^.pitch shr 2]))
end;
@@ -208,9 +208,9 @@
if (color and AMask) <> 0 then
begin
if (cReducedQuality and rqBlurryLand) = 0 then
- pLandColor:= @LandPixels[cpY + y, cpX + x]
+ pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x])
else
- pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
+ pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]);
alpha:= (color and AMask) shr AShift;
if ((alpha <> $FF) and ((pLandColor^) <> 0)) then
@@ -224,8 +224,8 @@
end;
pLandColor^:= color;
- if Land[cpY + y, cpX + x] <= lfAllObjMask then
- Land[cpY + y, cpX + x]:= lfObject
+ if LandGet(cpY + y, cpX + x) <= lfAllObjMask then
+ LandSet(cpY + y, cpX + x, lfObject)
end;
end;
p:= PLongwordArray(@(p^[Image^.pitch shr 2]))
@@ -263,9 +263,9 @@
color:= p^[x];
if (cReducedQuality and rqBlurryLand) = 0 then
- pLandColor:= @LandPixels[cpY + y, cpX + x]
+ pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x])
else
- pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
+ pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]);
landColor:= pLandColor^;
alpha:= (landColor and AMask) shr AShift;
@@ -282,8 +282,8 @@
or (LerpByte(alpha, 255, (color and AMask) shr AShift) shl AShift);
end;
- if (Land[cpY + y, cpX + x] <= lfAllObjMask) or (Land[cpY + y, cpX + x] and lfObject <> 0) then
- SetLand(Land[cpY + y, cpX + x], mp^[x]);
+ if (LandGet(cpY + y, cpX + x) <= lfAllObjMask) or (LandGet(cpY + y, cpX + x) and lfObject <> 0) then
+ SetLand(cpY + y, cpX + x, mp^[x]);
end;
p:= PLongwordArray(@(p^[Image^.pitch shr 2]));
@@ -341,7 +341,7 @@
begin
lRes:= 0;
for i:= y to Pred(y + h) do
- if Land[i, x] <> 0 then
+ if LandGet(i, x) <> 0 then
inc(lRes);
CountNonZeroz:= lRes;
end;
@@ -425,8 +425,8 @@
begin
bRes:= ((rect.y and LAND_HEIGHT_MASK) = 0) and ((by and LAND_HEIGHT_MASK) = 0)
and ((tmpx and LAND_WIDTH_MASK) = 0) and ((tmpx2 and LAND_WIDTH_MASK) = 0)
- and (Land[rect.y, tmpx] = Color) and (Land[by, tmpx] = Color)
- and (Land[rect.y, tmpx2] = Color) and (Land[by, tmpx2] = Color);
+ and (LandGet(rect.y, tmpx) = Color) and (LandGet(by, tmpx) = Color)
+ and (LandGet(rect.y, tmpx2) = Color) and (LandGet(by, tmpx2) = Color);
inc(tmpx);
dec(tmpx2)
end;
@@ -436,8 +436,8 @@
begin
bRes:= ((tmpy and LAND_HEIGHT_MASK) = 0) and ((tmpy2 and LAND_HEIGHT_MASK) = 0)
and ((rect.x and LAND_WIDTH_MASK) = 0) and ((bx and LAND_WIDTH_MASK) = 0)
- and (Land[tmpy, rect.x] = Color) and (Land[tmpy, bx] = Color)
- and (Land[tmpy2, rect.x] = Color) and (Land[tmpy2, bx] = Color);
+ and (LandGet(tmpy, rect.x) = Color) and (LandGet(tmpy, bx) = Color)
+ and (LandGet(tmpy2, rect.x) = Color) and (LandGet(tmpy2, bx) = Color);
inc(tmpy);
dec(tmpy2)
end;
@@ -459,7 +459,7 @@
begin
for tmpx := rect.x to bx do
begin
- if (((Land[rect.y, tmpx] and LandType) or (Land[by, tmpx] and LandType)) <> 0) then
+ if (((LandGet(rect.y, tmpx) and LandType) or (LandGet(by, tmpx) and LandType)) <> 0) then
begin
CheckLandAny := true;
exit;
@@ -467,7 +467,7 @@
end;
for tmpy := rect.y to by do
begin
- if (((Land[tmpy, rect.x] and LandType) or (Land[tmpy, bx] and LandType)) <> 0) then
+ if (((LandGet(tmpy, rect.x) and LandType) or (LandGet(tmpy, bx) and LandType)) <> 0) then
begin
CheckLandAny := true;
exit;
--- a/hedgewars/uLandOutline.pas Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-unit uLandOutline;
-
-interface
-
-uses uConsts, SDLh, uFloat;
-
-type TPixAr = record
- Count: Longword;
- ar: array[0..Pred(cMaxEdgePoints)] of TPoint;
- end;
-
-procedure DrawEdge(var pa: TPixAr; value: Word);
-procedure FillLand(x, y: LongInt; border, value: Word);
-procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat);
-
-implementation
-
-uses uLandGraphics, uDebug, uVariables, uLandTemplates;
-
-
-var Stack: record
- Count: Longword;
- points: array[0..8192] of record
- xl, xr, y, dir: LongInt;
- end
- end;
-
-
-procedure Push(_xl, _xr, _y, _dir: LongInt);
-begin
- if checkFails(Stack.Count <= 8192, 'FillLand: stack overflow', true) then exit;
- _y:= _y + _dir;
- if (_y < 0) or (_y >= LAND_HEIGHT) then
- exit;
- with Stack.points[Stack.Count] do
- begin
- xl:= _xl;
- xr:= _xr;
- y:= _y;
- dir:= _dir
- end;
- inc(Stack.Count)
-end;
-
-procedure Pop(var _xl, _xr, _y, _dir: LongInt);
-begin
- dec(Stack.Count);
- with Stack.points[Stack.Count] do
- begin
- _xl:= xl;
- _xr:= xr;
- _y:= y;
- _dir:= dir
- end
-end;
-
-procedure FillLand(x, y: LongInt; border, value: Word);
-var xl, xr, dir: LongInt;
-begin
- Stack.Count:= 0;
- xl:= x - 1;
- xr:= x;
- Push(xl, xr, y, -1);
- Push(xl, xr, y, 1);
- dir:= 0;
- while Stack.Count > 0 do
- begin
- Pop(xl, xr, y, dir);
- while (xl > 0) and (Land[y, xl] <> border) and (Land[y, xl] <> value) do
- dec(xl);
- while (xr < LAND_WIDTH - 1) and (Land[y, xr] <> border) and (Land[y, xr] <> value) do
- inc(xr);
- while (xl < xr) do
- begin
- while (xl <= xr) and ((Land[y, xl] = border) or (Land[y, xl] = value)) do
- inc(xl);
- x:= xl;
- while (xl <= xr) and (Land[y, xl] <> border) and (Land[y, xl] <> value) do
- begin
- Land[y, xl]:= value;
- inc(xl)
- end;
- if x < xl then
- begin
- Push(x, Pred(xl), y, dir);
- Push(x, Pred(xl), y,-dir);
- end;
- end;
- end;
-end;
-
-procedure DrawEdge(var pa: TPixAr; value: Word);
-var i: LongInt;
-begin
- i:= 0;
- with pa do
- while i < LongInt(Count) - 1 do
- if (ar[i + 1].X = NTPX) then
- inc(i, 2)
- else
- begin
- DrawLine(ar[i].x, ar[i].y, ar[i + 1].x, ar[i + 1].y, value);
- inc(i)
- end
-end;
-
-
-procedure Vector(p1, p2, p3: TPoint; var Vx, Vy: hwFloat);
-var d1, d2, d: hwFloat;
-begin
- Vx:= int2hwFloat(p1.X - p3.X);
- Vy:= int2hwFloat(p1.Y - p3.Y);
-
- d2:= Distance(Vx, Vy);
-
- if d2.QWordValue = 0 then
- begin
- Vx:= _0;
- Vy:= _0
- end
- else
- begin
- d:= DistanceI(p2.X - p1.X, p2.Y - p1.Y);
- d1:= DistanceI(p2.X - p3.X, p2.Y - p3.Y);
-
- if d1 < d then
- d:= d1;
- if d2 < d then
- d:= d2;
-
- d2:= d * _1div3 / d2;
-
- Vx:= Vx * d2;
- Vy:= Vy * d2
- end
-end;
-
-procedure AddLoopPoints(var pa, opa: TPixAr; StartI, EndI: LongInt; Delta: hwFloat);
-var i, pi, ni: LongInt;
- NVx, NVy, PVx, PVy: hwFloat;
- x1, x2, y1, y2: LongInt;
- tsq, tcb, t, r1, r2, r3, cx1, cx2, cy1, cy2: hwFloat;
- X, Y: LongInt;
-begin
- if pa.Count < cMaxEdgePoints - 2 then
- begin
- pi:= EndI;
- i:= StartI;
- ni:= Succ(StartI);
- {$HINTS OFF}
- Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy);
- {$HINTS ON}
- repeat
- i:= ni;
- inc(pi);
- if pi > EndI then
- pi:= StartI;
- inc(ni);
- if ni > EndI then
- ni:= StartI;
- PVx:= NVx;
- PVy:= NVy;
- Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy);
-
- x1:= opa.ar[pi].x;
- y1:= opa.ar[pi].y;
- x2:= opa.ar[i].x;
- y2:= opa.ar[i].y;
-
- cx1:= int2hwFloat(x1) - PVx;
- cy1:= int2hwFloat(y1) - PVy;
- cx2:= int2hwFloat(x2) + NVx;
- cy2:= int2hwFloat(y2) + NVy;
- t:= _0;
- while (t.Round = 0) and (pa.Count < cMaxEdgePoints-2) do
- begin
- tsq:= t * t;
- tcb:= tsq * t;
- r1:= (_1 - t*3 + tsq*3 - tcb);
- r2:= ( t*3 - tsq*6 + tcb*3);
- r3:= ( tsq*3 - tcb*3);
- X:= hwRound(r1 * x1 + r2 * cx1 + r3 * cx2 + tcb * x2);
- Y:= hwRound(r1 * y1 + r2 * cy1 + r3 * cy2 + tcb * y2);
- t:= t + Delta;
- pa.ar[pa.Count].x:= X;
- pa.ar[pa.Count].y:= Y;
- inc(pa.Count);
- //TryDo(pa.Count <= cMaxEdgePoints, 'Edge points overflow', true)
- end;
- until i = StartI;
- end;
-
- pa.ar[pa.Count].x:= opa.ar[StartI].X;
- pa.ar[pa.Count].y:= opa.ar[StartI].Y;
- inc(pa.Count)
-end;
-
-procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat);
-var i, StartLoop: LongInt;
- opa: TPixAr;
-begin
-opa:= pa;
-pa.Count:= 0;
-i:= 0;
-StartLoop:= 0;
-while (i < LongInt(opa.Count)) and (pa.Count < cMaxEdgePoints-1) do
- if (opa.ar[i + 1].X = NTPX) then
- begin
- AddLoopPoints(pa, opa, StartLoop, i, Delta);
- inc(i, 2);
- StartLoop:= i;
- pa.ar[pa.Count].X:= NTPX;
- pa.ar[pa.Count].Y:= 0;
- inc(pa.Count);
- end else inc(i)
-end;
-
-end.
--- a/hedgewars/uLandTexture.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLandTexture.pas Tue Dec 31 15:19:43 2024 +0100
@@ -30,7 +30,7 @@
procedure SetLandTexture;
implementation
-uses uConsts, GLunit, uTypes, uVariables, uTextures, uDebug, uRender, uUtils;
+uses uConsts, GLunit, uTypes, uVariables, uTextures, uDebug, uRender, uUtils, uLandUtils;
const TEXSIZE = 128;
// in avoid tile borders stretch the blurry texture by 1 pixel more
@@ -50,7 +50,7 @@
var ty: Longword;
begin
for ty:= 0 to TEXSIZE - 1 do
- Move(LandPixels[y * TEXSIZE + ty, x * TEXSIZE], tmpPixels[ty, 0], sizeof(Longword) * TEXSIZE);
+ Move(LandPixelRow(y * TEXSIZE + ty)^[x * TEXSIZE], tmpPixels[ty, 0], sizeof(Longword) * TEXSIZE);
Pixels:= @tmpPixels
end;
@@ -60,7 +60,7 @@
begin
for ty:= 0 to TEXSIZE - 1 do
for tx:= 0 to TEXSIZE - 1 do
- tmpPixels[ty, tx]:= Land[y * TEXSIZE + ty, x * TEXSIZE + tx] or AMask;
+ tmpPixels[ty, tx]:= LandGet(y * TEXSIZE + ty, x * TEXSIZE + tx) or AMask;
Pixels2:= @tmpPixels
end;
@@ -129,14 +129,14 @@
// first check edges
while isEmpty and (ty < TEXSIZE) do
begin
- isEmpty:= LandPixels[ly + ty, lx] and AMask = 0;
- if isEmpty then isEmpty:= LandPixels[ly + ty, Pred(lx + TEXSIZE)] and AMask = 0;
+ isEmpty:= LandPixelGet(ly + ty, lx) and AMask = 0;
+ if isEmpty then isEmpty:= LandPixelGet(ly + ty, Pred(lx + TEXSIZE)) and AMask = 0;
inc(ty)
end;
while isEmpty and (tx < TEXSIZE-1) do
begin
- isEmpty:= LandPixels[ly, lx + tx] and AMask = 0;
- if isEmpty then isEmpty:= LandPixels[Pred(ly + TEXSIZE), lx + tx] and AMask = 0;
+ isEmpty:= LandPixelGet(ly, lx + tx) and AMask = 0;
+ if isEmpty then isEmpty:= LandPixelGet(Pred(ly + TEXSIZE), lx + tx) and AMask = 0;
inc(tx)
end;
// then search every other remaining. does this sort of stuff defeat compiler opts?
@@ -146,7 +146,7 @@
tx:= 2;
while isEmpty and (tx < TEXSIZE-1) do
begin
- isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0;
+ isEmpty:= LandPixelGet(ly + ty, lx + tx) and AMask = 0;
inc(tx,2)
end;
inc(ty,2);
@@ -158,7 +158,7 @@
tx:= 1;
while isEmpty and (tx < TEXSIZE-1) do
begin
- isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0;
+ isEmpty:= LandPixelGet(ly + ty, lx + tx) and AMask = 0;
inc(tx,2)
end;
inc(ty,2);
--- a/hedgewars/uLandUtils.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uLandUtils.pas Tue Dec 31 15:19:43 2024 +0100
@@ -1,12 +1,159 @@
unit uLandUtils;
interface
+uses SDLh;
+procedure GenerateOutlineTemplatedLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
+procedure GenerateWfcTemplatedLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
+procedure GenerateMazeLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
procedure ResizeLand(width, height: LongWord);
+procedure DisposeLand();
procedure InitWorldEdges();
+function LandGet(y, x: LongInt): Word;
+procedure LandSet(y, x: LongInt; value: Word);
+function LandRow(row: LongInt): PWordArray;
+
+procedure FillLand(x, y: LongInt; border, value: Word);
+
+function LandPixelGet(y, x: LongInt): Longword;
+procedure LandPixelSet(y, x: LongInt; value: Longword);
+function LandPixelRow(row: LongInt): PLongwordArray;
+
+var gameField: pointer;
+
implementation
uses uUtils, uConsts, uVariables, uTypes;
+{$linklib hwengine_future}
+
+function create_empty_game_field(width, height: Longword): pointer; cdecl; external;
+procedure get_game_field_parameters(game_field: pointer; var width: LongInt; var height: LongInt; var play_width: LongInt; var play_height: LongInt); cdecl; external;
+procedure dispose_game_field(game_field: pointer); cdecl; external;
+
+function land_get(game_field: pointer; x, y: LongInt): Word; cdecl; external;
+procedure land_set(game_field: pointer; x, y: LongInt; value: Word); cdecl; external;
+function land_row(game_field: pointer; row: LongInt): PWordArray; cdecl; external;
+procedure land_fill(game_field: pointer; x, y: LongInt; border, fill: Word); cdecl; external;
+
+function land_pixel_get(game_field: pointer; x, y: LongInt): Longword; cdecl; external;
+procedure land_pixel_set(game_field: pointer; x, y: LongInt; value: Longword); cdecl; external;
+function land_pixel_row(game_field: pointer; row: LongInt): PLongwordArray; cdecl; external;
+
+function generate_outline_templated_game_field(feature_size: Longword; seed, template_type, data_path: PChar): pointer; cdecl; external;
+function generate_wfc_templated_game_field(feature_size: Longword; seed, template_type, data_path: PChar): pointer; cdecl; external;
+function generate_maze_game_field(feature_size: Longword; seed, template_type, data_path: PChar): pointer; cdecl; external;
+procedure apply_theme(game_field: pointer; data_path, theme_name: PChar); cdecl; external;
+
+function LandGet(y, x: LongInt): Word;
+begin
+ LandGet:= land_get(gameField, x, y)
+end;
+
+procedure LandSet(y, x: LongInt; value: Word);
+begin
+ land_set(gameField, x, y, value)
+end;
+
+function LandRow(row: LongInt): PWordArray;
+begin
+ LandRow:= land_row(gameField, row)
+end;
+
+procedure FillLand(x, y: LongInt; border, value: Word);
+begin
+ land_fill(gameField, x, y, border, value)
+end;
+
+function LandPixelGet(y, x: LongInt): Longword;
+begin
+ LandPixelGet:= land_pixel_get(gameField, x, y)
+end;
+
+procedure LandPixelSet(y, x: LongInt; value: Longword);
+begin
+ land_pixel_set(gameField, x, y, value)
+end;
+
+function LandPixelRow(row: LongInt): PLongwordArray;
+begin
+ LandPixelRow:= land_pixel_row(gameField, row)
+end;
+
+procedure GenerateOutlineTemplatedLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
+begin
+ seed[byte(seed[0]) + 1]:= #0;
+ templateType[byte(templateType[0]) + 1]:= #0;
+
+ gameField:= generate_outline_templated_game_field(featureSize, @seed[1], @templateType[1], PChar(dataPath));
+ get_game_field_parameters(gameField, LAND_WIDTH, LAND_HEIGHT, playWidth, playHeight);
+
+ MaxHedgehogs:= 32;
+ hasGirders:= true;
+
+ leftX:= (LAND_WIDTH - playWidth) div 2;
+ rightX:= Pred(leftX + playWidth);
+ topY:= LAND_HEIGHT - playHeight;
+ cWaterLine:= LAND_HEIGHT;
+
+ // let's assume those are powers of two
+ LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
+ LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
+
+ SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
+
+ initScreenSpaceVars();
+end;
+
+procedure GenerateWfcTemplatedLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
+begin
+ seed[byte(seed[0]) + 1]:= #0;
+ templateType[byte(templateType[0]) + 1]:= #0;
+
+ gameField:= generate_wfc_templated_game_field(featureSize, @seed[1], @templateType[1], PChar(dataPath));
+ get_game_field_parameters(gameField, LAND_WIDTH, LAND_HEIGHT, playWidth, playHeight);
+
+ MaxHedgehogs:= 32;
+ hasGirders:= true;
+
+ leftX:= (LAND_WIDTH - playWidth) div 2;
+ rightX:= Pred(leftX + playWidth);
+ topY:= LAND_HEIGHT - playHeight;
+ cWaterLine:= LAND_HEIGHT;
+
+ // let's assume those are powers of two
+ LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
+ LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
+
+ SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
+
+ initScreenSpaceVars();
+end;
+
+procedure GenerateMazeLand(featureSize: Longword; seed, templateType: shortstring; dataPath: ansistring);
+begin
+ seed[byte(seed[0]) + 1]:= #0;
+ templateType[byte(templateType[0]) + 1]:= #0;
+
+ gameField:= generate_maze_game_field(featureSize, @seed[1], @templateType[1], PChar(dataPath));
+ get_game_field_parameters(gameField, LAND_WIDTH, LAND_HEIGHT, playWidth, playHeight);
+
+ MaxHedgehogs:= 32;
+ hasGirders:= true;
+
+ leftX:= (LAND_WIDTH - playWidth) div 2;
+ rightX:= Pred(leftX + playWidth);
+ topY:= LAND_HEIGHT - playHeight;
+ cWaterLine:= LAND_HEIGHT;
+
+ // let's assume those are powers of two
+ LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
+ LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
+
+ SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
+
+ initScreenSpaceVars();
+end;
+
procedure ResizeLand(width, height: LongWord);
var potW, potH: LongInt;
begin
@@ -19,12 +166,8 @@
LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
cWaterLine:= LAND_HEIGHT;
- if (cReducedQuality and rqBlurryLand) = 0 then
- SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)
- else
- SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2);
- SetLength(Land, LAND_HEIGHT, LAND_WIDTH);
+ gameField:= create_empty_game_field(LAND_WIDTH, LAND_HEIGHT);
SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
// 0.5 is already approaching on unplayable
if (width div 4096 >= 2) or (height div 2048 >= 2) then cMaxZoomLevel:= cMaxZoomLevel/2;
@@ -33,6 +176,11 @@
initScreenSpaceVars();
end;
+procedure DisposeLand();
+begin
+ dispose_game_field(gameField)
+end;
+
procedure InitWorldEdges();
var cy, cx, lx, ly: LongInt;
found: boolean;
@@ -70,7 +218,7 @@
for cx:= 0 to lx do
begin
for cy:= ly downto 0 do
- if Land[cy, cx] <> 0 then
+ if LandGet(cy, cx) <> 0 then
begin
leftX:= max(0, cx - cWorldEdgeDist);
// break out of both loops
@@ -85,7 +233,7 @@
for cx:= lx downto 0 do
begin
for cy:= ly downto 0 do
- if Land[cy, cx] <> 0 then
+ if LandGet(cy, cx) <> 0 then
begin
rightX:= min(lx, cx + cWorldEdgeDist);
// break out of both loops
--- a/hedgewars/uMisc.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uMisc.pas Tue Dec 31 15:19:43 2024 +0100
@@ -29,10 +29,10 @@
function doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface;
function MakeScreenshot(filename: shortstring; k: LongInt; dump: LongWord): boolean;
function GetTeamStatString(p: PTeam): shortstring;
-function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline;
+function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect;
implementation
-uses uVariables, uUtils
+uses uVariables, uUtils, uLandUtils
{$IFDEF PNG_SCREENSHOTS}, PNGh, png {$ENDIF};
type PScreenshot = ^TScreenshot;
@@ -288,18 +288,18 @@
for y:= 0 to LAND_HEIGHT-1 do
for x:= 0 to LAND_WIDTH-1 do
if dump = 2 then
- PLongWordArray(p)^[y*LAND_WIDTH+x]:= LandPixels[LAND_HEIGHT-1-y, x]
+ PLongWordArray(p)^[y*LAND_WIDTH+x]:= LandPixelGet(LAND_HEIGHT-1-y, x)
else
begin
- if Land[LAND_HEIGHT-1-y, x] and lfIndestructible = lfIndestructible then
+ if LandGet(LAND_HEIGHT-1-y, x) and lfIndestructible = lfIndestructible then
PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or RMask)
- else if Land[LAND_HEIGHT-1-y, x] and lfIce = lfIce then
+ else if LandGet(LAND_HEIGHT-1-y, x) and lfIce = lfIce then
PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or BMask)
- else if Land[LAND_HEIGHT-1-y, x] and lfBouncy = lfBouncy then
+ else if LandGet(LAND_HEIGHT-1-y, x) and lfBouncy = lfBouncy then
PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or GMask)
- else if Land[LAND_HEIGHT-1-y, x] and lfObject = lfObject then
+ else if LandGet(LAND_HEIGHT-1-y, x) and lfObject = lfObject then
PLongWordArray(p)^[y*LAND_WIDTH+x]:= $FFFFFFFF
- else if Land[LAND_HEIGHT-1-y, x] and lfBasic = lfBasic then
+ else if LandGet(LAND_HEIGHT-1-y, x) and lfBasic = lfBasic then
PLongWordArray(p)^[y*LAND_WIDTH+x]:= AMask
else
PLongWordArray(p)^[y*LAND_WIDTH+x]:= 0
@@ -353,7 +353,7 @@
end;
end;
-function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline;
+function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect;
begin
SDL_RectMake.x:= x;
SDL_RectMake.y:= y;
--- a/hedgewars/uRandom.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uRandom.pas Tue Dec 31 15:19:43 2024 +0100
@@ -32,8 +32,8 @@
procedure SetRandomSeed(Seed: shortstring; dropAdditionalPart: boolean); // Sets the seed that should be used for generating pseudo-random values.
function GetRandomf: hwFloat; // Returns a pseudo-random hwFloat.
-function GetRandom(m: LongWord): LongWord; inline; // Returns a positive pseudo-random integer smaller than m.
-procedure AddRandomness(r: LongWord); inline;
+function GetRandom(m: LongWord): LongWord; // Returns a positive pseudo-random integer smaller than m.
+procedure AddRandomness(r: LongWord);
function rndSign(num: hwFloat): hwFloat; // Returns num with a random chance of having a inverted sign.
@@ -42,13 +42,13 @@
var cirbuf: array[0..63] of Longword;
n: byte;
-procedure AddRandomness(r: LongWord); inline;
+procedure AddRandomness(r: LongWord);
begin
n:= (n + 1) and $3F;
cirbuf[n]:= cirbuf[n] xor r;
end;
-function GetNext: Longword; inline;
+function GetNext: Longword;
begin
n:= (n + 1) and $3F;
cirbuf[n]:=
@@ -90,7 +90,7 @@
GetRandomf.QWordValue:= GetNext
end;
-function GetRandom(m: LongWord): LongWord; inline;
+function GetRandom(m: LongWord): LongWord;
begin
GetNext;
GetRandom:= GetNext mod m
--- a/hedgewars/uRender.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uRender.pas Tue Dec 31 15:19:43 2024 +0100
@@ -30,18 +30,18 @@
procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
procedure DrawSprite (Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
-procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline;
+procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
procedure DrawSpriteClipped (Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
procedure DrawSpriteRotated (Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
procedure DrawSpriteRotatedF (Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
procedure DrawSpriteRotatedFReal(Sprite: TSprite; X, Y: Real; Frame, Dir: LongInt; Angle: real);
procedure DrawSpritePivotedF(Sprite: TSprite; X, Y, Frame, Dir, PivotX, PivotY: LongInt; Angle: real);
-procedure DrawTexture (X, Y: LongInt; Texture: PTexture); inline;
+procedure DrawTexture (X, Y: LongInt; Texture: PTexture);
procedure DrawTexture (X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
procedure DrawTexture2 (X, Y: LongInt; Texture: PTexture; Scale, Overlap: GLfloat);
-procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
-procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
+procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
procedure DrawTextureFromRectDir(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture; Dir: LongInt);
procedure DrawTextureCentered (X, Top: LongInt; Source: PTexture);
procedure DrawTextureF (Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
@@ -53,9 +53,9 @@
procedure DrawCircle (X, Y, Radius, Width: LongInt; color: LongWord);
procedure DrawCircleFilled (X, Y, Radius: LongInt; r, g, b, a: Byte);
-procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
+procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord);
procedure DrawLine (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
-procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); inline;
+procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord);
procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; r, g, b, a: Byte);
procedure DrawLineOnScreen (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
procedure DrawRect (rect: TSDL_Rect; r, g, b, a: Byte; Fill: boolean);
@@ -70,19 +70,19 @@
{$ENDIF}
procedure RenderSetClearColor (r, g, b, a: real);
procedure Tint (r, g, b, a: Byte);
-procedure Tint (c: Longword); inline;
-procedure untint(); inline;
-procedure setTintAdd (enable: boolean); inline;
+procedure Tint (c: Longword);
+procedure untint();
+procedure setTintAdd (enable: boolean);
// call this to finish the rendering of current frame
procedure FinishRender();
-function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
-function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline;
+function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean;
+function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean;
// 0 => not offscreen, <0 => left/top of screen >0 => right/below of screen
-function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline;
-function isDyAreaOffscreen(Y, Height: LongInt): LongInt; inline;
+function isDxAreaOffscreen(X, Width: LongInt): LongInt;
+function isDyAreaOffscreen(Y, Height: LongInt): LongInt;
procedure SetScale(f: GLfloat);
procedure UpdateViewLimits();
@@ -97,15 +97,15 @@
procedure EnableTexture(enable:Boolean);
-procedure SetTexCoordPointer(p: Pointer;n: Integer); inline;
-procedure SetVertexPointer(p: Pointer;n: Integer); inline;
-procedure SetColorPointer(p: Pointer;n: Integer); inline;
+procedure SetTexCoordPointer(p: Pointer;n: Integer);
+procedure SetVertexPointer(p: Pointer;n: Integer);
+procedure SetColorPointer(p: Pointer;n: Integer);
-procedure UpdateModelviewProjection(); inline;
+procedure UpdateModelviewProjection();
-procedure openglPushMatrix (); inline;
-procedure openglPopMatrix (); inline;
-procedure openglTranslatef (X, Y, Z: GLfloat); inline;
+procedure openglPushMatrix ();
+procedure openglPopMatrix ();
+procedure openglTranslatef (X, Y, Z: GLfloat);
implementation
@@ -147,12 +147,12 @@
procedure DeleteFramebuffer(var frame, depth, tex: GLuint); forward;
{$ENDIF}
-function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
+function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean;
begin
isAreaOffscreen:= (isDxAreaOffscreen(X, Width) <> 0) or (isDyAreaOffscreen(Y, Height) <> 0);
end;
-function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline;
+function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean;
var dRightX, dBottomY, dLeftX, dTopY: LongInt;
begin
dRightX:= (X - ViewRightX);
@@ -166,14 +166,14 @@
((dTopY > 0) and (sqr(dTopY) > RadiusSquared))
end;
-function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline;
+function isDxAreaOffscreen(X, Width: LongInt): LongInt;
begin
if X > ViewRightX then exit(1);
if X + Width < ViewLeftX then exit(-1);
isDxAreaOffscreen:= 0;
end;
-function isDyAreaOffscreen(Y, Height: LongInt): LongInt; inline;
+function isDyAreaOffscreen(Y, Height: LongInt): LongInt;
begin
if Y > ViewBottomY then exit(1);
if Y + Height < ViewTopY then exit(-1);
@@ -658,7 +658,7 @@
// disable/lower perspective correction (will not need it anyway)
end;
-procedure openglLoadIdentity(); inline;
+procedure openglLoadIdentity();
begin
{$IFDEF GL2}
hglLoadIdentity();
@@ -667,7 +667,7 @@
{$ENDIF}
end;
-procedure openglTranslProjMatrix(X, Y, Z: GLfloat); inline;
+procedure openglTranslProjMatrix(X, Y, Z: GLfloat);
begin
{$IFDEF GL2}
hglMatrixMode(MATRIX_PROJECTION);
@@ -680,7 +680,7 @@
{$ENDIF}
end;
-procedure openglPushMatrix(); inline;
+procedure openglPushMatrix();
begin
{$IFDEF GL2}
hglPushMatrix();
@@ -689,7 +689,7 @@
{$ENDIF}
end;
-procedure openglPopMatrix(); inline;
+procedure openglPopMatrix();
begin
{$IFDEF GL2}
hglPopMatrix();
@@ -698,7 +698,7 @@
{$ENDIF}
end;
-procedure openglTranslatef(X, Y, Z: GLfloat); inline;
+procedure openglTranslatef(X, Y, Z: GLfloat);
begin
{$IFDEF GL2}
hglTranslatef(X, Y, Z);
@@ -707,7 +707,7 @@
{$ENDIF}
end;
-procedure openglScalef(ScaleX, ScaleY, ScaleZ: GLfloat); inline;
+procedure openglScalef(ScaleX, ScaleY, ScaleZ: GLfloat);
begin
{$IFDEF GL2}
hglScalef(ScaleX, ScaleY, ScaleZ);
@@ -716,7 +716,7 @@
{$ENDIF}
end;
-procedure openglRotatef(RotX, RotY, RotZ: GLfloat; dir: LongInt); inline;
+procedure openglRotatef(RotX, RotY, RotZ: GLfloat; dir: LongInt);
{ workaround for pascal bug https://bugs.freepascal.org/view.php?id=27222 }
var tmpdir: LongInt;
begin
@@ -728,7 +728,7 @@
{$ENDIF}
end;
-procedure openglUseColorOnly(b :boolean); inline;
+procedure openglUseColorOnly(b :boolean);
begin
if b then
begin
@@ -755,7 +755,7 @@
EnableTexture(not b);
end;
-procedure UpdateModelviewProjection(); inline;
+procedure UpdateModelviewProjection();
{$IFDEF GL2}
var
mvp: TMatrix4x4f;
@@ -770,7 +770,7 @@
{$ENDIF}
end;
-procedure SetTexCoordPointer(p: Pointer; n: Integer); inline;
+procedure SetTexCoordPointer(p: Pointer; n: Integer);
begin
{$IFDEF GL2}
glBindBuffer(GL_ARRAY_BUFFER, tBuffer);
@@ -786,7 +786,7 @@
{$ENDIF}
end;
-procedure SetVertexPointer(p: Pointer; n: Integer); inline;
+procedure SetVertexPointer(p: Pointer; n: Integer);
begin
{$IFDEF GL2}
glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
@@ -802,7 +802,7 @@
{$ENDIF}
end;
-procedure SetColorPointer(p: Pointer; n: Integer); inline;
+procedure SetColorPointer(p: Pointer; n: Integer);
begin
{$IFDEF GL2}
glBindBuffer(GL_ARRAY_BUFFER, cBuffer);
@@ -887,19 +887,19 @@
UpdateModelviewProjection;
end;
-procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline;
+procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
begin
r.y:= r.y + Height * Position;
r.h:= Height;
DrawTextureFromRect(X, Y, @r, SpritesData[Sprite].Texture)
end;
-procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
begin
DrawTextureFromRectDir(X, Y, r^.w, r^.h, r, SourceTexture, 1)
end;
-procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
begin
DrawTextureFromRectDir(X, Y, W, H, r, SourceTexture, 1)
end;
@@ -967,7 +967,7 @@
end;
-procedure DrawTexture(X, Y: LongInt; Texture: PTexture); inline;
+procedure DrawTexture(X, Y: LongInt; Texture: PTexture);
begin
DrawTexture(X, Y, Texture, 1.0);
end;
@@ -1375,7 +1375,7 @@
end;
// Same as below, but with color as LongWord
-procedure DrawLine(X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
+procedure DrawLine(X0, Y0, X1, Y1, Width: Single; color: LongWord);
begin
DrawLine(X0, Y0, X1, Y1, Width, (color shr 24) and $FF, (color shr 16) and $FF, (color shr 8) and $FF, color and $FF)
end;
@@ -1400,7 +1400,7 @@
end;
// Same as below, but with color as a longword
-procedure DrawLineWrapped(X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); inline;
+procedure DrawLineWrapped(X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord);
begin
DrawLineWrapped(X0, Y0, X1, Y1, Width, goesLeft, Wraps, (color shr 24) and $FF, (color shr 16) and $FF, (color shr 8) and $FF, color and $FF);
end;
@@ -2073,7 +2073,7 @@
end;
-procedure openglTint(r, g, b, a: Byte); inline;
+procedure openglTint(r, g, b, a: Byte);
{$IFDEF GL2}
const
scale:Real = 1.0/255.0;
@@ -2109,20 +2109,20 @@
LastTint:= nc;
end;
-procedure Tint(c: Longword); inline;
+procedure Tint(c: Longword);
begin
if c = LastTint then exit;
Tint(((c shr 24) and $FF), ((c shr 16) and $FF), (c shr 8) and $FF, (c and $FF))
end;
-procedure untint(); inline;
+procedure untint();
begin
if cWhiteColor = LastTint then exit;
openglTint($FF, $FF, $FF, $FF);
LastTint:= cWhiteColor;
end;
-procedure setTintAdd(enable: boolean); inline;
+procedure setTintAdd(enable: boolean);
begin
{$IFDEF GL2}
if enable then
--- a/hedgewars/uRenderUtils.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uRenderUtils.pas Tue Dec 31 15:19:43 2024 +0100
@@ -26,13 +26,13 @@
procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean);
procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL
-procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline;
+procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt);
procedure copyToXYFromRect(src, dest: PSDL_Surface; srcX, srcY, srcW, srcH, destX, destY: LongInt);
function GetSurfaceFrameCoordinateX(Surface: PSDL_Surface; Frame, frameWidth, frameHeight: LongInt): LongInt;
function GetSurfaceFrameCoordinateY(Surface: PSDL_Surface; Frame, frameHeight: LongInt): LongInt;
-procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline;
+procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt);
procedure DrawSpriteFrame2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt; frame: LongInt);
procedure DrawLine2Surf(dest: PSDL_Surface; x0,y0,x1,y1:LongInt; r,g,b: byte);
procedure DrawRoundRect(rect: PSDL_Rect; BorderColor, FillColor: Longword; Surface: PSDL_Surface; Clear: boolean);
@@ -41,7 +41,7 @@
function RenderStringTexLim(s: ansistring; Color: Longword; font: THWFont; maxLength: LongWord): PTexture;
function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture;
-function IsTooDarkToRead(TextColor: Longword): boolean; inline;
+function IsTooDarkToRead(TextColor: Longword): boolean;
implementation
uses uVariables, uConsts, uTextures, SysUtils, uUtils, uDebug;
@@ -99,7 +99,7 @@
GetSurfaceFrameCoordinateY:= (Frame mod ny) * frameHeight;
end;
-function IsTooDarkToRead(TextColor: LongWord): boolean; inline;
+function IsTooDarkToRead(TextColor: LongWord): boolean;
var clr: TSDL_Color;
begin
clr.r:= (TextColor shr 16) and $FF;
@@ -178,7 +178,7 @@
SDL_UnlockSurface(Surface);
end;
-procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline;
+procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt);
begin
// copy from complete src
copyToXYFromRect(src, dest, 0, 0, src^.w, src^.h, destX, destY);
@@ -254,7 +254,7 @@
SDL_UnlockSurface(dest);
end;
-procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline;
+procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt);
begin
DrawSpriteFrame2Surf(sprite, dest, x, y, 0);
end;
--- a/hedgewars/uScript.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uScript.pas Tue Dec 31 15:19:43 2024 +0100
@@ -184,14 +184,14 @@
LuaError('-- SYNTAX: ' + call + ' ( ' + paramsyntax + ' )');
end;
-procedure LuaParameterCountError(expected, call, paramsyntax: shortstring; wrongcount: LongInt); inline;
+procedure LuaParameterCountError(expected, call, paramsyntax: shortstring; wrongcount: LongInt);
begin
// TODO: i18n?
LuaCallError('Wrong number of parameters! (is: ' + inttostr(wrongcount) + ', should be: '+ expected + ')', call, paramsyntax);
end;
// compare with allowed count
-function CheckLuaParamCount(L : Plua_State; count: LongInt; call, paramsyntax: shortstring): boolean; inline;
+function CheckLuaParamCount(L : Plua_State; count: LongInt; call, paramsyntax: shortstring): boolean;
var c: LongInt;
begin
c:= lua_gettop(L);
@@ -205,7 +205,7 @@
end;
// check if is either count1 or count2
-function CheckAndFetchParamCount(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+function CheckAndFetchParamCount(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean;
begin
actual:= lua_gettop(L);
if (actual <> count1) and (actual <> count2) then
@@ -218,7 +218,7 @@
end;
// check if is in range of count1 and count2
-function CheckAndFetchParamCountRange(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+function CheckAndFetchParamCountRange(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean;
begin
actual:= lua_gettop(L);
if (actual < count1) or (actual > count2) then
@@ -231,7 +231,7 @@
end;
// check if is same or higher as minCount
-function CheckAndFetchLuaParamMinCount(L : Plua_State; minCount: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+function CheckAndFetchLuaParamMinCount(L : Plua_State; minCount: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean;
begin
actual:= lua_gettop(L);
if (actual < minCount) then
@@ -243,7 +243,7 @@
CheckAndFetchLuaParamMinCount:= true;
end;
-function LuaToGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -256,7 +256,7 @@
LuaToGearTypeOrd:= i;
end;
-function LuaToVisualGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToVisualGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -269,7 +269,7 @@
LuaToVisualGearTypeOrd:= i;
end;
-function LuaToAmmoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToAmmoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -282,7 +282,7 @@
LuaToAmmoTypeOrd:= i;
end;
-function LuaToStatInfoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToStatInfoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -295,7 +295,7 @@
LuaToStatInfoTypeOrd:= i;
end;
-function LuaToSoundOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToSoundOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -334,7 +334,7 @@
LuaToGoalStrIdOrd:= i;
end;
-function LuaToHogEffectOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToHogEffectOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -347,7 +347,7 @@
LuaToHogEffectOrd:= i;
end;
-function LuaToCapGroupOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToCapGroupOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -360,7 +360,7 @@
LuaToCapGroupOrd:= i;
end;
-function LuaToSpriteOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToSpriteOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
@@ -373,7 +373,7 @@
LuaToSpriteOrd:= i;
end;
-function LuaToMapGenOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+function LuaToMapGenOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt;
begin
if lua_isnoneornil(L, i) then i:= -1
else i:= Trunc(lua_tonumber(L, i));
--- a/hedgewars/uStore.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uStore.pas Tue Dec 31 15:19:43 2024 +0100
@@ -59,7 +59,7 @@
procedure InitOffscreenOpenGL;
{$ENDIF}
-procedure WarpMouse(x, y: Word); inline;
+procedure WarpMouse(x, y: Word);
procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
procedure SetSkyColor(r, g, b: real);
@@ -1381,7 +1381,7 @@
// for sdl2 we provide a SDL_WarpMouse() which just calls this function
// this has the advantage of reducing 'uses' and 'ifdef' statements
// (SDLwindow is a private member of this module)
-procedure WarpMouse(x, y: Word); inline;
+procedure WarpMouse(x, y: Word);
begin
SDL_WarpMouseInWindow(SDLwindow, x, y);
end;
--- a/hedgewars/uTextures.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uTextures.pas Tue Dec 31 15:19:43 2024 +0100
@@ -26,14 +26,14 @@
procedure Surface2GrayScale(surf: PSDL_Surface);
function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture;
procedure PrettifySurfaceAlpha(surf: PSDL_Surface; pixels: PLongwordArray);
-procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord);
+procedure PrettifyAlpha2D(height, width: LongWord);
procedure FreeAndNilTexture(var tex: PTexture);
procedure initModule;
procedure freeModule;
implementation
-uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole;
+uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole, uLandUtils;
var TextureList: PTexture;
@@ -194,7 +194,7 @@
PrettifyAlpha(pixels, nil, si, li, w);
end;
-procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord);
+procedure PrettifyAlpha2D(height, width: LongWord);
var
// current y; last x, second last y of array;
y, lx, sly: LongWord;
@@ -203,10 +203,10 @@
lx:= width - 1;
for y:= 0 to sly do
begin
- PrettifyAlpha(PLongWordArray(pixels[y]), PLongWordArray(pixels[y+1]), 0, lx, 0);
+ PrettifyAlpha(LandPixelRow(y), LandPixelRow(y+1), 0, lx, 0);
end;
// don't forget last row
- PrettifyAlpha(PLongWordArray(pixels[sly+1]), nil, 0, lx, 0);
+ PrettifyAlpha(LandPixelRow(sly+1), nil, 0, lx, 0);
end;
function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture;
--- a/hedgewars/uTouch.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uTouch.pas Tue Dec 31 15:19:43 2024 +0100
@@ -613,7 +613,7 @@
fingerHasMoved := trunc(sqrt(sqr(finger.X-finger.historicalX) + sqr(finger.y-finger.historicalY))) > 30;
end;
-function calculateDelta(finger1, finger2: TTouch_Data): LongInt; inline;
+function calculateDelta(finger1, finger2: TTouch_Data): LongInt;
begin
calculateDelta := Round(sqrt(sqr(finger2.x-finger1.x) + sqr(finger2.y-finger1.y)));
end;
--- a/hedgewars/uTypes.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uTypes.pas Tue Dec 31 15:19:43 2024 +0100
@@ -99,7 +99,7 @@
// Gears that interact with other Gears and/or Land
// first row of gears (<gtExplosives) should be avoided when searching a spawn place
- TGearType = (gtFlame, gtHedgehog, gtMine, gtCase, gtAirMine, gtExplosives,
+ TGearType = (gtFlame, gtHedgehog, gtMine, gtCase, gtAirMine, gtExplosives,
gtGrenade, gtShell, gtGrave, gtBee, // 9
gtShotgunShot, gtPickHammer, gtRope, // 12
gtDEagleShot, gtDynamite, gtClusterBomb, gtCluster, gtShover, // 17
@@ -196,7 +196,7 @@
TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical);
TWorldEdge = (weNone, weWrap, weBounce, weSea, weSky);
TUIDisplay = (uiAll, uiNoTeams, uiNone);
- TMapGen = (mgRandom, mgMaze, mgPerlin, mgDrawn, mgForts);
+ TMapGen = (mgRandom, mgMaze, mgPerlin, mgDrawn, mgForts, mgWFC);
THHFont = record
@@ -545,8 +545,6 @@
gidInfAttack, gidResetWeps, gidPerHogAmmo, gidTagTeam, gidMoreWind);
- TLandArray = packed array of array of LongWord;
- TCollisionArray = packed array of array of Word;
TDirtyTag = packed array of array of byte;
TGearPackArray = packed array of TGear;
--- a/hedgewars/uUtils.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uUtils.pas Tue Dec 31 15:19:43 2024 +0100
@@ -53,16 +53,16 @@
function EnumToStr(const en : TMsgStrId) : shortstring; overload;
function EnumToStr(const en : TGoalStrId) : shortstring; overload;
-function Min(a, b: LongInt): LongInt; inline;
-function MinD(a, b: double) : double; inline;
-function Max(a, b: LongInt): LongInt; inline;
+function Min(a, b: LongInt): LongInt;
+function MinD(a, b: double) : double;
+function Max(a, b: LongInt): LongInt;
function IntToStr(n: LongInt): shortstring;
function StrToInt(s: shortstring): LongInt;
//function StrToInt(s: shortstring; var success: boolean): LongInt;
function FloatToStr(n: hwFloat): shortstring;
-function DxDy2Angle(const _dY, _dX: hwFloat): real; inline;
+function DxDy2Angle(const _dY, _dX: hwFloat): real;
function DxDy2Angle32(const _dY, _dX: hwFloat): LongInt;
function DxDy2AttackAngle(const _dY, _dX: hwFloat): LongInt;
function DxDy2AttackAnglef(const _dY, _dX: extended): LongInt;
@@ -73,16 +73,16 @@
function DecodeBase64(s: shortstring): shortstring;
function isPowerOf2(i: Longword): boolean;
-function toPowerOf2(i: Longword): Longword; inline;
+function toPowerOf2(i: Longword): Longword;
-function endian(independent: LongWord): LongWord; inline;
+function endian(independent: LongWord): LongWord;
function CheckCJKFont(s: ansistring; font: THWFont): THWFont;
procedure AddFileLog(s: shortstring);
procedure AddFileLogRaw(s: pchar); cdecl;
-function CheckNoTeamOrHH: boolean; inline;
+function CheckNoTeamOrHH: boolean;
function GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt;
function GetLaunchY(at: TAmmoType; angle: LongInt): LongInt;
@@ -102,7 +102,7 @@
procedure SetLengthA(var s: ansistring; len: Longword);
{$ENDIF}
-function isPhone: Boolean; inline;
+function isPhone: Boolean;
{$IFDEF IPHONEOS}
procedure startLoadingIndicator; cdecl; external;
@@ -443,7 +443,7 @@
end;
-function DxDy2Angle(const _dY, _dX: hwFloat): real; inline;
+function DxDy2Angle(const _dY, _dX: hwFloat): real;
var dY, dX: Extended;
begin
dY:= hwFloat2Float(_dY);
@@ -469,7 +469,7 @@
DxDy2AttackAngle:= trunc(arctan2(dY, dX) * MaxAngleDivPI)
end;
-function DxDy2AttackAnglef(const _dY, _dX: extended): LongInt; inline;
+function DxDy2AttackAnglef(const _dY, _dX: extended): LongInt;
begin
DxDy2AttackAnglef:= trunc(arctan2(_dY, _dX) * (cMaxAngle/pi))
end;
@@ -539,7 +539,7 @@
end;
-function endian(independent: LongWord): LongWord; inline;
+function endian(independent: LongWord): LongWord;
begin
{$IFDEF ENDIAN_LITTLE}
endian:= independent;
@@ -716,7 +716,7 @@
{$ENDIF}
// this function is just to determine whether we are running on a limited screen device
-function isPhone: Boolean; inline;
+function isPhone: Boolean;
begin
isPhone:= false;
{$IFDEF IPHONEOS}
--- a/hedgewars/uVariables.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uVariables.pas Tue Dec 31 15:19:43 2024 +0100
@@ -303,7 +303,7 @@
SDLwindow: PSDL_Window;
SDLGLcontext: PSDL_GLContext;
-
+
/////////////////////////////////////
//Buttons
{$IFDEF USE_TOUCH_INTERFACE}
@@ -2589,8 +2589,6 @@
);
var
- Land: TCollisionArray;
- LandPixels: TLandArray;
LandDirty: TDirtyTag;
Flakes: TGearPackArray;
FlakesCount: Longword;
--- a/hedgewars/uVisualGears.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uVisualGears.pas Tue Dec 31 15:19:43 2024 +0100
@@ -117,7 +117,7 @@
end
end;
-function GetSprite(sprite, SDsprite: TSprite): TSprite; inline;
+function GetSprite(sprite, SDsprite: TSprite): TSprite;
begin
if SuddenDeathDmg then
exit(SDsprite)
@@ -125,7 +125,7 @@
exit(sprite);
end;
-function GetSpriteByWind(sprite, Lsprite: TSprite): TSprite; inline;
+function GetSpriteByWind(sprite, Lsprite: TSprite): TSprite;
begin
if (SpritesData[Lsprite].Texture <> nil) and (cWindSpeedf<0) then
exit(Lsprite)
@@ -133,7 +133,7 @@
exit(sprite);
end;
-function GetSpriteData(sprite, SDsprite: TSprite): PSpriteData; inline;
+function GetSpriteData(sprite, SDsprite: TSprite): PSpriteData;
begin
exit(@SpritesData[GetSprite(sprite, SDsprite)]);
end;
@@ -498,7 +498,7 @@
end;
end;
-procedure AddFlake; inline;
+procedure AddFlake;
begin
AddVisualGear(cLeftScreenBorder + random(cScreenSpace), LAND_HEIGHT-cCloudOffset+ random(cCloudOffset), vgtFlake);
end;
--- a/hedgewars/uVisualGearsHandlers.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uVisualGearsHandlers.pas Tue Dec 31 15:19:43 2024 +0100
@@ -71,7 +71,7 @@
procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
-function isSorterActive: boolean; inline;
+function isSorterActive: boolean;
procedure initModule;
implementation
@@ -573,7 +573,7 @@
end;
currsorter: PVisualGear = nil;
-function isSorterActive: boolean; inline;
+function isSorterActive: boolean;
begin
isSorterActive:= currsorter <> nil
end;
--- a/hedgewars/uVisualGearsList.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uVisualGearsList.pas Tue Dec 31 15:19:43 2024 +0100
@@ -22,9 +22,9 @@
interface
uses uTypes;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean; Layer: LongInt): PVisualGear;
procedure DeleteVisualGear(Gear: PVisualGear);
function VisualGearByUID(uid : Longword) : PVisualGear;
@@ -39,7 +39,7 @@
implementation
uses uCollisions, uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers, uScript;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear;
begin
// adjust some visual gear types if underwater
if CheckCoordInWater(X, Y) and ((Kind = vgtBeeTrace) or (Kind = vgtSmokeTrace) or (Kind = vgtEvilTrace)) then
@@ -48,12 +48,12 @@
AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false, -1);
end;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear;
begin
AddVisualGear:= AddVisualGear(X, Y, Kind, State, false, -1);
end;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
begin
AddVisualGear:= AddVisualGear(X, Y, Kind, State, Critical, -1);
end;
--- a/hedgewars/uWorld.pas Sat Sep 28 22:27:13 2024 +0200
+++ b/hedgewars/uWorld.pas Tue Dec 31 15:19:43 2024 +0100
@@ -1165,14 +1165,14 @@
var preShiftWorldDx: LongInt;
-procedure ShiftWorld(Dir: LongInt); inline;
+procedure ShiftWorld(Dir: LongInt);
begin
preShiftWorldDx:= WorldDx;
Dir := Dir * LongInt(playWidth);
WorldDx:= WorldDx + Dir;
end;
-procedure UnshiftWorld(); inline;
+procedure UnshiftWorld();
begin
WorldDx:= preShiftWorldDx;
end;
--- a/project_files/hwc/CMakeLists.txt Sat Sep 28 22:27:13 2024 +0200
+++ b/project_files/hwc/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -119,6 +119,7 @@
physfs
physlayer
m
+ hwengine_future
${HW_LINK_LIBS}
#TODO: add other libraries
)
--- a/rust/fpnum/Cargo.toml Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/fpnum/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -2,6 +2,7 @@
name = "fpnum"
version = "0.1.0"
authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
-edition = "2018"
+edition = "2021"
[dependencies]
+saturate = "0.1.0"
--- a/rust/fpnum/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/fpnum/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,4 +1,6 @@
-use std::{cmp, ops, ops::Shl};
+use std::{cmp, ops};
+use std::marker::PhantomData;
+use saturate::SaturatingInto;
const POSITIVE_MASK: u64 = 0x0000_0000_0000_0000;
const NEGATIVE_MASK: u64 = 0xFFFF_FFFF_FFFF_FFFF;
@@ -12,16 +14,20 @@
}
}
+struct FracBits<const N: u8>;
#[derive(Clone, Debug, Copy)]
-pub struct FPNum {
+pub struct FixedPoint<const FRAC_BITS: u8> {
sign_mask: u64,
value: u64,
+ _marker: PhantomData<FracBits<FRAC_BITS>>,
}
-impl FPNum {
+pub type FPNum = FixedPoint<20>;
+
+impl<const FRAC_BITS: u8> FixedPoint<FRAC_BITS> {
#[inline]
pub fn new(numerator: i32, denominator: u32) -> Self {
- FPNum::from(numerator) / denominator
+ Self::from(numerator) / denominator
}
#[inline]
@@ -49,24 +55,26 @@
Self {
sign_mask: POSITIVE_MASK,
value: self.value,
+ _marker: self._marker,
}
}
#[inline]
- pub fn round(&self) -> i32 {
- ((self.value >> 32) as i32 ^ self.sign_mask as i32).wrapping_sub(self.sign_mask as i32)
+ pub fn round(&self) -> i64 {
+ ((self.value >> FRAC_BITS) as i64 ^ self.sign_mask as i64).wrapping_sub(self.sign_mask as i64)
}
#[inline]
- pub const fn abs_round(&self) -> u32 {
- (self.value >> 32) as u32
+ pub const fn abs_round(&self) -> u64 {
+ self.value >> FRAC_BITS
}
#[inline]
pub fn sqr(&self) -> Self {
Self {
sign_mask: 0,
- value: ((self.value as u128).pow(2) >> 32) as u64,
+ value: ((self.value as u128).pow(2) >> FRAC_BITS).saturating_into(),
+ _marker: self._marker
}
}
@@ -76,92 +84,95 @@
Self {
sign_mask: POSITIVE_MASK,
- value: integral_sqrt(self.value) << 16,
+ value: integral_sqrt(self.value) << (FRAC_BITS / 2),
+ _marker: self._marker
}
}
#[inline]
- pub fn with_sign(&self, is_negative: bool) -> FPNum {
- FPNum {
+ pub fn with_sign(&self, is_negative: bool) -> Self {
+ Self {
sign_mask: bool_mask(is_negative),
..*self
}
}
#[inline]
- pub const fn with_sign_as(self, other: FPNum) -> FPNum {
- FPNum {
+ pub const fn with_sign_as(self, other: Self) -> Self {
+ Self {
sign_mask: other.sign_mask,
..self
}
}
-
+/*
#[inline]
pub const fn point(self) -> FPPoint {
FPPoint::new(self, self)
}
-
+*/
#[inline]
const fn temp_i128(self) -> i128 {
((self.value ^ self.sign_mask) as i128).wrapping_sub(self.sign_mask as i128)
}
}
-impl From<i32> for FPNum {
+impl<const FRAC_BITS: u8> From<i32> for FixedPoint<FRAC_BITS> {
#[inline]
fn from(n: i32) -> Self {
- FPNum {
+ Self {
sign_mask: bool_mask(n < 0),
- value: (n.abs() as u64) << 32,
+ value: (n.abs() as u64) << FRAC_BITS,
+ _marker: PhantomData,
}
}
}
-impl From<u32> for FPNum {
+impl<const FRAC_BITS: u8> From<u32> for FixedPoint<FRAC_BITS> {
#[inline]
fn from(n: u32) -> Self {
Self {
sign_mask: POSITIVE_MASK,
- value: (n as u64) << 32,
+ value: (n as u64) << FRAC_BITS,
+ _marker: PhantomData,
}
}
}
-impl From<FPNum> for f64 {
+impl<const FRAC_BITS: u8> From<FixedPoint<FRAC_BITS>> for f64 {
#[inline]
- fn from(n: FPNum) -> Self {
+ fn from(n: FixedPoint<FRAC_BITS>) -> Self {
if n.is_negative() {
- n.value as f64 / -0x1_0000_0000i64 as f64
+ n.value as f64 / -(1i64 << FRAC_BITS) as f64
} else {
- n.value as f64 / 0x1_0000_0000i64 as f64
+ n.value as f64 / (1i64 << FRAC_BITS) as f64
}
}
}
-impl PartialEq for FPNum {
+impl<const FRAC_BITS: u8> PartialEq for FixedPoint<FRAC_BITS> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.value == other.value && (self.sign_mask == other.sign_mask || self.value == 0)
}
}
-impl Eq for FPNum {}
+impl<const FRAC_BITS: u8> Eq for FixedPoint<FRAC_BITS> {}
-impl PartialOrd for FPNum {
+impl<const FRAC_BITS: u8> PartialOrd for FixedPoint<FRAC_BITS> {
#[inline]
- fn partial_cmp(&self, rhs: &Self) -> std::option::Option<std::cmp::Ordering> {
+ fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(rhs))
}
}
-impl Ord for FPNum {
+impl<const FRAC_BITS: u8> Ord for FixedPoint<FRAC_BITS> {
#[inline]
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
self.temp_i128().cmp(&(rhs.temp_i128()))
}
}
-impl ops::Add for FPNum {
+impl<const FRAC_BITS: u8> ops::Add for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
@@ -171,11 +182,12 @@
Self {
sign_mask: mask,
value: ((tmp as u64) ^ mask).wrapping_sub(mask),
+ _marker: PhantomData,
}
}
}
-impl ops::Sub for FPNum {
+impl<const FRAC_BITS: u8> ops::Sub for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
@@ -185,7 +197,7 @@
}
}
-impl ops::Neg for FPNum {
+impl<const FRAC_BITS: u8> ops::Neg for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
@@ -193,47 +205,51 @@
Self {
sign_mask: !self.sign_mask,
value: self.value,
+ _marker: PhantomData,
}
}
}
-impl ops::Mul for FPNum {
+impl<const FRAC_BITS: u8> ops::Mul for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Self {
sign_mask: self.sign_mask ^ rhs.sign_mask,
- value: ((self.value as u128 * rhs.value as u128) >> 32) as u64,
+ value: ((self.value as u128 * rhs.value as u128) >> FRAC_BITS).saturating_into(),
+ _marker: PhantomData,
}
}
}
-impl ops::Mul<i32> for FPNum {
+impl<const FRAC_BITS: u8> ops::Mul<i32> for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
fn mul(self, rhs: i32) -> Self {
Self {
sign_mask: self.sign_mask ^ bool_mask(rhs < 0),
- value: self.value * rhs.abs() as u64,
+ value: (self.value as u128 * rhs.abs() as u128).saturating_into(),
+ _marker: PhantomData,
}
}
}
-impl ops::Div for FPNum {
+impl<const FRAC_BITS: u8> ops::Div for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
Self {
sign_mask: self.sign_mask ^ rhs.sign_mask,
- value: (((self.value as u128) << 32) / rhs.value as u128) as u64,
+ value: (((self.value as u128) << FRAC_BITS) / rhs.value as u128).saturating_into(),
+ _marker: PhantomData,
}
}
}
-impl ops::Div<i32> for FPNum {
+impl<const FRAC_BITS: u8> ops::Div<i32> for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
@@ -241,11 +257,12 @@
Self {
sign_mask: self.sign_mask ^ bool_mask(rhs < 0),
value: self.value / rhs.abs() as u64,
+ _marker: PhantomData,
}
}
}
-impl ops::Div<u32> for FPNum {
+impl<const FRAC_BITS: u8> ops::Div<u32> for FixedPoint<FRAC_BITS> {
type Output = Self;
#[inline]
@@ -253,6 +270,7 @@
Self {
sign_mask: self.sign_mask,
value: self.value / rhs as u64,
+ _marker: PhantomData,
}
}
}
@@ -308,6 +326,7 @@
FPNum {
sign_mask: self.x_sign_mask as i32 as u64,
value: self.x_value,
+ _marker: PhantomData,
}
}
@@ -316,6 +335,7 @@
FPNum {
sign_mask: self.y_sign_mask as i32 as u64,
value: self.y_value,
+ _marker: PhantomData,
}
}
@@ -326,7 +346,7 @@
#[inline]
pub fn max_norm(&self) -> FPNum {
- std::cmp::max(self.x().abs(), self.y().abs())
+ cmp::max(self.x().abs(), self.y().abs())
}
#[inline]
@@ -345,6 +365,7 @@
FPNum {
sign_mask: POSITIVE_MASK,
value: integral_sqrt_ext(sqr),
+ _marker: PhantomData,
}
}
}
@@ -503,15 +524,17 @@
}
#[inline]
-pub fn distance<T>(x: T, y: T) -> FPNum
+pub fn distance<T, const FRAC_BITS: u8>(x: T, y: T) -> FixedPoint<FRAC_BITS>
where
- T: Into<i64> + std::fmt::Debug,
+ T: Into<i128> + std::fmt::Debug,
{
- let sqr: u128 = (x.into().pow(2) as u128).shl(64) + (y.into().pow(2) as u128).shl(64);
+ let [x_squared, y_squared] = [x, y].map(|i| (i.into().pow(2) as u128).saturating_mul(1 << FRAC_BITS << FRAC_BITS));
+ let sqr: u128 = x_squared.saturating_add(y_squared);
- FPNum {
+ FixedPoint {
sign_mask: POSITIVE_MASK,
value: integral_sqrt_ext(sqr),
+ _marker: PhantomData,
}
}
--- a/rust/integral-geometry/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/integral-geometry/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -4,7 +4,7 @@
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, RangeInclusive, Sub, SubAssign},
};
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub struct Point {
pub x: i32,
pub y: i32,
@@ -61,6 +61,14 @@
pub const fn rotate90(self) -> Self {
Self::new(self.y, -self.x)
}
+ #[inline]
+ pub const fn rotate180(self) -> Self {
+ Self::new(-self.x, -self.y)
+ }
+ #[inline]
+ pub const fn rotate270(self) -> Self {
+ Self::new(-self.y, self.x)
+ }
#[inline]
pub const fn cross(self, other: Point) -> i32 {
@@ -99,7 +107,7 @@
#[inline]
pub fn from_fppoint(p: &FPPoint) -> Self {
- Self::new(p.x().round(), p.y().round())
+ Self::new(p.x().round() as i32, p.y().round() as i32)
}
}
@@ -164,6 +172,11 @@
}
#[inline]
+ pub fn is_square(&self) -> bool {
+ self.width == self.height
+ }
+
+ #[inline]
pub const fn contains(&self, other: Self) -> bool {
self.width >= other.width && self.height >= other.height
}
@@ -491,7 +504,7 @@
#[inline]
pub fn with_margin(&self, margin: i32) -> Self {
- let offset = Point::diag(margin);
+ let offset = Point::new(min(margin, self.width() as i32 / 2), min(margin, self.height() as i32 / 2));
Self::new(self.top_left() + offset, self.bottom_right() - offset)
}
@@ -601,11 +614,11 @@
self.vertices.insert(edge_index + 1, vertex);
}
- pub fn iter<'a>(&'a self) -> impl Iterator<Item = &Point> + 'a {
+ pub fn iter(&self) -> impl Iterator<Item = &Point> {
(&self.vertices[..self.edges_count()]).iter()
}
- pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = &mut Point> + 'a {
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Point> {
let edges_count = self.edges_count();
let start = self.vertices.as_mut_ptr();
let end = unsafe { start.add(edges_count) };
--- a/rust/land2d/Cargo.toml Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/land2d/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -2,7 +2,7 @@
name = "land2d"
version = "0.1.0"
authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
-edition = "2018"
+edition = "2021"
[dependencies]
vec2d = { path = "../vec2d" }
--- a/rust/land2d/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/land2d/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,24 +1,25 @@
-use std::{cmp, ops::Index};
-
+use std::{cmp, ops::Index, ops::IndexMut};
+use vec2d::Vec2D;
use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, PotSize, Rect, Size, SizeMask};
+#[derive(Debug)]
pub struct Land2D<T> {
pixels: vec2d::Vec2D<T>,
play_box: Rect,
mask: SizeMask,
}
-impl<T: Copy + PartialEq> Land2D<T> {
- pub fn new(play_size: Size, fill_value: T) -> Self {
+impl<T: Copy + PartialEq + Default> Land2D<T> {
+ pub fn new(play_size: &Size, fill_value: T) -> Self {
let real_size = play_size.next_power_of_two();
let top_left = Point::new(
((real_size.width() - play_size.width) / 2) as i32,
(real_size.height() - play_size.height) as i32,
);
- let play_box = Rect::from_size(top_left, play_size);
+ let play_box = Rect::from_size(top_left, *play_size);
Self {
play_box,
- pixels: vec2d::Vec2D::new(real_size.size(), fill_value),
+ pixels: vec2d::Vec2D::new(&real_size.size(), fill_value),
mask: real_size.to_mask(),
}
}
@@ -99,6 +100,18 @@
}
#[inline]
+ pub fn get(&self, y: i32, x: i32) -> T {
+ if self.is_valid_coordinate(x, y) {
+ unsafe {
+ // hey, I just checked that coordinates are valid!
+ *self.pixels.get_unchecked(y as usize, x as usize)
+ }
+ } else {
+ T::default()
+ }
+ }
+
+ #[inline]
pub fn map_point<U: Default, F: FnOnce(&mut T) -> U>(&mut self, point: Point, f: F) -> U {
self.map(point.y, point.x, f)
}
@@ -288,6 +301,30 @@
}
}
+impl<T> IndexMut<usize> for Land2D<T> {
+ #[inline]
+ fn index_mut(&mut self, row: usize) -> &mut [T] {
+ &mut self.pixels[row]
+ }
+}
+
+impl<T> From<Vec2D<T>> for Land2D<T> {
+ fn from(vec: Vec2D<T>) -> Self {
+ let actual_size = vec.size();
+ let pot_size = actual_size.next_power_of_two();
+
+ assert_eq!(actual_size, pot_size.size());
+
+ let top_left = Point::new(0, 0);
+ let play_box = Rect::from_size(top_left, actual_size);
+ Self {
+ play_box,
+ pixels: vec,
+ mask: pot_size.to_mask(),
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
--- a/rust/landgen/Cargo.toml Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/landgen/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -2,9 +2,18 @@
name = "landgen"
version = "0.1.0"
authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
-edition = "2018"
+edition = "2021"
[dependencies]
integral-geometry = { path = "../integral-geometry" }
land2d = { path = "../land2d" }
-itertools = "0.7.8"
+vec2d = { path = "../vec2d" }
+itertools = "0.13"
+png = "0.17"
+
+[dev-dependencies]
+criterion = "0.5"
+
+[[bench]]
+name = "benchmark"
+harness = false
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/benches/benchmark.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,58 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use integral_geometry::{Point, Rect, Size};
+use landgen;
+use landgen::{LandGenerationParameters, LandGenerator};
+use landgen::outline_template_based::outline_template::OutlineTemplate;
+use landgen::outline_template_based::template_based::TemplatedLandGenerator;
+
+pub fn generate_outline(c: &mut Criterion) {
+ let template = OutlineTemplate {
+ islands: vec![
+ vec![
+ Rect::from_box(273, 273, 2048, 2048),
+ Rect::from_box(683, 683, 32, 63),
+ Rect::from_box(1092, 1092, 2048, 2048),
+ ],
+ vec![
+ Rect::from_box(1638, 1638, 2048, 2048),
+ Rect::from_box(2048, 2048, 32, 63),
+ Rect::from_box(2458, 2458, 2048, 2048),
+ ],
+ vec![
+ Rect::from_box(3004, 3004, 2048, 2048),
+ Rect::from_box(3413, 3413, 32, 63),
+ Rect::from_box(3823, 3823, 2048, 2048),
+ ],
+ ],
+ walls: vec![],
+ fill_points: vec![Point::new(1, 0)],
+ size: Size {
+ width: 4096,
+ height: 2048,
+ },
+ can_flip: false,
+ can_invert: false,
+ can_mirror: false,
+ is_negative: false,
+};
+
+ let parameters = LandGenerationParameters::new(
+ 0u16,
+ 32768u16,
+ 10,
+ false,
+ false
+ );
+
+ c.bench_function("outline_generation", |b| b.iter(|| {
+ fn prng() -> impl Iterator<Item = u32> {
+ (0..).map(|i| (i as u64 * 31_234_773 % 2_017_234_567) as u32)
+ }
+
+ let gen = TemplatedLandGenerator::new(black_box(template.clone()));
+ gen.generate_land(black_box(¶meters), &mut prng())
+ }));
+}
+
+criterion_group!(benches, generate_outline);
+criterion_main!(benches);
--- a/rust/landgen/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/landgen/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,7 +1,8 @@
-mod outline;
-pub mod outline_template;
-pub mod template_based;
+pub mod maze;
+pub mod outline_template_based;
+pub mod wavefront_collapse;
+#[derive(Clone, Copy)]
pub struct LandGenerationParameters<T> {
zero: T,
basic: T,
@@ -10,7 +11,7 @@
skip_bezier: bool,
}
-impl<T: Copy + PartialEq> LandGenerationParameters<T> {
+impl<T: Copy + PartialEq + Default> LandGenerationParameters<T> {
pub fn new(
zero: T,
basic: T,
@@ -26,20 +27,20 @@
skip_bezier,
}
}
+
+ pub fn zero(&self) -> T {
+ self.zero
+ }
+
+ pub fn basic(&self) -> T {
+ self.basic
+ }
}
pub trait LandGenerator {
- fn generate_land<T: Copy + PartialEq, I: Iterator<Item = u32>>(
+ fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
&self,
parameters: &LandGenerationParameters<T>,
random_numbers: &mut I,
) -> land2d::Land2D<T>;
}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/maze.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,477 @@
+use crate::outline_template_based::outline::OutlinePoints;
+use crate::{LandGenerationParameters, LandGenerator};
+use integral_geometry::{Point, Polygon, Rect, Size};
+use land2d::Land2D;
+
+#[derive(Clone)]
+pub struct MazeTemplate {
+ pub width: usize,
+ pub height: usize,
+ pub cell_size: usize,
+ pub inverted: bool,
+ pub distortion_limiting_factor: u32,
+ pub braidness: u32,
+}
+
+struct Maze {
+ inverted: bool,
+ braidness: u32,
+ off: Point,
+ num_cells: Size,
+ num_edges: Size,
+ seen_cells: Size,
+ cell_size: usize,
+ seen_list: Vec<Vec<Option<usize>>>,
+ walls: Vec<Vec<Vec<bool>>>,
+ edge_list: Vec<Vec<Vec<bool>>>,
+ last_cell: Vec<Point>,
+ came_from: Vec<Vec<Point>>,
+ came_from_pos: Vec<i32>,
+}
+
+fn in_line(p1: &Point, p2: &Point, p3: &Point) -> bool {
+ p1.x == p2.x && p2.x == p3.x || p1.y == p2.y && p2.y == p3.y
+}
+
+#[derive(Clone, Copy)]
+struct Direction(Point);
+
+impl Direction {
+ #[inline]
+ pub fn new(direction: usize) -> Self {
+ match direction % 4 {
+ 0 => Self(Point::new(0, -1)),
+ 1 => Self(Point::new(1, 0)),
+ 2 => Self(Point::new(0, 1)),
+ 3 => Self(Point::new(-1, 0)),
+ _ => panic!("Impossible"),
+ }
+ }
+
+ #[inline]
+ pub fn rotate_right(self) -> Self {
+ Self(self.0.rotate90())
+ }
+
+ #[inline]
+ pub fn rotate_left(self) -> Self {
+ Self(self.0.rotate270())
+ }
+
+ #[inline]
+ pub fn to_edge(self) -> Self {
+ Self(Point::new(
+ if self.0.x < 0 { 0 } else { self.0.x },
+ if self.0.y < 0 { 0 } else { self.0.y },
+ ))
+ }
+
+ #[inline]
+ pub fn orientation(&self) -> usize {
+ if self.0.x == 0 {
+ 0
+ } else {
+ 1
+ }
+ }
+}
+
+impl Maze {
+ pub fn new<I: Iterator<Item = u32>>(
+ size: &Size,
+ cell_size: usize,
+ num_steps: usize,
+ inverted: bool,
+ braidness: u32,
+ random_numbers: &mut I,
+ ) -> Self {
+ let num_cells = Size::new(
+ prev_odd(size.width / cell_size),
+ prev_odd(size.height / cell_size),
+ );
+
+ let num_edges = Size::new(num_cells.width - 1, num_cells.height - 1);
+ let seen_cells = Size::new(num_cells.width / 2, num_cells.height / 2);
+
+ let mut last_cell = vec![Point::diag(0); num_steps];
+ let came_from_pos = vec![0; num_steps];
+ let came_from = vec![vec![Point::diag(0); num_steps]; num_cells.area()];
+
+ let seen_list = vec![vec![None as Option<usize>; seen_cells.width]; seen_cells.height];
+ let walls = vec![vec![vec![true; seen_cells.width]; seen_cells.height]; 2];
+ let edge_list = vec![vec![vec![false; num_cells.width]; num_cells.height]; 2];
+
+ for current_step in 0..num_steps {
+ let x = random_numbers.next().unwrap_or_default() as usize % (seen_cells.width - 1)
+ / num_steps;
+ last_cell[current_step] = Point::new(
+ (x + current_step * seen_cells.width / num_steps) as i32,
+ random_numbers.next().unwrap_or_default() as i32 % seen_cells.height as i32,
+ );
+ }
+
+ let off_x = ((size.width - num_cells.width * cell_size) / 2) as i32;
+ let off_y = ((size.height - num_cells.height * cell_size) / 2) as i32;
+
+ Self {
+ inverted,
+ braidness,
+ off: Point::new(off_x, off_y),
+ num_cells,
+ num_edges,
+ seen_cells,
+ cell_size,
+ seen_list,
+ walls,
+ edge_list,
+ last_cell,
+ came_from,
+ came_from_pos,
+ }
+ }
+
+ fn see_cell<I: Iterator<Item = u32>>(
+ &mut self,
+ current_step: usize,
+ start_dir: Direction,
+ random_numbers: &mut I,
+ ) -> bool {
+ let mut dir = start_dir;
+ loop {
+ let p = self.last_cell[current_step];
+ self.seen_list[p.y as usize][p.x as usize] = Some(current_step);
+
+ let next_dir_clockwise = random_numbers.next().unwrap_or_default() % 2 == 0;
+
+ for _ in 0..5 {
+ let sp = p + dir.0;
+ let when_seen = if sp.x < 0
+ || sp.x >= self.seen_cells.width as i32
+ || sp.y < 0
+ || sp.y >= self.seen_cells.height as i32
+ {
+ Some(current_step)
+ } else {
+ self.seen_list[sp.y as usize][sp.x as usize]
+ };
+
+ match when_seen {
+ Some(a) if a == current_step => {
+ // try another direction
+ if !self.inverted
+ && random_numbers.next().unwrap_or_default() % self.braidness == 0
+ {
+ if dir.0.x == -1 && p.x > 0 {
+ self.walls[dir.orientation()][p.y as usize][p.x as usize - 1] =
+ false;
+ }
+ if dir.0.x == 1 && p.x < self.seen_cells.width as i32 - 1 {
+ self.walls[dir.orientation()][p.y as usize][p.x as usize] = false;
+ }
+ if dir.0.y == -1 && p.y > 0 {
+ self.walls[dir.orientation()][p.y as usize - 1][p.x as usize] =
+ false;
+ }
+ if dir.0.y == 1 && p.y < self.seen_cells.height as i32 - 1 {
+ self.walls[dir.orientation()][p.y as usize][p.x as usize] = false;
+ }
+ }
+
+ if next_dir_clockwise {
+ dir = dir.rotate_right();
+ } else {
+ dir = dir.rotate_left();
+ }
+ }
+ None => {
+ // cell was not seen yet, go there
+ let o_dir = dir.rotate_right().rotate_right();
+ let op = p - o_dir.to_edge().0;
+ self.walls[o_dir.orientation()][op.y as usize][op.x as usize] = false;
+ self.last_cell[current_step] = sp;
+ self.came_from_pos[current_step] += 1;
+ self.came_from[self.came_from_pos[current_step] as usize][current_step] = p;
+ return false;
+ }
+ _ => {
+ return true;
+ }
+ }
+ }
+
+ self.last_cell[current_step] =
+ self.came_from[self.came_from_pos[current_step] as usize][current_step];
+ self.came_from_pos[current_step] -= 1;
+
+ if self.came_from_pos[current_step] < 0 {
+ return true;
+ }
+ }
+ }
+
+ fn add_vertex(&mut self, p: Point, polygon: &mut Vec<Point>) {
+ let [x, y] = [p.x, p.y].map(|i| {
+ if self.inverted || i & 1 == 0 {
+ self.cell_size
+ } else {
+ self.cell_size * 2 / 3
+ }
+ });
+ let new_point = Point::new(
+ (p.x - 1) * self.cell_size as i32 + x as i32 + self.off.x,
+ (p.y - 1) * self.cell_size as i32 + y as i32 + self.off.y,
+ );
+
+ let nv = polygon.len();
+ if nv > 2 {
+ if in_line(&polygon[nv - 2], &polygon[nv - 1], &new_point) {
+ polygon.pop();
+ }
+ }
+
+ polygon.push(new_point);
+ }
+
+ fn add_edge(&mut self, p: Point, mut dir: Direction, polygon: &mut Vec<Point>) {
+ let mut next_p = Some(p);
+
+ while let Some(p) = next_p {
+ next_p = None;
+
+ for _ in 0..4 {
+ let cdir = dir.to_edge();
+
+ let np = p + cdir.0;
+
+ if np.x >= 0
+ && np.y >= 0
+ && np.x < self.num_cells.width as i32
+ && np.y < self.num_cells.height as i32
+ && self.edge_list[dir.orientation()][np.y as usize][np.x as usize]
+ {
+ self.edge_list[dir.orientation()][np.y as usize][np.x as usize] = false;
+ self.add_vertex(p + dir.0 + Point::new(1, 1), polygon);
+ next_p = Some(p + dir.0);
+ break;
+ }
+
+ dir = dir.rotate_right();
+ }
+ }
+ }
+
+ pub fn to_islands(mut self) -> (Vec<Polygon>, Vec<Point>) {
+ let mut islands: Vec<Polygon> = vec![];
+ let mut polygon: Vec<Point> = vec![];
+ let mut maze = vec![vec![false; self.num_cells.width]; self.num_cells.height];
+
+ for x in 0..self.seen_cells.width {
+ for y in 0..self.seen_cells.height {
+ if self.seen_list[y][x].is_some() {
+ maze[y * 2 + 1][x * 2 + 1] = true;
+ }
+ }
+
+ for y in 0..self.seen_cells.height - 1 {
+ if !self.walls[0][y][x] {
+ maze[y * 2 + 2][x * 2 + 1] = true;
+ }
+ }
+ }
+
+ for x in 0..self.seen_cells.width - 1 {
+ for y in 0..self.seen_cells.height {
+ if !self.walls[1][y][x] {
+ maze[y * 2 + 1][x * 2 + 2] = true;
+ }
+ }
+ }
+
+ for x in 0..self.num_edges.width {
+ for y in 0..self.num_cells.height {
+ self.edge_list[0][y][x] = maze[y][x] != maze[y][x + 1];
+ }
+ }
+
+ for x in 0..self.num_cells.width {
+ for y in 0..self.num_edges.height {
+ self.edge_list[1][y][x] = maze[y][x] != maze[y + 1][x];
+ }
+ }
+
+ let mut fill_points = vec![];
+
+ for x in 0..self.num_edges.width {
+ for y in 0..self.num_cells.height {
+ if self.edge_list[0][y][x] {
+ self.edge_list[0][y][x] = false;
+ self.add_vertex(Point::new(x as i32 + 1, y as i32 + 1), &mut polygon);
+ self.add_vertex(Point::new(x as i32 + 1, y as i32), &mut polygon);
+ self.add_edge(
+ Point::new(x as i32, y as i32 - 1),
+ Direction::new(0),
+ &mut polygon,
+ );
+
+ if polygon.len() > 4 {
+ if in_line(polygon.last().unwrap(), &polygon[0], &polygon[1]) {
+ polygon.pop();
+ }
+
+ for p in &polygon {
+ println!("{} {}", p.x, p.y);
+ }
+ println!("\ne\n");
+
+ islands.push(Polygon::new(&polygon));
+ }
+ polygon.clear();
+ }
+ }
+ }
+
+ for x in 0..self.num_cells.width {
+ for y in 0..self.num_cells.height {
+ if maze[y][x] {
+ let half_cell = self.cell_size / 2;
+ let fill_point = Point::new(
+ (x * self.cell_size + half_cell) as i32 + self.off.x,
+ (y * self.cell_size + half_cell) as i32 + self.off.y,
+ );
+ islands.push(Polygon::new(&[fill_point]));
+ fill_points.push(fill_point);
+
+ let mut points = vec![(x, y)];
+
+ while let Some((x, y)) = points.pop() {
+ if maze[y][x] {
+ maze[y][x] = false;
+
+ if x > 0 {
+ points.push((x - 1, y));
+ }
+ if x < self.num_cells.width - 1 {
+ points.push((x + 1, y));
+ }
+ if y > 0 {
+ points.push((x, y - 1));
+ }
+ if y < self.num_cells.height - 1 {
+ points.push((x, y + 1));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ (islands, fill_points)
+ }
+}
+
+pub struct MazeLandGenerator {
+ maze_template: MazeTemplate,
+}
+
+fn prev_odd(num: usize) -> usize {
+ if num & 1 == 0 {
+ num - 1
+ } else {
+ num
+ }
+}
+
+impl MazeLandGenerator {
+ pub fn new(maze_template: MazeTemplate) -> Self {
+ Self { maze_template }
+ }
+
+ fn generate_outline<I: Iterator<Item = u32>>(
+ &self,
+ size: &Size,
+ play_box: Rect,
+ intersections_box: Rect,
+ random_numbers: &mut I,
+ ) -> OutlinePoints {
+ let num_steps = if self.maze_template.inverted { 3 } else { 1 };
+ let mut step_done = vec![false; num_steps];
+ let mut done = false;
+
+ let mut maze = Maze::new(
+ &size,
+ self.maze_template.cell_size,
+ num_steps,
+ self.maze_template.inverted,
+ self.maze_template.braidness,
+ random_numbers,
+ );
+
+ while !done {
+ done = true;
+
+ for current_step in 0..num_steps {
+ if !step_done[current_step] {
+ let dir = Direction::new(random_numbers.next().unwrap_or_default() as usize);
+ step_done[current_step] = maze.see_cell(current_step, dir, random_numbers);
+ done = false;
+ }
+ }
+ }
+
+ let (islands, fill_points) = maze.to_islands();
+
+ OutlinePoints {
+ islands,
+ walls: vec![],
+ fill_points,
+ size: *size,
+ play_box,
+ intersections_box,
+ }
+ }
+}
+
+impl LandGenerator for MazeLandGenerator {
+ fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
+ &self,
+ parameters: &LandGenerationParameters<T>,
+ random_numbers: &mut I,
+ ) -> Land2D<T> {
+ let do_invert = self.maze_template.inverted;
+ let (basic, zero) = if do_invert {
+ (parameters.zero, parameters.basic)
+ } else {
+ (parameters.basic, parameters.zero)
+ };
+
+ let land_size = Size::new(self.maze_template.width, self.maze_template.height);
+ let mut land = Land2D::new(&land_size, basic);
+
+ let mut points = self.generate_outline(
+ &land.size().size(),
+ land.play_box(), //??? Rect::at_origin(land_size).with_margin(land_size.to_square().width as i32 * -2),
+ land.play_box(),
+ random_numbers,
+ );
+
+ if !parameters.skip_distort {
+ points.distort(
+ parameters.distance_divisor,
+ self.maze_template.distortion_limiting_factor,
+ random_numbers,
+ );
+ }
+
+ if !parameters.skip_bezier {
+ points.bezierize(5);
+ }
+
+ points.draw(&mut land, zero);
+
+ for p in &points.fill_points {
+ land.fill(*p, zero, zero)
+ }
+
+ land
+ }
+}
--- a/rust/landgen/src/outline.rs Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-use itertools::Itertools;
-use std::cmp::min;
-
-use integral_geometry::{Line, Point, Polygon, Ray, Rect, Size};
-use land2d::Land2D;
-
-use crate::outline_template::OutlineTemplate;
-
-pub struct OutlinePoints {
- pub islands: Vec<Polygon>,
- pub fill_points: Vec<Point>,
- pub size: Size,
- pub play_box: Rect,
- intersections_box: Rect,
-}
-
-impl OutlinePoints {
- pub fn from_outline_template<I: Iterator<Item = u32>>(
- outline_template: &OutlineTemplate,
- play_box: Rect,
- size: Size,
- random_numbers: &mut I,
- ) -> Self {
- Self {
- play_box,
- size,
- islands: outline_template
- .islands
- .iter()
- .map(|i| {
- i.iter()
- .zip(random_numbers.tuples())
- .map(|(rect, (rnd_a, rnd_b))| {
- play_box.top_left() + rect.quotient(rnd_a as usize, rnd_b as usize)
- })
- .collect::<Vec<_>>()
- .into()
- })
- .collect(),
- fill_points: outline_template.fill_points.clone(),
- intersections_box: Rect::at_origin(size)
- .with_margin(size.to_square().width as i32 * -2),
- }
- }
-
- pub fn total_len(&self) -> usize {
- self.islands.iter().map(|i| i.edges_count()).sum::<usize>() + self.fill_points.len()
- }
-
- pub fn iter(&self) -> impl Iterator<Item = &Point> {
- self.islands
- .iter()
- .flat_map(|p| p.iter())
- .chain(self.fill_points.iter())
- }
-
- pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Point> {
- self.islands
- .iter_mut()
- .flat_map(|i| i.iter_mut())
- .chain(self.fill_points.iter_mut())
- }
-
- fn divide_edge<I: Iterator<Item = u32>>(
- &self,
- segment: Line,
- distance_divisor: u32,
- random_numbers: &mut I,
- ) -> Option<Point> {
- #[inline]
- fn intersects(ray: &Ray, edge: &Line) -> bool {
- ray.orientation(edge.start) != ray.orientation(edge.end)
- }
-
- #[inline]
- fn solve_intersection(
- intersections_box: &Rect,
- ray: &Ray,
- edge: &Line,
- ) -> Option<(i32, u32)> {
- let edge_dir = edge.scaled_direction();
- let aqpb = ray.direction.cross(edge_dir) as i64;
-
- if aqpb != 0 {
- let mut iy = ((((edge.start.x - ray.start.x) as i64 * ray.direction.y as i64
- + ray.start.y as i64 * ray.direction.x as i64)
- * edge_dir.y as i64
- - edge.start.y as i64 * edge_dir.x as i64 * ray.direction.y as i64)
- / aqpb) as i32;
-
- // is there better way to do it?
- if iy < intersections_box.top() {
- iy = intersections_box.top();
- } else if iy > intersections_box.bottom() {
- iy = intersections_box.bottom();
- }
-
- let ix = if ray.direction.y.abs() > edge_dir.y.abs() {
- ray.start.x + ray.direction.cotangent_mul(iy - ray.start.y)
- } else {
- edge.start.x + edge_dir.cotangent_mul(iy - edge.start.y)
- };
-
- let intersection_point = Point::new(ix, iy).clamp(intersections_box);
- let diff_point = ray.start - intersection_point;
- let t = ray.direction.dot(diff_point);
-
- if diff_point.max_norm() >= std::i16::MAX as i32 {
- Some((t, std::i32::MAX as u32))
- } else {
- let d = diff_point.integral_norm();
-
- Some((t, d))
- }
- } else {
- None
- }
- }
-
- let min_distance = 40;
- // new point should fall inside this box
- let map_box = self.play_box.with_margin(min_distance);
-
- let normal = segment.scaled_normal();
- let normal_len = normal.integral_norm();
- let mid_point = segment.center();
-
- if (normal_len < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) {
- return None;
- }
-
- let normal_ray = Ray::new(mid_point, normal);
- let mut dist_left = (self.size.width + self.size.height) as u32;
- let mut dist_right = dist_left;
-
- // find distances to map borders
- if normal.x != 0 {
- // where the normal line intersects the left map border
- let left_intersection = Point::new(
- map_box.left(),
- mid_point.y + normal.tangent_mul(map_box.left() - mid_point.x),
- );
- dist_left = (mid_point - left_intersection).integral_norm();
-
- // same for the right border
- let right_intersection = Point::new(
- map_box.right(),
- mid_point.y + normal.tangent_mul(map_box.right() - mid_point.x),
- );
- dist_right = (mid_point - right_intersection).integral_norm();
-
- if normal.x > 0 {
- std::mem::swap(&mut dist_left, &mut dist_right);
- }
- }
-
- if normal.y != 0 {
- // where the normal line intersects the top map border
- let top_intersection = Point::new(
- mid_point.x + normal.cotangent_mul(map_box.top() - mid_point.y),
- map_box.top(),
- );
- let dl = (mid_point - top_intersection).integral_norm();
-
- // same for the bottom border
- let bottom_intersection = Point::new(
- mid_point.x + normal.cotangent_mul(map_box.bottom() - mid_point.y),
- map_box.bottom(),
- );
- let dr = (mid_point - bottom_intersection).integral_norm();
-
- if normal.y < 0 {
- dist_left = min(dist_left, dl);
- dist_right = min(dist_right, dr);
- } else {
- dist_left = min(dist_left, dr);
- dist_right = min(dist_right, dl);
- }
- }
-
- // now go through all other segments
- for s in self.segments_iter() {
- if s != segment {
- if intersects(&normal_ray, &s) {
- if let Some((t, d)) =
- solve_intersection(&self.intersections_box, &normal_ray, &s)
- {
- if t > 0 {
- dist_right = min(dist_right, d);
- } else {
- dist_left = min(dist_left, d);
- }
- }
- }
- }
- }
-
- // go through all points, including fill points
- for pi in self.iter().cloned() {
- if pi != segment.start && pi != segment.end {
- if intersects(&pi.ray_with_dir(normal), &segment) {
- // ray from segment.start
- if let Some((t, d)) = solve_intersection(
- &self.intersections_box,
- &normal_ray,
- &segment.start.line_to(pi),
- ) {
- if t > 0 {
- dist_right = min(dist_right, d);
- } else {
- dist_left = min(dist_left, d);
- }
- }
-
- // ray from segment.end
- if let Some((t, d)) = solve_intersection(
- &self.intersections_box,
- &normal_ray,
- &segment.end.line_to(pi),
- ) {
- if t > 0 {
- dist_right = min(dist_right, d);
- } else {
- dist_left = min(dist_left, d);
- }
- }
- }
- }
- }
-
- let max_dist = normal_len * 100 / distance_divisor;
- dist_left = min(dist_left, max_dist);
- dist_right = min(dist_right, max_dist);
-
- if dist_right + dist_left < min_distance as u32 * 2 + 10 {
- // limits are too narrow, just divide
- Some(mid_point)
- } else {
- // select distance within [-dist_right; dist_left], keeping min_distance in mind
- let d = -(dist_right as i32)
- + min_distance
- + random_numbers.next().unwrap() as i32
- % (dist_right as i32 + dist_left as i32 - min_distance * 2);
-
- Some(mid_point + normal * d / normal_len as i32)
- }
- }
-
- fn divide_edges<I: Iterator<Item = u32>>(
- &mut self,
- distance_divisor: u32,
- random_numbers: &mut I,
- ) {
- for is in 0..self.islands.len() {
- let mut i = 0;
- while i < self.islands[is].edges_count() {
- let segment = self.islands[is].get_edge(i);
- if let Some(new_point) = self.divide_edge(segment, distance_divisor, random_numbers)
- {
- self.islands[is].split_edge(i, new_point);
- i += 2;
- } else {
- i += 1;
- }
- }
- }
- }
-
- pub fn bezierize(&mut self, segments_number: u32) {
- for island in &mut self.islands {
- island.bezierize(segments_number);
- }
- }
-
- pub fn distort<I: Iterator<Item = u32>>(
- &mut self,
- distance_divisor: u32,
- random_numbers: &mut I,
- ) {
- loop {
- let old_len = self.total_len();
- self.divide_edges(distance_divisor, random_numbers);
-
- if self.total_len() == old_len {
- break;
- }
- }
- }
-
- pub fn draw<T: Copy + PartialEq>(&self, land: &mut Land2D<T>, value: T) {
- for segment in self.segments_iter() {
- land.draw_line(segment, value);
- }
- }
-
- fn segments_iter<'a>(&'a self) -> impl Iterator<Item = Line> + 'a {
- self.islands.iter().flat_map(|p| p.iter_edges())
- }
-
- pub fn mirror(&mut self) {
- let r = self.size.width as i32 - 1;
-
- self.iter_mut().for_each(|p| p.x = r - p.x);
- }
-
- pub fn flip(&mut self) {
- let t = self.size.height as i32 - 1;
-
- self.iter_mut().for_each(|p| p.y = t - p.y);
- }
-}
-
-#[test]
-fn points_test() {
- let size = Size::square(100);
- let mut points = OutlinePoints {
- islands: vec![
- Polygon::new(&[Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)]),
- Polygon::new(&[Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)]),
- ],
- fill_points: vec![Point::new(1, 1)],
- play_box: Rect::at_origin(size).with_margin(10),
- size: Size::square(100),
- intersections_box: Rect::at_origin(size),
- };
-
- let segments: Vec<Line> = points.segments_iter().collect();
- assert_eq!(
- segments.first(),
- Some(&Line::new(Point::new(0, 0), Point::new(20, 0)))
- );
- assert_eq!(
- segments.last(),
- Some(&Line::new(Point::new(20, 15), Point::new(10, 15)))
- );
-
- points.iter_mut().for_each(|p| p.x = 2);
-
- assert_eq!(points.fill_points[0].x, 2);
- assert_eq!(points.islands[0].get_edge(0).start.x, 2);
-}
--- a/rust/landgen/src/outline_template.rs Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-use integral_geometry::{Point, Rect, Size};
-
-#[derive(Clone, Debug)]
-pub struct OutlineTemplate {
- pub islands: Vec<Vec<Rect>>,
- pub fill_points: Vec<Point>,
- pub size: Size,
- pub can_flip: bool,
- pub can_invert: bool,
- pub can_mirror: bool,
- pub is_negative: bool,
-}
-
-impl OutlineTemplate {
- pub fn new(size: Size) -> Self {
- OutlineTemplate {
- size,
- islands: Vec::new(),
- fill_points: Vec::new(),
- can_flip: false,
- can_invert: false,
- can_mirror: false,
- is_negative: false,
- }
- }
-
- pub fn flippable(self) -> Self {
- Self {
- can_flip: true,
- ..self
- }
- }
-
- pub fn mirrorable(self) -> Self {
- Self {
- can_mirror: true,
- ..self
- }
- }
-
- pub fn invertable(self) -> Self {
- Self {
- can_invert: true,
- ..self
- }
- }
-
- pub fn negative(self) -> Self {
- Self {
- is_negative: true,
- ..self
- }
- }
-
- pub fn with_fill_points(self, fill_points: Vec<Point>) -> Self {
- Self {
- fill_points,
- ..self
- }
- }
-
- pub fn with_islands(self, islands: Vec<Vec<Rect>>) -> Self {
- Self { islands, ..self }
- }
-
- pub fn add_fill_points(mut self, points: &[Point]) -> Self {
- self.fill_points.extend_from_slice(points);
- self
- }
-
- pub fn add_island(mut self, island: &[Rect]) -> Self {
- self.islands.push(island.into());
- self
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/outline_template_based/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+pub mod outline;
+pub mod outline_template;
+pub mod template_based;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/outline_template_based/outline.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,371 @@
+use itertools::Itertools;
+use std::cmp::min;
+
+use integral_geometry::{Line, Point, Polygon, Ray, Rect, Size};
+use land2d::Land2D;
+
+use super::outline_template::OutlineTemplate;
+
+pub struct OutlinePoints {
+ pub islands: Vec<Polygon>,
+ pub walls: Vec<Polygon>,
+ pub fill_points: Vec<Point>,
+ pub size: Size,
+ pub play_box: Rect,
+ pub intersections_box: Rect,
+}
+
+impl OutlinePoints {
+ pub fn from_outline_template<I: Iterator<Item = u32>>(
+ outline_template: &OutlineTemplate,
+ play_box: Rect,
+ size: Size,
+ random_numbers: &mut I,
+ ) -> Self {
+ Self {
+ play_box,
+ size,
+ islands: outline_template
+ .islands
+ .iter()
+ .map(|i| {
+ i.iter()
+ .zip(random_numbers.tuples())
+ .map(|(rect, (rnd_a, rnd_b))| {
+ play_box.top_left() + rect.quotient(rnd_a as usize, rnd_b as usize)
+ })
+ .collect::<Vec<_>>()
+ .into()
+ })
+ .collect(),
+ walls: outline_template
+ .walls
+ .iter()
+ .map(|i| {
+ i.iter()
+ .zip(random_numbers.tuples())
+ .map(|(rect, (rnd_a, rnd_b))| {
+ play_box.top_left() + rect.quotient(rnd_a as usize, rnd_b as usize)
+ })
+ .collect::<Vec<_>>()
+ .into()
+ })
+ .collect(),
+ fill_points: outline_template.fill_points.clone(),
+ intersections_box: Rect::at_origin(size)
+ .with_margin(size.to_square().width as i32 * -2),
+ }
+ }
+
+ pub fn total_len(&self) -> usize {
+ self.islands.iter().map(|i| i.edges_count()).sum::<usize>() + self.fill_points.len()
+ }
+
+ pub fn iter(&self) -> impl Iterator<Item = &Point> {
+ self.islands
+ .iter()
+ .flat_map(|p| p.iter())
+ .chain(self.walls.iter().flat_map(|p| p.iter()))
+ .chain(self.fill_points.iter())
+ }
+
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Point> {
+ self.islands
+ .iter_mut()
+ .flat_map(|i| i.iter_mut())
+ .chain(self.walls.iter_mut().flat_map(|p| p.iter_mut()))
+ .chain(self.fill_points.iter_mut())
+ }
+
+ fn divide_edge<I: Iterator<Item = u32>>(
+ &self,
+ segment: Line,
+ distance_divisor: u32,
+ distortion_limiting_factor: u32,
+ random_numbers: &mut I,
+ ) -> Option<Point> {
+ #[inline]
+ fn intersects(ray: &Ray, edge: &Line) -> bool {
+ ray.orientation(edge.start) != ray.orientation(edge.end)
+ }
+
+ #[inline]
+ fn solve_intersection(
+ intersections_box: &Rect,
+ ray: &Ray,
+ edge: &Line,
+ ) -> Option<(i32, u32)> {
+ let edge_dir = edge.scaled_direction();
+ let aqpb = ray.direction.cross(edge_dir) as i64;
+
+ if aqpb != 0 {
+ let mut iy = ((((edge.start.x - ray.start.x) as i64 * ray.direction.y as i64
+ + ray.start.y as i64 * ray.direction.x as i64)
+ * edge_dir.y as i64
+ - edge.start.y as i64 * edge_dir.x as i64 * ray.direction.y as i64)
+ / aqpb) as i32;
+
+ // is there better way to do it?
+ if iy < intersections_box.top() {
+ iy = intersections_box.top();
+ } else if iy > intersections_box.bottom() {
+ iy = intersections_box.bottom();
+ }
+
+ let ix = if ray.direction.y.abs() > edge_dir.y.abs() {
+ ray.start.x + ray.direction.cotangent_mul(iy - ray.start.y)
+ } else {
+ edge.start.x + edge_dir.cotangent_mul(iy - edge.start.y)
+ };
+
+ let intersection_point = Point::new(ix, iy).clamp(intersections_box);
+ let diff_point = ray.start - intersection_point;
+ let t = ray.direction.dot(diff_point);
+
+ if diff_point.max_norm() >= std::i16::MAX as i32 {
+ Some((t, std::i32::MAX as u32))
+ } else {
+ let d = diff_point.integral_norm();
+
+ Some((t, d))
+ }
+ } else {
+ None
+ }
+ }
+
+ let min_distance = distance_divisor as i32;
+ // new point should fall inside this box
+ let map_box = self.play_box.with_margin(min_distance);
+
+ let normal = segment.scaled_normal();
+ let normal_len = normal.integral_norm();
+ let mid_point = segment.center();
+
+ if (normal_len < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) {
+ return None;
+ }
+
+ let normal_ray = Ray::new(mid_point, normal);
+ let mut dist_left = (self.size.width + self.size.height) as u32;
+ let mut dist_right = dist_left;
+
+ // find distances to map borders
+ if normal.x != 0 {
+ // where the normal line intersects the left map border
+ let left_intersection = Point::new(
+ map_box.left(),
+ mid_point.y + normal.tangent_mul(map_box.left() - mid_point.x),
+ );
+ dist_left = (mid_point - left_intersection).integral_norm();
+
+ // same for the right border
+ let right_intersection = Point::new(
+ map_box.right(),
+ mid_point.y + normal.tangent_mul(map_box.right() - mid_point.x),
+ );
+ dist_right = (mid_point - right_intersection).integral_norm();
+
+ if normal.x > 0 {
+ std::mem::swap(&mut dist_left, &mut dist_right);
+ }
+ }
+
+ if normal.y != 0 {
+ // where the normal line intersects the top map border
+ let top_intersection = Point::new(
+ mid_point.x + normal.cotangent_mul(map_box.top() - mid_point.y),
+ map_box.top(),
+ );
+ let dl = (mid_point - top_intersection).integral_norm();
+
+ // same for the bottom border
+ let bottom_intersection = Point::new(
+ mid_point.x + normal.cotangent_mul(map_box.bottom() - mid_point.y),
+ map_box.bottom(),
+ );
+ let dr = (mid_point - bottom_intersection).integral_norm();
+
+ if normal.y < 0 {
+ dist_left = min(dist_left, dl);
+ dist_right = min(dist_right, dr);
+ } else {
+ dist_left = min(dist_left, dr);
+ dist_right = min(dist_right, dl);
+ }
+ }
+
+ // now go through all other segments
+ for s in self.segments_iter() {
+ if s != segment && intersects(&normal_ray, &s) {
+ if let Some((t, d)) = solve_intersection(&self.intersections_box, &normal_ray, &s) {
+ if t > 0 {
+ dist_right = min(dist_right, d);
+ } else {
+ dist_left = min(dist_left, d);
+ }
+ }
+ }
+ }
+
+ // go through all points, including fill points
+ for pi in self.iter().cloned() {
+ if pi != segment.start
+ && pi != segment.end
+ && intersects(&pi.ray_with_dir(normal), &segment)
+ {
+ // ray from segment.start
+ if let Some((t, d)) = solve_intersection(
+ &self.intersections_box,
+ &normal_ray,
+ &segment.start.line_to(pi),
+ ) {
+ if t > 0 {
+ dist_right = min(dist_right, d);
+ } else {
+ dist_left = min(dist_left, d);
+ }
+ }
+
+ // ray from segment.end
+ if let Some((t, d)) = solve_intersection(
+ &self.intersections_box,
+ &normal_ray,
+ &segment.end.line_to(pi),
+ ) {
+ if t > 0 {
+ dist_right = min(dist_right, d);
+ } else {
+ dist_left = min(dist_left, d);
+ }
+ }
+ }
+ }
+
+ let max_dist = normal_len * 128 / distortion_limiting_factor;
+ dist_left = min(dist_left, max_dist);
+ dist_right = min(dist_right, max_dist);
+
+ if dist_right + dist_left < min_distance as u32 * 2 + 10 {
+ // limits are too narrow, just divide
+ Some(mid_point)
+ } else {
+ // select distance within [-dist_right; dist_left], keeping min_distance in mind
+ let d = -(dist_right as i32)
+ + min_distance
+ + random_numbers.next().unwrap() as i32
+ % (dist_right as i32 + dist_left as i32 - min_distance * 2);
+
+ Some(mid_point + normal * d / normal_len as i32)
+ }
+ }
+
+ fn divide_edges<I: Iterator<Item = u32>>(
+ &mut self,
+ distance_divisor: u32,
+ distortion_limiting_factor: u32,
+ random_numbers: &mut I,
+ ) {
+ for is in 0..self.islands.len() {
+ let mut i = 0;
+ while i < self.islands[is].edges_count() {
+ let segment = self.islands[is].get_edge(i);
+ if let Some(new_point) = self.divide_edge(
+ segment,
+ distance_divisor,
+ distortion_limiting_factor,
+ random_numbers,
+ ) {
+ self.islands[is].split_edge(i, new_point);
+ i += 2;
+ } else {
+ i += 1;
+ }
+ }
+ }
+ }
+
+ pub fn bezierize(&mut self, segments_number: u32) {
+ for island in &mut self.islands {
+ island.bezierize(segments_number);
+ }
+ }
+
+ pub fn distort<I: Iterator<Item = u32>>(
+ &mut self,
+ distance_divisor: u32,
+ distortion_limiting_factor: u32,
+ random_numbers: &mut I,
+ ) {
+ loop {
+ let old_len = self.total_len();
+ self.divide_edges(distance_divisor, distortion_limiting_factor, random_numbers);
+
+ if self.total_len() == old_len {
+ break;
+ }
+ }
+ }
+
+ pub fn draw<T: Copy + PartialEq + Default>(&self, land: &mut Land2D<T>, value: T) {
+ for segment in self.visible_segments_iter() {
+ land.draw_line(segment, value);
+ }
+ }
+
+ fn visible_segments_iter<'a>(&'a self) -> impl Iterator<Item = Line> + 'a {
+ self.islands
+ .iter()
+ .flat_map(|p| p.iter_edges())
+ }
+
+ fn segments_iter<'a>(&'a self) -> impl Iterator<Item = Line> + 'a {
+ self.islands
+ .iter()
+ .flat_map(|p| p.iter_edges())
+ .chain(self.walls.iter().flat_map(|p| p.iter_edges()))
+ }
+
+ pub fn mirror(&mut self) {
+ let r = self.size.width as i32 - 1;
+
+ self.iter_mut().for_each(|p| p.x = r - p.x);
+ }
+
+ pub fn flip(&mut self) {
+ let t = self.size.height as i32 - 1;
+
+ self.iter_mut().for_each(|p| p.y = t - p.y);
+ }
+}
+
+#[test]
+fn points_test() {
+ let size = Size::square(100);
+ let mut points = OutlinePoints {
+ islands: vec![
+ Polygon::new(&[Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)]),
+ Polygon::new(&[Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)]),
+ ],
+ walls: vec![],
+ fill_points: vec![Point::new(1, 1)],
+ play_box: Rect::at_origin(size).with_margin(10),
+ size: Size::square(100),
+ intersections_box: Rect::at_origin(size),
+ };
+
+ let segments: Vec<Line> = points.segments_iter().collect();
+ assert_eq!(
+ segments.first(),
+ Some(&Line::new(Point::new(0, 0), Point::new(20, 0)))
+ );
+ assert_eq!(
+ segments.last(),
+ Some(&Line::new(Point::new(20, 15), Point::new(10, 15)))
+ );
+
+ points.iter_mut().for_each(|p| p.x = 2);
+
+ assert_eq!(points.fill_points[0].x, 2);
+ assert_eq!(points.islands[0].get_edge(0).start.x, 2);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/outline_template_based/outline_template.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,85 @@
+use integral_geometry::{Point, Rect, Size};
+
+#[derive(Clone, Debug)]
+pub struct OutlineTemplate {
+ pub islands: Vec<Vec<Rect>>,
+ pub walls: Vec<Vec<Rect>>,
+ pub fill_points: Vec<Point>,
+ pub size: Size,
+ pub can_flip: bool,
+ pub can_invert: bool,
+ pub can_mirror: bool,
+ pub is_negative: bool,
+}
+
+impl OutlineTemplate {
+ pub fn new(size: Size) -> Self {
+ OutlineTemplate {
+ size,
+ islands: Vec::new(),
+ walls: Vec::new(),
+ fill_points: Vec::new(),
+ can_flip: false,
+ can_invert: false,
+ can_mirror: false,
+ is_negative: false,
+ }
+ }
+
+ pub fn flippable(self) -> Self {
+ Self {
+ can_flip: true,
+ ..self
+ }
+ }
+
+ pub fn mirrorable(self) -> Self {
+ Self {
+ can_mirror: true,
+ ..self
+ }
+ }
+
+ pub fn invertable(self) -> Self {
+ Self {
+ can_invert: true,
+ ..self
+ }
+ }
+
+ pub fn negative(self) -> Self {
+ Self {
+ is_negative: true,
+ ..self
+ }
+ }
+
+ pub fn cavern(self) -> Self {
+ Self {
+ is_negative: true,
+ can_invert: false,
+ ..self
+ }
+ }
+
+ pub fn with_fill_points(self, fill_points: Vec<Point>) -> Self {
+ Self {
+ fill_points,
+ ..self
+ }
+ }
+
+ pub fn with_islands(self, islands: Vec<Vec<Rect>>) -> Self {
+ Self { islands, ..self }
+ }
+
+ pub fn add_fill_points(mut self, points: &[Point]) -> Self {
+ self.fill_points.extend_from_slice(points);
+ self
+ }
+
+ pub fn add_island(mut self, island: &[Rect]) -> Self {
+ self.islands.push(island.into());
+ self
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/outline_template_based/template_based.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,80 @@
+use super::{outline::OutlinePoints, outline_template::OutlineTemplate};
+use crate::{LandGenerationParameters, LandGenerator};
+use land2d::Land2D;
+
+pub struct TemplatedLandGenerator {
+ outline_template: OutlineTemplate,
+}
+
+impl TemplatedLandGenerator {
+ pub fn new(outline_template: OutlineTemplate) -> Self {
+ Self { outline_template }
+ }
+}
+
+impl LandGenerator for TemplatedLandGenerator {
+ fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
+ &self,
+ parameters: &LandGenerationParameters<T>,
+ random_numbers: &mut I,
+ ) -> Land2D<T> {
+ let do_invert = self.outline_template.is_negative
+ && (!self.outline_template.can_invert || random_numbers.next().unwrap() & 1 == 0);
+ let (basic, zero) = if do_invert {
+ (parameters.zero, parameters.basic)
+ } else {
+ (parameters.basic, parameters.zero)
+ };
+
+ let mut land = Land2D::new(&self.outline_template.size, basic);
+
+ let mut points = OutlinePoints::from_outline_template(
+ &self.outline_template,
+ land.play_box(),
+ land.size().size(),
+ random_numbers,
+ );
+
+ // mirror
+ if self.outline_template.can_mirror {
+ if let Some(b) = random_numbers.next() {
+ if b & 1 != 0 {
+ points.mirror();
+ }
+ }
+ }
+
+ // flip
+ if self.outline_template.can_flip {
+ if let Some(b) = random_numbers.next() {
+ if b & 1 != 0 {
+ points.flip();
+ }
+ }
+ }
+
+ if !parameters.skip_distort {
+ let distortion_limiting_factor = 100 + random_numbers.next().unwrap() % 8 * 10;
+
+ points.distort(
+ parameters.distance_divisor,
+ distortion_limiting_factor,
+ random_numbers,
+ );
+ }
+
+ if !parameters.skip_bezier {
+ points.bezierize(5);
+ }
+
+ points.draw(&mut land, zero);
+
+ for p in &points.fill_points {
+ land.fill(*p, zero, zero)
+ }
+
+ points.draw(&mut land, basic);
+
+ land
+ }
+}
--- a/rust/landgen/src/template_based.rs Sat Sep 28 22:27:13 2024 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-use crate::{
- outline::OutlinePoints, outline_template::OutlineTemplate, LandGenerationParameters,
- LandGenerator,
-};
-use integral_geometry::{Point, Size};
-use land2d::Land2D;
-
-pub struct TemplatedLandGenerator {
- outline_template: OutlineTemplate,
-}
-
-impl TemplatedLandGenerator {
- pub fn new(outline_template: OutlineTemplate) -> Self {
- Self { outline_template }
- }
-}
-
-impl LandGenerator for TemplatedLandGenerator {
- fn generate_land<T: Copy + PartialEq, I: Iterator<Item = u32>>(
- &self,
- parameters: &LandGenerationParameters<T>,
- random_numbers: &mut I,
- ) -> Land2D<T> {
- let mut land = Land2D::new(self.outline_template.size, parameters.basic);
-
- let mut points = OutlinePoints::from_outline_template(
- &self.outline_template,
- land.play_box(),
- land.size().size(),
- random_numbers,
- );
-
- // mirror
- if self.outline_template.can_mirror {
- if let Some(b) = random_numbers.next() {
- if b & 1 != 0 {
- points.mirror();
- }
- }
- }
-
- // flip
- if self.outline_template.can_flip {
- if let Some(b) = random_numbers.next() {
- if b & 1 != 0 {
- points.flip();
- }
- }
- }
-
- if !parameters.skip_distort {
- points.distort(parameters.distance_divisor, random_numbers);
- }
-
- if !parameters.skip_bezier {
- points.bezierize(5);
- }
-
- points.draw(&mut land, parameters.zero);
-
- for p in &points.fill_points {
- land.fill(*p, parameters.zero, parameters.zero)
- }
-
- points.draw(&mut land, parameters.basic);
-
- land
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/wavefront_collapse/generator.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,344 @@
+use super::tile_image::{Edge, TileImage};
+use super::wavefront_collapse::{CollapseRule, Tile, WavefrontCollapse};
+use crate::{LandGenerationParameters, LandGenerator};
+use integral_geometry::Size;
+use png::Decoder;
+use std::collections::HashSet;
+use std::fs::File;
+use std::io::{BufReader, Result};
+use std::path::{Path, PathBuf};
+
+#[derive(Clone)]
+pub struct EdgeDescription {
+ pub name: String,
+ pub reversed: Option<bool>,
+ pub symmetrical: Option<bool>,
+}
+
+#[derive(Clone)]
+pub struct EdgesDescription {
+ pub top: EdgeDescription,
+ pub right: EdgeDescription,
+ pub bottom: EdgeDescription,
+ pub left: EdgeDescription,
+}
+
+#[derive(Clone)]
+pub struct TileDescription {
+ pub name: String,
+ pub edges: EdgesDescription,
+ pub is_negative: Option<bool>,
+ pub can_flip: Option<bool>,
+ pub can_mirror: Option<bool>,
+ pub can_rotate90: Option<bool>,
+ pub can_rotate180: Option<bool>,
+ pub can_rotate270: Option<bool>,
+}
+
+#[derive(Clone)]
+pub struct NonStrictEdgesDescription {
+ pub top: Option<EdgeDescription>,
+ pub right: Option<EdgeDescription>,
+ pub bottom: Option<EdgeDescription>,
+ pub left: Option<EdgeDescription>,
+}
+
+#[derive(Clone)]
+pub struct TemplateDescription {
+ pub size: Size,
+ pub tiles: Vec<TileDescription>,
+ pub edges: NonStrictEdgesDescription,
+ pub wrap: bool,
+}
+
+pub struct WavefrontCollapseLandGenerator {
+ pub template: TemplateDescription,
+ data_path: PathBuf,
+}
+
+impl WavefrontCollapseLandGenerator {
+ pub fn new(template: TemplateDescription, data_path: &Path) -> Self {
+ Self {
+ template,
+ data_path: data_path.to_owned(),
+ }
+ }
+
+ fn load_image_tiles<T: Copy + PartialEq + Default>(
+ &self,
+ parameters: &LandGenerationParameters<T>,
+ tile_description: &TileDescription,
+ ) -> Result<Vec<TileImage<T, String>>> {
+ let mut result = Vec::new();
+
+ let file = File::open(
+ self.data_path
+ .join("Tiles")
+ .join(&tile_description.name)
+ .as_path(),
+ )?;
+ let decoder = Decoder::new(BufReader::new(file));
+ let mut reader = decoder.read_info().unwrap();
+
+ let info = reader.info();
+ let mut tiles_image = vec2d::Vec2D::new(
+ &Size::new(info.width as usize, info.height as usize),
+ parameters.zero,
+ );
+
+ let mut buf = vec![0; reader.output_buffer_size()];
+ let info = reader.next_frame(&mut buf).unwrap();
+ let bytes = &buf[..info.buffer_size()];
+
+ let mut tiles_image_pixels = tiles_image.as_mut_slice().iter_mut();
+
+ let (zero, basic) = if tile_description.is_negative.unwrap_or_default() {
+ (parameters.basic(), parameters.zero())
+ } else {
+ (parameters.zero(), parameters.basic())
+ };
+
+ match info.color_type.samples() {
+ 1 => {
+ for line in bytes.chunks_exact(info.line_size) {
+ for value in line.iter() {
+ *tiles_image_pixels
+ .next()
+ .expect("vec2d size matching image dimensions") =
+ if *value == 0 { zero } else { basic };
+ }
+ }
+ }
+ a => {
+ for line in bytes.chunks_exact(info.line_size) {
+ for value in line.chunks_exact(a) {
+ print!("{:?},", value);
+ *tiles_image_pixels
+ .next()
+ .expect("vec2d size matching image dimensions") =
+ if value[0] == 0u8 { zero } else { basic };
+ }
+ }
+ }
+ }
+
+ let [top_edge, right_edge, bottom_edge, left_edge]: [Edge<String>; 4] = [
+ (&tile_description.edges.top).into(),
+ (&tile_description.edges.right).into(),
+ (&tile_description.edges.bottom).into(),
+ (&tile_description.edges.left).into(),
+ ];
+
+ let tile =
+ TileImage::<T, String>::new(tiles_image, top_edge, right_edge, bottom_edge, left_edge);
+
+ result.push(tile.clone());
+
+ if tile_description.can_flip.unwrap_or_default() {
+ result.push(tile.flipped());
+ }
+ if tile_description.can_mirror.unwrap_or_default() {
+ result.push(tile.mirrored());
+ }
+ if tile_description.can_flip.unwrap_or_default()
+ && tile_description.can_mirror.unwrap_or_default()
+ {
+ result.push(tile.mirrored().flipped());
+ }
+
+ if tile_description.can_rotate90.unwrap_or_default() {
+ result.push(tile.rotated90());
+ }
+ if tile_description.can_rotate180.unwrap_or_default() {
+ result.push(tile.rotated180());
+ }
+ if tile_description.can_rotate270.unwrap_or_default() {
+ result.push(tile.rotated270());
+ }
+
+ Ok(result)
+ }
+
+ pub fn load_template<T: Copy + PartialEq + Default>(
+ &self,
+ parameters: &LandGenerationParameters<T>,
+ ) -> Vec<TileImage<T, String>> {
+ let mut result = Vec::new();
+
+ for tile_description in self.template.tiles.iter() {
+ if let Ok(mut tiles) = self.load_image_tiles(parameters, tile_description) {
+ result.append(&mut tiles);
+ } else {
+ eprintln!("Failed to load a tile!");
+ }
+ }
+
+ result
+ }
+
+ pub fn build_rules<T: Copy + PartialEq + Default>(
+ &self,
+ tiles: &[TileImage<T, String>],
+ ) -> Vec<CollapseRule> {
+ let [grid_top_edge, grid_right_edge, grid_bottom_edge, grid_left_edge]: [Option<
+ Edge<String>,
+ >; 4] = [
+ self.template.edges.top.as_ref(),
+ self.template.edges.right.as_ref(),
+ self.template.edges.bottom.as_ref(),
+ self.template.edges.left.as_ref(),
+ ]
+ .map(|opt| opt.map(|d| d.into()));
+
+ let mut rules = Vec::<CollapseRule>::new();
+
+ let default_connection = HashSet::from_iter(vec![Tile::Empty].into_iter());
+ for (i, tile) in tiles.iter().enumerate() {
+ let mut right = default_connection.clone();
+ let mut bottom = default_connection.clone();
+ let mut left = default_connection.clone();
+ let mut top = default_connection.clone();
+
+ // compatibility with grid edges
+ if grid_top_edge
+ .as_ref()
+ .map(|e| e.is_compatible(tile.top_edge()))
+ .unwrap_or(true)
+ {
+ top.insert(Tile::Outside);
+ }
+ if grid_right_edge
+ .as_ref()
+ .map(|e| e.is_compatible(tile.right_edge()))
+ .unwrap_or(true)
+ {
+ right.insert(Tile::Outside);
+ }
+ if grid_bottom_edge
+ .as_ref()
+ .map(|e| e.is_compatible(tile.bottom_edge()))
+ .unwrap_or(true)
+ {
+ bottom.insert(Tile::Outside);
+ }
+ if grid_left_edge
+ .as_ref()
+ .map(|e| e.is_compatible(tile.left_edge()))
+ .unwrap_or(true)
+ {
+ left.insert(Tile::Outside);
+ }
+
+ // compatibility with itself
+ if tile.left_edge().is_compatible(tile.right_edge()) {
+ left.insert(Tile::Numbered(i));
+ right.insert(Tile::Numbered(i));
+ }
+
+ if tile.top_edge().is_compatible(tile.bottom_edge()) {
+ top.insert(Tile::Numbered(i));
+ bottom.insert(Tile::Numbered(i));
+ }
+
+ // compatibility with previously defined tiles
+ for p in 0..i {
+ if tiles[p].left_edge().is_compatible(tile.right_edge()) {
+ rules[p].left.insert(Tile::Numbered(i));
+ right.insert(Tile::Numbered(p));
+ }
+
+ if tiles[p].right_edge().is_compatible(tile.left_edge()) {
+ rules[p].right.insert(Tile::Numbered(i));
+ left.insert(Tile::Numbered(p));
+ }
+
+ if tiles[p].top_edge().is_compatible(tile.bottom_edge()) {
+ rules[p].top.insert(Tile::Numbered(i));
+ bottom.insert(Tile::Numbered(p));
+ }
+
+ if tiles[p].bottom_edge().is_compatible(tile.top_edge()) {
+ rules[p].bottom.insert(Tile::Numbered(i));
+ top.insert(Tile::Numbered(p));
+ }
+ }
+
+ rules.push(CollapseRule {
+ tile: Tile::Numbered(i),
+ top,
+ right,
+ bottom,
+ left,
+ });
+ }
+
+ rules
+ }
+}
+
+impl LandGenerator for WavefrontCollapseLandGenerator {
+ fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
+ &self,
+ parameters: &LandGenerationParameters<T>,
+ random_numbers: &mut I,
+ ) -> land2d::Land2D<T> {
+ let tiles = self.load_template(parameters);
+ let rules = self.build_rules(&tiles);
+
+ let mut wfc = WavefrontCollapse::new(self.template.wrap);
+ wfc.set_rules(rules);
+
+ let wfc_size = if let Some(first_tile) = tiles.first() {
+ let tile_size = first_tile.size();
+
+ Size::new(
+ self.template.size.width / tile_size.width,
+ self.template.size.height / tile_size.height,
+ )
+ } else {
+ Size::new(1, 1)
+ };
+
+ wfc.generate_map(&wfc_size, |_| {}, random_numbers);
+
+ // render tiles into resulting land array
+ let mut result = land2d::Land2D::new(&self.template.size, parameters.zero);
+ let offset_y = result.height() - result.play_height();
+ let offset_x = (result.width() - result.play_width()) / 2;
+
+ for row in 0..wfc_size.height {
+ for column in 0..wfc_size.width {
+ if let Some(Tile::Numbered(tile_index)) = wfc.grid().get(row, column) {
+ let tile = &tiles[*tile_index];
+
+ for tile_row in 0..tile.size().height {
+ for tile_column in 0..tile.size().width {
+ result.map(
+ (row * tile.size().height + tile_row + offset_y) as i32,
+ (column * tile.size().width + tile_column + offset_x) as i32,
+ |p| {
+ *p =
+ *tile.get(tile_row, tile_column).unwrap_or(¶meters.zero)
+ },
+ );
+ }
+ }
+ }
+ }
+ }
+
+ result
+ }
+}
+
+impl From<&EdgeDescription> for Edge<String> {
+ fn from(val: &EdgeDescription) -> Self {
+ let edge = Edge::new(val.name.clone(), val.symmetrical.unwrap_or_default());
+
+ if val.reversed.unwrap_or_default() {
+ edge.reversed()
+ } else {
+ edge
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/wavefront_collapse/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+pub mod generator;
+mod tile_image;
+mod transform;
+mod wavefront_collapse;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/wavefront_collapse/tile_image.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,242 @@
+use super::transform::Transform;
+use integral_geometry::Size;
+use std::rc::Rc;
+use vec2d::Vec2D;
+
+#[derive(PartialEq, Clone, Debug)]
+pub struct Edge<I: PartialEq + Clone> {
+ id: I,
+ symmetrical: bool,
+ reverse: bool,
+}
+
+impl<I: PartialEq + Clone> Edge<I> {
+ #[inline]
+ pub fn new(id: I, symmetrical: bool) -> Self {
+ Self {
+ id,
+ symmetrical,
+ reverse: false,
+ }
+ }
+
+ #[inline]
+ pub fn reversed(&self) -> Self {
+ Self {
+ id: self.id.clone(),
+ symmetrical: self.symmetrical,
+ reverse: !self.symmetrical && !self.reverse,
+ }
+ }
+
+ #[inline]
+ pub fn is_compatible(&self, other: &Self) -> bool {
+ self.id == other.id && ((self.reverse != other.reverse) || self.symmetrical)
+ }
+}
+
+#[derive(Clone)]
+pub struct TileImage<T, I: PartialEq + Clone> {
+ image: Rc<Vec2D<T>>,
+ pub transform: Transform,
+ top: Edge<I>,
+ right: Edge<I>,
+ bottom: Edge<I>,
+ left: Edge<I>,
+}
+
+impl<T: Copy, I: PartialEq + Clone> TileImage<T, I> {
+ pub fn new(
+ image: Vec2D<T>,
+ top: Edge<I>,
+ right: Edge<I>,
+ bottom: Edge<I>,
+ left: Edge<I>,
+ ) -> Self {
+ Self {
+ image: Rc::new(image),
+ transform: Transform::default(),
+ top,
+ right,
+ bottom,
+ left,
+ }
+ }
+
+ pub fn mirrored(&self) -> Self {
+ Self {
+ image: self.image.clone(),
+ transform: self.transform.mirror(),
+ top: self.top.reversed(),
+ right: self.left.reversed(),
+ bottom: self.bottom.reversed(),
+ left: self.right.reversed(),
+ }
+ }
+
+ pub fn flipped(&self) -> Self {
+ Self {
+ image: self.image.clone(),
+ transform: self.transform.flip(),
+ top: self.bottom.reversed(),
+ right: self.right.reversed(),
+ bottom: self.top.reversed(),
+ left: self.left.reversed(),
+ }
+ }
+
+ pub fn rotated90(&self) -> Self {
+ Self {
+ image: self.image.clone(),
+ transform: self.transform.rotate90(),
+ top: self.left.clone(),
+ right: self.top.clone(),
+ bottom: self.right.clone(),
+ left: self.bottom.clone(),
+ }
+ }
+
+ pub fn rotated180(&self) -> Self {
+ Self {
+ image: self.image.clone(),
+ transform: self.transform.rotate180(),
+ top: self.bottom.clone(),
+ right: self.left.clone(),
+ bottom: self.top.clone(),
+ left: self.right.clone(),
+ }
+ }
+
+ pub fn rotated270(&self) -> Self {
+ Self {
+ image: self.image.clone(),
+ transform: self.transform.rotate270(),
+ top: self.right.clone(),
+ right: self.bottom.clone(),
+ bottom: self.left.clone(),
+ left: self.top.clone(),
+ }
+ }
+
+ #[inline]
+ pub fn right_edge(&self) -> &Edge<I> {
+ &self.right
+ }
+
+ #[inline]
+ pub fn bottom_edge(&self) -> &Edge<I> {
+ &self.bottom
+ }
+
+ #[inline]
+ pub fn left_edge(&self) -> &Edge<I> {
+ &self.left
+ }
+
+ #[inline]
+ pub fn top_edge(&self) -> &Edge<I> {
+ &self.top
+ }
+
+ #[inline]
+ pub fn size(&self) -> Size {
+ match self.transform {
+ Transform::Rotate0(_) => self.image.size(),
+ Transform::Rotate90(_) => Size::new(self.image.size().height, self.image.size().width),
+ }
+ }
+
+ #[inline]
+ pub fn get(&self, row: usize, column: usize) -> Option<&T> {
+ match self.transform {
+ Transform::Rotate0(_) => {
+ let image_row = if self.transform.is_flipped() {
+ self.image.height().wrapping_sub(1).wrapping_sub(row)
+ } else {
+ row
+ };
+
+ let image_column = if self.transform.is_mirrored() {
+ self.image.width().wrapping_sub(1).wrapping_sub(column)
+ } else {
+ column
+ };
+
+ self.image.get(image_row, image_column)
+ }
+ Transform::Rotate90(_) => {
+ let image_row = if self.transform.is_mirrored() {
+ column
+ } else {
+ self.image.height().wrapping_sub(1).wrapping_sub(column)
+ };
+
+ let image_column = if self.transform.is_flipped() {
+ self.image.width().wrapping_sub(1).wrapping_sub(row)
+ } else {
+ row
+ };
+
+ self.image.get(image_row, image_column)
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_edge_new() {
+ let edge = Edge::new(1, true);
+ assert_eq!(edge.id, 1);
+ assert_eq!(edge.symmetrical, true);
+ assert_eq!(edge.reverse, false);
+ }
+
+ #[test]
+ fn test_edge_reversed() {
+ let edge = Edge::new(1, true);
+ let reversed = edge.reversed();
+ assert_eq!(reversed.id, edge.id);
+ assert_eq!(reversed.symmetrical, edge.symmetrical);
+ assert_eq!(reversed.reverse, false);
+
+ let edge = Edge::new(1, false);
+ let reversed = edge.reversed();
+ assert_eq!(reversed.id, edge.id);
+ assert_eq!(reversed.symmetrical, edge.symmetrical);
+ assert_eq!(reversed.reverse, true);
+ }
+
+ #[test]
+ fn test_edge_equality() {
+ let edge1 = Edge::new(1, true);
+ let edge2 = Edge::new(1, true);
+ assert_eq!(edge1, edge2);
+
+ let edge1 = Edge::new(1, false);
+ let edge2 = Edge::new(1, false);
+ assert_eq!(edge1, edge2);
+
+ let edge1 = Edge::new(1, false);
+ let edge2 = Edge::new(2, false);
+ assert_ne!(edge1, edge2);
+ }
+
+ #[test]
+ fn test_edge_equality_with_reverse() {
+ let edge1 = Edge::new(1, true);
+ let edge2 = edge1.reversed();
+ assert_eq!(edge1, edge2);
+
+ let edge1 = Edge::new(1, false);
+ let edge2 = edge1.reversed();
+ assert_ne!(edge1, edge2);
+
+ let edge1 = Edge::new(1, true);
+ let edge2 = edge1.reversed().reversed();
+ assert_eq!(edge1, edge2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/wavefront_collapse/transform.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,214 @@
+#[derive(Debug, PartialEq, Clone, Copy)]
+pub enum SymmetryTransform {
+ Id,
+ Flip,
+ Mirror,
+ FlipMirror,
+}
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+pub enum Transform {
+ Rotate0(SymmetryTransform),
+ Rotate90(SymmetryTransform),
+}
+
+impl Default for Transform {
+ fn default() -> Self {
+ Transform::Rotate0(SymmetryTransform::Id)
+ }
+}
+
+impl SymmetryTransform {
+ pub fn mirror(&self) -> Self {
+ use SymmetryTransform::*;
+ match self {
+ Id => Mirror,
+ Flip => FlipMirror,
+ Mirror => Id,
+ FlipMirror => Flip,
+ }
+ }
+
+ pub fn flip(&self) -> Self {
+ use SymmetryTransform::*;
+ match self {
+ Id => Flip,
+ Flip => Id,
+ Mirror => FlipMirror,
+ FlipMirror => Mirror,
+ }
+ }
+
+ pub fn is_mirrored(&self) -> bool {
+ use SymmetryTransform::*;
+ match self {
+ Id => false,
+ Flip => false,
+ Mirror => true,
+ FlipMirror => true,
+ }
+ }
+
+ pub fn is_flipped(&self) -> bool {
+ use SymmetryTransform::*;
+ match self {
+ Id => false,
+ Flip => true,
+ Mirror => false,
+ FlipMirror => true,
+ }
+ }
+}
+
+impl Transform {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn mirror(self) -> Transform {
+ match self {
+ Transform::Rotate0(s) => Transform::Rotate0(s.mirror()),
+ Transform::Rotate90(s) => Transform::Rotate90(s.flip()),
+ }
+ }
+
+ pub fn flip(self) -> Transform {
+ match self {
+ Transform::Rotate0(s) => Transform::Rotate0(s.flip()),
+ Transform::Rotate90(s) => Transform::Rotate90(s.mirror()),
+ }
+ }
+
+ pub fn rotate90(self) -> Transform {
+ match self {
+ Transform::Rotate0(s) => Transform::Rotate90(s),
+ Transform::Rotate90(s) => Transform::Rotate0(s.flip().mirror()),
+ }
+ }
+
+ pub fn rotate180(self) -> Transform {
+ match self {
+ Transform::Rotate0(s) => Transform::Rotate0(s.flip().mirror()),
+ Transform::Rotate90(s) => Transform::Rotate90(s.flip().mirror()),
+ }
+ }
+
+ pub fn rotate270(self) -> Transform {
+ match self {
+ Transform::Rotate0(s) => Transform::Rotate90(s.flip().mirror()),
+ Transform::Rotate90(s) => Transform::Rotate0(s),
+ }
+ }
+
+ pub fn is_mirrored(&self) -> bool {
+ match self {
+ Transform::Rotate0(s) => s.is_mirrored(),
+ Transform::Rotate90(s) => s.is_mirrored(),
+ }
+ }
+
+ pub fn is_flipped(&self) -> bool {
+ match self {
+ Transform::Rotate0(s) => s.is_flipped(),
+ Transform::Rotate90(s) => s.is_flipped(),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{SymmetryTransform::*, Transform::*, *};
+
+ // I totally wrote all of this myself and didn't use ChatGPT
+ #[test]
+ fn test_default() {
+ let rt = Transform::new();
+ assert_eq!(rt, Rotate0(Id));
+ }
+
+ #[test]
+ fn test_mirror() {
+ let rt = Rotate90(Flip);
+ let mirrored = rt.mirror();
+ assert_eq!(mirrored, Rotate90(Id));
+ }
+
+ #[test]
+ fn test_flip() {
+ let rt = Transform::new().rotate180().mirror();
+ let flipped = rt.flip();
+ assert_eq!(flipped, Rotate0(Id));
+ }
+
+ #[test]
+ fn test_rotate90() {
+ let rt = Rotate0(Id);
+ let rotated = rt.rotate90();
+ assert_eq!(rotated, Rotate90(Id));
+ }
+
+ #[test]
+ fn test_rotate180() {
+ let rt = Rotate90(Mirror);
+ let rotated = rt.rotate180();
+ assert_eq!(rotated, Rotate90(Flip));
+ }
+
+ #[test]
+ fn test_rotate270() {
+ let rt = Transform::new().rotate180().flip();
+ let rotated = rt.rotate270();
+ assert_eq!(rotated, Rotate90(Flip));
+ }
+
+ #[test]
+ fn test_rotate180_2() {
+ let rt = Transform::new().rotate180();
+ assert_eq!(rt, Rotate0(FlipMirror));
+ }
+
+ #[test]
+ fn test_rotation_chain() {
+ assert_eq!(
+ Transform::default(),
+ Transform::default()
+ .rotate90()
+ .rotate90()
+ .rotate90()
+ .rotate90()
+ );
+ assert_eq!(
+ Transform::default().rotate90(),
+ Transform::default().rotate180().rotate90().rotate180()
+ );
+ assert_eq!(
+ Transform::default().rotate180(),
+ Transform::default().rotate180().rotate270().rotate90()
+ );
+ }
+
+ #[test]
+ fn test_combinations_chain() {
+ assert_eq!(
+ Transform::default(),
+ Transform::default().flip().rotate180().flip().rotate180()
+ );
+ assert_eq!(
+ Transform::default(),
+ Transform::default()
+ .mirror()
+ .rotate180()
+ .mirror()
+ .rotate180()
+ );
+ assert_eq!(
+ Transform::default(),
+ Transform::default()
+ .rotate90()
+ .flip()
+ .rotate90()
+ .mirror()
+ .rotate180()
+ );
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,187 @@
+use integral_geometry::Size;
+use std::collections::HashSet;
+use vec2d::Vec2D;
+
+#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
+pub enum Tile {
+ Empty,
+ Outside,
+ Numbered(usize),
+}
+
+impl Default for Tile {
+ fn default() -> Self {
+ Tile::Outside
+ }
+}
+
+#[derive(Debug)]
+pub struct CollapseRule {
+ pub tile: Tile,
+ pub right: HashSet<Tile>,
+ pub bottom: HashSet<Tile>,
+ pub left: HashSet<Tile>,
+ pub top: HashSet<Tile>,
+}
+
+pub struct WavefrontCollapse {
+ rules: Vec<CollapseRule>,
+ grid: Vec2D<Tile>,
+ wrap: bool,
+}
+
+impl Default for WavefrontCollapse {
+ fn default() -> Self {
+ Self {
+ rules: Vec::new(),
+ grid: Vec2D::new(&Size::new(1, 1), Tile::Empty),
+ wrap: false,
+ }
+ }
+}
+
+impl WavefrontCollapse {
+ pub fn new(wrap: bool) -> Self {
+ Self {
+ rules: Vec::new(),
+ grid: Vec2D::new(&Size::new(1, 1), Tile::Empty),
+ wrap,
+ }
+ }
+
+ pub fn generate_map<I: Iterator<Item = u32>, F: FnOnce(&mut Vec2D<Tile>)>(
+ &mut self,
+ map_size: &Size,
+ seed_fn: F,
+ random_numbers: &mut I,
+ ) {
+ self.grid = Vec2D::new(map_size, Tile::Empty);
+
+ seed_fn(&mut self.grid);
+
+ while self.collapse_step(random_numbers) {}
+ }
+
+ pub fn set_rules(&mut self, rules: Vec<CollapseRule>) {
+ self.rules = rules;
+ }
+
+ fn get_tile(&self, y: usize, x: usize) -> Tile {
+ let x = if self.wrap {
+ if x == usize::MAX {
+ self.grid.width() - 1
+ } else if x == self.grid.width() {
+ 0
+ } else {
+ x
+ }
+ } else {
+ x
+ };
+
+ self.grid.get(y, x).copied().unwrap_or_default()
+ }
+
+ fn collapse_step<I: Iterator<Item = u32>>(&mut self, random_numbers: &mut I) -> bool {
+ let mut tiles_to_collapse = (usize::max_value(), Vec::new());
+
+ // Iterate through the tiles in the land
+ for x in 0..self.grid.width() {
+ for y in 0..self.grid.height() {
+ let current_tile = self.get_tile(y, x);
+
+ if let Tile::Empty = current_tile {
+ // calc entropy
+ let right_tile = self.get_tile(y, x + 1);
+ let bottom_tile = self.get_tile(y + 1, x);
+ let left_tile = self.get_tile(y, x.wrapping_sub(1));
+ let top_tile = self.get_tile(y.wrapping_sub(1), x);
+
+ let possibilities: Vec<Tile> = self
+ .rules
+ .iter()
+ .filter_map(|rule| {
+ if rule.right.contains(&right_tile)
+ && rule.bottom.contains(&bottom_tile)
+ && rule.left.contains(&left_tile)
+ && rule.top.contains(&top_tile)
+ {
+ Some(rule.tile)
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let entropy = possibilities.len();
+ if entropy > 0 {
+ if entropy <= tiles_to_collapse.0 {
+ let entry = (
+ y,
+ x,
+ possibilities
+ [random_numbers.next().unwrap_or_default() as usize % entropy],
+ );
+
+ if entropy < tiles_to_collapse.0 {
+ tiles_to_collapse = (entropy, vec![entry])
+ } else {
+ tiles_to_collapse.1.push(entry)
+ }
+ }
+ } else {
+ /*println!("We're here: {}, {}", x, y);
+ println!(
+ "Neighbour tiles are: {:?} {:?} {:?} {:?}",
+ right_tile, bottom_tile, left_tile, top_tile
+ );
+ println!("Rules are: {:?}", self.rules);*/
+
+ //todo!("no collapse possible - what to do?")
+ }
+ }
+ }
+ }
+
+ let tiles_to_collapse = tiles_to_collapse.1;
+ let possibilities_number = tiles_to_collapse.len();
+
+ if possibilities_number > 0 {
+ let (y, x, tile) = tiles_to_collapse
+ [random_numbers.next().unwrap_or_default() as usize % possibilities_number];
+
+ *self
+ .grid
+ .get_mut(y, x)
+ .expect("correct iteration over grid") = tile;
+
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn grid(&self) -> &Vec2D<Tile> {
+ &self.grid
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Tile, WavefrontCollapse};
+ use integral_geometry::Size;
+ use vec2d::Vec2D;
+
+ #[test]
+ fn test_wavefront_collapse() {
+ let size = Size::new(4, 4);
+ let mut rnd = [0u32; 64].into_iter().cycle();
+ let mut wfc = WavefrontCollapse::default();
+
+ wfc.generate_map(&size, |_| {}, &mut rnd);
+
+ let empty_land = Vec2D::new(&size, Tile::Empty);
+
+ assert_eq!(empty_land.as_slice(), wfc.grid().as_slice());
+ }
+}
--- a/rust/lfprng/Cargo.toml Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lfprng/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -5,3 +5,4 @@
edition = "2018"
[dependencies]
+rand = "0.8"
--- a/rust/lfprng/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lfprng/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,3 +1,5 @@
+use rand::{Error, RngCore, SeedableRng};
+
pub struct LaggedFibonacciPRNG {
circular_buffer: [u32; 64],
index: usize,
@@ -5,7 +7,7 @@
impl LaggedFibonacciPRNG {
pub fn new(init_values: &[u8]) -> Self {
- let mut buf = [0xa98765 + 68; 64];
+ let mut buf = [0xa98765; 64];
for i in 0..std::cmp::min(init_values.len(), 54) {
buf[i] = init_values[i] as u32;
@@ -30,10 +32,17 @@
#[inline]
fn get_next(&mut self) -> u32 {
+ const PRIME_NUM: u32 = 2147483629;
+
self.index = (self.index + 1) & 0x3f;
- self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f]
- + self.circular_buffer[(self.index + 9) & 0x3f])
- & 0x7fffffff;
+ let next_value = self.circular_buffer[(self.index + 40) & 0x3f]
+ + self.circular_buffer[(self.index + 9) & 0x3f];
+
+ self.circular_buffer[self.index] = if next_value > PRIME_NUM {
+ next_value - PRIME_NUM
+ } else {
+ next_value
+ };
self.circular_buffer[self.index]
}
@@ -60,6 +69,32 @@
}
}
+impl RngCore for LaggedFibonacciPRNG {
+ fn next_u32(&mut self) -> u32 {
+ self.get_next().wrapping_add(self.get_next())
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ ((self.next_u32() as u64) << 32) | self.next_u32() as u64
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ dest.iter_mut().for_each(|x| *x = self.next_u32() as u8);
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
+
+impl SeedableRng for LaggedFibonacciPRNG {
+ type Seed = [u8; 32];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ LaggedFibonacciPRNG::new(&seed)
+ }
+}
+
#[cfg(test)]
#[test]
fn compatibility() {
--- a/rust/lib-hedgewars-engine/src/instance.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lib-hedgewars-engine/src/instance.rs Tue Dec 31 15:19:43 2024 +0100
@@ -5,7 +5,7 @@
use hedgewars_engine_messages::queue::*;
use integral_geometry::{Point, Rect, Size};
-use landgen::outline_template::OutlineTemplate;
+use landgen::outline_template_based::outline_template::OutlineTemplate;
use std::path::Path;
--- a/rust/lib-hedgewars-engine/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lib-hedgewars-engine/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -5,7 +5,7 @@
mod world;
use std::{
- ffi::{CString, CStr},
+ ffi::{CStr, CString},
io::{Read, Write},
mem::replace,
os::raw::{c_char, c_void},
--- a/rust/lib-hedgewars-engine/src/render/gear.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lib-hedgewars-engine/src/render/gear.rs Tue Dec 31 15:19:43 2024 +0100
@@ -71,22 +71,10 @@
}
const SPRITE_LOAD_LIST: &[(SpriteId, &str)] = &[
- (
- SpriteId::Mine,
- "Graphics/MineOn.png",
- ),
- (
- SpriteId::Grenade,
- "Graphics/Bomb.png",
- ),
- (
- SpriteId::Cheese,
- "Graphics/cheese.png",
- ),
- (
- SpriteId::Cleaver,
- "Graphics/cleaver.png",
- ),
+ (SpriteId::Mine, "Graphics/MineOn.png"),
+ (SpriteId::Grenade, "Graphics/Bomb.png"),
+ (SpriteId::Cheese, "Graphics/cheese.png"),
+ (SpriteId::Cleaver, "Graphics/cleaver.png"),
];
const MAX_SPRITES: usize = SpriteId::MaxSprite as usize + 1;
--- a/rust/lib-hedgewars-engine/src/world.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/lib-hedgewars-engine/src/world.rs Tue Dec 31 15:19:43 2024 +0100
@@ -7,8 +7,9 @@
use integral_geometry::{Point, Rect, Size};
use land2d::Land2D;
use landgen::{
- outline_template::OutlineTemplate, template_based::TemplatedLandGenerator,
- LandGenerationParameters, LandGenerator,
+ outline_template_based::outline_template::OutlineTemplate,
+ outline_template_based::template_based::TemplatedLandGenerator, LandGenerationParameters,
+ LandGenerator,
};
use lfprng::LaggedFibonacciPRNG;
use std::path::{Path, PathBuf};
@@ -69,9 +70,16 @@
use mapgen::{theme::Theme, MapGenerator};
if let Some(ref state) = self.game_state {
+ self.camera.position = state.land.play_box().center();
+
+ let parameters = LandGenerationParameters::new(0u32, 0x8000u32, 0, false, false);
let theme =
Theme::load(self.data_path.join(Path::new("Themes/Cheese/")).as_path()).unwrap();
- let texture = MapGenerator::new().make_texture(&state.land, &theme);
+ let texture = MapGenerator::<OutlineTemplate>::new().make_texture(
+ &state.land,
+ ¶meters,
+ &theme,
+ );
if let Some(ref mut renderer) = self.map_renderer {
renderer.init(&texture);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,18 @@
+[package]
+name = "lib-hwengine-future"
+version = "0.1.0"
+edition = "2021"
+authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+land2d = { path = "../land2d" }
+integral-geometry = { path = "../integral-geometry" }
+mapgen = { path = "../mapgen" }
+landgen = { path = "../landgen" }
+lfprng = { path = "../lfprng" }
+
+[lib]
+name = "hwengine_future"
+crate-type = ["cdylib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/src/ai/action.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,29 @@
+#[derive(Clone)]
+pub enum Direction {
+ Left,
+ Right,
+}
+#[derive(Clone)]
+pub enum Action {
+ Walk(Direction),
+ LongJump,
+ HighJump(usize),
+}
+
+pub struct Actions {
+ actions: Vec<Action>,
+}
+
+impl Actions {
+ pub fn new() -> Self {
+ Self { actions: vec![] }
+ }
+
+ pub fn push(&mut self, action: Action) {
+ self.actions.push(action)
+ }
+
+ pub fn pop(&mut self) -> Option<Action> {
+ self.actions.pop()
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/src/ai/ammo.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,77 @@
+#[repr(usize)]
+pub enum AmmoType {
+ Nothing,
+ Grenade,
+ ClusterBomb,
+ Bazooka,
+ Bee,
+ Shotgun,
+ PickHammer, // 6
+ Skip,
+ Rope,
+ Mine,
+ DEagle,
+ Dynamite,
+ FirePunch,
+ Whip, // 13
+ BaseballBat,
+ Parachute,
+ AirAttack,
+ MineStrike,
+ BlowTorch, // 18
+ Girder,
+ Teleport,
+ Switch,
+ Mortar,
+ Kamikaze,
+ Cake, // 24
+ Seduction,
+ Watermelon,
+ HellishBomb,
+ Napalm,
+ Drill,
+ Ballgun, // 30
+ RCPlane,
+ LowGravity,
+ ExtraDamage,
+ Invulnerable,
+ ExtraTime, // 35
+ LaserSight,
+ Vampiric,
+ SniperRifle,
+ Jetpack,
+ Molotov,
+ Birdy,
+ PortalGun, // 42
+ Piano,
+ GasBomb,
+ SineGun,
+ Flamethrower,
+ SMine,
+ Hammer, // 48
+ Resurrector,
+ DrillStrike,
+ Snowball,
+ Tardis,
+ LandGun, // 53
+ IceGun,
+ Knife,
+ Rubber,
+ AirMine,
+ Creeper,
+ Minigun,
+ Sentry, // 60
+ Count,
+}
+
+impl TryFrom<usize> for AmmoType {
+ type Error = &'static str;
+
+ fn try_from(value: usize) -> Result<Self, Self::Error> {
+ if value < Self::Count as usize {
+ Ok(unsafe { std::mem::transmute(value) })
+ } else {
+ Err("Invalid ammo type")
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/src/ai/attack_tests.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,20 @@
+use crate::ai::ammo::AmmoType;
+use crate::ai::Target;
+use crate::GameField;
+
+fn analyze_grenade(game_field: &GameField, targets: &[Target], my_x: f32, my_y: f32) {}
+
+impl AmmoType {
+ pub(crate) fn analyze_attacks(
+ &self,
+ game_field: &GameField,
+ targets: &[Target],
+ my_x: f32,
+ my_y: f32,
+ ) {
+ match self {
+ AmmoType::Grenade => analyze_grenade(game_field, targets, my_x, my_y),
+ _ => {}
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/src/ai/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,119 @@
+mod action;
+pub mod ammo;
+mod attack_tests;
+
+use crate::GameField;
+use action::*;
+use integral_geometry::Point;
+use std::collections::HashMap;
+
+pub struct Target {
+ point: Point,
+ health: i32,
+ radius: u32,
+ density: f32,
+}
+
+pub struct Hedgehog {
+ pub(crate) x: f32,
+ pub(crate) y: f32,
+ pub(crate) ammo: [u32; ammo::AmmoType::Count as usize],
+}
+
+pub struct AI<'a> {
+ game_field: &'a GameField,
+ ammo: [u32; ammo::AmmoType::Count as usize],
+ targets: Vec<Target>,
+ team: Vec<Hedgehog>,
+ planned_actions: Option<Actions>,
+}
+
+#[derive(Clone)]
+pub(crate) struct Waypoint {
+ x: f32,
+ y: f32,
+ ticks: usize,
+ damage: usize,
+ previous_point: Option<(usize, Action)>,
+}
+
+#[derive(Default)]
+pub(crate) struct Waypoints {
+ key_points: Vec<Waypoint>,
+ points: HashMap<Point, Waypoint>,
+}
+
+impl Waypoints {
+ fn add_keypoint(&mut self, waypoint: Waypoint) {
+ let [x, y] = [waypoint.x, waypoint.y].map(|i| i as i32);
+ let point = Point::new(x, y);
+ self.key_points.push(waypoint.clone());
+ self.points.insert(point, waypoint);
+ }
+}
+
+impl IntoIterator for Waypoints {
+ type Item = Waypoint;
+ type IntoIter = std::collections::hash_map::IntoValues<Point, Waypoint>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.points.into_values()
+ }
+}
+
+impl<'a> AI<'a> {
+ pub fn new(game_field: &'a GameField) -> AI<'a> {
+ Self {
+ game_field,
+ ammo: [0; ammo::AmmoType::Count as usize],
+ targets: vec![],
+ team: vec![],
+ planned_actions: None,
+ }
+ }
+
+ pub fn set_available_ammo(&mut self, ammo: [u32; ammo::AmmoType::Count as usize]) {
+ self.ammo = ammo;
+ }
+
+ pub fn get_team_mut(&mut self) -> &mut Vec<Hedgehog> {
+ &mut self.team
+ }
+
+ pub fn walk(&self, hedgehog: &Hedgehog) {
+ let mut stack = Vec::<usize>::new();
+ let mut waypoints = Waypoints::default();
+
+ waypoints.add_keypoint(Waypoint {
+ x: hedgehog.x,
+ y: hedgehog.y,
+ ticks: 0,
+ damage: 0,
+ previous_point: None,
+ });
+
+ while let Some(waypoint) = stack.pop() {
+ // find other positions
+ }
+
+ for Waypoint { x, y, .. } in waypoints {
+ self.analyze_position_attacks(x, y);
+ }
+ }
+
+ fn analyze_position_attacks(&self, x: f32, y: f32) {
+ self.ammo
+ .iter()
+ .enumerate()
+ .filter(|&(_, &count)| count > 0u32)
+ .for_each(|(a, &count)| {
+ let a = ammo::AmmoType::try_from(a).expect("What are you iterating over?");
+
+ a.analyze_attacks(self.game_field, &self.targets, x, y)
+ });
+ }
+
+ pub fn have_plan(&self) -> bool {
+ self.planned_actions.is_some()
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/lib-hwengine-future/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,293 @@
+mod ai;
+
+use integral_geometry::{Point, Size};
+
+use ai::*;
+use landgen::{
+ maze::MazeTemplate, outline_template_based::outline_template::OutlineTemplate,
+ wavefront_collapse::generator::TemplateDescription as WfcTemplate, LandGenerationParameters,
+ LandGenerator,
+};
+use lfprng::LaggedFibonacciPRNG;
+use mapgen::{theme::Theme, MapGenerator};
+use std::fs;
+use std::ptr::slice_from_raw_parts;
+use std::{ffi::CStr, path::Path};
+
+#[repr(C)]
+pub struct GameField {
+ collision: land2d::Land2D<u16>,
+ pixels: land2d::Land2D<u32>,
+ landgen_parameters: Option<LandGenerationParameters<u16>>,
+}
+
+#[no_mangle]
+pub extern "C" fn get_game_field_parameters(
+ game_field: &GameField,
+ width: &mut i32,
+ height: &mut i32,
+ play_width: &mut i32,
+ play_height: &mut i32,
+) {
+ *width = game_field.collision.width() as i32;
+ *height = game_field.collision.height() as i32;
+
+ *play_width = game_field.collision.play_width() as i32;
+ *play_height = game_field.collision.play_height() as i32;
+}
+
+#[no_mangle]
+pub extern "C" fn create_empty_game_field(width: u32, height: u32) -> *mut GameField {
+ let game_field = Box::new(GameField {
+ collision: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0),
+ pixels: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0),
+ landgen_parameters: None,
+ });
+
+ Box::into_raw(game_field)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn generate_outline_templated_game_field(
+ feature_size: u32,
+ seed: *const i8,
+ template_type: *const i8,
+ data_path: *const i8,
+) -> *mut GameField {
+ let data_path: &str = CStr::from_ptr(data_path).to_str().unwrap();
+ let data_path = Path::new(&data_path);
+
+ let seed: &str = CStr::from_ptr(seed).to_str().unwrap();
+ let template_type: &str = CStr::from_ptr(template_type).to_str().unwrap();
+
+ let mut random_numbers_gen = LaggedFibonacciPRNG::new(seed.as_bytes());
+
+ let yaml_templates =
+ fs::read_to_string(data_path.join(Path::new("map_templates.yaml")).as_path())
+ .expect("Error reading map templates file");
+ let mut map_gen = MapGenerator::<OutlineTemplate>::new(data_path);
+ map_gen.import_yaml_templates(&yaml_templates);
+
+ let distance_divisor = feature_size.pow(2) / 8 + 10;
+ let params = LandGenerationParameters::new(0u16, 0x8000u16, distance_divisor, false, false);
+ let template = map_gen
+ .get_template(template_type, &mut random_numbers_gen)
+ .expect("Error reading outline templates file")
+ .clone();
+ let landgen = map_gen.build_generator(template);
+ let collision = landgen.generate_land(¶ms, &mut random_numbers_gen);
+ let size = collision.size().size();
+
+ let game_field = Box::new(GameField {
+ collision,
+ pixels: land2d::Land2D::new(&size, 0),
+ landgen_parameters: Some(params),
+ });
+
+ Box::into_raw(game_field)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn generate_wfc_templated_game_field(
+ feature_size: u32,
+ seed: *const i8,
+ template_type: *const i8,
+ data_path: *const i8,
+) -> *mut GameField {
+ let data_path: &str = CStr::from_ptr(data_path).to_str().unwrap();
+ let data_path = Path::new(&data_path);
+
+ let seed: &str = CStr::from_ptr(seed).to_str().unwrap();
+ let template_type: &str = CStr::from_ptr(template_type).to_str().unwrap();
+
+ let mut random_numbers_gen = LaggedFibonacciPRNG::new(seed.as_bytes());
+
+ let yaml_templates =
+ fs::read_to_string(data_path.join(Path::new("wfc_templates.yaml")).as_path())
+ .expect("Error reading map templates file");
+ let mut map_gen = MapGenerator::<WfcTemplate>::new(data_path);
+ map_gen.import_yaml_templates(&yaml_templates);
+
+ let distance_divisor = feature_size.pow(2) / 8 + 10;
+ let params = LandGenerationParameters::new(0u16, 0x8000u16, distance_divisor, false, false);
+ let template = map_gen
+ .get_template(template_type, &mut random_numbers_gen)
+ .expect("Error reading wfc templates file")
+ .clone();
+ let landgen = map_gen.build_generator(template);
+ let collision = landgen.generate_land(¶ms, &mut random_numbers_gen);
+ let size = collision.size().size();
+
+ let game_field = Box::new(GameField {
+ collision,
+ pixels: land2d::Land2D::new(&size, 0),
+ landgen_parameters: Some(params),
+ });
+
+ Box::into_raw(game_field)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn generate_maze_game_field(
+ feature_size: u32,
+ seed: *const i8,
+ template_type: *const i8,
+ data_path: *const i8,
+) -> *mut GameField {
+ let data_path: &str = CStr::from_ptr(data_path).to_str().unwrap();
+ let data_path = Path::new(&data_path);
+
+ let seed: &str = CStr::from_ptr(seed).to_str().unwrap();
+ let template_type: &str = CStr::from_ptr(template_type).to_str().unwrap();
+
+ let mut random_numbers_gen = LaggedFibonacciPRNG::new(seed.as_bytes());
+
+ let yaml_templates =
+ fs::read_to_string(data_path.join(Path::new("maze_templates.yaml")).as_path())
+ .expect("Error reading map templates file");
+
+ let mut map_gen = MapGenerator::<MazeTemplate>::new(data_path);
+ map_gen.import_yaml_templates(&yaml_templates);
+
+ let distance_divisor = feature_size.pow(2) / 8 + 10;
+ let params = LandGenerationParameters::new(0u16, 0x8000u16, distance_divisor, false, false);
+
+ let template = map_gen
+ .get_template(template_type, &mut random_numbers_gen)
+ .expect("Error reading maze templates file")
+ .clone();
+
+ let landgen = map_gen.build_generator(template);
+ let collision = landgen.generate_land(¶ms, &mut random_numbers_gen);
+ let size = collision.size().size();
+
+ let game_field = Box::new(GameField {
+ collision,
+ pixels: land2d::Land2D::new(&size, 0),
+ landgen_parameters: Some(params),
+ });
+
+ Box::into_raw(game_field)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn apply_theme(
+ game_field: &mut GameField,
+ data_path: *const i8,
+ theme_name: *const i8,
+) {
+ let data_path: &str = CStr::from_ptr(data_path).to_str().unwrap();
+ let data_path = Path::new(&data_path);
+
+ let theme_name: &str = CStr::from_ptr(theme_name).to_str().unwrap();
+ let map_gen = MapGenerator::<()>::new(data_path);
+
+ let theme = Theme::load(
+ data_path
+ .join(Path::new("Themes"))
+ .join(Path::new(theme_name))
+ .as_path(),
+ )
+ .unwrap();
+
+ let params = game_field
+ .landgen_parameters
+ .expect("Land generator parameters specified");
+ let pixels = map_gen.make_texture(&game_field.collision, ¶ms, &theme);
+
+ game_field.pixels = pixels.into();
+}
+
+#[no_mangle]
+pub extern "C" fn land_get(game_field: &GameField, x: i32, y: i32) -> u16 {
+ game_field.collision.get(y, x)
+}
+
+#[no_mangle]
+pub extern "C" fn land_set(game_field: &mut GameField, x: i32, y: i32, value: u16) {
+ game_field.collision.map(y, x, |p| *p = value);
+}
+
+#[no_mangle]
+pub extern "C" fn land_row(game_field: &mut GameField, row: i32) -> *mut u16 {
+ game_field.collision[row as usize].as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn land_fill(
+ game_field: &mut GameField,
+ x: i32,
+ y: i32,
+ border_value: u16,
+ fill_value: u16,
+) {
+ game_field
+ .collision
+ .fill(Point::new(x, y), border_value, fill_value)
+}
+
+#[no_mangle]
+pub extern "C" fn land_pixel_get(game_field: &GameField, x: i32, y: i32) -> u32 {
+ game_field.pixels.get(y, x)
+}
+
+#[no_mangle]
+pub extern "C" fn land_pixel_set(game_field: &mut GameField, x: i32, y: i32, value: u32) {
+ game_field.pixels.map(y, x, |p| *p = value);
+}
+
+#[no_mangle]
+pub extern "C" fn land_pixel_row(game_field: &mut GameField, row: i32) -> *mut u32 {
+ game_field.pixels[row as usize].as_mut_ptr()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn dispose_game_field(game_field: *mut GameField) {
+ drop(Box::from_raw(game_field));
+}
+
+#[no_mangle]
+pub extern "C" fn create_ai(game_field: &GameField) -> *mut AI {
+ Box::into_raw(Box::new(AI::new(game_field)))
+}
+
+#[no_mangle]
+pub extern "C" fn ai_clear_team(ai: &mut AI) {
+ *ai.get_team_mut() = vec![];
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn ai_add_team_hedgehog(
+ ai: &mut AI,
+ x: f32,
+ y: f32,
+ ammo_counts: *const u32,
+) {
+ let ammo_counts =
+ &*slice_from_raw_parts(ammo_counts, crate::ai::ammo::AmmoType::Count as usize);
+ let ammo_counts = std::array::from_fn(|i| ammo_counts[i].clone());
+
+ ai.get_team_mut().push(Hedgehog {
+ x,
+ y,
+ ammo: ammo_counts,
+ });
+}
+
+#[no_mangle]
+pub extern "C" fn ai_think(ai: &AI) {}
+
+#[no_mangle]
+pub extern "C" fn ai_have_plan(ai: &AI) -> bool {
+ ai.have_plan()
+}
+
+#[no_mangle]
+pub extern "C" fn ai_get(ai: &AI) -> bool {
+ ai.have_plan()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn dispose_ai(ai: *mut AI) {
+ drop(Box::from_raw(ai));
+}
--- a/rust/mapgen/Cargo.toml Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/mapgen/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -11,7 +11,7 @@
lfprng = { path = "../lfprng" }
integral-geometry = { path = "../integral-geometry" }
-rand = "0.5"
+rand = "0.8"
serde = "1.0"
serde_yaml = "0.8"
serde_derive = "1.0"
--- a/rust/mapgen/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/mapgen/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,79 +1,28 @@
+mod template;
pub mod theme;
use self::theme::Theme;
-use integral_geometry::{Point, Rect, Size};
-use land2d::Land2D;
-use landgen::outline_template::OutlineTemplate;
-use rand::{thread_rng, Rng};
-use serde_derive::Deserialize;
-use serde_yaml;
-use std::{borrow::Borrow, collections::hash_map::HashMap, mem::replace};
-use vec2d::Vec2D;
-
-#[derive(Deserialize)]
-struct PointDesc {
- x: u32,
- y: u32,
-}
+use crate::template::outline::TemplateCollectionDesc as OutlineTemplateCollectionDesc;
+use crate::template::wavefront_collapse::TemplateCollectionDesc as WfcTemplateCollectionDesc;
+use crate::template::maze::TemplateCollectionDesc as MazeTemplateCollectionDesc;
-#[derive(Deserialize)]
-struct RectDesc {
- x: u32,
- y: u32,
- w: u32,
- h: u32,
-}
-
-#[derive(Deserialize)]
-struct TemplateDesc {
- width: usize,
- height: usize,
- can_flip: bool,
- can_invert: bool,
- can_mirror: bool,
- is_negative: bool,
- put_girders: bool,
- max_hedgehogs: u8,
- outline_points: Vec<Vec<RectDesc>>,
- fill_points: Vec<PointDesc>,
-}
+use std::path::{Path, PathBuf};
-#[derive(Deserialize)]
-struct TemplateCollectionDesc {
- templates: Vec<TemplateDesc>,
- template_types: HashMap<String, Vec<usize>>,
-}
+use land2d::Land2D;
+use landgen::{
+ outline_template_based::{
+ outline_template::OutlineTemplate, template_based::TemplatedLandGenerator,
+ },
+ wavefront_collapse::generator::{
+ TemplateDescription as WfcTemplate, WavefrontCollapseLandGenerator,
+ },
+ maze::{MazeTemplate, MazeLandGenerator},
+ LandGenerationParameters, LandGenerator,
+};
+use rand::{seq::SliceRandom, Rng};
-impl From<&TemplateDesc> for OutlineTemplate {
- fn from(desc: &TemplateDesc) -> Self {
- OutlineTemplate {
- islands: desc
- .outline_points
- .iter()
- .map(|v| {
- v.iter()
- .map(|r| {
- Rect::from_size(
- Point::new(r.x as i32, r.y as i32),
- Size::new(r.w as usize, r.h as usize),
- )
- })
- .collect()
- })
- .collect(),
- fill_points: desc
- .fill_points
- .iter()
- .map(|p| Point::new(p.x as i32, p.y as i32))
- .collect(),
- size: Size::new(desc.width, desc.height),
- can_flip: desc.can_flip,
- can_invert: desc.can_invert,
- can_mirror: desc.can_mirror,
- is_negative: desc.is_negative,
- }
- }
-}
+use std::{borrow::Borrow, collections::hash_map::HashMap};
+use vec2d::Vec2D;
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct TemplateType(String);
@@ -85,43 +34,35 @@
}
#[derive(Debug)]
-pub struct MapGenerator {
- pub(crate) templates: HashMap<TemplateType, Vec<OutlineTemplate>>,
+pub struct MapGenerator<T> {
+ pub(crate) templates: HashMap<TemplateType, Vec<T>>,
+ data_path: PathBuf,
}
-impl MapGenerator {
- pub fn new() -> Self {
+impl<T> MapGenerator<T> {
+ pub fn new(data_path: &Path) -> Self {
Self {
templates: HashMap::new(),
+ data_path: data_path.to_owned(),
}
}
- pub fn import_yaml_templates(&mut self, text: &str) {
- let mut desc: TemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
- let templates = replace(&mut desc.templates, vec![]);
- self.templates = desc
- .template_types
- .into_iter()
- .map(|(size, indices)| {
- (
- TemplateType(size),
- indices.iter().map(|i| (&templates[*i]).into()).collect(),
- )
- })
- .collect();
+ pub fn get_template<R: Rng>(&self, template_type: &str, rng: &mut R) -> Option<&T> {
+ self.templates
+ .get(template_type)
+ .and_then(|t| t.as_slice().choose(rng))
}
- pub fn get_template(&self, template_type: &str) -> Option<&OutlineTemplate> {
- self.templates
- .get(template_type)
- .and_then(|t| thread_rng().choose(t))
- }
-
- pub fn make_texture<LandT>(&self, land: &Land2D<LandT>, theme: &Theme) -> Vec2D<u32>
+ pub fn make_texture<LandT>(
+ &self,
+ land: &Land2D<LandT>,
+ parameters: &LandGenerationParameters<LandT>,
+ theme: &Theme,
+ ) -> Vec2D<u32>
where
LandT: Copy + Default + PartialEq,
{
- let mut texture = Vec2D::new(land.size().size(), 0);
+ let mut texture = Vec2D::new(&land.size().size(), 0);
if let Some(land_sprite) = theme.land_texture() {
for (row_index, (land_row, tex_row)) in land.rows().zip(texture.rows_mut()).enumerate()
@@ -131,6 +72,7 @@
while sprite_row.len() < land.width() - x_offset {
let copy_range = x_offset..x_offset + sprite_row.len();
tex_row_copy(
+ parameters.basic(),
&land_row[copy_range.clone()],
&mut tex_row[copy_range],
sprite_row,
@@ -142,6 +84,7 @@
if x_offset < land.width() {
let final_range = x_offset..land.width();
tex_row_copy(
+ parameters.basic(),
&land_row[final_range.clone()],
&mut tex_row[final_range],
&sprite_row[..land.width() - x_offset],
@@ -158,6 +101,7 @@
let mut offsets = vec![255u8; land.width()];
land_border_pass(
+ parameters.basic(),
land.rows().rev().zip(texture.rows_mut().rev()),
&mut offsets,
border_width,
@@ -170,6 +114,7 @@
offsets.iter_mut().for_each(|v| *v = 255);
land_border_pass(
+ parameters.basic(),
land.rows().zip(texture.rows_mut()),
&mut offsets,
border_width,
@@ -181,13 +126,87 @@
}
}
+impl MapGenerator<OutlineTemplate> {
+ pub fn import_yaml_templates(&mut self, text: &str) {
+ let mut desc: OutlineTemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
+ let templates = std::mem::take(&mut desc.templates);
+ self.templates = desc
+ .template_types
+ .into_iter()
+ .map(|(size, indices)| {
+ (
+ TemplateType(size),
+ indices
+ .indices
+ .iter()
+ .map(|i| Into::<OutlineTemplate>::into(templates[*i].clone()))
+ .map(|o| {
+ if indices.force_invert == Some(true) {
+ o.cavern()
+ } else {
+ o
+ }
+ })
+ .collect(),
+ )
+ })
+ .collect();
+ }
+
+ pub fn build_generator(&self, template: OutlineTemplate) -> impl LandGenerator {
+ TemplatedLandGenerator::new(template)
+ }
+}
+
+impl MapGenerator<WfcTemplate> {
+ pub fn import_yaml_templates(&mut self, text: &str) {
+ let mut desc: WfcTemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
+ let templates = std::mem::take(&mut desc.templates);
+ self.templates = desc
+ .template_types
+ .into_iter()
+ .map(|(size, indices)| {
+ (
+ TemplateType(size),
+ indices.iter().map(|i| (&templates[*i]).into()).collect(),
+ )
+ })
+ .collect();
+ }
+
+ pub fn build_generator(&self, template: WfcTemplate) -> impl LandGenerator {
+ WavefrontCollapseLandGenerator::new(template, &self.data_path)
+ }
+}
+
+impl MapGenerator<MazeTemplate> {
+ pub fn import_yaml_templates(&mut self, text: &str) {
+ let mut desc: MazeTemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
+ let templates = std::mem::take(&mut desc.templates);
+ self.templates = desc
+ .template_types
+ .into_iter()
+ .map(|(size, indices)| {
+ (
+ TemplateType(size),
+ indices.iter().map(|i| (&templates[*i]).into()).collect(),
+ )
+ })
+ .collect();
+ }
+
+ pub fn build_generator(&self, template: MazeTemplate) -> impl LandGenerator {
+ MazeLandGenerator::new(template)
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Color(u32);
impl Color {
#[inline]
fn red(self) -> u8 {
- (self.0 >> 0 & 0xFF) as u8
+ (self.0 & 0xFF) as u8
}
#[inline]
@@ -219,11 +238,16 @@
let red = lerp(target.red(), source.red(), source.alpha());
let green = lerp(target.green(), source.green(), source.alpha());
let blue = lerp(target.blue(), source.blue(), source.alpha());
- (red as u32) << 0 | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24
+ (red as u32) | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24
}
-fn land_border_pass<'a, LandT, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F)
-where
+fn land_border_pass<'a, LandT, T, F>(
+ basic_value: LandT,
+ rows: T,
+ offsets: &mut [u8],
+ border_width: u8,
+ pixel_getter: F,
+) where
LandT: Default + PartialEq + 'a,
T: Iterator<Item = (&'a [LandT], &'a mut [u32])>,
F: (Fn(usize, usize) -> u32),
@@ -235,7 +259,7 @@
.zip(offsets.iter_mut())
.enumerate()
{
- *offset_v = if *land_v == LandT::default() {
+ *offset_v = if *land_v == basic_value {
if *offset_v < border_width {
*tex_v = blend(pixel_getter(x, *offset_v as usize), *tex_v)
}
@@ -247,22 +271,24 @@
}
}
-fn tex_row_copy<LandT>(land_row: &[LandT], tex_row: &mut [u32], sprite_row: &[u32])
-where
+fn tex_row_copy<LandT>(
+ basic_value: LandT,
+ land_row: &[LandT],
+ tex_row: &mut [u32],
+ sprite_row: &[u32],
+) where
LandT: Default + PartialEq,
{
for ((land_v, tex_v), sprite_v) in land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row) {
- *tex_v = if *land_v == LandT::default() {
- *sprite_v
- } else {
- 0
- }
+ *tex_v = if *land_v == basic_value { *sprite_v } else { 0 }
}
}
#[cfg(test)]
mod tests {
- use crate::{MapGenerator, TemplateType};
+ use std::path::Path;
+ use crate::{MapGenerator, OutlineTemplate, TemplateType};
+ use rand::thread_rng;
#[test]
fn simple_load() {
@@ -293,17 +319,18 @@
- {x: 1023, y: 0}
template_types:
- test: [0]
+ test:
+ indices: [0]
"#;
- let mut generator = MapGenerator::new();
+ let mut generator = MapGenerator::<OutlineTemplate>::new(Path::new(""));
generator.import_yaml_templates(&text);
assert!(generator
.templates
.contains_key(&TemplateType("test".to_string())));
- let template = generator.get_template("test").unwrap();
+ let template = generator.get_template("test", &mut thread_rng()).unwrap();
assert_eq!(template.islands[0].len(), 7);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/mapgen/src/template/maze.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,33 @@
+use landgen::maze::MazeTemplate;
+use serde_derive::Deserialize;
+
+use std::collections::hash_map::HashMap;
+#[derive(Deserialize)]
+pub struct TemplateDesc {
+ width: usize,
+ height: usize,
+ max_hedgehogs: u8,
+ cell_size: usize,
+ distortion_limiting_factor: u32,
+ braidness: u32,
+ invert: bool,
+}
+
+#[derive(Deserialize)]
+pub struct TemplateCollectionDesc {
+ pub templates: Vec<TemplateDesc>,
+ pub template_types: HashMap<String, Vec<usize>>,
+}
+
+impl From<&TemplateDesc> for MazeTemplate {
+ fn from(desc: &TemplateDesc) -> Self {
+ MazeTemplate {
+ width: desc.width,
+ height: desc.height,
+ cell_size: desc.cell_size,
+ inverted: desc.invert,
+ distortion_limiting_factor: desc.distortion_limiting_factor,
+ braidness: desc.braidness,
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/mapgen/src/template/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+pub mod outline;
+pub mod wavefront_collapse;
+pub mod maze;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/mapgen/src/template/outline.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,92 @@
+use integral_geometry::{Point, Rect, Size};
+
+use landgen::outline_template_based::outline_template::OutlineTemplate;
+use serde_derive::Deserialize;
+
+use std::collections::hash_map::HashMap;
+
+#[derive(Deserialize, Clone)]
+pub struct PointDesc {
+ x: u32,
+ y: u32,
+}
+
+#[derive(Deserialize, Clone)]
+pub struct RectDesc {
+ x: u32,
+ y: u32,
+ w: u32,
+ h: u32,
+}
+
+#[derive(Deserialize, Clone)]
+pub struct TemplateDesc {
+ width: usize,
+ height: usize,
+ can_flip: bool,
+ can_invert: bool,
+ can_mirror: bool,
+ is_negative: bool,
+ put_girders: bool,
+ max_hedgehogs: u8,
+ outline_points: Vec<Vec<RectDesc>>,
+ walls: Option<Vec<Vec<RectDesc>>>,
+ fill_points: Vec<PointDesc>,
+}
+
+#[derive(Deserialize)]
+pub struct TemplateTypeDesc {
+ pub indices: Vec<usize>,
+ pub force_invert: Option<bool>,
+}
+
+#[derive(Deserialize)]
+pub struct TemplateCollectionDesc {
+ pub templates: Vec<TemplateDesc>,
+ pub template_types: HashMap<String, TemplateTypeDesc>,
+}
+
+impl From<TemplateDesc> for OutlineTemplate {
+ fn from(desc: TemplateDesc) -> Self {
+ OutlineTemplate {
+ islands: desc
+ .outline_points
+ .iter()
+ .map(|v| {
+ v.iter()
+ .map(|r| {
+ Rect::from_size(
+ Point::new(r.x as i32, r.y as i32),
+ Size::new(r.w as usize, r.h as usize),
+ )
+ })
+ .collect()
+ })
+ .collect(),
+ walls: desc
+ .walls.unwrap_or_default()
+ .iter()
+ .map(|v| {
+ v.iter()
+ .map(|r| {
+ Rect::from_size(
+ Point::new(r.x as i32, r.y as i32),
+ Size::new(r.w as usize, r.h as usize),
+ )
+ })
+ .collect()
+ })
+ .collect(),
+ fill_points: desc
+ .fill_points
+ .iter()
+ .map(|p| Point::new(p.x as i32, p.y as i32))
+ .collect(),
+ size: Size::new(desc.width, desc.height),
+ can_flip: desc.can_flip,
+ can_invert: desc.can_invert,
+ can_mirror: desc.can_mirror,
+ is_negative: desc.is_negative,
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/mapgen/src/template/wavefront_collapse.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,105 @@
+use integral_geometry::Size;
+
+use landgen::wavefront_collapse::generator::*;
+use serde_derive::Deserialize;
+
+use std::collections::hash_map::HashMap;
+
+#[derive(Deserialize)]
+#[serde(remote = "EdgeDescription")]
+pub struct EdgeDesc {
+ pub name: String,
+ pub reversed: Option<bool>,
+ pub symmetrical: Option<bool>,
+}
+
+#[derive(Deserialize)]
+#[serde(remote = "EdgesDescription")]
+pub struct EdgesDesc {
+ #[serde(with = "EdgeDesc")]
+ pub top: EdgeDescription,
+ #[serde(with = "EdgeDesc")]
+ pub right: EdgeDescription,
+ #[serde(with = "EdgeDesc")]
+ pub bottom: EdgeDescription,
+ #[serde(with = "EdgeDesc")]
+ pub left: EdgeDescription,
+}
+
+#[derive(Deserialize)]
+#[serde(remote = "TileDescription")]
+pub struct TileDesc {
+ pub name: String,
+ #[serde(with = "EdgesDesc")]
+ pub edges: EdgesDescription,
+ pub is_negative: Option<bool>,
+ pub can_flip: Option<bool>,
+ pub can_mirror: Option<bool>,
+ pub can_rotate90: Option<bool>,
+ pub can_rotate180: Option<bool>,
+ pub can_rotate270: Option<bool>,
+}
+
+#[derive(Deserialize)]
+pub struct TileDescriptionHelper(#[serde(with = "TileDesc")] TileDescription);
+#[derive(Deserialize)]
+pub struct EdgeDescriptionHelper(#[serde(with = "EdgeDesc")] EdgeDescription);
+
+#[derive(Deserialize)]
+pub struct NonStrictEdgesDesc {
+ pub top: Option<EdgeDescriptionHelper>,
+ pub right: Option<EdgeDescriptionHelper>,
+ pub bottom: Option<EdgeDescriptionHelper>,
+ pub left: Option<EdgeDescriptionHelper>,
+}
+
+#[derive(Deserialize)]
+pub struct TemplateDesc {
+ pub width: usize,
+ pub height: usize,
+ pub can_invert: bool,
+ pub is_negative: bool,
+ pub put_girders: bool,
+ pub max_hedgehogs: u8,
+ pub wrap: bool,
+ pub edges: Option<NonStrictEdgesDesc>,
+ pub tiles: Vec<TileDescriptionHelper>,
+}
+
+#[derive(Deserialize)]
+pub struct TemplateCollectionDesc {
+ pub templates: Vec<TemplateDesc>,
+ pub template_types: HashMap<String, Vec<usize>>,
+}
+
+impl From<&TemplateDesc> for TemplateDescription {
+ fn from(desc: &TemplateDesc) -> Self {
+ let [top, right, bottom, left] = if let Some(edges) = &desc.edges {
+ [
+ edges.top.as_ref(),
+ edges.right.as_ref(),
+ edges.bottom.as_ref(),
+ edges.left.as_ref(),
+ ]
+ .map(|e| e.map(|EdgeDescriptionHelper(e)| e.clone()))
+ } else {
+ [None, None, None, None]
+ };
+
+ Self {
+ size: Size::new(desc.width, desc.height),
+ tiles: desc
+ .tiles
+ .iter()
+ .map(|TileDescriptionHelper(t)| t.clone())
+ .collect(),
+ wrap: desc.wrap,
+ edges: NonStrictEdgesDescription {
+ top,
+ right,
+ bottom,
+ left,
+ },
+ }
+ }
+}
--- a/rust/mapgen/src/theme.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/mapgen/src/theme.rs Tue Dec 31 15:19:43 2024 +0100
@@ -48,7 +48,7 @@
pub fn to_transposed(&self) -> ThemeSprite {
let size = self.size().transpose();
- let mut pixels = Vec2D::new(size, 0u32);
+ let mut pixels = Vec2D::new(&size, 0u32);
for (y, row) in self.pixels.rows().enumerate() {
for (x, v) in row.iter().enumerate() {
pixels[x][y] = *v;
@@ -238,7 +238,7 @@
}
let size = Size::new(info.width as usize, info.height as usize);
- let mut pixels: Vec2D<u32> = Vec2D::new(size, 0);
+ let mut pixels: Vec2D<u32> = Vec2D::new(&size, 0);
reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?;
Ok(ThemeSprite { pixels })
--- a/rust/vec2d/src/lib.rs Sat Sep 28 22:27:13 2024 +0200
+++ b/rust/vec2d/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -1,9 +1,10 @@
+use integral_geometry::Size;
use std::{
ops::{Index, IndexMut},
- slice::SliceIndex
+ slice::SliceIndex,
};
-use integral_geometry::Size;
+#[derive(Debug)]
pub struct Vec2D<T> {
data: Vec<T>,
size: Size,
@@ -33,7 +34,7 @@
}
}
-impl <T> Vec2D<T> {
+impl<T> Vec2D<T> {
#[inline]
pub fn width(&self) -> usize {
self.size.width
@@ -51,8 +52,11 @@
}
impl<T: Copy> Vec2D<T> {
- pub fn new(size: Size, value: T) -> Self {
- Self { size, data: vec![value; size.area()] }
+ pub fn new(size: &Size, value: T) -> Self {
+ Self {
+ size: *size,
+ data: vec![value; size.area()],
+ }
}
#[inline]
@@ -67,21 +71,41 @@
#[inline]
pub fn get(&self, row: usize, column: usize) -> Option<&<usize as SliceIndex<[T]>>::Output> {
- self.data.get(row * self.width() + column)
+ if row < self.height() && column < self.width() {
+ Some(unsafe { self.data.get_unchecked(row * self.width() + column) })
+ } else {
+ None
+ }
}
#[inline]
- pub fn get_mut(&mut self, row: usize, column: usize) -> Option<&mut <usize as SliceIndex<[T]>>::Output> {
- self.data.get_mut(row * self.size.width + column)
+ pub fn get_mut(
+ &mut self,
+ row: usize,
+ column: usize,
+ ) -> Option<&mut <usize as SliceIndex<[T]>>::Output> {
+ if row < self.height() && column < self.width() {
+ Some(unsafe { self.data.get_unchecked_mut(row * self.size.width + column) })
+ } else {
+ None
+ }
}
#[inline]
- pub unsafe fn get_unchecked(&self, row: usize, column: usize) -> &<usize as SliceIndex<[T]>>::Output {
+ pub unsafe fn get_unchecked(
+ &self,
+ row: usize,
+ column: usize,
+ ) -> &<usize as SliceIndex<[T]>>::Output {
self.data.get_unchecked(row * self.width() + column)
}
#[inline]
- pub unsafe fn get_unchecked_mut(&mut self, row: usize, column: usize) -> &mut <usize as SliceIndex<[T]>>::Output {
+ pub unsafe fn get_unchecked_mut(
+ &mut self,
+ row: usize,
+ column: usize,
+ ) -> &mut <usize as SliceIndex<[T]>>::Output {
self.data.get_unchecked_mut(row * self.size.width + column)
}
@@ -98,11 +122,8 @@
#[inline]
pub unsafe fn as_bytes(&self) -> &[u8] {
- use std::{
- slice,
- mem
- };
-
+ use std::{mem, slice};
+
slice::from_raw_parts(
self.data.as_ptr() as *const u8,
self.data.len() * mem::size_of::<T>(),
@@ -122,6 +143,17 @@
}
}
+impl<T: Clone> Vec2D<T> {
+ pub fn from_iter<I: IntoIterator<Item = T>>(iter: I, size: &Size) -> Option<Vec2D<T>> {
+ let data: Vec<T> = iter.into_iter().collect();
+ if size.width * size.height == data.len() {
+ Some(Vec2D { data, size: *size })
+ } else {
+ None
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
--- a/share/hedgewars/Data/CMakeLists.txt Sat Sep 28 22:27:13 2024 +0200
+++ b/share/hedgewars/Data/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -10,6 +10,7 @@
Scripts
Sounds
Themes
+ Tiles
misc
)
add_subdirectory(${dir})
@@ -18,3 +19,9 @@
if(${GL2})
add_subdirectory(Shaders)
endif(${GL2})
+
+install(FILES
+ map_templates.yaml
+ maze_templates.yaml
+ wfc_templates.yaml
+ DESTINATION ${SHAREPATH}Data)
Binary file share/hedgewars/Data/Tiles/120_bar.png has changed
Binary file share/hedgewars/Data/Tiles/120_corner.png has changed
Binary file share/hedgewars/Data/Tiles/120_filled.png has changed
Binary file share/hedgewars/Data/Tiles/120_two_corners.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Tiles/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+file(GLOB tiles *.png)
+
+install(FILES
+ ${tiles}
+ DESTINATION ${SHAREPATH}Data/Tiles)
--- a/share/hedgewars/Data/map_templates.yaml Sat Sep 28 22:27:13 2024 +0200
+++ b/share/hedgewars/Data/map_templates.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -32,6 +32,10 @@
- {x: 2018, y: 872, w: 276, h: 314}
- {x: 2110, y: 1250, w: 130, h: 86}
- {x: 2134, y: 1424, w: 1, h: 1}
+ walls:
+ -
+ - {x: 1570, y: 1424, w: 1, h: 1}
+ - {x: 1610, y: 104, w: 150, h: 10}
fill_points:
- {x: 1023, y: 0}
@@ -193,7 +197,7 @@
-
- {x: 674, y: 1424, w: 1, h: 1}
- {x: 590, y: 1318, w: 168, h: 26}
- - {x: 782, y: 976, w: 122, h: 314}
+ - {x: 632, y: 876, w: 122, h: 314}
- {x: 968, y: 1144, w: 56, h: 180}
- {x: 1078, y: 1256, w: 64, h: 56}
- {x: 1140, y: 1050, w: 106, h: 220}
@@ -203,9 +207,16 @@
- {x: 1350, y: 1152, w: 152, h: 146}
- {x: 1572, y: 1174, w: 60, h: 152}
- {x: 1684, y: 1122, w: 150, h: 138}
- - {x: 1894, y: 764, w: 56, h: 582}
+ - {x: 1934, y: 764, w: 56, h: 582}
- {x: 2020, y: 1174, w: 94, h: 232}
- {x: 2012, y: 1424, w: 1, h: 1}
+ walls:
+ -
+ - {x: 990, y: 1070, w: 1, h: 1}
+ - {x: 200, y: 10, w: 350, h: 1}
+ -
+ - {x: 1600, y: 1100, w: 1, h: 1}
+ - {x: 2300, y: 10, w: 200, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -226,16 +237,22 @@
- {x: 768, y: 1422, w: 2, h: 2}
- {x: 666, y: 1240, w: 302, h: 110}
- {x: 694, y: 912, w: 104, h: 290}
- - {x: 970, y: 980, w: 364, h: 122}
- - {x: 968, y: 840, w: 368, h: 100}
+ - {x: 970, y: 980, w: 164, h: 122}
+ - {x: 968, y: 840, w: 268, h: 100}
- {x: 632, y: 660, w: 482, h: 130}
- {x: 1178, y: 642, w: 62, h: 64}
- {x: 1390, y: 554, w: 58, h: 246}
- {x: 1600, y: 676, w: 590, h: 98}
- - {x: 1488, y: 842, w: 214, h: 188}
+ - {x: 1488, y: 842, w: 114, h: 188}
- {x: 1450, y: 1086, w: 406, h: 92}
- {x: 1984, y: 902, w: 190, h: 412}
- {x: 2046, y: 1420, w: 2, h: 2}
+ walls:
+ -
+ - {x: 1400, y: 822, w: 1, h: 1}
+ - {x: 1400, y: 1222, w: 1, h: 1}
+ - {x: 1900, y: 1240, w: 1, h: 100}
+ - {x: 1100, y: 1402, w: 1, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -294,6 +311,10 @@
- {x: 1940, y: 988, w: 212, h: 50}
- {x: 1864, y: 1146, w: 128, h: 146}
- {x: 2030, y: 1424, w: 20, h: 1}
+ walls:
+ -
+ - {x: 1410, y: 924, w: 20, h: 1}
+ - {x: 1100, y: 2, w: 800, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -363,15 +384,17 @@
- {x: 640, y: 1082, w: 140, h: 150}
- {x: 714, y: 868, w: 352, h: 94}
- {x: 1126, y: 646, w: 106, h: 282}
- - {x: 1302, y: 790, w: 368, h: 142}
+ - {x: 1302, y: 790, w: 338, h: 142}
- {x: 1358, y: 988, w: 116, h: 244}
- {x: 1276, y: 1424, w: 14, h: 1}
-
- {x: 1464, y: 1424, w: 22, h: 1}
- - {x: 1688, y: 1195, w: 120, h: 120}
- - {x: 1858, y: 674, w: 354, h: 448}
- - {x: 2088, y: 1195, w: 120, h: 120}
+ - {x: 1888, y: 674, w: 354, h: 448}
- {x: 2182, y: 1424, w: 2, h: 1}
+ walls:
+ -
+ - {x: 1380, y: 1424, w: 1, h: 1}
+ - {x: 2250, y: 2, w: 1, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -390,14 +413,18 @@
outline_points:
-
- {x: 674, y: 1424, w: 166, h: 1}
- - {x: 730, y: 1262, w: 96, h: 92}
- - {x: 892, y: 1090, w: 152, h: 250}
- - {x: 1146, y: 1046, w: 36, h: 270}
- - {x: 1338, y: 1026, w: 54, h: 224}
- - {x: 1534, y: 1046, w: 44, h: 216}
- - {x: 1692, y: 1030, w: 46, h: 300}
- - {x: 1848, y: 1064, w: 158, h: 272}
+ - {x: 792, y: 990, w: 152, h: 250}
+ - {x: 1848, y: 964, w: 158, h: 272}
- {x: 1984, y: 1424, w: 136, h: 1}
+ walls:
+ -
+ - {x: 980, y: 1284, w: 1, h: 50}
+ - {x: 1800, y: 1284, w: 1, h: 50}
+ -
+ - {x: 380, y: 610, w: 1, h: 200}
+ - {x: 2340, y: 610, w: 1, h: 200}
+ - {x: 2540, y: 1500, w: 1, h: 1}
+ - {x: 280, y: 1500, w: 1, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -418,16 +445,23 @@
- {x: 760, y: 1424, w: 2, h: 2}
- {x: 642, y: 1030, w: 46, h: 286}
- {x: 854, y: 1072, w: 194, h: 56}
- - {x: 654, y: 734, w: 534, h: 200}
+ - {x: 654, y: 734, w: 534, h: 100}
- {x: 1270, y: 676, w: 58, h: 468}
- {x: 1476, y: 672, w: 198, h: 112}
- {x: 1400, y: 1424, w: 64, h: 2}
-
- {x: 1644, y: 1424, w: 64, h: 2}
- {x: 1756, y: 894, w: 184, h: 94}
- - {x: 2000, y: 814, w: 76, h: 358}
- {x: 2148, y: 984, w: 108, h: 304}
- {x: 2088, y: 1424, w: 176, h: 1}
+ walls:
+ -
+ - {x: 1560, y: 1424, w: 1, h: 1}
+ - {x: 1880, y: 1, w: 140, h: 1}
+ -
+ - {x: 860, y: 1424, w: 1, h: 1}
+ - {x: 1160, y: 1090, w: 1, h: 1}
+ - {x: 1330, y: 1424, w: 1, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -446,20 +480,27 @@
outline_points:
-
- {x: 846, y: 1424, w: 140, h: 2}
- - {x: 680, y: 1272, w: 196, h: 32}
- {x: 654, y: 1080, w: 262, h: 134}
- - {x: 1054, y: 1072, w: 220, h: 136}
- - {x: 1008, y: 890, w: 268, h: 110}
- - {x: 700, y: 762, w: 104, h: 200}
+ - {x: 1154, y: 1072, w: 160, h: 136}
+ - {x: 1148, y: 850, w: 168, h: 110}
+ - {x: 700, y: 762, w: 104, h: 60}
- {x: 846, y: 624, w: 306, h: 58}
- - {x: 1316, y: 588, w: 84, h: 206}
- - {x: 1548, y: 574, w: 104, h: 220}
- {x: 1826, y: 576, w: 120, h: 202}
- {x: 1956, y: 818, w: 192, h: 68}
- - {x: 1626, y: 948, w: 246, h: 88}
- - {x: 1656, y: 1106, w: 194, h: 150}
+ - {x: 1606, y: 828, w: 126, h: 88}
+ - {x: 1606, y: 1106, w: 94, h: 150}
- {x: 1968, y: 1106, w: 198, h: 152}
- {x: 1844, y: 1424, w: 2, h: 2}
+ walls:
+ -
+ - {x: 0, y: 854, w: 1, h: 1}
+ - {x: 980, y: 985, w: 1, h: 1}
+ -
+ - {x: 1870, y: 1050, w: 1, h: 1}
+ - {x: 3000, y: 804, w: 1, h: 1}
+ -
+ - {x: 1420, y: 750, w: 90, h: 100}
+ - {x: 1450, y: 1424, w: 51, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -509,27 +550,32 @@
-
- {x: 702, y: 1424, w: 2, h: 2}
- {x: 640, y: 1290, w: 44, h: 94}
- - {x: 750, y: 1262, w: 44, h: 94}
- {x: 860, y: 1306, w: 78, h: 70}
- {x: 866, y: 1424, w: 2, h: 2}
-
- {x: 1204, y: 1424, w: 2, h: 2}
- - {x: 1120, y: 1182, w: 108, h: 174}
- - {x: 884, y: 1024, w: 314, h: 98}
- - {x: 710, y: 882, w: 76, h: 230}
- - {x: 834, y: 686, w: 220, h: 154}
- - {x: 1240, y: 674, w: 56, h: 266}
- - {x: 1424, y: 644, w: 78, h: 304}
- - {x: 1648, y: 646, w: 116, h: 162}
+ - {x: 1120, y: 982, w: 108, h: 174}
+ - {x: 610, y: 842, w: 116, h: 230}
+ - {x: 1034, y: 686, w: 620, h: 154}
- {x: 1980, y: 726, w: 190, h: 228}
- - {x: 1760, y: 1004, w: 140, h: 84}
- - {x: 1596, y: 1140, w: 242, h: 118}
+ - {x: 1536, y: 1040, w: 242, h: 118}
- {x: 1616, y: 1424, w: 2, h: 2}
-
- {x: 1894, y: 1424, w: 2, h: 2}
- {x: 1850, y: 1328, w: 88, h: 34}
- {x: 1998, y: 1238, w: 96, h: 112}
- {x: 2056, y: 1424, w: 2, h: 2}
+ walls:
+ -
+ - {x: 0, y: 1200, w: 1, h: 1}
+ - {x: 1040, y: 1200, w: 1, h: 1}
+ - {x: 1040, y: 1500, w: 1, h: 1}
+ - {x: 0, y: 1500, w: 2, h: 2}
+ -
+ - {x: 3100, y: 1120, w: 1, h: 1}
+ - {x: 1770, y: 1220, w: 1, h: 1}
+ - {x: 1770, y: 1500, w: 1, h: 1}
+ - {x: 3100, y: 1500, w: 2, h: 2}
fill_points:
- {x: 1023, y: 0}
@@ -594,17 +640,18 @@
-
- {x: 630, y: 1424, w: 2, h: 2}
- {x: 566, y: 1256, w: 128, h: 118}
- - {x: 752, y: 1256, w: 98, h: 114}
- - {x: 748, y: 1074, w: 140, h: 138}
- - {x: 956, y: 1072, w: 136, h: 142}
- - {x: 1146, y: 1070, w: 114, h: 252}
- - {x: 1324, y: 778, w: 120, h: 390}
- - {x: 1522, y: 862, w: 114, h: 210}
- - {x: 1724, y: 706, w: 130, h: 252}
- - {x: 1936, y: 606, w: 278, h: 234}
- - {x: 1924, y: 1044, w: 272, h: 52}
- - {x: 1972, y: 1252, w: 180, h: 56}
+ - {x: 2036, y: 636, w: 78, h: 234}
- {x: 1998, y: 1424, w: 42, h: 2}
+ walls:
+ -
+ - {x: 330, y: 1500, w: 2, h: 1}
+ - {x: 366, y: 1156, w: 64, h: 64}
+ - {x: 2086, y: 460, w: 200, h: 60}
+ - {x: 2100, y: 1500, w: 200, h: 1}
+ -
+ - {x: 830, y: 1424, w: 2, h: 1}
+ - {x: 1686, y: 1060, w: 200, h: 60}
+ - {x: 1650, y: 1424, w: 200, h: 1}
fill_points:
- {x: 1023, y: 0}
@@ -898,33 +945,31 @@
-
- {x: 474, y: 1424, w: 1, h: 1}
- {x: 390, y: 1318, w: 168, h: 26}
- - {x: 582, y: 976, w: 122, h: 314}
- - {x: 768, y: 1144, w: 56, h: 180}
- - {x: 878, y: 1256, w: 64, h: 56}
- - {x: 940, y: 1050, w: 106, h: 220}
+ - {x: 940, y: 1080, w: 106, h: 220}
- {x: 844, y: 896, w: 162, h: 140}
- - {x: 696, y: 610, w: 886, h: 174}
+ - {x: 796, y: 610, w: 686, h: 174}
- {x: 1134, y: 848, w: 296, h: 108}
- {x: 1150, y: 1152, w: 152, h: 146}
- - {x: 1372, y: 1174, w: 60, h: 152}
- - {x: 1484, y: 1122, w: 150, h: 138}
- {x: 1694, y: 764, w: 56, h: 582}
- - {x: 1820, y: 1174, w: 94, h: 232}
- - {x: 1812, y: 1424, w: 1, h: 1}
+ - {x: 1712, y: 1424, w: 1, h: 1}
-
- {x: 2110, y: 1424, w: 2, h: 2}
- {x: 1992, y: 1030, w: 46, h: 286}
- {x: 2204, y: 1072, w: 194, h: 56}
- {x: 2004, y: 734, w: 534, h: 200}
- - {x: 2620, y: 676, w: 58, h: 468}
- - {x: 2826, y: 672, w: 198, h: 112}
+ - {x: 2626, y: 672, w: 198, h: 112}
- {x: 2750, y: 1424, w: 64, h: 2}
-
- {x: 2994, y: 1424, w: 64, h: 2}
- {x: 3106, y: 894, w: 184, h: 94}
- - {x: 3350, y: 814, w: 76, h: 358}
- {x: 3498, y: 984, w: 108, h: 304}
- {x: 3438, y: 1424, w: 176, h: 1}
+ walls:
+ -
+ - {x: 1870, y: 1500, w: 1, h: 1}
+ - {x: 1780, y: 500, w: 168, h: 26}
+ - {x: 2880, y: 500, w: 265, h: 26}
+ - {x: 2880, y: 1500, w: 1, h: 1}
fill_points:
- {x: 2047, y: 0}
@@ -984,23 +1029,26 @@
-
- {x: 362, y: 1424, w: 400, h: 1}
- {x: 426, y: 634, w: 142, h: 360}
- - {x: 1136, y: 1140, w: 400, h: 200}
- - {x: 1776, y: 576, w: 186, h: 550}
- - {x: 1630, y: 1424, w: 454, h: 1}
+ - {x: 1206, y: 1140, w: 200, h: 200}
+ - {x: 1776, y: 576, w: 70, h: 550}
+ - {x: 1540, y: 1424, w: 120, h: 1}
-
- {x: 1938, y: 1424, w: 190, h: 1}
- - {x: 1990, y: 1082, w: 140, h: 150}
- {x: 2064, y: 868, w: 352, h: 94}
- - {x: 2476, y: 646, w: 106, h: 282}
- - {x: 2652, y: 790, w: 368, h: 142}
- - {x: 2708, y: 988, w: 116, h: 244}
+ - {x: 2652, y: 790, w: 168, h: 142}
- {x: 2626, y: 1424, w: 14, h: 1}
-
- {x: 2814, y: 1424, w: 22, h: 1}
- - {x: 3038, y: 1195, w: 120, h: 120}
- {x: 3208, y: 674, w: 354, h: 448}
- - {x: 3438, y: 1195, w: 120, h: 120}
- {x: 3532, y: 1424, w: 2, h: 1}
+ walls:
+ -
+ - {x: 560, y: 0, w: 260, h: 1}
+ - {x: 1250, y: 880, w: 40, h: 200}
+ - {x: 2000, y: 0, w: 260, h: 1}
+ - {x: 1880, y: 1500, w: 1, h: 1}
+ - {x: 2700, y: 1500, w: 1, h: 1}
+ - {x: 3050, y: 0, w: 480, h: 1}
fill_points:
- {x: 2047, y: 0}
@@ -1019,56 +1067,44 @@
outline_points:
-
- {x: 564, y: 1424, w: 20, h: 1}
- - {x: 490, y: 1260, w: 64, h: 62}
- - {x: 686, y: 1150, w: 52, h: 146}
- - {x: 456, y: 990, w: 116, h: 144}
- - {x: 670, y: 868, w: 138, h: 168}
- {x: 442, y: 642, w: 158, h: 162}
- - {x: 708, y: 710, w: 198, h: 72}
- {x: 970, y: 628, w: 118, h: 134}
- - {x: 836, y: 1118, w: 142, h: 132}
- - {x: 1168, y: 1100, w: 172, h: 58}
- - {x: 1170, y: 1204, w: 172, h: 62}
- - {x: 1432, y: 1104, w: 82, h: 226}
+ - {x: 836, y: 1118, w: 142, h: 32}
- {x: 1556, y: 994, w: 64, h: 152}
- {x: 1414, y: 734, w: 106, h: 152}
- - {x: 1610, y: 660, w: 380, h: 82}
- - {x: 1728, y: 822, w: 30, h: 118}
- - {x: 1740, y: 988, w: 212, h: 50}
- - {x: 1664, y: 1146, w: 128, h: 146}
+ - {x: 1610, y: 660, w: 260, h: 82}
- {x: 1830, y: 1424, w: 20, h: 1}
-
- {x: 2140, y: 1424, w: 1, h: 1}
- - {x: 2076, y: 1302, w: 44, h: 54}
- {x: 2234, y: 1236, w: 58, h: 90}
- - {x: 2066, y: 1134, w: 80, h: 80}
- {x: 2046, y: 1004, w: 96, h: 108}
- {x: 2226, y: 1046, w: 110, h: 112}
- {x: 2034, y: 692, w: 118, h: 164}
- - {x: 2228, y: 796, w: 130, h: 110}
- - {x: 2316, y: 598, w: 344, h: 78}
- - {x: 2488, y: 826, w: 50, h: 40}
+ - {x: 2316, y: 598, w: 264, h: 78}
- {x: 2426, y: 960, w: 32, h: 148}
- - {x: 2498, y: 1050, w: 160, h: 34}
- {x: 2474, y: 1188, w: 36, h: 136}
- {x: 2814, y: 1248, w: 48, h: 48}
- {x: 2886, y: 1128, w: 64, h: 88}
- - {x: 2758, y: 1060, w: 70, h: 74}
- - {x: 2916, y: 996, w: 68, h: 70}
- - {x: 2918, y: 884, w: 68, h: 82}
- - {x: 2758, y: 724, w: 44, h: 140}
+ - {x: 2798, y: 724, w: 44, h: 140}
- {x: 3072, y: 706, w: 52, h: 66}
- - {x: 3054, y: 902, w: 58, h: 66}
- {x: 3034, y: 1160, w: 76, h: 112}
- - {x: 3180, y: 1162, w: 124, h: 64}
- - {x: 3272, y: 872, w: 54, h: 134}
- - {x: 3210, y: 596, w: 246, h: 62}
+ - {x: 3290, y: 1162, w: 40, h: 64}
+ - {x: 3310, y: 596, w: 46, h: 62}
- {x: 3506, y: 554, w: 38, h: 238}
- - {x: 3612, y: 748, w: 28, h: 28}
- - {x: 3492, y: 924, w: 144, h: 94}
- - {x: 3432, y: 1078, w: 248, h: 20}
- - {x: 3432, y: 1202, w: 238, h: 16}
- {x: 3480, y: 1424, w: 1, h: 1}
+ walls:
+ -
+ - {x: 1264, y: 1024, w: 20, h: 1}
+ - {x: 1070, y: 0, w: 400, h: 1}
+ -
+ - {x: 2670, y: 1170, w: 1, h: 1}
+ - {x: 2610, y: 0, w: 200, h: 1}
+ -
+ - {x: 3210, y: 1100, w: 1, h: 1}
+ - {x: 3100, y: 0, w: 210, h: 1}
+ -
+ - {x: 710, y: 1250, w: 1, h: 120}
+ - {x: 1630, y: 1200, w: 1, h: 170}
fill_points:
- {x: 2047, y: 0}
@@ -1089,20 +1125,16 @@
- {x: 610, y: 1424, w: 1, h: 1}
- {x: 360, y: 1160, w: 130, h: 170}
- {x: 542, y: 1106, w: 316, h: 150}
- - {x: 438, y: 786, w: 270, h: 180}
- {x: 446, y: 576, w: 242, h: 156}
- - {x: 752, y: 528, w: 610, h: 300}
- - {x: 950, y: 868, w: 352, h: 324}
- - {x: 850, y: 1424, w: 500, h: 1}
- - {x: 1450, y: 1500, w: 1, h: 1}
+ - {x: 752, y: 528, w: 350, h: 300}
+ - {x: 950, y: 1424, w: 300, h: 1}
+ -
- {x: 1690, y: 1424, w: 1, h: 1}
- {x: 1652, y: 1304, w: 74, h: 12}
- - {x: 1448, y: 975, w: 68, h: 425}
+ - {x: 1448, y: 975, w: 68, h: 385}
- {x: 1626, y: 992, w: 140, h: 142}
- {x: 1510, y: 592, w: 150, h: 350}
- {x: 1788, y: 594, w: 148, h: 242}
- - {x: 1818, y: 872, w: 276, h: 314}
- - {x: 1910, y: 1250, w: 130, h: 86}
- {x: 1934, y: 1424, w: 1, h: 1}
-
- {x: 2202, y: 1424, w: 2, h: 2}
@@ -1113,21 +1145,23 @@
-
- {x: 2704, y: 1424, w: 2, h: 2}
- {x: 2620, y: 1182, w: 108, h: 174}
- - {x: 2384, y: 1024, w: 314, h: 98}
- - {x: 2210, y: 882, w: 76, h: 230}
+ - {x: 2210, y: 902, w: 76, h: 230}
- {x: 2334, y: 686, w: 220, h: 154}
- - {x: 2740, y: 674, w: 56, h: 266}
- - {x: 2924, y: 644, w: 78, h: 304}
- - {x: 3148, y: 646, w: 116, h: 162}
- - {x: 3480, y: 726, w: 190, h: 228}
- - {x: 3260, y: 1004, w: 140, h: 84}
- - {x: 3096, y: 1140, w: 242, h: 118}
+ - {x: 3480, y: 680, w: 190, h: 228}
+ - {x: 3096, y: 1010, w: 242, h: 118}
- {x: 3116, y: 1424, w: 2, h: 2}
-
- {x: 3394, y: 1424, w: 2, h: 2}
- {x: 3350, y: 1328, w: 88, h: 34}
- {x: 3498, y: 1238, w: 96, h: 112}
- {x: 3556, y: 1424, w: 2, h: 2}
+ walls:
+ -
+ - {x: 1300, y: 1500, w: 1, h: 1}
+ - {x: 1100, y: 960, w: 280, h: 40}
+ - {x: 1200, y: 1, w: 280, h: 1}
+ - {x: 2000, y: 400, w: 250, h: 1}
+ - {x: 2020, y: 1500, w: 20, h: 1}
fill_points:
- {x: 2047, y: 0}
@@ -1157,19 +1191,14 @@
- {x: 1212, y: 990, w: 188, h: 298}
- {x: 1440, y: 1068, w: 136, h: 172}
- {x: 1470, y: 594, w: 120, h: 392}
- - {x: 1714, y: 594, w: 364, h: 362}
- - {x: 1650, y: 1052, w: 315, h: 232}
+ - {x: 1714, y: 594, w: 220, h: 362}
- {x: 1660, y: 1424, w: 25, h: 1}
-
- {x: 1986, y: 1424, w: 2, h: 2}
- - {x: 1944, y: 1286, w: 84, h: 54}
- {x: 1912, y: 1086, w: 150, h: 166}
- {x: 2378, y: 1240, w: 186, h: 98}
- - {x: 2444, y: 1004, w: 124, h: 58}
- {x: 2320, y: 582, w: 112, h: 194}
- - {x: 2688, y: 660, w: 92, h: 132}
- {x: 3010, y: 574, w: 154, h: 196}
- - {x: 2860, y: 974, w: 118, h: 64}
- {x: 2752, y: 1222, w: 328, h: 92}
- {x: 3296, y: 1030, w: 242, h: 222}
- {x: 3298, y: 1316, w: 254, h: 50}
@@ -1192,36 +1221,24 @@
outline_points:
-
- {x: 554, y: 1424, w: 1, h: 1}
- - {x: 432, y: 1326, w: 226, h: 60}
- - {x: 320, y: 1246, w: 298, h: 62}
- - {x: 480, y: 1104, w: 210, h: 102}
- {x: 408, y: 822, w: 192, h: 248}
- - {x: 492, y: 560, w: 206, h: 240}
- {x: 726, y: 572, w: 92, h: 334}
- - {x: 662, y: 928, w: 226, h: 126}
- {x: 756, y: 1078, w: 268, h: 156}
- {x: 922, y: 564, w: 138, h: 500}
- {x: 1090, y: 556, w: 94, h: 352}
- - {x: 1098, y: 962, w: 170, h: 264}
- - {x: 1292, y: 784, w: 84, h: 446}
+ - {x: 1198, y: 962, w: 170, h: 264}
- {x: 1406, y: 600, w: 158, h: 278}
- - {x: 1500, y: 890, w: 104, h: 336}
- {x: 1616, y: 946, w: 90, h: 398}
- - {x: 1746, y: 592, w: 134, h: 532}
- - {x: 1902, y: 646, w: 156, h: 258}
- - {x: 1900, y: 948, w: 132, h: 340}
- - {x: 1734, y: 1298, w: 252, h: 82}
+ - {x: 1746, y: 592, w: 94, h: 532}
+ - {x: 1734, y: 1348, w: 252, h: 32}
- {x: 1804, y: 1424, w: 1, h: 1}
-
- {x: 2096, y: 1424, w: 140, h: 2}
- - {x: 1930, y: 1272, w: 196, h: 32}
- - {x: 1904, y: 1080, w: 262, h: 134}
- - {x: 2304, y: 1072, w: 220, h: 136}
+ - {x: 1944, y: 1080, w: 262, h: 134}
+ - {x: 2344, y: 1072, w: 200, h: 136}
- {x: 2258, y: 890, w: 268, h: 110}
- {x: 1950, y: 762, w: 104, h: 200}
- {x: 2096, y: 624, w: 306, h: 58}
- - {x: 2566, y: 588, w: 84, h: 206}
- - {x: 2798, y: 574, w: 104, h: 220}
- {x: 3076, y: 576, w: 120, h: 202}
- {x: 3206, y: 818, w: 192, h: 68}
- {x: 2876, y: 948, w: 246, h: 88}
@@ -1250,29 +1267,24 @@
- {x: 698, y: 1110, w: 308, h: 60}
- {x: 928, y: 1252, w: 434, h: 40}
- {x: 1374, y: 1112, w: 332, h: 40}
- - {x: 1602, y: 1238, w: 226, h: 36}
- {x: 1730, y: 1424, w: 1, h: 1}
-
- - {x: 1860, y: 898, w: 111, h: 111}
- - {x: 1470, y: 876, w: 34, h: 102}
- - {x: 882, y: 814, w: 284, h: 132}
+ - {x: 1660, y: 898, w: 111, h: 111}
- {x: 430, y: 728, w: 126, h: 168}
- {x: 610, y: 574, w: 114, h: 100}
- - {x: 990, y: 572, w: 352, h: 120}
- - {x: 1474, y: 528, w: 60, h: 240}
- - {x: 1634, y: 622, w: 254, h: 116}
+ - {x: 1534, y: 622, w: 254, h: 116}
-
- {x: 1960, y: 1424, w: 2, h: 2}
- {x: 1842, y: 1030, w: 46, h: 286}
- {x: 2054, y: 1072, w: 194, h: 56}
- {x: 1854, y: 734, w: 534, h: 200}
- - {x: 2470, y: 676, w: 58, h: 468}
+ - {x: 2470, y: 676, w: 58, h: 640}
- {x: 2676, y: 672, w: 198, h: 112}
- {x: 2600, y: 1424, w: 64, h: 2}
-
- {x: 2844, y: 1424, w: 64, h: 2}
- {x: 2956, y: 894, w: 184, h: 94}
- - {x: 3200, y: 814, w: 76, h: 358}
+ - {x: 3200, y: 814, w: 76, h: 510}
- {x: 3348, y: 984, w: 108, h: 304}
- {x: 3288, y: 1424, w: 176, h: 1}
fill_points:
@@ -1344,22 +1356,16 @@
- {x: 474, y: 1424, w: 1, h: 1}
- {x: 390, y: 1318, w: 168, h: 26}
- {x: 582, y: 976, w: 122, h: 314}
- - {x: 768, y: 1144, w: 56, h: 180}
- {x: 878, y: 1256, w: 64, h: 56}
- - {x: 940, y: 1050, w: 106, h: 220}
- {x: 844, y: 896, w: 162, h: 140}
- {x: 696, y: 610, w: 886, h: 174}
- {x: 1134, y: 848, w: 296, h: 108}
- {x: 1150, y: 1152, w: 152, h: 146}
- - {x: 1372, y: 1174, w: 60, h: 152}
- - {x: 1484, y: 1122, w: 150, h: 138}
- {x: 1694, y: 764, w: 56, h: 582}
- - {x: 1820, y: 1174, w: 94, h: 232}
- {x: 1812, y: 1424, w: 1, h: 1}
-
- {x: 2088, y: 1424, w: 190, h: 1}
- {x: 2140, y: 1082, w: 140, h: 150}
- - {x: 2214, y: 868, w: 352, h: 94}
- {x: 2626, y: 646, w: 106, h: 282}
- {x: 2802, y: 790, w: 368, h: 142}
- {x: 2858, y: 988, w: 116, h: 244}
@@ -1451,29 +1457,26 @@
-
- {x: 362, y: 1424, w: 400, h: 1}
- {x: 426, y: 634, w: 142, h: 360}
- - {x: 1136, y: 1140, w: 400, h: 200}
- - {x: 1776, y: 576, w: 186, h: 550}
- - {x: 1630, y: 1424, w: 454, h: 1}
+ - {x: 1036, y: 1140, w: 400, h: 200}
+ - {x: 1576, y: 576, w: 186, h: 550}
+ - {x: 1430, y: 1424, w: 454, h: 1}
-
- {x: 1964, y: 1424, w: 20, h: 1}
- - {x: 1890, y: 1260, w: 64, h: 62}
- - {x: 2086, y: 1150, w: 52, h: 146}
- - {x: 1856, y: 990, w: 116, h: 144}
- - {x: 2070, y: 868, w: 138, h: 168}
- {x: 1842, y: 642, w: 158, h: 162}
- - {x: 2108, y: 710, w: 198, h: 72}
- {x: 2370, y: 628, w: 118, h: 134}
- {x: 2236, y: 1118, w: 142, h: 132}
- - {x: 2568, y: 1100, w: 172, h: 58}
- - {x: 2570, y: 1204, w: 172, h: 62}
- {x: 2832, y: 1104, w: 82, h: 226}
- - {x: 2956, y: 994, w: 64, h: 152}
- {x: 2814, y: 734, w: 106, h: 152}
- {x: 3010, y: 660, w: 380, h: 82}
- - {x: 3128, y: 822, w: 30, h: 118}
- - {x: 3140, y: 988, w: 212, h: 50}
- - {x: 3064, y: 1146, w: 128, h: 146}
- {x: 3230, y: 1424, w: 20, h: 1}
+ walls:
+ -
+ - {x: 400, y: 1, w: 300, h: 1}
+ - {x: 1500, y: 1, w: 300, h: 1}
+ - {x: 1200, y: 1100, w: 1, h: 1}
+ -
+ - {x: 2500, y: 1, w: 400, h: 1}
+ - {x: 2580, y: 1100, w: 1, h: 1}
fill_points:
- {x: 2047, y: 0}
@@ -1556,24 +1559,10 @@
max_hedgehogs: 32
outline_points:
-
- - {x: 324, y: 756, w: 196, h: 204}
- - {x: 224, y: 596, w: 404, h: 60}
- - {x: 240, y: 268, w: 464, h: 152}
- - {x: 876, y: 236, w: 168, h: 348}
- - {x: 1204, y: 56, w: 148, h: 700}
- - {x: 1516, y: 52, w: 192, h: 664}
- - {x: 1808, y: 60, w: 328, h: 496}
- - {x: 2292, y: 92, w: 184, h: 492}
- - {x: 2664, y: 216, w: 196, h: 340}
- - {x: 3004, y: 108, w: 176, h: 480}
- - {x: 3260, y: 368, w: 120, h: 348}
- - {x: 3476, y: 460, w: 208, h: 448}
- - {x: 3268, y: 906, w: 192, h: 96}
- - {x: 2876, y: 664, w: 204, h: 310}
- - {x: 2240, y: 748, w: 344, h: 224}
- - {x: 1584, y: 796, w: 440, h: 250}
- - {x: 892, y: 852, w: 324, h: 184}
- - {x: 576, y: 976, w: 16, h: 28}
+ - {x: 324, y: 876, w: 86, h: 106}
+ - {x: 240, y: 248, w: 264, h: 152}
+ - {x: 3476, y: 210, w: 64, h: 248}
+ - {x: 3468, y: 866, w: 192, h: 96}
fill_points:
- {x: 2047, y: 0}
@@ -1591,23 +1580,15 @@
max_hedgehogs: 48
outline_points:
-
- - {x: 700, y: 2100, w: 120, h: 175}
- - {x: 800, y: 1200, w: 120, h: 175}
+ - {x: 700, y: 2100, w: 120, h: 1}
- {x: 900, y: 400, w: 120, h: 150}
- - {x: 1100, y: 600, w: 120, h: 150}
- - {x: 1300, y: 900, w: 120, h: 150}
- - {x: 1000, y: 1000, w: 120, h: 150}
- - {x: 1700, y: 1850, w: 120, h: 175}
- - {x: 2048, y: 2100, w: 120, h: 175}
+ - {x: 1100, y: 1600, w: 120, h: 150}
+ - {x: 1930, y: 2100, w: 120, h: 1}
-
- - {x: 2048, y: 2100, w: 120, h: 150}
- - {x: 2400, y: 1850, w: 120, h: 150}
- - {x: 2600, y: 1000, w: 120, h: 175}
- - {x: 2800, y: 900, w: 120, h: 150}
- - {x: 3000, y: 600, w: 120, h: 150}
+ - {x: 2048, y: 2100, w: 120, h: 1}
+ - {x: 2600, y: 1600, w: 120, h: 175}
- {x: 3200, y: 400, w: 120, h: 150}
- - {x: 3300, y: 1200, w: 120, h: 150}
- - {x: 3400, y: 2100, w: 120, h: 175}
+ - {x: 3400, y: 2100, w: 120, h: 1}
-
- {x: 1450, y: 700, w: 125, h: 125}
- {x: 1850, y: 500, w: 125, h: 125}
@@ -1615,9 +1596,16 @@
- {x: 2500, y: 700, w: 125, h: 125}
-
- {x: 1550, y: 1500, w: 125, h: 125}
- - {x: 1830, y: 1150, w: 125, h: 125}
- - {x: 2260, y: 1000, w: 125, h: 125}
+ - {x: 1630, y: 1150, w: 125, h: 125}
+ - {x: 2260, y: 1200, w: 125, h: 125}
- {x: 2250, y: 1400, w: 125, h: 125}
+ walls:
+ -
+ - {x: 1390, y: 1500, w: 42, h: 175}
+ - {x: 1200, y: 270, w: 42, h: 175}
+ - {x: 2900, y: 260, w: 42, h: 175}
+ - {x: 2450, y: 1550, w: 90, h: 90}
+ - {x: 2000, y: 1950, w: 90, h: 90}
fill_points:
- {x: 2047, y: 0}
@@ -1636,20 +1624,19 @@
outline_points:
-
- {x: 100, y: 2100, w: 1, h: 1}
- - {x: 100, y: 1600, w: 250, h: 500}
- - {x: 400, y: 600, w: 250, h: 1500}
- - {x: 700, y: 1600, w: 250, h: 600}
- - {x: 1000, y: 1800, w: 250, h: 300}
- - {x: 1300, y: 500, w: 250, h: 1600}
- - {x: 1600, y: 1700, w: 150, h: 400}
- - {x: 1800, y: 1600, w: 150, h: 500}
- - {x: 2000, y: 1400, w: 150, h: 700}
- - {x: 2200, y: 300, w: 250, h: 1800}
- - {x: 2500, y: 1500, w: 250, h: 600}
- - {x: 2800, y: 1900, w: 250, h: 200}
- - {x: 3100, y: 1600, w: 250, h: 500}
- - {x: 3400, y: 600, w: 250, h: 1500}
- - {x: 3700, y: 1800, w: 150, h: 300}
+ - {x: 100, y: 1500, w: 250, h: 500}
+ - {x: 400, y: 500, w: 250, h: 1500}
+ - {x: 700, y: 1400, w: 250, h: 600}
+ - {x: 1000, y: 1700, w: 250, h: 300}
+ - {x: 1300, y: 400, w: 250, h: 1600}
+ - {x: 1600, y: 1600, w: 150, h: 400}
+ - {x: 1800, y: 1500, w: 150, h: 500}
+ - {x: 2000, y: 1300, w: 150, h: 700}
+ - {x: 2200, y: 200, w: 250, h: 1800}
+ - {x: 2500, y: 1400, w: 250, h: 600}
+ - {x: 2800, y: 1800, w: 250, h: 200}
+ - {x: 3100, y: 1500, w: 250, h: 500}
+ - {x: 3400, y: 500, w: 250, h: 1500}
- {x: 3700, y: 2100, w: 1, h: 1}
fill_points:
- {x: 2047, y: 0}
@@ -2053,7 +2040,7 @@
- {x: 3925, y: 2098, w: 75, h: 50}
- {x: 4050, y: 2173, w: 50, h: 75}
fill_points:
- - {x: 4095, y: 0}
+ - {x: 4094, y: 0}
@@ -2086,9 +2073,9 @@
fill_points:
- {x: 1, y: 90}
- {x: 1, y: 500}
- - {x: 4095, y: 500}
+ - {x: 4094, y: 500}
- {x: 1, y: 1200}
- - {x: 4095, y: 1200}
+ - {x: 4094, y: 1200}
- {x: 1, y: 2010}
@@ -2158,9 +2145,369 @@
- {x: 1023, y: 0}
+
+ # 47
+ -
+ width: 3072
+ height: 1424
+ can_flip: false
+ can_invert: false
+ can_mirror: true
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 250, y: 1424, w: 1, h: 1}
+ - {x: 350, y: 1100, w: 800, h: 40}
+ - {x: 1250, y: 1424, w: 1, h: 5}
+ -
+ - {x: 1800, y: 1424, w: 1, h: 1}
+ - {x: 1900, y: 1100, w: 800, h: 40}
+ - {x: 2800, y: 1424, w: 1, h: 5}
+ -
+ - {x: 250, y: 624, w: 1, h: 1}
+ - {x: 350, y: 800, w: 800, h: 40}
+ - {x: 1250, y: 624, w: 1, h: 5}
+ -
+ - {x: 1800, y: 624, w: 1, h: 1}
+ - {x: 1900, y: 800, w: 800, h: 40}
+ - {x: 2800, y: 624, w: 1, h: 5}
+ walls:
+ -
+ - {x: 1386, y: 0, w: 300, h: 1}
+ - {x: 1386, y: 1424, w: 300, h: 1}
+ -
+ - {x: 0, y: 875, w: 1, h: 150}
+ - {x: 3072, y: 875, w: 1, h: 150}
+ fill_points:
+ - {x: 1386, y: 0}
+
+
+
+ # 48
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 273, y: 1024, w: 1, h: 1}
+ - {x: 683, y: 32, w: 1, h: 32}
+ - {x: 1092, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1638, y: 1024, w: 1, h: 1}
+ - {x: 2048, y: 32, w: 1, h: 32}
+ - {x: 2458, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3004, y: 1024, w: 1, h: 1}
+ - {x: 3413, y: 32, w: 1, h: 32}
+ - {x: 3823, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 1365, y: 0, w: 1, h: 1}
+ - {x: 1365, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2731, y: 0, w: 1, h: 1}
+ - {x: 2731, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
+
+ # 49
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 205, y: 1024, w: 1, h: 1}
+ - {x: 512, y: 32, w: 1, h: 32}
+ - {x: 819, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1229, y: 1024, w: 1, h: 1}
+ - {x: 1536, y: 32, w: 1, h: 32}
+ - {x: 1843, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2253, y: 1024, w: 1, h: 1}
+ - {x: 2560, y: 32, w: 1, h: 32}
+ - {x: 2867, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3277, y: 1024, w: 1, h: 1}
+ - {x: 3584, y: 32, w: 1, h: 32}
+ - {x: 3891, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 1024, y: 0, w: 1, h: 1}
+ - {x: 1024, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2048, y: 0, w: 1, h: 1}
+ - {x: 2048, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3072, y: 0, w: 1, h: 1}
+ - {x: 3072, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
+
+ # 50
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 164, y: 1024, w: 1, h: 1}
+ - {x: 410, y: 32, w: 1, h: 32}
+ - {x: 655, y: 1024, w: 1, h: 1}
+ -
+ - {x: 983, y: 1024, w: 1, h: 1}
+ - {x: 1229, y: 32, w: 1, h: 32}
+ - {x: 1475, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1802, y: 1024, w: 1, h: 1}
+ - {x: 2048, y: 32, w: 1, h: 32}
+ - {x: 2294, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2621, y: 1024, w: 1, h: 1}
+ - {x: 2867, y: 32, w: 1, h: 32}
+ - {x: 3113, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3441, y: 1024, w: 1, h: 1}
+ - {x: 3686, y: 32, w: 1, h: 32}
+ - {x: 3932, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 819, y: 0, w: 1, h: 1}
+ - {x: 819, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1638, y: 0, w: 1, h: 1}
+ - {x: 1638, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2458, y: 0, w: 1, h: 1}
+ - {x: 2458, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3277, y: 0, w: 1, h: 1}
+ - {x: 3277, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
+
+ # 51
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 137, y: 1024, w: 1, h: 1}
+ - {x: 341, y: 32, w: 1, h: 32}
+ - {x: 546, y: 1024, w: 1, h: 1}
+ -
+ - {x: 819, y: 1024, w: 1, h: 1}
+ - {x: 1024, y: 32, w: 1, h: 32}
+ - {x: 1229, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1502, y: 1024, w: 1, h: 1}
+ - {x: 1707, y: 32, w: 1, h: 32}
+ - {x: 1911, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2185, y: 1024, w: 1, h: 1}
+ - {x: 2389, y: 32, w: 1, h: 32}
+ - {x: 2594, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2867, y: 1024, w: 1, h: 1}
+ - {x: 3072, y: 32, w: 1, h: 32}
+ - {x: 3277, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3550, y: 1024, w: 1, h: 1}
+ - {x: 3755, y: 32, w: 1, h: 32}
+ - {x: 3959, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 683, y: 0, w: 1, h: 1}
+ - {x: 683, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1365, y: 0, w: 1, h: 1}
+ - {x: 1365, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2048, y: 0, w: 1, h: 1}
+ - {x: 2048, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2731, y: 0, w: 1, h: 1}
+ - {x: 2731, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3413, y: 0, w: 1, h: 1}
+ - {x: 3413, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
+
+ # 52
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 117, y: 1024, w: 1, h: 1}
+ - {x: 293, y: 32, w: 1, h: 32}
+ - {x: 468, y: 1024, w: 1, h: 1}
+ -
+ - {x: 702, y: 1024, w: 1, h: 1}
+ - {x: 878, y: 32, w: 1, h: 32}
+ - {x: 1053, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1287, y: 1024, w: 1, h: 1}
+ - {x: 1463, y: 32, w: 1, h: 32}
+ - {x: 1638, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1872, y: 1024, w: 1, h: 1}
+ - {x: 2048, y: 32, w: 1, h: 32}
+ - {x: 2224, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2458, y: 1024, w: 1, h: 1}
+ - {x: 2633, y: 32, w: 1, h: 32}
+ - {x: 2809, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3043, y: 1024, w: 1, h: 1}
+ - {x: 3218, y: 32, w: 1, h: 32}
+ - {x: 3394, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3628, y: 1024, w: 1, h: 1}
+ - {x: 3803, y: 32, w: 1, h: 32}
+ - {x: 3979, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 585, y: 0, w: 1, h: 1}
+ - {x: 585, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1170, y: 0, w: 1, h: 1}
+ - {x: 1170, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1755, y: 0, w: 1, h: 1}
+ - {x: 1755, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2341, y: 0, w: 1, h: 1}
+ - {x: 2341, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2926, y: 0, w: 1, h: 1}
+ - {x: 2926, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3511, y: 0, w: 1, h: 1}
+ - {x: 3511, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
+
+ # 53
+ -
+ width: 4096
+ height: 1024
+ can_flip: false
+ can_invert: false
+ can_mirror: false
+ is_negative: false
+ put_girders: false
+ max_hedgehogs: 48
+ outline_points:
+ -
+ - {x: 102, y: 1024, w: 1, h: 1}
+ - {x: 256, y: 32, w: 1, h: 32}
+ - {x: 410, y: 1024, w: 1, h: 1}
+ -
+ - {x: 614, y: 1024, w: 1, h: 1}
+ - {x: 768, y: 32, w: 1, h: 32}
+ - {x: 922, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1126, y: 1024, w: 1, h: 1}
+ - {x: 1280, y: 32, w: 1, h: 32}
+ - {x: 1434, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1638, y: 1024, w: 1, h: 1}
+ - {x: 1792, y: 32, w: 1, h: 32}
+ - {x: 1946, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2150, y: 1024, w: 1, h: 1}
+ - {x: 2304, y: 32, w: 1, h: 32}
+ - {x: 2458, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2662, y: 1024, w: 1, h: 1}
+ - {x: 2816, y: 32, w: 1, h: 32}
+ - {x: 2970, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3174, y: 1024, w: 1, h: 1}
+ - {x: 3328, y: 32, w: 1, h: 32}
+ - {x: 3482, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3686, y: 1024, w: 1, h: 1}
+ - {x: 3840, y: 32, w: 1, h: 32}
+ - {x: 3994, y: 1024, w: 1, h: 1}
+ walls:
+ -
+ - {x: 512, y: 0, w: 1, h: 1}
+ - {x: 512, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1024, y: 0, w: 1, h: 1}
+ - {x: 1024, y: 1024, w: 1, h: 1}
+ -
+ - {x: 1536, y: 0, w: 1, h: 1}
+ - {x: 1536, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2048, y: 0, w: 1, h: 1}
+ - {x: 2048, y: 1024, w: 1, h: 1}
+ -
+ - {x: 2560, y: 0, w: 1, h: 1}
+ - {x: 2560, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3072, y: 0, w: 1, h: 1}
+ - {x: 3072, y: 1024, w: 1, h: 1}
+ -
+ - {x: 3584, y: 0, w: 1, h: 1}
+ - {x: 3584, y: 1024, w: 1, h: 1}
+ fill_points:
+ - {x: 1, y: 0}
+
+
template_types:
- small: [39, 40, 42]
- medium: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 46]
- large: [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 43]
- cavern: [36, 2, 3, 21, 29, 45]
- wacky: [37, 38, 41, 43, 44]
+ small:
+ indices: [39, 40, 42]
+ medium:
+ indices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 46, 47]
+ large:
+ indices: [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 43, 48, 49, 50, 51, 52, 53]
+ cavern:
+ indices: [36, 2, 3, 21, 29, 45]
+ force_invert: true
+ wacky:
+ indices: [37, 38, 41, 43, 44]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/maze_templates.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,131 @@
+# Templates for maze map generator in hedgewars
+
+templates:
+ # 00
+ -
+ width: 2048
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 100
+ distortion_limiting_factor: 140
+ braidness: 12
+ invert: false
+
+ # 01
+ -
+ width: 1536
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 64
+ distortion_limiting_factor: 160
+ braidness: 8
+ invert: false
+
+ # 02
+ -
+ width: 2048
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 140
+ distortion_limiting_factor: 140
+ braidness: 12
+ invert: false
+
+ # 03
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 160
+ distortion_limiting_factor: 180
+ braidness: 16
+ invert: false
+
+ # 04
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 240
+ distortion_limiting_factor: 220
+ braidness: 20
+ invert: false
+
+ # 05
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 280
+ distortion_limiting_factor: 220
+ braidness: 20
+ invert: false
+
+ # 06
+ -
+ width: 1024
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 64
+ distortion_limiting_factor: 150
+ braidness: 3
+ invert: true
+
+ # 07
+ -
+ width: 2048
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 80
+ distortion_limiting_factor: 150
+ braidness: 5
+ invert: true
+
+ # 08
+ -
+ width: 2048
+ height: 1024
+ max_hedgehogs: 64
+ cell_size: 120
+ distortion_limiting_factor: 150
+ braidness: 5
+ invert: true
+
+ # 09
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 140
+ distortion_limiting_factor: 200
+ braidness: 10
+ invert: true
+
+ # 10
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 220
+ distortion_limiting_factor: 250
+ braidness: 10
+ invert: true
+
+ # 11
+ -
+ width: 4096
+ height: 2048
+ max_hedgehogs: 64
+ cell_size: 256
+ distortion_limiting_factor: 280
+ braidness: 10
+ invert: true
+
+template_types:
+ small_tunnels: [0, 1]
+ medium_tunnels: [2, 3]
+ large_tunnels: [4, 5]
+ small_islands: [6, 7]
+ medium_islands: [8, 9]
+ large_islands: [10, 11]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/wfc_templates.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,196 @@
+---
+# Templates for wavefront collapse map generator in hedgewars
+
+templates:
+ - &template_00
+ width: 3960
+ height: 1920
+ can_invert: false
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 40
+ wrap: true
+ edges:
+ bottom:
+ name: "ff"
+ symmetrical: true
+ tiles: &template_00_tiles
+ - name: "120_bar.png"
+ edges:
+ top:
+ name: "ff"
+ symmetrical: true
+ right:
+ name: "fe"
+ bottom:
+ name: "ee"
+ symmetrical: true
+ left:
+ name: "fe"
+ reversed: true
+ is_negative: true
+ can_mirror: false
+ can_flip: false
+ can_rotate90: true
+ can_rotate180: true
+ can_rotate270: true
+ - name: "120_corner.png"
+ edges:
+ top:
+ name: "fe"
+ right:
+ name: "ee"
+ symmetrical: true
+ bottom:
+ name: "ee"
+ symmetrical: true
+ left:
+ name: "fe"
+ reversed: true
+ is_negative: true
+ can_mirror: false
+ can_flip: false
+ can_rotate90: true
+ can_rotate180: true
+ can_rotate270: true
+ - name: "120_corner.png"
+ edges:
+ top:
+ name: "fe"
+ reversed: true
+ right:
+ name: "ff"
+ symmetrical: true
+ bottom:
+ name: "ff"
+ symmetrical: true
+ left:
+ name: "fe"
+ is_negative: false
+ can_mirror: false
+ can_flip: false
+ can_rotate90: true
+ can_rotate180: true
+ can_rotate270: true
+ - name: "120_filled.png"
+ edges:
+ top:
+ name: "ff"
+ symmetrical: true
+ right:
+ name: "ff"
+ symmetrical: true
+ bottom:
+ name: "ff"
+ symmetrical: true
+ left:
+ name: "ff"
+ symmetrical: true
+ is_negative: true
+ can_mirror: false
+ can_flip: false
+ can_rotate90: false
+ can_rotate180: false
+ can_rotate270: false
+ - name: "120_filled.png"
+ edges:
+ top:
+ name: "ee"
+ symmetrical: true
+ right:
+ name: "ee"
+ symmetrical: true
+ bottom:
+ name: "ee"
+ symmetrical: true
+ left:
+ name: "ee"
+ symmetrical: true
+ is_negative: false
+ can_mirror: false
+ can_flip: false
+ can_rotate90: false
+ can_rotate180: false
+ can_rotate270: false
+ - name: "120_two_corners.png"
+ edges:
+ top:
+ name: "fe"
+ right:
+ name: "fe"
+ reversed: true
+ bottom:
+ name: "fe"
+ left:
+ name: "fe"
+ reversed: true
+ is_negative: true
+ can_mirror: true
+ can_flip: false
+ can_rotate90: false
+ can_rotate180: false
+ can_rotate270: false
+
+ - &template_01
+ width: 3960
+ height: 1920
+ can_invert: false
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 40
+ wrap: false
+ edges: &open_edges
+ top:
+ name: "ee"
+ symmetrical: true
+ right:
+ name: "ee"
+ symmetrical: true
+ bottom:
+ name: "ff"
+ symmetrical: true
+ left:
+ name: "ee"
+ symmetrical: true
+ tiles: *template_00_tiles
+
+ - &template_02
+ width: 1200
+ height: 600
+ can_invert: false
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 24
+ wrap: false
+ edges: *open_edges
+ tiles: *template_00_tiles
+
+ - &template_03
+ width: 720
+ height: 7920
+ can_invert: false
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 64
+ wrap: false
+ edges: *open_edges
+ tiles: *template_00_tiles
+
+
+ - &template_04
+ width: 2200
+ height: 960
+ can_invert: false
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 24
+ wrap: false
+ edges: *open_edges
+ tiles: *template_00_tiles
+
+template_types:
+ small: [2]
+ medium: [4]
+ large: [1]
+ cavern: [0]
+ wacky: [3]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/FUNDING.yml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,1 @@
+github: ["jschwe"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/ISSUE_TEMPLATE/bug_report.yml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,81 @@
+name: Bug Report
+description: File a bug report
+title: "[Bug]: "
+labels: ["bug", "triage"]
+assignees:
+ - jschwe
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ - type: textarea
+ attributes:
+ label: Current Behavior
+ description: A concise description of what you're experiencing.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Expected Behavior
+ description: A concise description of what you expected to happen.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Steps To Reproduce
+ description: Steps to reproduce the behavior.
+ placeholder: |
+ 1. In this environment...
+ 2. With this config...
+ 3. Run '...'
+ 4. See error...
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Environment
+ description: |
+ examples:
+ - **OS**: Ubuntu 22.04
+ - **CMake**: 3.22.0
+ - **CMake Generator**: Ninja 1.11
+ value: |
+ - OS:
+ - CMake:
+ - CMake Generator:
+ render: markdown
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: CMake configure log with Debug log-level
+ description: |
+ Output when configuring with `cmake -S<source_dir> -B<build_dir> --log-level=DEBUG <your_other_options>`:
+ <details><summary>CMake configure log</summary>
+ <p>
+
+ ```
+ <log>
+ ```
+
+ </p>
+ </details>
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: CMake Build step log
+ description: |
+ Output when building with `cmake --build <build_dir> --verbose`:
+ <details><summary>CMake build log</summary>
+ <p>
+
+ ```
+ <log>
+ ```
+
+ </p>
+ </details>
+ validations:
+ required: false
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/determine_compiler.sh Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+compiler_kind="$1"
+runner_os="$2"
+target_abi="$3"
+target_system_name="$4"
+target_arch="$5"
+
+set -e
+
+if [[ -z "$GITHUB_OUTPUT" ]]; then
+ echo "Error: This script should only be run in github actions environment"
+ exit 1
+fi
+if [[ -z "${runner_os}" || -z "${target_abi}" || -z "${target_arch}" ]]; then
+ echo "Error: Not all required parameters where set"
+ exit 1
+fi
+if [[ -z "${compiler_kind}" || "${compiler_kind}" == "default" ]]; then
+ echo "compiler option was not set. Determining default compiler."
+ if [[ "${runner_os}" == "Windows" ]]; then
+ if [[ "${target_abi}" == "msvc" ]]; then
+ compiler_kind=msvc
+ elif [[ "${target_abi}" == "gnu" ]]; then
+ compiler_kind=gcc
+ else
+ echo "Unknown abi for Windows: ${target_abi}"
+ exit 1
+ fi
+ elif [[ "${runner_os}" == "macOS" ]]; then
+ compiler_kind="clang"
+ elif [[ "${runner_os}" == "Linux" ]]; then
+ compiler_kind="gcc"
+ else
+ echo "Unknown Runner OS: ${runner_os}"
+ exit 1
+ fi
+fi
+echo "Compiler Family: '${compiler_kind}'"
+
+if [[ "${compiler_kind}" == "clang" ]]; then
+ c_compiler="clang"
+ cxx_compiler="clang++"
+elif [[ "${compiler_kind}" == "msvc" ]]; then
+ c_compiler="cl"
+ cxx_compiler="cl"
+elif [[ "${compiler_kind}" == "gcc" ]]; then
+ if [[ -z "${target_system_name}" ]]; then
+ c_compiler="gcc"
+ cxx_compiler="g++"
+ else
+ c_compiler="${target_arch}-linux-gnu-gcc"
+ cxx_compiler="${target_arch}-linux-gnu-g++"
+ fi
+fi
+echo "Chose C compiler: '${c_compiler}'"
+echo "Chose C++ compiler: '${cxx_compiler}'"
+echo "c_compiler=-DCMAKE_C_COMPILER=${c_compiler}" >> $GITHUB_OUTPUT
+echo "cxx_compiler=-DCMAKE_CXX_COMPILER=${cxx_compiler}" >> $GITHUB_OUTPUT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-apple-darwin-clang.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
+set(CMAKE_C_COMPILER_TARGET "aarch64-apple-darwin")
+set(CMAKE_CXX_COMPILER_TARGET "aarch64-apple-darwin")
+set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-clang.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
+set(CMAKE_C_COMPILER_TARGET "aarch64-linux-gnu")
+set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/aarch64-unknown-linux-gnu-gcc.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc")
+set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++")
+set(CMAKE_SYSTEM_NAME "Linux")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-clang.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
+set(CMAKE_C_COMPILER_TARGET "i686-pc-linux-gnu")
+set(CMAKE_CXX_COMPILER_TARGET "i686-pc-linux-gnu")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/i686-unknown-linux-gnu-gcc.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+set(CMAKE_C_COMPILER "i686-linux-gnu-gcc")
+set(CMAKE_CXX_COMPILER "i686-linux-gnu-g++")
+set(CMAKE_SYSTEM_NAME "Linux")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-apple-darwin-clang.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
+set(CMAKE_C_COMPILER_TARGET "x86_64-apple-darwin")
+set(CMAKE_CXX_COMPILER_TARGET "x86_64-apple-darwin")
+set(CMAKE_SYSTEM_NAME "Darwin")
+set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
+set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
+set(CMAKE_C_COMPILER_TARGET "x86_64-pc-windows-gnu")
+set(CMAKE_CXX_COMPILER_TARGET "x86_64-pc-windows-gnu")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-clang.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+# Assumption: This is the native host target.
+set(CMAKE_C_COMPILER "clang")
+set(CMAKE_CXX_COMPILER "clang++")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/scripts/toolchains/x86_64-unknown-linux-gnu-gcc.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+# Assumption: This is the native host target.
+set(CMAKE_C_COMPILER "gcc")
+set(CMAKE_CXX_COMPILER "g++")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/gh-pages.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,78 @@
+name: Deploy GH pages
+on:
+ push:
+ branches:
+ - master
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow one concurrent deployment
+concurrency:
+ group: "pages"
+ cancel-in-progress: true
+
+jobs:
+ # Build and deploy the documentation of master and the stable/v0.5 branch
+ deploy:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Install mdbook
+ env:
+ MDBOOK_VERSION: 'v0.4.27'
+ run: |
+ mkdir mdbook
+ curl -sSL https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
+ echo `pwd`/mdbook >> $GITHUB_PATH
+ - name: Checkout master
+ uses: actions/checkout@v4
+ with:
+ path: main
+ - name: Checkout stable/v0.5
+ uses: actions/checkout@v4
+ with:
+ path: stable-v0.5
+ ref: 'stable/v0.5'
+ - name: Setup Pages
+ uses: actions/configure-pages@v3
+ - name: Build mdbook for main branch
+ working-directory: 'main/doc'
+ run: mdbook build
+ - name: Build mdbook for stable/v0.5 branch
+ working-directory: 'stable-v0.5/doc'
+ run: mdbook build
+ # Override mdbooks default highlight.js with a custom version containing CMake support.
+ - uses: actions/checkout@v4
+ with:
+ repository: 'highlightjs/highlight.js'
+ # mdbook currently (as of v0.4.27) does not support v11 yet.
+ ref: '10.7.3'
+ path: highlightjs
+ - name: Build custom highlight.js
+ run: |
+ npm install
+ node tools/build.js :common cmake yaml
+ working-directory: highlightjs
+ - name: Override highlightjs
+ run: |
+ cp highlightjs/build/highlight.min.js main/doc/book/highlight.js
+ cp highlightjs/build/highlight.min.js stable-v0.5/doc/book/highlight.js
+ - name: Copy stable doc into main
+ run: mkdir main/doc/book/v0.5 && cp -a stable-v0.5/doc/book/. main/doc/book/v0.5/
+ - name: Debug print
+ run: ls -la main/doc/book/v0.5
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v2
+ with:
+ path: 'main/doc/book'
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/linux.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,58 @@
+# Workflow file for Linux hosts
+name: Corrosion on Linux
+on:
+ workflow_call:
+ inputs:
+ ubuntu_version:
+ required: false
+ type: string
+ default: "latest"
+ cmake:
+ required: false
+ type: string
+ default: "3.22.6"
+ generator:
+ required: true
+ type: string
+ c_compiler:
+ required: true
+ type: string
+ rust:
+ required: false
+ type: string
+ default: 1.46.0
+ target_arch:
+ required: false
+ type: string
+ default: x86_64
+
+jobs:
+ linux:
+ name: Test Linux
+ runs-on: ubuntu-${{ inputs.ubuntu_version }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "${{ inputs.cmake }}"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{inputs.rust}}
+ targets: ${{inputs.target_arch}}-unknown-linux-gnu
+ - name: Install Cross Compiler
+ shell: bash
+ run: |
+ echo "::group::apt-install"
+ sudo apt-get update
+ sudo apt-get install -y "g++-${{inputs.target_arch}}-linux-gnu"
+ echo "::endgroup::"
+ if: ${{ 'Linux' == runner.os && inputs.target_arch != 'x86_64' }}
+ - name: Configure Corrosion
+ run: cmake -S. -Bbuild -G "${{ inputs.generator }}" "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ inputs.target_arch }}-unknown-linux-gnu-${{ inputs.c_compiler }}"
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/test.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,454 @@
+name: Tests
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - 'master'
+ - 'stable/**'
+jobs:
+
+ visual_studio_base:
+ name: Test Visual Studio (base)
+ uses: ./.github/workflows/visual_studio.yaml
+ with:
+ vs_version: "2022"
+ rust: 1.46.0
+
+ visual_studio_stage2:
+ name: Test Visual Studio
+ uses: ./.github/workflows/visual_studio.yaml
+ needs:
+ - visual_studio_base
+ strategy:
+ matrix:
+ vs_version:
+ - "2019"
+ - "2022"
+ arch:
+ - x86_64
+ - i686
+ - aarch64
+ rust:
+ - "1.54.0"
+ include:
+ - arch: x86_64
+ vs_version: 2022
+ rust: stable
+ - arch: x86_64
+ vs_version: 2022
+ rust: nightly
+ with:
+ vs_version: "${{ matrix.vs_version}}"
+ rust: 1.54.0
+ target_arch: "${{ matrix.arch}}"
+
+ windows_ninja_cl:
+ name: Test Windows Ninja MSVC
+ runs-on: ${{ matrix.os }}
+ needs:
+ - visual_studio_base
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ arch:
+ - x86_64
+ - i686
+ - aarch64
+ compiler:
+ - cl
+ - clang-cl
+ - clang
+ include:
+ - os: windows-2022
+ vs_version: vs-2022
+ cmake: 3.22.6
+ - rust: 1.54.0
+ # Add variable mapping for ilammy/msvc-dev-cmd action
+ - arch: x86_64
+ msvc_dev_arch: amd64
+ - arch: i686
+ msvc_dev_arch: amd64_x86
+ - arch: aarch64
+ msvc_dev_arch: amd64_arm64
+ exclude:
+ # Not sure what parameters CMake needs when cross-compiling with clang-cl, so exclude for now
+ - compiler: clang-cl
+ arch: i686
+ - compiler: clang-cl
+ arch: aarch64
+ - compiler: clang
+ arch: i686
+ - compiler: clang
+ arch: aarch64
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "${{ matrix.cmake }}"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{matrix.rust}}
+ targets: ${{matrix.arch}}-pc-windows-msvc
+ - name: Setup MSVC Development Environment
+ uses: ilammy/msvc-dev-cmd@v1
+ with:
+ arch: ${{ matrix.msvc_dev_arch }}
+ - name: Configure
+ run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "ninja-${{ matrix.arch }}-pc-windows-msvc-${{ matrix.compiler }}"
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
+
+ windows_gnu:
+ name: Test Windows GNU
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ arch:
+ - x86_64
+ # - i686
+ # - aarch64
+ compiler:
+ - gcc # Clang only has experimental support for Cygwin / MinGW, so we don't test it
+ generator:
+ - ninja
+ - make
+ include:
+ - cmake: 3.22.6
+ - rust: 1.54.0
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "${{ matrix.cmake }}"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{matrix.rust}}
+ targets: ${{matrix.arch}}-pc-windows-gnu
+ - name: Configure
+ run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ matrix.generator }}-${{ matrix.arch }}-pc-windows-gnu-${{ matrix.compiler }}"
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
+
+ windows_gnullvm_msys2:
+ name: Test Windows gnullvm on msys2
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ arch:
+ - x86_64
+ # - i686
+ # - aarch64
+ generator:
+ - Ninja
+ - MSYS Makefiles
+ include:
+ - arch: x86_64
+ msystem: CLANG64
+# - arch: i686
+# msystem: CLANG32
+# - arch: aarch64
+# msystem: CLANGARM64
+ defaults:
+ run:
+ shell: msys2 {0}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable
+ targets: ${{matrix.arch}}-pc-windows-gnullvm
+ - uses: msys2/setup-msys2@v2
+ with:
+ msystem: ${{matrix.msystem}}
+ path-type: inherit
+ install: >-
+ git
+ make
+ pacboy: >-
+ toolchain:p
+ cmake:p
+ ninja:p
+ - name: Configure
+ run: cmake -S. -Bbuild -G "${{matrix.generator}}" --toolchain=.github/scripts/toolchains/${{matrix.arch}}-pc-windows-gnullvm.cmake
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
+
+# For now just test if hostbuild works when cross-compiling on windows.
+# For testing everything we would also need to install a cross-compiler first.
+ windows_cross_hostbuild:
+ name: Test Windows Cross
+ runs-on: windows-2022
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "~3.22.0"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable
+ targets: aarch64-unknown-linux-gnu
+ - name: Configure
+ run: cmake -S. -Bbuild "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" -DRust_CARGO_TARGET=aarch64-unknown-linux-gnu
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -R hostbuild
+
+ linux_base:
+ name: Test Linux (base)
+ uses: ./.github/workflows/linux.yaml
+ with:
+ c_compiler: "gcc"
+ generator: "Ninja"
+
+ linux_stage2:
+ name: Test Linux
+ needs:
+ - linux_base
+ uses: ./.github/workflows/linux.yaml
+ with:
+ target_arch: "${{ matrix.arch }}"
+ c_compiler: "${{ matrix.compiler }}"
+ generator: "${{ matrix.generator }}"
+ strategy:
+ fail-fast: false
+ matrix:
+ arch:
+ - x86_64
+ - i686
+ - aarch64
+ compiler:
+ - gcc
+ generator:
+ - "Ninja"
+ - "Unix Makefiles"
+ include:
+ # rustc doesn't support cross-compiling with clang out of the box, since
+ # clang requires a --target parameter. Corrosion currently can only pass
+ # this for the top-level crate, so linking of cdylibs that are built as
+ # dependencies of this crate will fail if they exist.
+ # Solutions would be to make cross-compiling with clang work out-of-the-box
+ # in rustc, or working around it in corrosion by adding a linker-wrapper.
+ # For this reason we only test clang with the host target for now.
+ - arch: x86_64
+ compiler: clang
+ generator: "Ninja"
+ - arch: x86_64
+ generator: "Ninja Multi-Config"
+ compiler: gcc
+
+ darwin:
+ name: Test MacOS
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ arch:
+ - x86_64
+ - aarch64
+ compiler:
+ - clang
+ generator:
+ - "Ninja"
+ - "Xcode"
+ include:
+ - os: macos-latest
+ - cmake: 3.22.6
+ - rust: 1.54.0
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "${{ matrix.cmake }}"
+ ninjaVersion: "~1.10.0"
+ # Install cbindgen before Rust to use recent default Rust version.
+ - name: Install cbindgen
+ run: cargo install cbindgen
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{matrix.rust}}
+ targets: ${{matrix.arch}}-apple-darwin
+ - name: Configure
+ run: cmake -S. -Bbuild --log-level=DEBUG -G "${{ matrix.generator }}" "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "${{ matrix.arch }}-apple-darwin-${{ matrix.compiler }}"
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
+
+
+ test_cxxbridge:
+ name: Test cxxbridge integration
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ - ubuntu-latest
+ - macos-13
+ include:
+ # Should be in sync with the `cxx` version the Carg.lock of the cxxbridge tests,
+ # otherwise the caching will not work and the cmd will be built from source.
+ - cxxbridge_version: "1.0.86"
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/cache@v4
+ id: cache_cxxbridge
+ with:
+ path: "~/.cargo/bin/cxxbridge*"
+ key: ${{ runner.os }}-cxxbridge_${{ matrix.cxxbridge_version }}
+ - name: Install cxxbridge
+ if: steps.cache_cxxbridge.outputs.cache-hit != 'true'
+ run: cargo install cxxbridge-cmd@${{ matrix.cxxbridge_version }}
+ - name: Install lld
+ run: sudo apt update && sudo apt install -y lld
+ if: ${{ 'Linux' == runner.os }}
+ - name: Setup MSVC Development Environment
+ uses: ilammy/msvc-dev-cmd@v1
+ if: runner.os == 'Windows'
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "~3.22.0"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable minus 2 releases
+ - name: Configure
+ run: >
+ cmake
+ -S.
+ -Bbuild
+ -GNinja
+ -DCORROSION_VERBOSE_OUTPUT=ON
+ -DCORROSION_TESTS_CXXBRIDGE=ON
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3 -R "^cxxbridge"
+
+ autoinstall_cargo_target:
+ name: Test Auto-installing Cargo target via rustup
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@stable
+ - name: Install Cross Compiler
+ shell: bash
+ run: |
+ echo "::group::apt-install"
+ sudo apt-get update
+ sudo apt-get install -y gcc-aarch64-linux-gnu
+ echo "::endgroup::"
+ - name: Assert rustup target is not installed
+ run: rustup show | ( ! grep aarch64)
+ - name: Configure Corrosion
+ run: cmake -S. -Bbuild -GNinja -DRust_RUSTUP_INSTALL_MISSING_TARGET=ON --preset "aarch64-unknown-linux-gnu-gcc"
+ - name: Check rustup target is installed after configuring
+ run: rustup show | grep aarch64
+
+ install:
+ name: Test Corrosion as a Library
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ - ubuntu-latest
+ - macos-13
+ include:
+ - rust: 1.54.0
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup MSVC Development Environment
+ uses: ilammy/msvc-dev-cmd@v1
+ if: runner.os == 'Windows'
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "~3.22.0"
+ ninjaVersion: "~1.10.0"
+ # Install cbindgen before Rust to use recent default Rust version.
+ - name: Install cbindgen
+ run: cargo install cbindgen
+ - name: Install Rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{matrix.rust}}
+ - name: Test Corrosion as installed module
+ run: >
+ cmake
+ -S.
+ -Bbuild
+ -GNinja
+ -DCORROSION_VERBOSE_OUTPUT=ON
+ -DCMAKE_BUILD_TYPE=Release
+ -DCORROSION_TESTS_INSTALL_CORROSION=ON
+ &&
+ cd build
+ &&
+ ctest --output-on-failure -C Release -j 3
+
+ # We want an "accumulation" job here because it is easier to specify required
+ # jobs here via needs, then in the github UI, since we use matrix jobs.
+ ci-success:
+ name: bors-ci-status
+ if: ${{ always() }}
+ needs:
+ - visual_studio_stage2
+ - windows_ninja_cl
+ - windows_gnu
+ - windows_gnullvm_msys2
+ - linux_stage2
+ - darwin
+ - test_cxxbridge
+ - autoinstall_cargo_target
+ - install
+ runs-on: ubuntu-latest
+ # Step copied from: https://github.com/cross-rs/cross/blob/80c9f9109a719ffb0f694060ddc6e371d5b3a540/.github/workflows/ci.yml#L361
+ steps:
+ - name: Result
+ run: |
+ jq -C <<< "${needs}"
+ # Check if all needs were successful or skipped.
+ "$(jq -r 'all(.result as $result | (["success", "skipped"] | contains([$result])))' <<< "${needs}")"
+ env:
+ needs: ${{ toJson(needs) }}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.github/workflows/visual_studio.yaml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,53 @@
+name: Corrosion with Visual Studio
+
+on:
+ workflow_call:
+ inputs:
+ vs_version:
+ required: true
+ type: string
+ default: 2022
+ cmake:
+ required: false
+ type: string
+ default: "3.22.6"
+ rust:
+ required: false
+ type: string
+ default: 1.46.0
+ target_arch:
+ required: false
+ type: string
+ default: x86_64
+
+jobs:
+ visual_studio:
+ name: Test Visual Studio ${{ inputs.vs_version }}
+ runs-on: "windows-${{ inputs.vs_version }}"
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install CMake
+ uses: lukka/get-cmake@519de0c7b4812477d74976b2523a9417f552d126
+ with:
+ cmakeVersion: "${{ inputs.cmake }}"
+ ninjaVersion: "~1.10.0"
+ - name: Install Rust
+ id: install_rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{inputs.rust}}
+ targets: ${{inputs.target_arch}}-pc-windows-msvc
+ # The initial configure for MSVC is quite slow, so we cache the build directory
+ # (including the build directories of the tests) since reconfiguring is
+ # significantly faster.
+ - name: Cache MSVC build directory
+ id: cache-msvc-builddir
+ uses: actions/cache@v4
+ with:
+ path: build
+ key: ${{ inputs.os }}-${{ inputs.target_arch }}-${{ inputs.rust }}-msvc-${{ inputs.vs_version}}-build
+ - name: Configure
+ run: cmake -S. -Bbuild -DCORROSION_TESTS_KEEP_BUILDDIRS=ON "-DRust_TOOLCHAIN=${{steps.install_rust.outputs.name}}" --preset "vs-${{ inputs.vs_version }}-${{ inputs.target_arch }}"
+ - name: Run Tests
+ working-directory: build
+ run: ctest --output-on-failure --build-config Debug -j 3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/.gitignore Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+
+**/target/
+**/*.rs.bk
+build*/
+.vscode
+.idea
+cmake-build-*
+test/test_header.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,86 @@
+cmake_minimum_required(VERSION 3.22)
+project(Corrosion
+ # Official releases will be major.minor.patch. When the `tweak` field is
+ # set it indicates that we are on a commit, that is not a officially
+ # tagged release. Users don't need to care about this, it is mainly to
+ # clearly see in configure logs which version was used, without needing to
+ # rely on `git`, since Corrosion may be installed or otherwise packaged.
+ VERSION 0.99.99 # 1.0-pre-release
+ LANGUAGES NONE
+ HOMEPAGE_URL "https://corrosion-rs.github.io/corrosion/"
+)
+
+# ==== Corrosion Configuration ====
+
+option(
+ CORROSION_BUILD_TESTS
+ "Build Corrosion test project"
+ ${PROJECT_IS_TOP_LEVEL}
+)
+
+if (PROJECT_IS_TOP_LEVEL)
+ # We need to enable a language for corrosions test to work.
+ # For projects using corrosion this is not needed
+ enable_language(C)
+endif()
+
+# This little bit self-hosts the Corrosion toolchain to build the generator
+# tool.
+#
+# It is strongly encouraged to install Corrosion separately and use
+# `find_package(Corrosion REQUIRED)` instead if that works with your workflow.
+option(CORROSION_INSTALL_ONLY "Only add rules for installing Corrosion itself." OFF)
+if (NOT CORROSION_INSTALL_ONLY)
+ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+ include(Corrosion)
+endif()
+
+# Testing
+if (CORROSION_BUILD_TESTS)
+ include(CTest)
+ add_subdirectory(test)
+endif()
+
+# If Corrosion is a subdirectory, do not enable its install code
+if (NOT PROJECT_IS_TOP_LEVEL)
+ return()
+endif()
+
+# Installation
+
+include(GNUInstallDirs)
+
+# Generate the Config file
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+ cmake/CorrosionConfig.cmake.in CorrosionConfig.cmake
+ INSTALL_DESTINATION
+ "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/Corrosion"
+)
+
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfigVersion.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY
+ SameMajorVersion
+ ARCH_INDEPENDENT
+)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/CorrosionConfigVersion.cmake"
+ DESTINATION
+ "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/Corrosion"
+)
+
+# These CMake scripts are needed both for the install and as a subdirectory
+install(
+ FILES
+ cmake/Corrosion.cmake
+ cmake/CorrosionGenerator.cmake
+ cmake/FindRust.cmake
+ DESTINATION
+ "${CMAKE_INSTALL_FULL_DATADIR}/cmake"
+)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/CMakePresets.json Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,290 @@
+{
+ "version": 3,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 22,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "hidden": true,
+ "generator": "Ninja"
+ },
+ {
+ "name": "ninja-mc",
+ "hidden": true,
+ "generator": "Ninja Multi-Config"
+ },
+ {
+ "name": "make",
+ "hidden": true,
+ "generator": "Unix Makefiles"
+ },
+ {
+ "name": "vs-2019",
+ "hidden": true,
+ "generator": "Visual Studio 16 2019"
+ },
+ {
+ "name": "vs-2022",
+ "hidden": true,
+ "generator": "Visual Studio 17 2022"
+ },
+ {
+ "name": "windows-only",
+ "hidden": true,
+ "condition": {
+ "type": "equals",
+ "lhs": "${hostSystemName}",
+ "rhs": "Windows"
+ }
+ },
+ {
+ "name": "windows-10-cross",
+ "hidden": true,
+ "cacheVariables": {
+ "CMAKE_SYSTEM_NAME": "Windows",
+ "CMAKE_SYSTEM_VERSION": "10.0"
+ },
+ "condition": {
+ "type": "equals",
+ "lhs": "${hostSystemName}",
+ "rhs": "Windows"
+ }
+ },
+ {
+ "name": "x86_64-pc-windows-msvc",
+ "hidden": true,
+ "inherits": ["windows-only"],
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "x86_64-pc-windows-msvc"
+ }
+ },
+ {
+ "name": "i686-pc-windows-msvc",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "i686-pc-windows-msvc"
+ }
+ },
+ {
+ "name": "aarch64-pc-windows-msvc",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "aarch64-pc-windows-msvc"
+ }
+ },
+ {
+ "name": "x86_64-unknown-linux-gnu",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "x86_64-unknown-linux-gnu"
+ }
+ },
+ {
+ "name": "i686-unknown-linux-gnu",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "i686-unknown-linux-gnu"
+ }
+ },
+ {
+ "name": "aarch64-unknown-linux-gnu",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "aarch64-unknown-linux-gnu"
+ }
+ },
+ {
+ "name": "x86_64-apple-darwin",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "x86_64-apple-darwin"
+ }
+ },
+ {
+ "name": "aarch64-apple-darwin",
+ "hidden": true,
+ "cacheVariables": {
+ "Rust_CARGO_TARGET": "aarch64-apple-darwin"
+ }
+ },
+ {
+ "name": "vs-platform-arm64",
+ "hidden": true,
+ "inherits": ["aarch64-pc-windows-msvc","windows-10-cross"],
+ "architecture": {
+ "value": "ARM64"
+ }
+ },
+ {
+ "name": "vs-platform-x64",
+ "hidden": true,
+ "inherits": ["x86_64-pc-windows-msvc"],
+ "architecture": {
+ "value": "x64"
+ }
+ },
+ {
+ "name": "vs-platform-i686",
+ "hidden": true,
+ "inherits": ["i686-pc-windows-msvc", "windows-10-cross"],
+ "architecture": {
+ "value": "Win32"
+ }
+ },
+ {
+ "name": "vs-2019-x86_64",
+ "inherits": ["vs-platform-x64", "vs-2019"]
+ },
+ {
+ "name": "vs-2022-x86_64",
+ "inherits": ["vs-platform-x64", "vs-2022"]
+ },
+ {
+ "name": "vs-2019-i686",
+ "inherits": ["vs-platform-i686", "vs-2019"]
+ },
+ {
+ "name": "vs-2022-i686",
+ "inherits": ["vs-platform-i686", "vs-2022"]
+ },
+ {
+ "name": "vs-2019-aarch64",
+ "inherits": ["vs-platform-arm64", "vs-2019"]
+ },
+ {
+ "name": "vs-2022-aarch64",
+ "inherits": ["vs-platform-arm64", "vs-2022"]
+ },
+ {
+ "name": "clang",
+ "hidden": true,
+ "cacheVariables": {
+ "CMAKE_C_COMPILER": "clang",
+ "CMAKE_CXX_COMPILER": "clang++"
+ }
+ },
+ {
+ "name": "host-gcc",
+ "hidden": true,
+ "cacheVariables": {
+ "CMAKE_C_COMPILER": "gcc",
+ "CMAKE_CXX_COMPILER": "g++"
+ }
+ },
+ {
+ "name": "clang-cl",
+ "hidden": true,
+ "inherits": ["windows-only"],
+ "cacheVariables": {
+ "CMAKE_C_COMPILER": "clang-cl",
+ "CMAKE_CXX_COMPILER": "clang-cl"
+ }
+ },
+ {
+ "name": "cl",
+ "hidden": true,
+ "inherits": ["windows-only"],
+ "cacheVariables": {
+ "CMAKE_C_COMPILER": "cl",
+ "CMAKE_CXX_COMPILER": "cl"
+ }
+ },
+ {
+ "name": "ninja-x86_64-pc-windows-msvc-cl",
+ "inherits": ["ninja", "x86_64-pc-windows-msvc", "cl"]
+ },
+ {
+ "name": "ninja-x86_64-pc-windows-msvc-clang-cl",
+ "inherits": ["ninja", "x86_64-pc-windows-msvc", "clang-cl"]
+ },
+ {
+ "name": "ninja-x86_64-pc-windows-msvc-clang",
+ "inherits": ["ninja", "x86_64-pc-windows-msvc", "clang"]
+ },
+ {
+ "name": "ninja-i686-pc-windows-msvc-cl",
+ "inherits": ["ninja", "i686-pc-windows-msvc", "cl", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-i686-pc-windows-msvc-clang-cl",
+ "inherits": ["ninja", "i686-pc-windows-msvc", "clang-cl", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-i686-pc-windows-msvc-clang",
+ "inherits": ["ninja", "i686-pc-windows-msvc", "clang", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-aarch64-pc-windows-msvc-cl",
+ "inherits": ["ninja", "aarch64-pc-windows-msvc", "cl", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-aarch64-pc-windows-msvc-clang-cl",
+ "inherits": ["ninja", "aarch64-pc-windows-msvc", "clang-cl", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-aarch64-pc-windows-msvc-clang",
+ "inherits": ["ninja", "aarch64-pc-windows-msvc", "clang", "windows-10-cross"]
+ },
+ {
+ "name": "ninja-x86_64-pc-windows-gnullvm",
+ "inherits": ["ninja", "windows-only", "clang"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake"
+ },
+ {
+ "name": "make-x86_64-pc-windows-gnullvm",
+ "inherits": ["make", "windows-only", "clang"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/x86_64-pc-windows-gnullvm.cmake"
+ },
+ {
+ "name": "ninja-x86_64-pc-windows-gnu-gcc",
+ "inherits": ["ninja", "host-gcc", "windows-only"]
+ },
+ {
+ "name": "make-x86_64-pc-windows-gnu-gcc",
+ "inherits": ["make", "host-gcc", "windows-only"]
+ },
+ {
+ "name": "x86_64-unknown-linux-gnu-clang",
+ "inherits": ["x86_64-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "x86_64-unknown-linux-gnu-gcc",
+ "inherits": ["x86_64-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "i686-unknown-linux-gnu-clang",
+ "inherits": ["i686-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "i686-unknown-linux-gnu-gcc",
+ "inherits": ["i686-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "aarch64-unknown-linux-gnu-clang",
+ "inherits": ["aarch64-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "aarch64-unknown-linux-gnu-gcc",
+ "inherits": ["aarch64-unknown-linux-gnu"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "x86_64-apple-darwin-clang",
+ "inherits": ["x86_64-apple-darwin", "clang"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ },
+ {
+ "name": "aarch64-apple-darwin-clang",
+ "inherits": ["aarch64-apple-darwin"],
+ "toolchainFile": "${sourceDir}/.github/scripts/toolchains/${presetName}.cmake"
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/LICENSE Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Andrew Gaspar
+
+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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/README.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,50 @@
+# Corrosion
+[![Build Status](https://github.com/corrosion-rs/corrosion/actions/workflows/test.yaml/badge.svg)](https://github.com/corrosion-rs/corrosion/actions?query=branch%3Amaster)
+[![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://corrosion-rs.github.io/corrosion/)
+![License](https://img.shields.io/badge/license-MIT-blue)
+
+Corrosion, formerly known as cmake-cargo, is a tool for integrating Rust into an existing CMake
+project. Corrosion can automatically import executables, static libraries, and dynamic libraries
+from a workspace or package manifest (`Cargo.toml` file).
+
+## Features
+- Automatic Import of Executable, Static, and Shared Libraries from Rust Crate
+- Easy Installation of Rust Executables
+- Trivially Link Rust Executables to C/C++ Libraries in Tree
+- Multi-Config Generator Support
+- Simple Cross-Compilation
+
+## Sample Usage with FetchContent
+
+Using the CMake `FetchContent` module allows you to easily integrate corrosion into your build.
+Other methods including installing corrosion or adding it as a subdirectory are covered in the
+[setup chapter](https://corrosion-rs.github.io/corrosion/setup_corrosion.html) of the
+corrosion [documentation](https://corrosion-rs.github.io/corrosion/).
+
+```cmake
+include(FetchContent)
+
+FetchContent_Declare(
+ Corrosion
+ GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
+ GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
+)
+FetchContent_MakeAvailable(Corrosion)
+
+# Import targets defined in a package or workspace manifest `Cargo.toml` file
+corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml)
+
+add_executable(your_cpp_bin main.cpp)
+target_link_libraries(your_cpp_bin PUBLIC rust-lib)
+```
+
+## Requirements
+
+### Stable v0.5 Release
+
+- CMake 3.15 or newer. Some features may only be available on more recent CMake versions
+- Rust 1.46 or newer. Some platforms / features may require more recent Rust versions
+
+### Development (master branch)
+
+- CMake 3.22 or newer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/RELEASES.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,477 @@
+# Unreleased
+
+### Breaking Changes
+
+- The master branch of corrosion now requires CMake 3.22. See also the
+ [v0.4.0 Release notes](#040-lts-2023-06-01) for more details.
+- Removed native tooling and the corresponding option `CORROSION_NATIVE_TOOLING`.
+ Corrosion now always uses pure CMake.
+
+### New features
+
+- Support using the `$<CONFIG>` generator expression in `OUTPUT_DIRECTORY`. [#459]
+- Add `OVERRIDE_CRATE_TYPE` option to corrosion_import_crate, allowing users to override
+ the crate-types of Rust libraries (e.g. force building as a staticlib instead of an rlib).
+- Support *-windows-gnullvm targets.
+- experimental support in corrosion_install for installing libraries and header files
+
+[#459]: https://github.com/corrosion-rs/corrosion/pull/459
+
+# v0.5.0 (2024-05-11)
+
+### Breaking Changes
+
+- Dashes (`-`) in names of imported CMake **library** targets are now replaced with underscores (`_`).
+ See [issue #501] for details. Users on older Corrosion versions will experience the same
+ change when using Rust 1.79 or newer. `bin` targets are not affected by this change.
+
+[issue #501]: https://github.com/corrosion-rs/corrosion/issues/501
+
+# v0.4.10 (2024-05-11)
+
+### New features
+
+- `corrosion_experimental_cbindgen()` can now be called multiple times on the same Rust target,
+ as long as the output header name differs. This may be useful to generate separate C and C++
+ bindings. [#507]
+- If `corrosion_link_libraries()` is called on a Rust static library target, then
+ `target_link_libraries()` is called to propagate the dependencies to C/C++ consumers.
+ Previously a warning was emitted in this case and the arguments ignored. [#506]
+
+### Fixes
+
+- Combine `-framework` flags on macos to avoid linker deduplication errors [#455]
+- `corrosion_experimental_cbindgen()` will now correctly use the package name, instead of assuming that
+ the package and crate name are identical. ([11e27c])
+- Set the `AR_<triple>` variable for `cc-rs` (except for msvc targets) [#456]
+- Fix hostbuild when cross-compiling to windows [#477]
+- Consider vworks executable suffix [#504]
+- `corrosion_experimental_cbindgen()` now forwards the Rust target-triple (e.g. `aarch64-unknown-linux-gnu`)
+ to cbindgen via the `TARGET` environment variable. The `hostbuild` property is considered. [#507]
+- Fix linking errors with Rust >= 1.79 and `-msvc` targets.` [#511]
+
+
+[#455]: https://github.com/corrosion-rs/corrosion/pull/455
+[#456]: https://github.com/corrosion-rs/corrosion/pull/456
+[#477]: https://github.com/corrosion-rs/corrosion/pull/477
+[#504]: https://github.com/corrosion-rs/corrosion/pull/504
+[#506]: https://github.com/corrosion-rs/corrosion/pull/506
+[#507]: https://github.com/corrosion-rs/corrosion/pull/507
+[#511]: https://github.com/corrosion-rs/corrosion/pull/511
+[11e27c]: https://github.com/corrosion-rs/corrosion/pull/514/commits/11e27cde2cf32c7ed539c96eb03c2f10035de538
+
+# v0.4.9 (2024-05-01)
+
+### New Features
+
+- Automatically detect Rust target for OpenHarmony ([#510]).
+
+### Fixes
+
+- Make find_package portable ([#509]).
+
+[#510]: https://github.com/corrosion-rs/corrosion/pull/510
+[#509]: https://github.com/corrosion-rs/corrosion/pull/509
+
+# v0.4.8 (2024-04-03)
+
+### Fixes
+
+- Fix an internal error when passing both the `PROFILE` and `CRATES` option to
+ `corrosion_import_crate()` ([#496]).
+
+[#496]: https://github.com/corrosion-rs/corrosion/pull/496
+
+# v0.4.7 (2024-01-19)
+
+### Fixes
+
+- The C/C++ compiler passed from corrosion to `cc-rs` can now be overridden by users setting
+ `CC_<target>` (e.g. `CC_x86_64-unknown-linux-gnu=/path/to/my-compiler`) environment variables ([#475]).
+
+[#475]: https://github.com/corrosion-rs/corrosion/pull/475
+
+# v0.4.6 (2024-01-17)
+
+### Fixes
+
+- Fix hostbuild executables when cross-compiling from non-windows to windows targets.
+ (Only with CMake >= 3.19).
+
+# v0.4.5 (2023-11-30)
+
+### Fixes
+
+- Fix hostbuild executables when cross-compiling on windows to non-windows targets
+ (Only with CMake >= 3.19).
+
+# v0.4.4 (2023-10-06)
+
+### Fixes
+
+- Add `chimera` ([#445]) and `unikraft` ([#446]) to the list of known vendors
+
+[#445]: https://github.com/corrosion-rs/corrosion/pull/445
+[#446]: https://github.com/corrosion-rs/corrosion/pull/446
+
+# v0.4.3 (2023-09-09)
+
+### Fixes
+
+- Fix the PROFILE option with CMake < 3.19 [#427]
+- Relax vendor parsing for espressif targets (removes warnings)
+- Fix an issue detecting required link libraries with Rust >= 1.71
+ when the cmake build directory is located in a Cargo workspace.
+
+# 0.4.2 (2023-07-16)
+
+### Fixes
+
+- Fix an issue when cross-compiling with clang
+- Fix detecting required libraries with cargo 1.71
+
+### New features
+
+- Users can now set `Rust_RESOLVE_RUSTUP_TOOLCHAINS` to `OFF`, which will result in Corrosion
+ not attempting to resolve rustc/cargo.
+
+# 0.4.1 (2023-06-03)
+
+This is a bugfix release.
+
+### Fixes
+
+- Fixes a regression on multi-config Generators
+
+# 0.4.0 LTS (2023-06-01)
+
+No changes compared to v0.4.0-beta2.
+
+## Announcements
+
+The `v0.4.x` LTS series will be the last release to support older CMake and Rust versions.
+If necessary, fixes will be backported to the v0.4 branch. New features will not be
+actively backported after the next major release, but community contributions are possible.
+The `v0.4.x` series is currently planned to be maintained until the end of 2024.
+
+The following major release will increase the minimum required CMake version to 3.22. The
+minimum supported Rust version will also be increased to make use of newly added flags, but
+the exact version is not fixed yet.
+
+
+## Changes compared to v0.3.5:
+
+### Breaking Changes
+
+- The Visual Studio Generators now require at least CMake 3.20.
+ This was previously announced in the 0.3.0 release notes and is the same
+ requirement as for the other Multi-Config Generators.
+- The previously deprecated function `corrosion_set_linker_language()`
+ will now raise an error when called and may be removed without further
+ notice in future stable releases. Use `corrosion_set_linker()` instead.
+- Improved the FindRust target triple detection, which may cause different behavior in some cases.
+ The detection does not require an enabled language anymore and will always fall back
+ to the default host target triple. A warning is issued if target triple detection failed.
+
+### Potentially Breaking Changes
+
+- Corrosion now sets the `IMPORTED_NO_SONAME` property for shared rust libraries, since by
+ default they won't have an `soname` field.
+ If you add a rustflag like `-Clink-arg=-Wl,-soname,libmycrate.so` in your project,
+ you should set this property to false on the shared rust library.
+- Corrosion now uses a mechanism to determine which native libraries need to be linked with
+ Rust `staticlib` targets into C/C++ targets. The previous mechanism contained a hardcoded list.
+ The new mechanism asks `rustc` which libraries are needed at minimum for a given
+ target triple (with `std` support). This should not be a breaking change, but if you
+ do encounter a new linking issue when upgrading with `staticlib` targets, please open an
+ issue.
+
+### New features
+
+- `corrosion_import_crate()` has two new options `LOCKED` and `FROZEN` which pass the
+ `--locked` and `--frozen` flags to all invocations of cargo.
+- `FindRust` now provides cache variables containing information on the default host
+ target triple:
+ - `Rust_CARGO_HOST_ARCH`
+ - `Rust_CARGO_HOST_VENDOR`
+ - `Rust_CARGO_HOST_OS`
+ - `Rust_CARGO_HOST_ENV`
+
+### Other changes
+
+- When installing Corrosion with CMake >= 3.19, the legacy Generator tool is
+ no longer built and installed by default.
+- Corrosion now issues a warning when setting the linker or setting linker
+ options for a Rust static library.
+- Corrosion no longer enables the `C` language when CMake is in crosscompiling mode and
+ no languages where previously enabled. This is not considered a breaking change.
+- `corrosion_import_crate()` now warns about unexpected arguments.
+
+### Fixes
+
+- Fix building when the `dev` profile is explicitly set by the user.
+
+## Experimental features (may be changed or removed without a major version bump)
+
+- Experimental cxxbridge and cbindgen integration.
+- Add a helper function to parse the package version from a Cargo.toml file
+- Expose rustup toolchains discovered by `FindRust` in the following cache variables
+ which contain a list.
+ - `Rust_RUSTUP_TOOLCHAINS`: List of toolchains names
+ - `Rust_RUSTUP_TOOLCHAINS_VERSION`: List of `rustc` version of the toolchains
+ - `Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH`: List of the path to `rustc`
+ - `Rust_RUSTUP_TOOLCHAINS_CARGO_PATH`: List of the path to `cargo`. Entries may be `NOTFOUND` if cargo
+ is not available for that toolchain.
+- Add target properties `INTERFACE_CORROSION_RUSTC` and `INTERFACE_CORROSION_CARGO`, which may
+ be set to paths to `rustc` and `cargo` respectively to override the toolchain for a specific
+ target.
+
+# 0.3.5 (2023-03-19)
+
+- Fix building the Legacy Generator on Rust toolchains < 1.56 ([#365])
+
+[#365]: https://github.com/corrosion-rs/corrosion/pull/365
+
+# 0.3.4 (2023-03-02)
+
+## Fixes
+
+- Fix hostbuild (when CMake/Cargo is configured for cross-compiling) if clang is used ([#338]).
+
+## Other
+
+- Pass `--no-deps` to cargo metadata ([#334]).
+- Bump the legacy generator dependencies
+
+[#334]: https://github.com/corrosion-rs/corrosion/pull/334
+[#338]: https://github.com/corrosion-rs/corrosion/pull/338
+
+
+# 0.3.3 (2023-02-17)
+
+## New features (Only available on CMake >= 3.19)
+
+- Add new `IMPORTED_CRATES` flag to `corrosion_import_crate()` to retrieve the list of imported crates in the current
+ scope ([#312](https://github.com/corrosion-rs/corrosion/pull/312)).
+
+## Fixes
+
+- Fix imported location target property when the rust target name contains dashes
+ and a custom OUTPUT_DIRECTORY was specified by the user ([#322](https://github.com/corrosion-rs/corrosion/pull/322)).
+- Fix building for custom rust target-triples ([#316](https://github.com/corrosion-rs/corrosion/pull/316))
+
+# 0.3.2 (2023-01-11)
+
+## New features (Only available on CMake >= 3.19)
+
+- Add new `CRATE_TYPES` flag to `corrosion_import_crate()` to restrict which
+ crate types should be imported ([#269](https://github.com/corrosion-rs/corrosion/pull/269)).
+- Add `NO_LINKER_OVERRIDE` flag to let Rust choose the default linker for the target
+ instead of what Corrosion thinks is the appropriate linker driver ([#272](https://github.com/corrosion-rs/corrosion/pull/272)).
+
+## Fixes
+
+- Fix clean target when cross-compiling ([#291](https://github.com/corrosion-rs/corrosion/pull/291)).
+- Don't set the linker for Rust static libraries ([#275](https://github.com/corrosion-rs/corrosion/pull/275)).
+- Minor fixes in FindRust [#297](https://github.com/corrosion-rs/corrosion/pull/297):
+ - fix a logic error in the version detection
+ - fix a logic error in `QUIET` mode when rustup is not found.
+
+# 0.3.1 (2022-12-13)
+
+### Fixes
+
+- Fix a regression in detecting the MSVC abi ([#256])
+- Fix an issue on macOS 13 which affected rust crates compiling C++ code in build scripts ([#254]).
+- Fix corrosion not respecting `CMAKE_<XYZ>_OUTPUT_DIRECTORY` values ([#268]).
+- Don't override rusts linker choice for the msvc abi (previously this was only skipped for msvc generators) ([#271])
+
+[#254]: https://github.com/corrosion-rs/corrosion/pull/254
+[#256]: https://github.com/corrosion-rs/corrosion/pull/256
+[#268]: https://github.com/corrosion-rs/corrosion/pull/268
+[#271]: https://github.com/corrosion-rs/corrosion/pull/271
+
+# 0.3.0 (2022-10-31)
+
+## Breaking
+
+- The minimum supported rust version (MSRV) was increased to 1.46, due to a cargo issue that recently
+ surfaced on CI when using crates.io. On MacOS 12 and Windows-2022 at least Rust 1.54 is required.
+- MacOS 10 and 11 are no longer officially supported and untested in CI.
+- The minimum required CMake version is now 3.15.
+- Adding a `PRE_BUILD` custom command on a `cargo-build_<target_name>` CMake target will no
+ longer work as expected. To support executing user defined commands before cargo build is
+ invoked users should use the newly added targets `cargo-prebuild` (before all cargo build invocations)
+ or `cargo-prebuild_<target_name>` as a dependency target.
+ Example: `add_dependencies(cargo-prebuild code_generator_target)`
+
+### Breaking: Removed previously deprecated functionality
+- Removed `add_crate()` function. Use `corrosio_import_crate()` instead.
+- Removed `cargo_link_libraries()` function. Use `corrosion_link_libraries()` instead.
+- Removed experimental CMake option `CORROSION_EXPERIMENTAL_PARSER`.
+ The corresponding stable option is `CORROSION_NATIVE_TOOLING` albeit with inverted semantics.
+- Previously Corrosion would set the `HOST_CC` and `HOST_CXX` environment variables when invoking
+ cargo build, if the environment variables `CC` and `CXX` outside of CMake where set.
+ However this did not work as expected in all cases and sometimes the `HOST_CC` variable would be set
+ to a cross-compiler for unknown reasons. For this reason `HOST_CC` and `HOST_CXX` are not set by
+ corrosion anymore, but users can still set them manually if required via `corrosion_set_env_vars()`.
+- The `CARGO_RUST_FLAGS` family of cache variables were removed. Corrosion does not internally use them
+ anymore.
+
+## Potentially breaking
+
+- The working directory when invoking `cargo build` was changed to the directory of the Manifest
+ file. This now allows cargo to pick up `.cargo/config.toml` files located in the source tree.
+ ([205](https://github.com/corrosion-rs/corrosion/pull/205))
+- Corrosion internally invokes `cargo build`. When passing arguments to `cargo build`, Corrosion
+ now uses the CMake `VERBATIM` option. In rare cases this may require you to change how you quote
+ parameters passed to corrosion (e.g. via `corrosion_add_target_rustflags()`).
+ For example setting a `cfg` option previously required double escaping the rustflag like this
+ `"--cfg=something=\\\"value\\\""`, but now it can be passed to corrosion without any escapes:
+ `--cfg=something="value"`.
+- Corrosion now respects the CMake `OUTPUT_DIRECTORY` target properties. More details in the "New features" section.
+
+## New features
+
+- Support setting rustflags for only the main target and none of its dependencies ([215](https://github.com/corrosion-rs/corrosion/pull/215)).
+ A new function `corrosion_add_target_local_rustflags(target_name rustc_flag [more_flags ...])`
+ is added for this purpose.
+ This is useful in cases where you only need rustflags on the main-crate, but need to set different
+ flags for different targets. Without "local" Rustflags this would require rebuilds of the
+ dependencies when switching targets.
+- Support explicitly selecting a linker ([208](https://github.com/corrosion-rs/corrosion/pull/208)).
+ The linker can be selected via `corrosion_set_linker(target_name linker)`.
+ Please note that this only has an effect for targets, where the final linker invocation is done
+ by cargo, i.e. targets where foreign code is linked into rust code and not the other way around.
+- Corrosion now respects the CMake `OUTPUT_DIRECTORY` target properties and copies build artifacts to the expected
+ locations ([217](https://github.com/corrosion-rs/corrosion/pull/217)), if the properties are set.
+ This feature requires at least CMake 3.19 and is enabled by default if supported. Please note that the `OUTPUT_NAME`
+ target properties are currently not supported.
+ Specifically, the following target properties are now respected:
+ - [ARCHIVE_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.html)
+ - [LIBRARY_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html)
+ - [RUNTIME_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html)
+ - [PDB_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html)
+- Corrosion now supports packages with potentially multiple binaries (bins) and a library (lib) at the
+ same time. The only requirement is that the names of all `bin`s and `lib`s in the whole project must be unique.
+ Users can set the names in the `Cargo.toml` by adding `name = <unique_name>` in the `[[bin]]` and `[lib]` tables.
+- FindRust now has improved support for the `VERSION` option of `find_package` and will now attempt to find a matching
+ toolchain version. Previously it was only checked if the default toolchain matched to required version.
+- For rustup managed toolchains a CMake error is issued with a helpful message if the required target for
+ the selected toolchain is not installed.
+
+## Fixes
+
+- Fix a CMake developer Warning when a Multi-Config Generator and Rust executable targets
+ ([#213](https://github.com/corrosion-rs/corrosion/pull/213)).
+- FindRust now respects the `QUIET` option to `find_package()` in most cases.
+
+## Deprecation notice
+
+- Support for the MSVC Generators with CMake toolchains before 3.20 is deprecated and will be removed in the next
+ release (v0.4). All other Multi-config Generators already require CMake 3.20.
+
+## Internal Changes
+
+- The CMake Generator written in Rust and `CorrosionGenerator.cmake` which are responsible for parsing
+ `cargo metadata` output to create corresponding CMake targets for all Rust targets now share most code.
+ This greatly simplified the CMake generator written in Rust and makes it much easier maintaining and adding
+ new features regardless of how `cargo metadata` is parsed.
+
+# 0.2.2 (2022-09-01)
+
+## Fixes
+
+- Do not use C++17 in the tests (makes tests work with older C++ compilers) ([184](https://github.com/corrosion-rs/corrosion/pull/184))
+- Fix finding cargo on NixOS ([192](https://github.com/corrosion-rs/corrosion/pull/192))
+- Fix issue with Rustflags test when using a Build type other than Debug and Release ([203](https://github.com/corrosion-rs/corrosion/pull/203)).
+
+# 0.2.1 (2022-05-07)
+
+## Fixes
+
+- Fix missing variables provided by corrosion, when corrosion is used as a subdirectory ([181](https://github.com/corrosion-rs/corrosion/pull/181)):
+ Public [Variables](https://github.com/corrosion-rs/corrosion#information-provided-by-corrosion) set
+ by Corrosion were not visible when using Corrosion as a subdirectory, due to the wrong scope of
+ the variables. This was fixed by promoting the respective variables to Cache variables.
+
+# 0.2.0 (2022-05-05)
+
+## Breaking changes
+
+- Removed the integrator build script ([#156](https://github.com/corrosion-rs/corrosion/pull/156)).
+ The build script provided by corrosion (for rust code that links in foreign code) is no longer necessary,
+ so users can just remove the dependency.
+
+## Deprecations
+
+- Direct usage of the following target properties has been deprecated. The names of the custom properties are
+ no longer considered part of the public API and may change in the future. Instead, please use the functions
+ provided by corrosion. Internally different property names are used depending on the CMake version.
+ - `CORROSION_FEATURES`, `CORROSION_ALL_FEATURES`, `CORROSION_NO_DEFAULT_FEATURES`. Instead please use
+ `corrosion_set_features()`. See the updated Readme for details.
+ - `CORROSION_ENVIRONMENT_VARIABLES`. Please use `corrosion_set_env_vars()` instead.
+ - `CORROSION_USE_HOST_BUILD`. Please use `corrosion_set_hostbuild()` instead.
+- The Minimum CMake version will likely be increased for the next major release. At the very least we want to drop
+ support for CMake 3.12, but requiring CMake 3.16 or even 3.18 is also on the table. If you are using a CMake version
+ that would be no longer supported by corrosion, please comment on issue
+ [#168](https://github.com/corrosion-rs/corrosion/issues/168), so that we can gauge the number of affected users.
+
+## New features
+
+- Add `NO_STD` option to `corrosion_import_crate` ([#154](https://github.com/corrosion-rs/corrosion/pull/154)).
+- Remove the requirement of building the Rust based generator crate for CMake >= 3.19. This makes using corrosion as
+ a subdirectory as fast as the installed version (since everything is done in CMake).
+ ([#131](https://github.com/corrosion-rs/corrosion/pull/131), [#161](https://github.com/corrosion-rs/corrosion/pull/161))
+ If you do choose to install Corrosion, then by default the old Generator is still compiled and installed, so you can
+ fall back to using it in case you use multiple cmake versions on the same machine for different projects.
+
+## Fixes
+
+- Fix Corrosion on MacOS 11 and 12 ([#167](https://github.com/corrosion-rs/corrosion/pull/167) and
+ [#164](https://github.com/corrosion-rs/corrosion/pull/164)).
+- Improve robustness of parsing the LLVM version (exported in `Rust_LLVM_VERSION`). It now also works for
+ Rust versions, where the LLVM version is reported as `MAJOR.MINOR`. ([#148](https://github.com/corrosion-rs/corrosion/pull/148))
+- Fix a bug which occurred when Corrosion was added multiple times via `add_subdirectory()`
+ ([#143](https://github.com/corrosion-rs/corrosion/pull/143)).
+- Set `CC_<target_triple_undercore>` and `CXX_<target_triple_undercore>` environment variables for the invocation of
+ `cargo build` to the compilers selected by CMake (if any)
+ ([#138](https://github.com/corrosion-rs/corrosion/pull/138) and [#161](https://github.com/corrosion-rs/corrosion/pull/161)).
+ This should ensure that C dependencies built in cargo buildscripts via [cc-rs](https://github.com/alexcrichton/cc-rs)
+ use the same compiler as CMake built dependencies. Users can override the compiler by specifying the higher
+ priority environment variable variants with dashes instead of underscores (See cc-rs documentation for details).
+- Fix Ninja-Multiconfig Generator support for CMake versions >= 3.20. Previous CMake versions are missing a feature,
+ which prevents us from supporting the Ninja-Multiconfig generator. ([#137](https://github.com/corrosion-rs/corrosion/pull/137))
+
+
+# 0.1.0 (2022-02-01)
+
+This is the first release of corrosion after it was moved to the new corrosion-rs organization.
+Since there are no previous releases, this is not a complete changelog but only lists changes since
+September 2021.
+
+## New features
+- [Add --profile support for rust >= 1.57](https://github.com/corrosion-rs/corrosion/pull/130):
+ Allows users to specify a custom cargo profile with
+ `corrosion_import_crate(... PROFILE <profilename>)`.
+- [Add support for specifying per-target Rustflags](https://github.com/corrosion-rs/corrosion/pull/127):
+ Rustflags can be added via `corrosion_add_target_rustflags(<target_name> [rustflags1...])`
+- [Add `Rust_IS_NIGHTLY` and `Rust_LLVM_VERSION` variables](https://github.com/corrosion-rs/corrosion/pull/123):
+ This may be useful if you want to conditionally enabled features when using a nightly toolchain
+ or a specific LLVM Version.
+- [Let `FindRust` fail gracefully if rustc is not found](https://github.com/corrosion-rs/corrosion/pull/111):
+ This allows using `FindRust` in a more general setting (without corrosion).
+- [Add support for cargo feature selection](https://github.com/corrosion-rs/corrosion/pull/108):
+ See the [README](https://github.com/corrosion-rs/corrosion#cargo-feature-selection) for details on
+ how to select features.
+
+
+## Fixes
+- [Fix the cargo-clean target](https://github.com/corrosion-rs/corrosion/pull/129)
+- [Fix #84: CorrosionConfig.cmake looks in wrong place for Corrosion::Generator when CMAKE_INSTALL_LIBEXEC is an absolute path](https://github.com/corrosion-rs/corrosion/pull/122/commits/6f29af3ac53917ca2e0638378371e715a18a532d)
+- [Fix #116: (Option CORROSION_INSTALL_EXECUTABLE not working)](https://github.com/corrosion-rs/corrosion/commit/97d44018fac1b1a2a7c095288c628f5bbd9b3184)
+- [Fix building on Windows with rust >= 1.57](https://github.com/corrosion-rs/corrosion/pull/120)
+
+## Known issues:
+- Corrosion is currently not working on macos-11 and newer. See issue [#104](https://github.com/corrosion-rs/corrosion/issues/104).
+ Contributions are welcome.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/cmake/Corrosion.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,2052 @@
+cmake_minimum_required(VERSION 3.22)
+
+list(APPEND CMAKE_MESSAGE_CONTEXT "Corrosion")
+
+message(DEBUG "Using Corrosion ${Corrosion_VERSION} with CMake ${CMAKE_VERSION} "
+ "and the `${CMAKE_GENERATOR}` Generator"
+)
+
+get_cmake_property(COR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG)
+set(COR_IS_MULTI_CONFIG "${COR_IS_MULTI_CONFIG}" CACHE BOOL "Do not change this" FORCE)
+mark_as_advanced(FORCE COR_IS_MULTI_CONFIG)
+
+
+if(NOT COR_IS_MULTI_CONFIG AND DEFINED CMAKE_CONFIGURATION_TYPES)
+ message(WARNING "The Generator is ${CMAKE_GENERATOR}, which is not a multi-config "
+ "Generator, but CMAKE_CONFIGURATION_TYPES is set. Please don't set "
+ "CMAKE_CONFIGURATION_TYPES unless you are using a multi-config Generator."
+ )
+endif()
+
+option(CORROSION_VERBOSE_OUTPUT "Enables verbose output from Corrosion and Cargo" OFF)
+
+if(DEFINED CORROSION_RESPECT_OUTPUT_DIRECTORY AND NOT CORROSION_RESPECT_OUTPUT_DIRECTORY)
+ message(WARNING "The option CORROSION_RESPECT_OUTPUT_DIRECTORY was removed."
+ " Corrosion now always attempts to respect the output directory.")
+endif()
+
+option(
+ CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED
+ "Surpresses a warning if the parsing the target triple failed."
+ OFF
+)
+
+find_package(Rust REQUIRED)
+
+if(CMAKE_GENERATOR MATCHES "Visual Studio"
+ AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL CMAKE_VS_PLATFORM_NAME_DEFAULT)
+ AND Rust_VERSION VERSION_LESS "1.54")
+ message(FATAL_ERROR "Due to a cargo issue, cross-compiling with a Visual Studio generator and rust versions"
+ " before 1.54 is not supported. Rust build scripts would be linked with the cross-compiler linker, which"
+ " causes the build to fail. Please upgrade your Rust version to 1.54 or newer.")
+endif()
+
+# message(STATUS "Using Corrosion as a subdirectory")
+
+get_property(
+ RUSTC_EXECUTABLE
+ TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
+)
+
+get_property(
+ CARGO_EXECUTABLE
+ TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
+)
+
+function(_corrosion_bin_target_suffix target_name out_var_suffix)
+ get_target_property(hostbuild "${target_name}" ${_CORR_PROP_HOST_BUILD})
+ if((hostbuild AND CMAKE_HOST_WIN32)
+ OR ((NOT hostbuild) AND (Rust_CARGO_TARGET_OS STREQUAL "windows")))
+ set(_suffix ".exe")
+ elseif(Rust_CARGO_TARGET_OS STREQUAL "vxworks")
+ set(_suffix ".vxe")
+ else()
+ set(_suffix "")
+ endif()
+ set(${out_var_suffix} "${_suffix}" PARENT_SCOPE)
+endfunction()
+
+# Do not call this function directly!
+#
+# This function should be called deferred to evaluate target properties late in the configure stage.
+# IMPORTED_LOCATION does not support Generator expressions, so we must evaluate the output
+# directory target property value at configure time. This function must be deferred to the end of
+# the configure stage, so we can be sure that the output directory is not modified afterwards.
+function(_corrosion_set_imported_location_deferred target_name base_property output_directory_property filename)
+ # The output directory property is expected to be set on the exposed target (without postfix),
+ # but we need to set the imported location on the actual library target with postfix.
+ if("${target_name}" MATCHES "^(.+)-(static|shared)$")
+ set(output_dir_prop_target_name "${CMAKE_MATCH_1}")
+ else()
+ set(output_dir_prop_target_name "${target_name}")
+ endif()
+
+ # Append .exe suffix for executable by-products if the target is windows or if it's a host
+ # build and the host is Windows.
+ get_target_property(target_type ${target_name} TYPE)
+ if(${target_type} STREQUAL "EXECUTABLE" AND (NOT "${filename}" MATCHES "\.pdb$"))
+ _corrosion_bin_target_suffix(${target_name} "suffix")
+ string(APPEND filename "${suffix}")
+ endif()
+
+ get_target_property(output_directory "${output_dir_prop_target_name}" "${output_directory_property}")
+ message(DEBUG "Output directory property (target ${output_dir_prop_target_name}): ${output_directory_property} dir: ${output_directory}")
+
+ foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER "${config_type}" config_type_upper)
+ get_target_property(output_dir_curr_config ${output_dir_prop_target_name}
+ "${output_directory_property}_${config_type_upper}"
+ )
+ if(output_dir_curr_config)
+ set(curr_out_dir "${output_dir_curr_config}")
+ elseif(output_directory)
+ set(curr_out_dir "${output_directory}")
+ else()
+ set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${curr_out_dir}")
+ message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
+ " to `${curr_out_dir}/${filename}`.")
+
+ string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir)
+ if(NOT ("${stripped_out_dir}" STREQUAL "${curr_out_dir}"))
+ message(FATAL_ERROR "${output_directory_property} for target ${output_dir_prop_target_name} "
+ "contained an unexpected Generator expression. Output dir: `${curr_out_dir}`"
+ "Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
+ endif()
+
+ # For Multiconfig we want to specify the correct location for each configuration
+ set_property(
+ TARGET ${target_name}
+ PROPERTY "${base_property}_${config_type_upper}"
+ "${curr_out_dir}/${filename}"
+ )
+ set(base_output_directory "${curr_out_dir}")
+ endforeach()
+
+ if(NOT COR_IS_MULTI_CONFIG)
+ if(output_directory)
+ set(base_output_directory "${output_directory}")
+ else()
+ set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ string(REPLACE "\$<CONFIG>" "${CMAKE_BUILD_TYPE}" base_output_directory "${base_output_directory}")
+ string(GENEX_STRIP "${base_output_directory}" stripped_out_dir)
+ if(NOT ("${stripped_out_dir}" STREQUAL "${base_output_directory}"))
+ message(FATAL_ERROR "${output_dir_prop_target_name} for target ${output_dir_prop_target_name} "
+ "contained an unexpected Generator expression. Output dir: `${base_output_directory}`"
+ "Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
+ endif()
+ endif()
+
+ message(DEBUG "Setting ${base_property} for target ${target_name}"
+ " to `${base_output_directory}/${filename}`.")
+
+ # IMPORTED_LOCATION must be set regardless of possible overrides. In the multiconfig case,
+ # the last configuration "wins" (IMPORTED_LOCATION is not documented to have Genex support).
+ set_property(
+ TARGET ${target_name}
+ PROPERTY "${base_property}" "${base_output_directory}/${filename}"
+ )
+endfunction()
+
+# Set the imported location of a Rust target.
+#
+# Rust targets are built via custom targets / custom commands. The actual artifacts are exposed
+# to CMake as imported libraries / executables that depend on the cargo_build command. For CMake
+# to find the built artifact we need to set the IMPORTED location to the actual location on disk.
+# Corrosion tries to copy the artifacts built by cargo to standard locations. The IMPORTED_LOCATION
+# is set to point to the copy, and not the original from the cargo build directory.
+#
+# Parameters:
+# - target_name: Name of the Rust target
+# - base_property: Name of the base property - i.e. `IMPORTED_LOCATION` or `IMPORTED_IMPLIB`.
+# - output_directory_property: Target property name that determines the standard location for the
+# artifact.
+# - filename of the artifact.
+function(_corrosion_set_imported_location target_name base_property output_directory_property filename)
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER
+ CALL
+ _corrosion_set_imported_location_deferred
+ [[${target_name}]]
+ [[${base_property}]]
+ [[${output_directory_property}]]
+ [[${filename}]]
+ )
+ ")
+endfunction()
+
+function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_names cargo_build_dir file_names)
+ if(ARGN)
+ message(FATAL_ERROR "Unexpected additional arguments")
+ endif()
+
+ foreach(output_dir_prop_name ${output_dir_prop_names})
+ get_target_property(output_dir ${target_name} "${output_dir_prop_name}")
+ if(output_dir)
+ break()
+ endif()
+ endforeach()
+
+ # A Genex expanding to the output directory depending on the configuration.
+ set(multiconfig_out_dir_genex "")
+
+ foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER "${config_type}" config_type_upper)
+ foreach(output_dir_prop_name ${output_dir_prop_names})
+ get_target_property(output_dir_curr_config ${target_name} "${output_dir_prop_name}_${config_type_upper}")
+ if(output_dir_curr_config)
+ break()
+ endif()
+ endforeach()
+
+ if(output_dir_curr_config)
+ set(curr_out_dir "${output_dir_curr_config}")
+ elseif(output_dir)
+ # Fallback to `output_dir` if specified
+ # Note: Multi-configuration generators append a per-configuration subdirectory to the
+ # specified directory unless a generator expression is used (from CMake documentation).
+ set(curr_out_dir "${output_dir}")
+ else()
+ # Fallback to the default directory. We do not append the configuration directory here
+ # and instead let CMake do this, since otherwise the resolving of dynamic library
+ # imported paths may fail.
+ set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ set(multiconfig_out_dir_genex "${multiconfig_out_dir_genex}$<$<CONFIG:${config_type}>:${curr_out_dir}>")
+ endforeach()
+
+ if(COR_IS_MULTI_CONFIG)
+ set(output_dir "${multiconfig_out_dir_genex}")
+ else()
+ if(NOT output_dir)
+ # Fallback to default directory.
+ set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ endif()
+
+ # Append .exe suffix for executable by-products if the target is windows or if it's a host
+ # build and the host is Windows.
+ get_target_property(target_type "${target_name}" TYPE)
+ if (target_type STREQUAL "EXECUTABLE")
+ list(LENGTH file_names list_len)
+ if(NOT list_len EQUAL "1")
+ message(FATAL_ERROR
+ "Internal error: Exactly one filename should be passed for executable types.")
+ endif()
+ _corrosion_bin_target_suffix(${target_name} "suffix")
+ if(suffix AND (NOT "${file_names}" MATCHES "\.pdb$"))
+ # For executable targets we know / checked that only one file will be passed.
+ string(APPEND file_names "${suffix}")
+ endif()
+ endif()
+ set(src_file_names "${file_names}")
+ if(Rust_CARGO_TARGET_ENV STREQUAL "gnullvm")
+ # Workaround for cargo not exposing implibs yet.
+ list(TRANSFORM src_file_names PREPEND "deps/" REGEX "\.dll\.a$")
+ endif()
+ list(TRANSFORM src_file_names PREPEND "${cargo_build_dir}/")
+ list(TRANSFORM file_names PREPEND "${output_dir}/" OUTPUT_VARIABLE dst_file_names)
+ message(DEBUG "Adding command to copy byproducts `${file_names}` to ${dst_file_names}")
+ add_custom_command(TARGET _cargo-build_${target_name}
+ POST_BUILD
+ # output_dir may contain a Generator expression.
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different
+ # tested to work with both multiple files and paths with spaces
+ ${src_file_names}
+ "${output_dir}"
+ BYPRODUCTS ${dst_file_names}
+ COMMENT "Copying byproducts `${file_names}` to ${output_dir}"
+ VERBATIM
+ COMMAND_EXPAND_LISTS
+ )
+endfunction()
+
+# Copy the artifacts generated by cargo to the appropriate destination.
+#
+# Parameters:
+# - target_name: The name of the Rust target
+# - output_dir_prop_names: The property name(s) controlling the destination (e.g.
+# `LIBRARY_OUTPUT_DIRECTORY` or `PDB_OUTPUT_DIRECTORY;RUNTIME_OUTPUT_DIRECTORY`)
+# - cargo_build_dir: the directory cargo build places it's output artifacts in.
+# - filenames: the file names of any output artifacts as a list.
+function(_corrosion_copy_byproducts target_name output_dir_prop_names cargo_build_dir file_names)
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER
+ CALL
+ _corrosion_copy_byproduct_deferred
+ [[${target_name}]]
+ [[${output_dir_prop_names}]]
+ [[${cargo_build_dir}]]
+ [[${file_names}]]
+ )
+ ")
+endfunction()
+
+
+# Add targets for the static and/or shared libraries of the rust target.
+# The generated byproduct names are returned via the `OUT_<type>_BYPRODUCTS` arguments.
+function(_corrosion_add_library_target)
+ set(OPTIONS "")
+ set(ONE_VALUE_KEYWORDS
+ WORKSPACE_MANIFEST_PATH
+ TARGET_NAME
+ OUT_ARCHIVE_OUTPUT_BYPRODUCTS
+ OUT_SHARED_LIB_BYPRODUCTS
+ OUT_PDB_BYPRODUCT
+ )
+ set(MULTI_VALUE_KEYWORDS LIB_KINDS)
+ cmake_parse_arguments(PARSE_ARGV 0 CALT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
+
+ if(DEFINED CALT_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Internal error - unexpected arguments: ${CALT_UNPARSED_ARGUMENTS}")
+ elseif(DEFINED CALT_KEYWORDS_MISSING_VALUES)
+ message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
+ "${CALT_KEYWORDS_MISSING_VALUES}")
+ endif()
+ list(TRANSFORM ONE_VALUE_KEYWORDS PREPEND CALT_ OUTPUT_VARIABLE required_arguments)
+ foreach(required_argument ${required_arguments} )
+ if(NOT DEFINED "${required_argument}")
+ message(FATAL_ERROR "Internal error: Missing required argument ${required_argument}."
+ "Complete argument list: ${ARGN}"
+ )
+ endif()
+ endforeach()
+ if("staticlib" IN_LIST CALT_LIB_KINDS)
+ set(has_staticlib TRUE)
+ endif()
+ if("cdylib" IN_LIST CALT_LIB_KINDS)
+ set(has_cdylib TRUE)
+ endif()
+
+ if(NOT (has_staticlib OR has_cdylib))
+ message(FATAL_ERROR "Unknown library type(s): ${CALT_LIB_KINDS}")
+ endif()
+ set(workspace_manifest_path "${CALT_WORKSPACE_MANIFEST_PATH}")
+ set(target_name "${CALT_TARGET_NAME}")
+
+ set(is_windows "")
+ set(is_windows_gnu "")
+ set(is_windows_msvc "")
+ set(is_macos "")
+ if(Rust_CARGO_TARGET_OS STREQUAL "windows")
+ set(is_windows TRUE)
+ if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
+ set(is_windows_msvc TRUE)
+ elseif(Rust_CARGO_TARGET_ENV STREQUAL "gnu" OR Rust_CARGO_TARGET_ENV STREQUAL "gnullvm")
+ set(is_windows_gnu TRUE)
+ endif()
+ elseif(Rust_CARGO_TARGET_OS STREQUAL "darwin")
+ set(is_macos TRUE)
+ endif()
+
+ # target file names
+ string(REPLACE "-" "_" lib_name "${target_name}")
+
+ if(is_windows_msvc)
+ set(static_lib_name "${lib_name}.lib")
+ else()
+ set(static_lib_name "lib${lib_name}.a")
+ endif()
+
+ if(is_windows)
+ set(dynamic_lib_name "${lib_name}.dll")
+ elseif(is_macos)
+ set(dynamic_lib_name "lib${lib_name}.dylib")
+ else()
+ set(dynamic_lib_name "lib${lib_name}.so")
+ endif()
+
+ if(is_windows_msvc)
+ set(implib_name "${lib_name}.dll.lib")
+ elseif(is_windows_gnu)
+ set(implib_name "lib${lib_name}.dll.a")
+ elseif(is_windows)
+ message(FATAL_ERROR "Unknown windows environment - Can't determine implib name")
+ endif()
+
+
+ set(pdb_name "${lib_name}.pdb")
+
+ set(archive_output_byproducts "")
+ if(has_staticlib)
+ list(APPEND archive_output_byproducts ${static_lib_name})
+ endif()
+
+ if(has_cdylib)
+ set("${CALT_OUT_SHARED_LIB_BYPRODUCTS}" "${dynamic_lib_name}" PARENT_SCOPE)
+ if(is_windows)
+ list(APPEND archive_output_byproducts ${implib_name})
+ endif()
+ if(is_windows_msvc)
+ set("${CALT_OUT_PDB_BYPRODUCT}" "${pdb_name}" PARENT_SCOPE)
+ endif()
+ endif()
+ set("${CALT_OUT_ARCHIVE_OUTPUT_BYPRODUCTS}" "${archive_output_byproducts}" PARENT_SCOPE)
+
+ if(has_staticlib)
+ add_library(${target_name}-static STATIC IMPORTED GLOBAL)
+ add_dependencies(${target_name}-static cargo-build_${target_name})
+ set_target_properties(${target_name}-static PROPERTIES COR_FILE_NAME ${static_lib_name})
+
+ _corrosion_set_imported_location("${target_name}-static" "IMPORTED_LOCATION"
+ "ARCHIVE_OUTPUT_DIRECTORY"
+ "${static_lib_name}")
+
+ # Todo: NO_STD target property?
+ if(NOT COR_NO_STD)
+ set_property(
+ TARGET ${target_name}-static
+ PROPERTY INTERFACE_LINK_LIBRARIES ${Rust_CARGO_TARGET_LINK_NATIVE_LIBS}
+ )
+ set_property(
+ TARGET ${target_name}-static
+ PROPERTY INTERFACE_LINK_OPTIONS ${Rust_CARGO_TARGET_LINK_OPTIONS}
+ )
+ if(is_macos)
+ set_property(TARGET ${target_name}-static
+ PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
+ )
+ endif()
+ endif()
+ endif()
+
+ if(has_cdylib)
+ add_library(${target_name}-shared SHARED IMPORTED GLOBAL)
+ add_dependencies(${target_name}-shared cargo-build_${target_name})
+ set_target_properties(${target_name}-shared PROPERTIES COR_FILE_NAME ${dynamic_lib_name})
+
+ # Todo: (Not new issue): What about IMPORTED_SONAME and IMPORTED_NO_SYSTEM?
+ _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_LOCATION"
+ "LIBRARY_OUTPUT_DIRECTORY"
+ "${dynamic_lib_name}"
+ )
+ # In the future we would probably prefer to let Rust set the soname for packages >= 1.0.
+ # This is tracked in issue #333.
+ set_target_properties(${target_name}-shared PROPERTIES IMPORTED_NO_SONAME TRUE)
+
+ if(is_windows)
+ _corrosion_set_imported_location("${target_name}-shared" "IMPORTED_IMPLIB"
+ "ARCHIVE_OUTPUT_DIRECTORY"
+ "${implib_name}"
+ )
+ set_target_properties(${target_name}-shared PROPERTIES COR_IMPLIB_FILE_NAME ${implib_name})
+ endif()
+
+ if(is_macos)
+ set_property(TARGET ${target_name}-shared
+ PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
+ )
+ endif()
+ endif()
+
+ if(has_cdylib AND has_staticlib)
+ if(BUILD_SHARED_LIBS)
+ target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
+ else()
+ target_link_libraries(${target_name} INTERFACE ${target_name}-static)
+ endif()
+ elseif(has_cdylib)
+ target_link_libraries(${target_name} INTERFACE ${target_name}-shared)
+ else()
+ target_link_libraries(${target_name} INTERFACE ${target_name}-static)
+ endif()
+endfunction()
+
+function(_corrosion_add_bin_target workspace_manifest_path bin_name out_bin_byproduct out_pdb_byproduct)
+ if(NOT bin_name)
+ message(FATAL_ERROR "No bin_name in _corrosion_add_bin_target for target ${target_name}")
+ endif()
+
+ string(REPLACE "-" "_" bin_name_underscore "${bin_name}")
+
+ set(pdb_name "${bin_name_underscore}.pdb")
+
+ if(Rust_CARGO_TARGET_ENV STREQUAL "msvc")
+ set(${out_pdb_byproduct} "${pdb_name}" PARENT_SCOPE)
+ endif()
+
+ # Potential .exe suffix will be added later, also depending on possible hostbuild
+ # target property
+ set(bin_filename "${bin_name}")
+ set(${out_bin_byproduct} "${bin_filename}" PARENT_SCOPE)
+ add_dependencies(${bin_name} cargo-build_${bin_name})
+
+ if(Rust_CARGO_TARGET_OS STREQUAL "darwin")
+ set_property(TARGET ${bin_name}
+ PROPERTY INTERFACE_LINK_DIRECTORIES "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
+ )
+ endif()
+
+ _corrosion_set_imported_location("${bin_name}" "IMPORTED_LOCATION"
+ "RUNTIME_OUTPUT_DIRECTORY"
+ "${bin_filename}"
+ )
+
+endfunction()
+
+
+include(CorrosionGenerator)
+
+# Note: `cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)` requires CMake 3.25,
+# so we offer our own option to control verbosity of downstream commands (e.g. cargo build)
+if (CORROSION_VERBOSE_OUTPUT)
+ set(_CORROSION_VERBOSE_OUTPUT_FLAG --verbose CACHE INTERNAL "")
+else()
+ # We want to silence some less important commands by default.
+ set(_CORROSION_QUIET_OUTPUT_FLAG --quiet CACHE INTERNAL "")
+endif()
+
+set(_CORROSION_CARGO_VERSION ${Rust_CARGO_VERSION} CACHE INTERNAL "cargo version used by corrosion")
+set(_CORROSION_RUST_CARGO_TARGET ${Rust_CARGO_TARGET} CACHE INTERNAL "target triple used by corrosion")
+set(_CORROSION_RUST_CARGO_HOST_TARGET ${Rust_CARGO_HOST_TARGET} CACHE INTERNAL "host triple used by corrosion")
+set(_CORROSION_RUSTC "${RUSTC_EXECUTABLE}" CACHE INTERNAL "Path to rustc used by corrosion")
+set(_CORROSION_CARGO "${CARGO_EXECUTABLE}" CACHE INTERNAL "Path to cargo used by corrosion")
+
+string(REPLACE "-" "_" _CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${Rust_CARGO_TARGET}")
+set(_CORROSION_RUST_CARGO_TARGET_UNDERSCORE "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" CACHE INTERNAL "lowercase target triple with underscores")
+string(TOUPPER "${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}" _CORROSION_TARGET_TRIPLE_UPPER)
+set(_CORROSION_RUST_CARGO_TARGET_UPPER
+ "${_CORROSION_TARGET_TRIPLE_UPPER}"
+ CACHE INTERNAL
+ "target triple in uppercase with underscore"
+)
+
+# We previously specified some Custom properties as part of our public API, however the chosen names prevented us from
+# supporting CMake versions before 3.19. In order to both support older CMake versions and not break existing code
+# immediately, we are using a different property name depending on the CMake version. However users avoid using
+# any of the properties directly, as they are no longer part of the public API and are to be considered deprecated.
+# Instead use the corrosion_set_... functions as documented in the Readme.
+set(_CORR_PROP_FEATURES CORROSION_FEATURES CACHE INTERNAL "")
+set(_CORR_PROP_ALL_FEATURES CORROSION_ALL_FEATURES CACHE INTERNAL "")
+set(_CORR_PROP_NO_DEFAULT_FEATURES CORROSION_NO_DEFAULT_FEATURES CACHE INTERNAL "")
+set(_CORR_PROP_ENV_VARS CORROSION_ENVIRONMENT_VARIABLES CACHE INTERNAL "")
+set(_CORR_PROP_HOST_BUILD CORROSION_USE_HOST_BUILD CACHE INTERNAL "")
+
+# Add custom command to build one target in a package (crate)
+#
+# A target may be either a specific bin
+function(_add_cargo_build out_cargo_build_out_dir)
+ set(options NO_LINKER_OVERRIDE)
+ set(one_value_args PACKAGE TARGET MANIFEST_PATH WORKSPACE_MANIFEST_PATH)
+ set(multi_value_args BYPRODUCTS TARGET_KINDS)
+ cmake_parse_arguments(
+ ACB
+ "${options}"
+ "${one_value_args}"
+ "${multi_value_args}"
+ ${ARGN}
+ )
+
+ if(DEFINED ACB_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Internal error - unexpected arguments: "
+ ${ACB_UNPARSED_ARGUMENTS})
+ elseif(DEFINED ACB_KEYWORDS_MISSING_VALUES)
+ message(FATAL_ERROR "Internal error - missing values for the following arguments: "
+ ${ACB_KEYWORDS_MISSING_VALUES})
+ endif()
+
+ set(package_name "${ACB_PACKAGE}")
+ set(target_name "${ACB_TARGET}")
+ set(path_to_toml "${ACB_MANIFEST_PATH}")
+ set(target_kinds "${ACB_TARGET_KINDS}")
+ set(workspace_manifest_path "${ACB_WORKSPACE_MANIFEST_PATH}")
+ set(build_byproducts "${ACB_BYPRODUCTS}")
+
+ unset(cargo_rustc_crate_types)
+ if(NOT target_kinds)
+ message(FATAL_ERROR "TARGET_KINDS not specified")
+ elseif("staticlib" IN_LIST target_kinds OR "cdylib" IN_LIST target_kinds)
+ set(cargo_rustc_filter "--lib")
+ if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.64")
+ # https://doc.rust-lang.org/1.64.0/cargo/commands/cargo-rustc.html
+ # `--crate-type` is documented since Rust 1.64 for `cargo rustc`.
+ # We just unconditionally set it when available, to support overriding the crate type.
+ # Due to https://github.com/rust-lang/cargo/issues/14498 we can't use one argument and pass a
+ # comma seperated list. Instead we use multiple arguments.
+ set(cargo_rustc_crate_types "${target_kinds}")
+ list(TRANSFORM cargo_rustc_crate_types PREPEND "--crate-type=")
+ endif()
+ elseif("bin" IN_LIST target_kinds)
+ set(cargo_rustc_filter "--bin=${target_name}")
+ else()
+ message(FATAL_ERROR "TARGET_KINDS contained unknown kind `${target_kind}`")
+ endif()
+
+ if (NOT IS_ABSOLUTE "${path_to_toml}")
+ set(path_to_toml "${CMAKE_SOURCE_DIR}/${path_to_toml}")
+ endif()
+ get_filename_component(workspace_toml_dir ${path_to_toml} DIRECTORY )
+
+ if (CMAKE_VS_PLATFORM_NAME)
+ set (build_dir "${CMAKE_VS_PLATFORM_NAME}/$<CONFIG>")
+ elseif(COR_IS_MULTI_CONFIG)
+ set (build_dir "$<CONFIG>")
+ else()
+ set (build_dir .)
+ endif()
+
+ # If a CMake sysroot is specified, forward it to the linker rustc invokes, too. CMAKE_SYSROOT is documented
+ # to be passed via --sysroot, so we assume that when it's set, the linker supports this option in that style.
+ if(CMAKE_CROSSCOMPILING AND CMAKE_SYSROOT)
+ set(corrosion_link_args "--sysroot=${CMAKE_SYSROOT}")
+ endif()
+
+ if(COR_ALL_FEATURES)
+ set(all_features_arg --all-features)
+ endif()
+ if(COR_NO_DEFAULT_FEATURES)
+ set(no_default_features_arg --no-default-features)
+ endif()
+
+ set(global_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_RUSTFLAGS>>")
+ set(local_rustflags_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LOCAL_RUSTFLAGS>>")
+
+ # todo: this probably should be TARGET_GENEX_EVAL
+ set(features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_FEATURES}>>")
+ set(features_genex "$<$<BOOL:${features_target_property}>:--features=$<JOIN:${features_target_property},$<COMMA>>>")
+
+ # target property overrides corrosion_import_crate argument
+ set(all_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ALL_FEATURES}>>")
+ set(all_features_arg "$<$<BOOL:${all_features_target_property}>:--all-features>")
+
+ set(no_default_features_target_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_NO_DEFAULT_FEATURES}>>")
+ set(no_default_features_arg "$<$<BOOL:${no_default_features_target_property}>:--no-default-features>")
+
+ set(build_env_variable_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_ENV_VARS}>>")
+ set(hostbuild_override "$<BOOL:$<TARGET_PROPERTY:${target_name},${_CORR_PROP_HOST_BUILD}>>")
+ set(if_not_host_build_condition "$<NOT:${hostbuild_override}>")
+
+ set(corrosion_link_args "$<${if_not_host_build_condition}:${corrosion_link_args}>")
+ # We always set `--target`, so that cargo always places artifacts into a directory with the
+ # target triple.
+ set(cargo_target_option "--target=$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${_CORROSION_RUST_CARGO_TARGET}>")
+
+ # The target may be a filepath to custom target json file. For host targets we assume that they are built-in targets.
+ _corrosion_strip_target_triple(${_CORROSION_RUST_CARGO_TARGET} stripped_target_triple)
+ set(target_artifact_dir "$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${stripped_target_triple}>")
+
+ set(flags_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO_FLAGS>>")
+
+ set(explicit_linker_property "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_LINKER>")
+ set(explicit_linker_defined "$<BOOL:${explicit_linker_property}>")
+
+ set(cargo_profile_target_property "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO_PROFILE>>")
+
+ # Option to override the rustc/cargo binary to something other than the global default
+ set(rustc_override "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_RUSTC>")
+ set(cargo_override "$<TARGET_PROPERTY:${target_name},INTERFACE_CORROSION_CARGO>")
+ set(rustc_bin "$<IF:$<BOOL:${rustc_override}>,${rustc_override},${_CORROSION_RUSTC}>")
+ set(cargo_bin "$<IF:$<BOOL:${cargo_override}>,${cargo_override},${_CORROSION_CARGO}>")
+
+
+ # Rust will add `-lSystem` as a flag for the linker on macOS. Adding the -L flag via RUSTFLAGS only fixes the
+ # problem partially - buildscripts still break, since they won't receive the RUSTFLAGS. This seems to only be a
+ # problem if we specify the linker ourselves (which we do, since this is necessary for e.g. linking C++ code).
+ # We can however set `LIBRARY_PATH`, which is propagated to the build-script-build properly.
+ if(NOT CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ # not needed anymore on macos 13 (and causes issues)
+ if(${CMAKE_SYSTEM_VERSION} VERSION_LESS 22)
+ set(cargo_library_path "LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
+ endif()
+ elseif(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ if(${CMAKE_HOST_SYSTEM_VERSION} VERSION_LESS 22)
+ set(cargo_library_path "$<${hostbuild_override}:LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib>")
+ endif()
+ endif()
+
+ set(cargo_profile_set "$<BOOL:${cargo_profile_target_property}>")
+ # In the default case just specify --release or nothing to stay compatible with
+ # older rust versions.
+ set(default_profile_option "$<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:>>>:--release>")
+ # evaluates to either `--profile=<custom_profile>`, `--release` or nothing (for debug).
+ set(cargo_profile "$<IF:${cargo_profile_set},--profile=${cargo_profile_target_property},${default_profile_option}>")
+
+ # If the profile name is `dev` change the dir name to `debug`.
+ set(is_dev_profile "$<STREQUAL:${cargo_profile_target_property},dev>")
+ set(profile_dir_override "$<${is_dev_profile}:debug>")
+ set(profile_dir_is_overridden "$<BOOL:${profile_dir_override}>")
+ set(custom_profile_build_type_dir "$<IF:${profile_dir_is_overridden},${profile_dir_override},${cargo_profile_target_property}>")
+
+ set(default_build_type_dir "$<IF:$<OR:$<CONFIG:Debug>,$<CONFIG:>>,debug,release>")
+ set(build_type_dir "$<IF:${cargo_profile_set},${custom_profile_build_type_dir},${default_build_type_dir}>")
+
+ set(cargo_target_dir "${CMAKE_BINARY_DIR}/${build_dir}/cargo/build")
+ set(cargo_build_dir "${cargo_target_dir}/${target_artifact_dir}/${build_type_dir}")
+ set("${out_cargo_build_out_dir}" "${cargo_build_dir}" PARENT_SCOPE)
+
+ set(corrosion_cc_rs_flags)
+
+ if(CMAKE_C_COMPILER)
+ # This variable is read by cc-rs (often used in build scripts) to determine the c-compiler.
+ # It can still be overridden if the user sets the non underscore variant via the environment variables
+ # on the target.
+ list(APPEND corrosion_cc_rs_flags "CC_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_C_COMPILER}")
+ endif()
+ if(CMAKE_CXX_COMPILER)
+ list(APPEND corrosion_cc_rs_flags "CXX_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_CXX_COMPILER}")
+ endif()
+ # cc-rs doesn't seem to support `llvm-ar` (commandline syntax), wo we might as well just use
+ # the default AR.
+ if(CMAKE_AR AND NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc"))
+ list(APPEND corrosion_cc_rs_flags "AR_${_CORROSION_RUST_CARGO_TARGET_UNDERSCORE}=${CMAKE_AR}")
+ endif()
+
+ # Since we instruct cc-rs to use the compiler found by CMake, it is likely one that requires also
+ # specifying the target sysroot to use. CMake's generator makes sure to pass --sysroot with
+ # CMAKE_OSX_SYSROOT. Fortunately the compilers Apple ships also respect the SDKROOT environment
+ # variable, which we can set for use when cc-rs invokes the compiler.
+ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
+ list(APPEND corrosion_cc_rs_flags "SDKROOT=${CMAKE_OSX_SYSROOT}")
+ endif()
+
+ # Ensure that cc-rs targets same Apple platform version as the CMake build
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_DEPLOYMENT_TARGET)
+ list(APPEND corrosion_cc_rs_flags "MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ endif()
+
+ corrosion_add_target_local_rustflags("${target_name}" "$<$<BOOL:${corrosion_link_args}>:-Clink-args=${corrosion_link_args}>")
+
+ # todo: this should probably also be guarded by if_not_host_build_condition.
+ if(COR_NO_STD)
+ corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=no")
+ else()
+ corrosion_add_target_local_rustflags("${target_name}" "-Cdefault-linker-libraries=yes")
+ endif()
+
+ set(global_joined_rustflags "$<JOIN:${global_rustflags_target_property}, >")
+ set(global_rustflags_genex "$<$<BOOL:${global_rustflags_target_property}>:RUSTFLAGS=${global_joined_rustflags}>")
+ set(local_rustflags_delimiter "$<$<BOOL:${local_rustflags_target_property}>:-->")
+ set(local_rustflags_genex "$<$<BOOL:${local_rustflags_target_property}>:${local_rustflags_target_property}>")
+
+ set(deps_link_languages_prop "$<TARGET_PROPERTY:_cargo-build_${target_name},CARGO_DEPS_LINKER_LANGUAGES>")
+ set(deps_link_languages "$<TARGET_GENEX_EVAL:_cargo-build_${target_name},${deps_link_languages_prop}>")
+ set(target_uses_cxx "$<IN_LIST:CXX,${deps_link_languages}>")
+ unset(default_linker)
+ # With the MSVC ABI rustc only supports directly invoking the linker - Invoking cl as the linker driver is not supported.
+ if(NOT (Rust_CARGO_TARGET_ENV STREQUAL "msvc" OR COR_NO_LINKER_OVERRIDE))
+ set(default_linker "$<IF:$<BOOL:${target_uses_cxx}>,${CMAKE_CXX_COMPILER},${CMAKE_C_COMPILER}>")
+ endif()
+ # Used to set a linker for a specific target-triple.
+ set(cargo_target_linker_var "CARGO_TARGET_${_CORROSION_RUST_CARGO_TARGET_UPPER}_LINKER")
+ set(linker "$<IF:${explicit_linker_defined},${explicit_linker_property},${default_linker}>")
+ set(cargo_target_linker $<$<BOOL:${linker}>:${cargo_target_linker_var}=${linker}>)
+
+ if(Rust_CROSSCOMPILING AND (CMAKE_C_COMPILER_TARGET OR CMAKE_CXX_COMPILER_TARGET))
+ set(linker_target_triple "$<IF:$<BOOL:${target_uses_cxx}>,${CMAKE_CXX_COMPILER_TARGET},${CMAKE_C_COMPILER_TARGET}>")
+ set(rustflag_linker_arg "-Clink-args=--target=${linker_target_triple}")
+ set(rustflag_linker_arg "$<${if_not_host_build_condition}:${rustflag_linker_arg}>")
+ # Skip adding the linker argument, if the linker is explicitly set, since the
+ # explicit_linker_property will not be set when this function runs.
+ # Passing this rustflag is necessary for clang.
+ corrosion_add_target_local_rustflags("${target_name}" "$<$<NOT:${explicit_linker_defined}>:${rustflag_linker_arg}>")
+ endif()
+
+ message(DEBUG "TARGET ${target_name} produces byproducts ${build_byproducts}")
+
+ add_custom_target(
+ _cargo-build_${target_name}
+ # Build crate
+ COMMAND
+ ${CMAKE_COMMAND} -E env
+ "${build_env_variable_genex}"
+ "${global_rustflags_genex}"
+ "${cargo_target_linker}"
+ "${corrosion_cc_rs_flags}"
+ "${cargo_library_path}"
+ "CORROSION_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}"
+ "CARGO_BUILD_RUSTC=${rustc_bin}"
+ "${cargo_bin}"
+ rustc
+ ${cargo_rustc_filter}
+ ${cargo_target_option}
+ ${_CORROSION_VERBOSE_OUTPUT_FLAG}
+ ${all_features_arg}
+ ${no_default_features_arg}
+ ${features_genex}
+ --package ${package_name}
+ ${cargo_rustc_crate_types}
+ --manifest-path "${path_to_toml}"
+ --target-dir "${cargo_target_dir}"
+ ${cargo_profile}
+ ${flags_genex}
+ # Any arguments to cargo must be placed before this line
+ ${local_rustflags_delimiter}
+ ${local_rustflags_genex}
+
+ # Note: `BYPRODUCTS` may not contain **target specific** generator expressions.
+ # This means we cannot use `${cargo_build_dir}`, since it currently uses `$<TARGET_PROPERTY>`
+ # to determine the correct target directory, depending on if the hostbuild target property is
+ # set or not.
+ # BYPRODUCTS "${cargo_build_dir}/${build_byproducts}"
+ # The build is conducted in the directory of the Manifest, so that configuration files such as
+ # `.cargo/config.toml` or `toolchain.toml` are applied as expected.
+ WORKING_DIRECTORY "${workspace_toml_dir}"
+ USES_TERMINAL
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+ )
+
+ # User exposed custom target, that depends on the internal target.
+ # Corrosion post build steps are added on the internal target, which
+ # ensures that they run before any user defined post build steps on this
+ # target.
+ add_custom_target(
+ cargo-build_${target_name}
+ ALL
+ )
+ add_dependencies(cargo-build_${target_name} _cargo-build_${target_name})
+
+ # Add custom target before actual build that user defined custom commands (e.g. code generators) can
+ # use as a hook to do something before the build. This mainly exists to not expose the `_cargo-build` targets.
+ add_custom_target(cargo-prebuild_${target_name})
+ add_dependencies(_cargo-build_${target_name} cargo-prebuild_${target_name})
+ if(NOT TARGET cargo-prebuild)
+ add_custom_target(cargo-prebuild)
+ endif()
+ add_dependencies(cargo-prebuild cargo-prebuild_${target_name})
+
+ add_custom_target(
+ cargo-clean_${target_name}
+ COMMAND
+ "${cargo_bin}" clean ${cargo_target_option}
+ -p ${package_name} --manifest-path ${path_to_toml}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${build_dir}
+ USES_TERMINAL
+ )
+
+ if (NOT TARGET cargo-clean)
+ add_custom_target(cargo-clean)
+ endif()
+ add_dependencies(cargo-clean cargo-clean_${target_name})
+endfunction()
+
+#[=======================================================================[.md:
+ANCHOR: corrosion-import-crate
+```cmake
+corrosion_import_crate(
+ MANIFEST_PATH <path/to/cargo.toml>
+ [ALL_FEATURES]
+ [NO_DEFAULT_FEATURES]
+ [NO_STD]
+ [NO_LINKER_OVERRIDE]
+ [LOCKED]
+ [FROZEN]
+ [PROFILE <cargo-profile>]
+ [IMPORTED_CRATES <variable-name>]
+ [CRATE_TYPES <crate_type1> ... <crate_typeN>]
+ [OVERRIDE_CRATE_TYPE <crate_name>=<crate_type1,crate_type2,...> ...]
+ [CRATES <crate1> ... <crateN>]
+ [FEATURES <feature1> ... <featureN>]
+ [FLAGS <flag1> ... <flagN>]
+)
+```
+* **MANIFEST_PATH**: Path to a [Cargo.toml Manifest] file.
+* **ALL_FEATURES**: Equivalent to [--all-features] passed to cargo build
+* **NO_DEFAULT_FEATURES**: Equivalent to [--no-default-features] passed to cargo build
+* **NO_STD**: Disable linking of standard libraries (required for no_std crates).
+* **NO_LINKER_OVERRIDE**: Will let Rust/Cargo determine which linker to use instead of corrosion (when linking is invoked by Rust)
+* **LOCKED**: Pass [`--locked`] to cargo build and cargo metadata.
+* **FROZEN**: Pass [`--frozen`] to cargo build and cargo metadata.
+* **PROFILE**: Specify cargo build profile (`dev`/`release` or a [custom profile]; `bench` and `test` are not supported)
+* **IMPORTED_CRATES**: Save the list of imported crates into the variable with the provided name in the current scope.
+* **CRATE_TYPES**: Only import the specified crate types. Valid values: `staticlib`, `cdylib`, `bin`.
+* **OVERRIDE_CRATE_TYPE**: Override the crate-types of a cargo crate with the given comma-separated values.
+ Internally uses the `rustc` flag [`--crate-type`] to override the crate-type.
+ Valid values for the crate types are the library types `staticlib` and `cdylib`.
+* **CRATES**: Only import the specified crates from a workspace. Values: Crate names.
+* **FEATURES**: Enable the specified features. Equivalent to [--features] passed to `cargo build`.
+* **FLAGS**: Arbitrary flags to `cargo build`.
+
+[custom profile]: https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles
+[--all-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
+[--no-default-features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
+[--features]: https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options
+[`--locked`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
+[`--frozen`]: https://doc.rust-lang.org/cargo/commands/cargo.html#manifest-options
+[`--crate-type`]: https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit
+[Cargo.toml Manifest]: https://doc.rust-lang.org/cargo/appendix/glossary.html#manifest
+
+ANCHOR_END: corrosion-import-crate
+#]=======================================================================]
+function(corrosion_import_crate)
+ set(OPTIONS ALL_FEATURES NO_DEFAULT_FEATURES NO_STD NO_LINKER_OVERRIDE LOCKED FROZEN)
+ set(ONE_VALUE_KEYWORDS MANIFEST_PATH PROFILE IMPORTED_CRATES)
+ set(MULTI_VALUE_KEYWORDS CRATE_TYPES CRATES FEATURES FLAGS OVERRIDE_CRATE_TYPE)
+ cmake_parse_arguments(COR "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}" ${ARGN})
+ list(APPEND CMAKE_MESSAGE_CONTEXT "corrosion_import_crate")
+
+ if(DEFINED COR_UNPARSED_ARGUMENTS)
+ message(AUTHOR_WARNING "Unexpected arguments: " ${COR_UNPARSED_ARGUMENTS}
+ "\nCorrosion will ignore these unexpected arguments."
+ )
+ endif()
+ if(DEFINED COR_KEYWORDS_MISSING_VALUES)
+ message(DEBUG "Note: the following keywords passed to corrosion_import_crate had no associated value(s): "
+ ${COR_KEYWORDS_MISSING_VALUES}
+ )
+ endif()
+ if (NOT DEFINED COR_MANIFEST_PATH)
+ message(FATAL_ERROR "MANIFEST_PATH is a required keyword to corrosion_add_crate")
+ endif()
+ _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE COR no_linker_override)
+ _corrosion_option_passthrough_helper(LOCKED COR locked)
+ _corrosion_option_passthrough_helper(FROZEN COR frozen)
+ _corrosion_arg_passthrough_helper(CRATES COR crate_allowlist)
+ _corrosion_arg_passthrough_helper(CRATE_TYPES COR crate_types)
+
+ if(COR_PROFILE)
+ if(Rust_VERSION VERSION_LESS 1.57.0)
+ message(FATAL_ERROR "Selecting custom profiles via `PROFILE` requires at least rust 1.57.0, but you "
+ "have ${Rust_VERSION}."
+ )
+ # The profile name could be part of a Generator expression, so this won't catch all occurences.
+ # Since it is hard to add an error message for genex, we don't do that here.
+ elseif("${COR_PROFILE}" STREQUAL "test" OR "${COR_PROFILE}" STREQUAL "bench")
+ message(FATAL_ERROR "Corrosion does not support building Rust crates with the cargo profiles"
+ " `test` or `bench`. These profiles add a hash to the output artifact name that we"
+ " cannot predict. Please consider using a custom cargo profile which inherits from the"
+ " built-in profile instead."
+ )
+ endif()
+ endif()
+
+ # intended to be used with foreach(... ZIP_LISTS ...), meaning
+ # that the crate_types at index i of `override_crate_type_types_list` are
+ # for the package_name at index i of `override_crate_type_package_name_list`.
+ # It would really be nice if CMake had structs or dicts.
+ unset(override_crate_type_package_name_list)
+ unset(override_crate_type_types_list)
+ unset(OVERRIDE_CRATE_TYPE_ARGS)
+ if(DEFINED COR_OVERRIDE_CRATE_TYPE)
+ string(JOIN " " usage_help
+ "Each argument to OVERRIDE_CRATE_TYPE must be of the form `<package_name>=<crate_type(s)>."
+ "The package_name must be a valid cargo package name and the crate_type must be "
+ "a comma-seperated list with valid values being `staticlib`, `cdylib` and `bin`"
+ )
+ foreach(entry IN LISTS COR_OVERRIDE_CRATE_TYPE)
+ string(REPLACE "=" ";" key_val_list ${entry})
+ list(LENGTH key_val_list key_val_list_len)
+ if(NOT key_val_list_len EQUAL "2")
+ message(FATAL_ERROR "Invalid argument: `${entry}` for parameter OVERRIDE_CRATE_TYPE!\n"
+ "${usage_help}"
+ )
+ endif()
+ list(GET key_val_list "0" package_name)
+ list(GET key_val_list "1" crate_types)
+ list(APPEND override_crate_type_package_name_list "${package_name}")
+ list(APPEND override_crate_type_types_list "${crate_types}")
+ endforeach()
+ list(LENGTH override_crate_type_package_name_list num_override_packages)
+ list(LENGTH override_crate_type_types_list num_override_packages2)
+ if("${Rust_VERSION}" VERSION_LESS "1.64")
+ message(WARNING "OVERRIDE_CRATE_TYPE requires at Rust 1.64 or newer. Ignoring the option")
+ elseif(NOT num_override_packages EQUAL num_override_packages2)
+ message(WARNING "Internal error while parsing OVERRIDE_CRATE_TYPE arguments.\n"
+ "Corrosion will ignore this argument and continue."
+ )
+ else()
+ # Pass by ref: we intentionally pass the list names here!
+ set(override_crate_types_arg "OVERRIDE_CRATE_TYPE_ARGS" "override_crate_type_package_name_list" "override_crate_type_types_list")
+ endif()
+ endif()
+
+ if (NOT IS_ABSOLUTE "${COR_MANIFEST_PATH}")
+ set(COR_MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${COR_MANIFEST_PATH})
+ endif()
+
+ set(additional_cargo_flags ${COR_FLAGS})
+
+ if(COR_LOCKED AND NOT "--locked" IN_LIST additional_cargo_flags)
+ list(APPEND additional_cargo_flags "--locked")
+ endif()
+ if(COR_FROZEN AND NOT "--frozen" IN_LIST additional_cargo_flags)
+ list(APPEND additional_cargo_flags "--frozen")
+ endif()
+
+ set(imported_crates "")
+
+ _generator_add_cargo_targets(
+ MANIFEST_PATH
+ "${COR_MANIFEST_PATH}"
+ IMPORTED_CRATES
+ imported_crates
+ ${crate_allowlist}
+ ${crate_types}
+ ${no_linker_override}
+ ${override_crate_types_arg}
+ )
+
+ # Not target props yet:
+ # NO_STD
+ # NO_LINKER_OVERRIDE # We could simply zero INTERFACE_CORROSION_LINKER if this is set.
+ # LOCKED / FROZEN get merged into FLAGS after cargo metadata.
+
+ # Initialize the target properties with the arguments to corrosion_import_crate.
+ set_target_properties(
+ ${imported_crates}
+ PROPERTIES
+ "${_CORR_PROP_ALL_FEATURES}" "${COR_ALL_FEATURES}"
+ "${_CORR_PROP_NO_DEFAULT_FEATURES}" "${COR_NO_DEFAULT_FEATURES}"
+ "${_CORR_PROP_FEATURES}" "${COR_FEATURES}"
+ INTERFACE_CORROSION_CARGO_PROFILE "${COR_PROFILE}"
+ INTERFACE_CORROSION_CARGO_FLAGS "${additional_cargo_flags}"
+ )
+
+ # _CORR_PROP_ENV_VARS
+ if(DEFINED COR_IMPORTED_CRATES)
+ set(${COR_IMPORTED_CRATES} ${imported_crates} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(corrosion_set_linker target_name linker)
+ if(NOT linker)
+ message(FATAL_ERROR "The linker passed to `corrosion_set_linker` may not be empty")
+ elseif(NOT TARGET "${target_name}")
+ message(FATAL_ERROR "The target `${target_name}` does not exist.")
+ endif()
+ if(MSVC)
+ message(WARNING "Explicitly setting the linker with the MSVC toolchain is currently not supported and ignored")
+ endif()
+
+ if(TARGET "${target_name}-static" AND NOT TARGET "${target_name}-shared")
+ message(WARNING "The target ${target_name} builds a static library."
+ "The linker is never invoked for a static library so specifying a linker has no effect."
+ )
+ endif()
+
+ set_property(
+ TARGET ${target_name}
+ PROPERTY INTERFACE_CORROSION_LINKER "${linker}"
+ )
+endfunction()
+
+function(corrosion_set_hostbuild target_name)
+ # Configure the target to be compiled for the Host target and ignore any cross-compile configuration.
+ set_property(
+ TARGET ${target_name}
+ PROPERTY ${_CORR_PROP_HOST_BUILD} 1
+ )
+endfunction()
+
+# Add flags for rustc (RUSTFLAGS) which affect the target and all of it's Rust dependencies
+#
+# Additional rustflags may be passed as optional parameters after rustflag.
+# Please note, that if you import multiple targets from a package or workspace, but set different
+# Rustflags via this function, the Rust dependencies will have to be rebuilt when changing targets.
+# Consider `corrosion_add_target_local_rustflags()` as an alternative to avoid this.
+function(corrosion_add_target_rustflags target_name rustflag)
+ # Additional rustflags may be passed as optional parameters after rustflag.
+ set_property(
+ TARGET ${target_name}
+ APPEND
+ PROPERTY INTERFACE_CORROSION_RUSTFLAGS ${rustflag} ${ARGN}
+ )
+endfunction()
+
+# Add flags for rustc (RUSTFLAGS) which only affect the target, but none of it's (Rust) dependencies
+#
+# Additional rustflags may be passed as optional parameters after rustc_flag.
+function(corrosion_add_target_local_rustflags target_name rustc_flag)
+ # Set Rustflags via `cargo rustc` which only affect the current crate, but not dependencies.
+ set_property(
+ TARGET ${target_name}
+ APPEND
+ PROPERTY INTERFACE_CORROSION_LOCAL_RUSTFLAGS ${rustc_flag} ${ARGN}
+ )
+endfunction()
+
+function(corrosion_set_env_vars target_name env_var)
+ # Additional environment variables may be passed as optional parameters after env_var.
+ set_property(
+ TARGET ${target_name}
+ APPEND
+ PROPERTY ${_CORR_PROP_ENV_VARS} ${env_var} ${ARGN}
+ )
+endfunction()
+
+function(corrosion_set_cargo_flags target_name)
+ # corrosion_set_cargo_flags(<target_name> [<flag1> ... ])
+
+ set_property(
+ TARGET ${target_name}
+ APPEND
+ PROPERTY INTERFACE_CORROSION_CARGO_FLAGS ${ARGN}
+ )
+endfunction()
+
+function(corrosion_set_features target_name)
+ # corrosion_set_features(<target_name> [ALL_FEATURES=Bool] [NO_DEFAULT_FEATURES] [FEATURES <feature1> ... ])
+ set(options NO_DEFAULT_FEATURES)
+ set(one_value_args ALL_FEATURES)
+ set(multi_value_args FEATURES)
+ cmake_parse_arguments(
+ PARSE_ARGV 1
+ SET
+ "${options}"
+ "${one_value_args}"
+ "${multi_value_args}"
+ )
+
+ if(DEFINED SET_ALL_FEATURES)
+ set_property(
+ TARGET ${target_name}
+ PROPERTY ${_CORR_PROP_ALL_FEATURES} ${SET_ALL_FEATURES}
+ )
+ endif()
+ if(SET_NO_DEFAULT_FEATURES)
+ set_property(
+ TARGET ${target_name}
+ PROPERTY ${_CORR_PROP_NO_DEFAULT_FEATURES} 1
+ )
+ endif()
+ if(SET_FEATURES)
+ set_property(
+ TARGET ${target_name}
+ APPEND
+ PROPERTY ${_CORR_PROP_FEATURES} ${SET_FEATURES}
+ )
+ endif()
+endfunction()
+
+function(corrosion_link_libraries target_name)
+ if(TARGET "${target_name}-static")
+ message(DEBUG "The target ${target_name} builds a static Rust library."
+ "Calling `target_link_libraries()` instead."
+ )
+ target_link_libraries("${target_name}-static" INTERFACE ${ARGN})
+ if(NOT TARGET "${target_name}-shared")
+ # Early return, since Rust won't invoke the linker for static libraries
+ return()
+ endif()
+ endif()
+ foreach(library ${ARGN})
+ set_property(
+ TARGET _cargo-build_${target_name}
+ APPEND
+ PROPERTY CARGO_DEPS_LINKER_LANGUAGES
+ $<TARGET_PROPERTY:${library},LINKER_LANGUAGE>
+ )
+
+ if (TARGET "${library}")
+ corrosion_add_target_local_rustflags(${target_name}
+ "-L$<TARGET_LINKER_FILE_DIR:${library}>"
+ "-l$<TARGET_LINKER_FILE_BASE_NAME:${library}>"
+ )
+ add_dependencies(_cargo-build_${target_name} ${library})
+ elseif(IS_ABSOLUTE "${library}")
+ # Linking via full path (See https://doc.rust-lang.org/rustc/command-line-arguments.html#linking-modifiers-verbatim)
+ corrosion_add_target_local_rustflags(${target_name} "-Clink-arg=${library}")
+ else()
+ # We have to assume ${library} is a non-CMake library name
+ corrosion_add_target_local_rustflags(${target_name} "-l${library}")
+ endif()
+ endforeach()
+endfunction()
+
+#[=======================================================================[.md:
+ANCHOR: corrosion-install
+** EXPERIMENTAL **: This function is currently still considered experimental
+ and is not officially released yet. Feedback and Suggestions are welcome.
+
+```cmake
+corrosion_install(TARGETS <target1> ... <targetN> [EXPORT <export-name>]
+ [[ARCHIVE|LIBRARY|RUNTIME|PUBLIC_HEADER]
+ [DESTINATION <dir>]
+ [PERMISSIONS <permissions...>]
+ [CONFIGURATIONS [Debug|Release|<other-configuration>]]
+ ] [...])
+```
+* **TARGETS**: Target or targets to install.
+* **EXPORT**: Creates an export that can be installed with `install(EXPORT)`. <export-name> must be globally unique.
+ Also creates a file at ${CMAKE_BINARY_DIR}/corrosion/<export-name>Corrosion.cmake that must be included in the installed config file.
+* **ARCHIVE**/**LIBRARY**/**RUNTIME**/PUBLIC_HEADER: Designates that the following settings only apply to that specific type of object.
+* **DESTINATION**: The subdirectory within the CMAKE_INSTALL_PREFIX that a specific object should be placed. Defaults to values from GNUInstallDirs.
+* **PERMISSIONS**: The permissions of files copied into the install prefix.
+
+Any `PUBLIC` or `INTERFACE` [file sets] will be installed.
+
+[file sets]: https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets
+
+ANCHOR_END: corrosion-install
+#]=======================================================================]
+function(corrosion_install)
+ # Default install dirs
+ include(GNUInstallDirs)
+
+ # Parse arguments to corrosion_install
+ list(GET ARGN 0 INSTALL_TYPE)
+ list(REMOVE_AT ARGN 0)
+
+ # The different install types that are supported. Some targets may have more than one of these
+ # types. For example, on Windows, a shared library will have both an ARCHIVE component and a
+ # RUNTIME component.
+ set(INSTALL_TARGET_TYPES ARCHIVE LIBRARY RUNTIME PRIVATE_HEADER PUBLIC_HEADER)
+
+ # Arguments to each install target type
+ set(OPTIONS)
+ set(ONE_VALUE_ARGS DESTINATION)
+ set(MULTI_VALUE_ARGS PERMISSIONS CONFIGURATIONS)
+ set(TARGET_ARGS ${OPTIONS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
+
+ if (INSTALL_TYPE STREQUAL "TARGETS")
+ # Extract targets
+ set(INSTALL_TARGETS)
+ list(LENGTH ARGN ARGN_LENGTH)
+ set(DELIMITERS EXPORT ${INSTALL_TARGET_TYPES} ${TARGET_ARGS})
+ while(ARGN_LENGTH)
+ # If we hit another keyword, stop - we've found all the targets
+ list(GET ARGN 0 FRONT)
+ if (FRONT IN_LIST DELIMITERS)
+ break()
+ endif()
+
+ list(APPEND INSTALL_TARGETS ${FRONT})
+ list(REMOVE_AT ARGN 0)
+
+ # Update ARGN_LENGTH
+ list(LENGTH ARGN ARGN_LENGTH)
+ endwhile()
+
+ # Check if there are any args left before proceeding
+ list(LENGTH ARGN ARGN_LENGTH)
+ if (ARGN_LENGTH)
+ list(GET ARGN 0 FRONT)
+ if (FRONT STREQUAL "EXPORT")
+ list(REMOVE_AT ARGN 0) # Pop "EXPORT"
+
+ list(GET ARGN 0 EXPORT_NAME)
+ list(REMOVE_AT ARGN 0) # Pop <export-name>
+ set(EXTRA_TARGETS_EXPORT_NAME ${EXPORT_NAME}Corrosion.cmake)
+ set(EXPORT_NAME EXPORT ${EXPORT_NAME})
+ set(EXPORT_FILE_PATH "${CMAKE_BINARY_DIR}/corrosion/${EXTRA_TARGETS_EXPORT_NAME}")
+ # Remove first, since otherwise we will append to the file on every reconfigure.
+ # Assumes that the corrosion_install will only be called once for a given EXPORT_NAME.
+ file(REMOVE "${EXPORT_FILE_PATH}")
+ endif()
+ else()
+ # Prevent variable set in user code from interfering
+ set(EXPORT_NAME)
+ endif()
+
+ # Loop over all arguments and get options for each install target type
+ list(LENGTH ARGN ARGN_LENGTH)
+ while(ARGN_LENGTH)
+ # Check if we're dealing with arguments for a specific install target type, or with
+ # default options for all target types.
+ list(GET ARGN 0 FRONT)
+ if (FRONT IN_LIST INSTALL_TARGET_TYPES)
+ set(INSTALL_TARGET_TYPE ${FRONT})
+ list(REMOVE_AT ARGN 0)
+ else()
+ set(INSTALL_TARGET_TYPE DEFAULT)
+ endif()
+
+ # Gather the arguments to this install type
+ set(ARGS)
+ while(ARGN_LENGTH)
+ # If the next keyword is an install target type, then break - arguments have been
+ # gathered.
+ list(GET ARGN 0 FRONT)
+ if (FRONT IN_LIST INSTALL_TARGET_TYPES)
+ break()
+ endif()
+
+ list(APPEND ARGS ${FRONT})
+ list(REMOVE_AT ARGN 0)
+
+ list(LENGTH ARGN ARGN_LENGTH)
+ endwhile()
+
+ # Parse the arguments and register the file install
+ cmake_parse_arguments(
+ COR "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGS})
+
+ if (COR_DESTINATION)
+ set(COR_INSTALL_${INSTALL_TARGET_TYPE}_DESTINATION ${COR_DESTINATION})
+ endif()
+
+ if (COR_PERMISSIONS)
+ set(COR_INSTALL_${INSTALL_TARGET_TYPE}_PERMISSIONS ${COR_PERMISSIONS})
+ endif()
+
+ if (COR_CONFIGURATIONS)
+ set(COR_INSTALL_${INSTALL_TARGET_TYPE}_CONFIGURATIONS ${COR_CONFIGURATIONS})
+ endif()
+
+ # Update ARG_LENGTH
+ list(LENGTH ARGN ARGN_LENGTH)
+ endwhile()
+
+ # Default permissions for all files
+ set(DEFAULT_PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
+
+ # Loop through each install target and register file installations
+ foreach(INSTALL_TARGET ${INSTALL_TARGETS})
+ if(NOT TARGET ${INSTALL_TARGET})
+ message(FATAL_ERROR "Install target ${INSTALL_TARGET} is not a valid target")
+ endif()
+ # Don't both implementing target type differentiation using generator expressions since
+ # TYPE cannot change after target creation
+ get_property(
+ TARGET_TYPE
+ TARGET ${INSTALL_TARGET} PROPERTY TYPE
+ )
+
+ # Install executable files first
+ if (TARGET_TYPE STREQUAL "EXECUTABLE")
+ if (DEFINED COR_INSTALL_RUNTIME_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_RUNTIME_DESTINATION})
+ elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
+ else()
+ set(DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif()
+
+ if (DEFINED COR_INSTALL_RUNTIME_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_RUNTIME_PERMISSIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
+ else()
+ set(
+ PERMISSIONS
+ ${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
+ endif()
+
+ if (DEFINED COR_INSTALL_RUNTIME_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_RUNTIME_CONFIGURATIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
+ else()
+ set(CONFIGURATIONS)
+ endif()
+
+ install(
+ FILES $<TARGET_FILE:${INSTALL_TARGET}>
+ DESTINATION ${DESTINATION}
+ PERMISSIONS ${PERMISSIONS}
+ ${CONFIGURATIONS}
+ )
+ elseif(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
+ if(TARGET ${INSTALL_TARGET}-static)
+ if (DEFINED COR_INSTALL_ARCHIVE_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_ARCHIVE_DESTINATION})
+ elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
+ else()
+ set(DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ endif()
+
+ if (DEFINED COR_INSTALL_ARCHIVE_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_ARCHIVE_PERMISSIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
+ else()
+ set(PERMISSIONS ${DEFAULT_PERMISSIONS})
+ endif()
+
+ if (DEFINED COR_INSTALL_ARCHIVE_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_ARCHIVE_CONFIGURATIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
+ else()
+ set(CONFIGURATIONS)
+ endif()
+
+ install(
+ FILES $<TARGET_PROPERTY:${INSTALL_TARGET}-static,IMPORTED_LOCATION>
+ DESTINATION ${DESTINATION}
+ PERMISSIONS ${PERMISSIONS}
+ ${CONFIGURATIONS}
+ )
+
+ if(EXPORT_NAME)
+ get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-static COR_FILE_NAME)
+ file(APPEND "${EXPORT_FILE_PATH}"
+"
+add_library(${INSTALL_TARGET}-static STATIC IMPORTED)
+set_target_properties(${INSTALL_TARGET}-static
+ PROPERTIES
+ IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\"
+)
+"
+ )
+ endif()
+ endif()
+
+ if(TARGET ${INSTALL_TARGET}-shared)
+ if (DEFINED COR_INSTALL_LIBRARY_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_LIBRARY_DESTINATION})
+ elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
+ else()
+ set(DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ endif()
+
+ if (DEFINED COR_INSTALL_LIBRARY_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_LIBRARY_PERMISSIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
+ else()
+ set(
+ PERMISSIONS
+ ${DEFAULT_PERMISSIONS} OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
+ )
+ endif()
+
+ if (DEFINED COR_INSTALL_LIBRARY_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_LIBRARY_CONFIGURATIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
+ else()
+ set(CONFIGURATIONS)
+ endif()
+
+ install(
+ IMPORTED_RUNTIME_ARTIFACTS ${INSTALL_TARGET}-shared
+ PERMISSIONS ${PERMISSIONS}
+ DESTINATION ${DESTINATION}
+ ${CONFIGURATIONS}
+ )
+
+ if(EXPORT_NAME)
+ get_target_property(COR_FILE_NAME ${INSTALL_TARGET}-shared COR_FILE_NAME)
+ file(APPEND "${EXPORT_FILE_PATH}"
+"
+add_library(${INSTALL_TARGET}-shared SHARED IMPORTED)
+set_target_properties(${INSTALL_TARGET}-shared
+ PROPERTIES
+ IMPORTED_LOCATION \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_FILE_NAME}\"
+)
+"
+ )
+
+ get_target_property(COR_IMPLIB_FILE_NAME ${INSTALL_TARGET}-shared COR_IMPLIB_FILE_NAME)
+ if (NOT COR_IMPLIB_FILE_NAME MATCHES .*-NOTFOUND)
+ file(APPEND "${EXPORT_FILE_PATH}"
+"
+set_target_properties(${INSTALL_TARGET}-shared
+ PROPERTIES
+ IMPORTED_IMPLIB \"\${PACKAGE_PREFIX_DIR}/${DESTINATION}/${COR_IMPLIB_FILE_NAME}\"
+)"
+ )
+ endif()
+ endif()
+ endif()
+ else()
+ message(FATAL_ERROR "Unknown target type ${TARGET_TYPE} for install target ${INSTALL_TARGET}")
+ endif()
+
+ # Executables can also have export tables, so they _might_ also need header files
+ if (DEFINED COR_INSTALL_PUBLIC_HEADER_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_PUBLIC_HEADER_DESTINATION})
+ elseif (DEFINED COR_INSTALL_DEFAULT_DESTINATION)
+ set(DESTINATION ${COR_INSTALL_DEFAULT_DESTINATION})
+ else()
+ set(DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+ endif()
+
+ if (DEFINED COR_INSTALL_PUBLIC_HEADER_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_PUBLIC_HEADER_PERMISSIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_PERMISSIONS)
+ set(PERMISSIONS ${COR_INSTALL_DEFAULT_PERMISSIONS})
+ else()
+ # Directories need OWNER_EXECUTE in order to be deletable by owner
+ set(PERMISSIONS ${DEFAULT_PERMISSIONS} OWNER_EXECUTE)
+ endif()
+
+ if (DEFINED COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_PUBLIC_HEADER_CONFIGURATIONS})
+ elseif (DEFINED COR_INSTALL_DEFAULT_CONFIGURATIONS)
+ set(CONFIGURATIONS CONFIGURATIONS ${COR_INSTALL_DEFAULT_CONFIGURATIONS})
+ else()
+ set(CONFIGURATIONS)
+ endif()
+
+ get_target_property(FILE_SET ${INSTALL_TARGET} INTERFACE_HEADER_SETS)
+ if(NOT FILE_SET OR FILE_SET MATCHES .*-NOTFOUND)
+ set(TARGET_HAS_FILE_SET FALSE)
+ else()
+ set(TARGET_HAS_FILE_SET TRUE)
+ endif()
+
+ if(NOT TARGET_HAS_FILE_SET)
+ if(EXPORT_NAME)
+ # We still need to generate a EXPORT but we can't do that with install(DIRECTORY)
+ install(TARGETS ${INSTALL_TARGET} ${EXPORT_NAME})
+ endif()
+
+ set(PUBLIC_HEADER_PROPERTIES INCLUDE_DIRECTORIES PUBLIC_INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES)
+ foreach(PUBLIC_HEADER_PROPERTY ${PUBLIC_HEADER_PROPERTIES})
+ get_target_property(PUBLIC_HEADER ${INSTALL_TARGET} ${PUBLIC_HEADER_PROPERTY})
+
+ if(NOT PUBLIC_HEADER MATCHES .*-NOTFOUND)
+ foreach(INCLUDE_DIRECTORY ${PUBLIC_HEADER})
+ install(
+ DIRECTORY ${INCLUDE_DIRECTORY}
+ DESTINATION .
+ FILE_PERMISSIONS ${PERMISSIONS}
+ DIRECTORY_PERMISSIONS ${PERMISSIONS}
+ ${CONFIGURATIONS}
+ )
+ endforeach()
+ endif()
+ endforeach()
+ else()
+ install(
+ TARGETS ${INSTALL_TARGET}
+ ${EXPORT_NAME}
+ FILE_SET HEADERS
+ DESTINATION ${DESTINATION}
+ PERMISSIONS ${PERMISSIONS}
+ ${CONFIGURATIONS}
+ )
+ endif()
+ endforeach()
+
+ elseif(INSTALL_TYPE STREQUAL "EXPORT")
+ message(FATAL_ERROR "install(EXPORT ...) not yet implemented")
+ else()
+ message(FATAL_ERROR "Unknown arg: ${INSTALL_TYPE}")
+ endif()
+endfunction()
+
+#[=======================================================================[.md:
+** EXPERIMENTAL **: This function is currently still considered experimental
+ and is not officially released yet. Feedback and Suggestions are welcome.
+
+ANCHOR: corrosion_add_cxxbridge
+
+```cmake
+corrosion_add_cxxbridge(cxx_target
+ CRATE <imported_target_name>
+ REGEN_TARGET <regen_target_name>
+ [FILES <file1.rs> <file2.rs>]
+)
+```
+
+Adds build-rules to create C++ bindings using the [cxx] crate.
+
+### Arguments:
+* `cxxtarget`: Name of the C++ library target for the bindings, which corrosion will create.
+* **FILES**: Input Rust source file containing #[cxx::bridge].
+* **CRATE**: Name of an imported Rust target. Note: Parameter may be renamed before release
+* **REGEN_TARGET**: Name of a custom target that will regenerate the cxx bindings **without** recompiling. Note: Parameter may be renamed before release
+
+#### Currently missing arguments
+
+The following arguments to cxxbridge **currently** have no way to be passed by the user:
+- `--cfg`
+- `--cxx-impl-annotations`
+- `--include`
+
+The created rules approximately do the following:
+- Check which version of `cxx` the Rust crate specified by the `CRATE` argument depends on.
+- Check if the exact same version of `cxxbridge-cmd` is installed (available in `PATH`)
+- If not, create a rule to build the exact same version of `cxxbridge-cmd`.
+- Create rules to run `cxxbridge` and generate
+ - The `rust/cxx.h` header
+ - A header and source file for each of the files specified in `FILES`
+- The generated sources (and header include directories) are added to the `cxxtarget` CMake
+ library target.
+
+### Limitations
+
+We currently require the `CRATE` argument to be a target imported by Corrosion, however,
+Corrosion does not import `rlib` only libraries. As a workaround users can add
+`staticlib` to their list of crate kinds. In the future this may be solved more properly,
+by either adding an option to also import Rlib targets (without build rules) or by
+adding a `MANIFEST_PATH` argument to this function, specifying where the crate is.
+
+### Contributing
+
+Specifically some more realistic test / demo projects and feedback about limitations would be
+welcome.
+
+[cxx]: https://github.com/dtolnay/cxx
+
+ANCHOR_END: corrosion_add_cxxbridge
+#]=======================================================================]
+function(corrosion_add_cxxbridge cxx_target)
+ set(OPTIONS)
+ set(ONE_VALUE_KEYWORDS CRATE REGEN_TARGET)
+ set(MULTI_VALUE_KEYWORDS FILES)
+ cmake_parse_arguments(PARSE_ARGV 1 _arg "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
+
+ set(required_keywords CRATE FILES)
+ foreach(keyword ${required_keywords})
+ if(NOT DEFINED "_arg_${keyword}")
+ message(FATAL_ERROR "Missing required parameter `${keyword}`.")
+ elseif("${_arg_${keyword}}" STREQUAL "")
+ message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.")
+ endif()
+ endforeach()
+
+ get_target_property(manifest_path "${_arg_CRATE}" INTERFACE_COR_PACKAGE_MANIFEST_PATH)
+
+ if(NOT EXISTS "${manifest_path}")
+ message(FATAL_ERROR "Internal error: No package manifest found at ${manifest_path}")
+ endif()
+
+ get_filename_component(manifest_dir ${manifest_path} DIRECTORY)
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env
+ "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
+ ${_CORROSION_CARGO} tree -i cxx --depth=0
+ WORKING_DIRECTORY "${manifest_dir}"
+ RESULT_VARIABLE cxx_version_result
+ OUTPUT_VARIABLE cxx_version_output
+ )
+ if(NOT "${cxx_version_result}" EQUAL "0")
+ message(FATAL_ERROR "Crate ${_arg_CRATE} does not depend on cxx.")
+ endif()
+ if(cxx_version_output MATCHES "cxx v([0-9]+.[0-9]+.[0-9]+)")
+ set(cxx_required_version "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Failed to parse cxx version from cargo tree output: `cxx_version_output`")
+ endif()
+
+ # First check if a suitable version of cxxbridge is installed
+ find_program(INSTALLED_CXXBRIDGE cxxbridge PATHS "$ENV{HOME}/.cargo/bin/")
+ mark_as_advanced(INSTALLED_CXXBRIDGE)
+ if(INSTALLED_CXXBRIDGE)
+ execute_process(COMMAND ${INSTALLED_CXXBRIDGE} --version OUTPUT_VARIABLE cxxbridge_version_output)
+ if(cxxbridge_version_output MATCHES "cxxbridge ([0-9]+.[0-9]+.[0-9]+)")
+ set(cxxbridge_version "${CMAKE_MATCH_1}")
+ else()
+ set(cxxbridge_version "")
+ endif()
+ endif()
+
+ set(cxxbridge "")
+ if(cxxbridge_version)
+ if(cxxbridge_version VERSION_EQUAL cxx_required_version)
+ set(cxxbridge "${INSTALLED_CXXBRIDGE}")
+ if(NOT TARGET "cxxbridge_v${cxx_required_version}")
+ # Add an empty target.
+ add_custom_target("cxxbridge_v${cxx_required_version}"
+ )
+ endif()
+ endif()
+ endif()
+
+ # No suitable version of cxxbridge was installed, so use custom target to build correct version.
+ if(NOT cxxbridge)
+ if(NOT TARGET "cxxbridge_v${cxx_required_version}")
+ unset(executable_postfix)
+ if(Rust_CARGO_HOST_OS STREQUAL "windows")
+ set(executable_postfix ".exe")
+ endif()
+ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}"
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
+ COMMAND
+ ${CMAKE_COMMAND} -E env
+ "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
+ ${_CORROSION_CARGO} install
+ cxxbridge-cmd
+ --version "${cxx_required_version}"
+ --root "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}"
+ --quiet
+ # todo: use --target-dir to potentially reuse artifacts
+ COMMENT "Building cxxbridge (version ${cxx_required_version})"
+ )
+ add_custom_target("cxxbridge_v${cxx_required_version}"
+ DEPENDS "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}"
+ )
+ endif()
+ set(cxxbridge "${CMAKE_BINARY_DIR}/corrosion/cxxbridge_v${cxx_required_version}/bin/cxxbridge${executable_postfix}")
+ endif()
+
+
+ # The generated folder structure will be of the following form
+ #
+ # CMAKE_CURRENT_BINARY_DIR
+ # corrosion_generated
+ # cxxbridge
+ # <cxx_target>
+ # include
+ # <cxx_target>
+ # <headers>
+ # rust
+ # cxx.h
+ # src
+ # <sourcefiles>
+ # cbindgen
+ # ...
+ # other
+ # ...
+
+ set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated")
+ set(generated_dir "${corrosion_generated_dir}/cxxbridge/${cxx_target}")
+ set(header_placement_dir "${generated_dir}/include/${cxx_target}")
+ set(source_placement_dir "${generated_dir}/src")
+
+ add_library(${cxx_target} STATIC)
+ target_include_directories(${cxx_target}
+ PUBLIC
+ $<BUILD_INTERFACE:${generated_dir}/include>
+ $<INSTALL_INTERFACE:include>
+ )
+
+ # cxx generated code is using c++11 features in headers, so propagate c++11 as minimal requirement
+ target_compile_features(${cxx_target} PUBLIC cxx_std_11)
+
+ # Todo: target_link_libraries is only necessary for rust2c projects.
+ # It is possible that checking if the rust crate is an executable is a sufficient check,
+ # but some more thought may be needed here.
+ # Maybe we should also let the user do this, since for c2rust, the user also has to call
+ # corrosion_link_libraries() themselves.
+ get_target_property(crate_target_type ${_arg_CRATE} TYPE)
+ if (NOT crate_target_type STREQUAL "EXECUTABLE")
+ target_link_libraries(${cxx_target} PRIVATE ${_arg_CRATE})
+ endif()
+
+ file(MAKE_DIRECTORY "${generated_dir}/include/rust")
+ add_custom_command(
+ OUTPUT "${generated_dir}/include/rust/cxx.h"
+ COMMAND
+ ${cxxbridge} --header --output "${generated_dir}/include/rust/cxx.h"
+ DEPENDS "cxxbridge_v${cxx_required_version}"
+ COMMENT "Generating rust/cxx.h header"
+ )
+
+ set(GENERATED_FILES "${generated_dir}/include/rust/cxx.h")
+
+ foreach(filepath ${_arg_FILES})
+ get_filename_component(filename ${filepath} NAME_WE)
+ get_filename_component(directory ${filepath} DIRECTORY)
+ set(directory_component "")
+ if(directory)
+ set(directory_component "${directory}/")
+ endif()
+ # todo: convert potentially absolute paths to relative paths..
+ set(cxx_header ${directory_component}${filename}.h)
+ set(cxx_source ${directory_component}${filename}.cpp)
+
+ # todo: not all projects may use the `src` directory.
+ set(rust_source_path "${manifest_dir}/src/${filepath}")
+
+ file(MAKE_DIRECTORY "${header_placement_dir}/${directory}" "${source_placement_dir}/${directory}")
+
+ add_custom_command(
+ OUTPUT
+ "${header_placement_dir}/${cxx_header}"
+ "${source_placement_dir}/${cxx_source}"
+ COMMAND
+ ${cxxbridge} ${rust_source_path} --header --output "${header_placement_dir}/${cxx_header}"
+ COMMAND
+ ${cxxbridge} ${rust_source_path}
+ --output "${source_placement_dir}/${cxx_source}"
+ --include "${cxx_target}/${cxx_header}"
+ DEPENDS "cxxbridge_v${cxx_required_version}" "${rust_source_path}"
+ COMMENT "Generating cxx bindings for crate ${_arg_CRATE} and file src/${filepath}"
+ )
+
+ list(APPEND GENERATED_FILES
+ "${header_placement_dir}/${cxx_header}"
+ "${source_placement_dir}/${cxx_source}")
+ endforeach()
+ target_sources(${cxx_target} PRIVATE ${GENERATED_FILES})
+
+ if(DEFINED _arg_REGEN_TARGET)
+ add_custom_target(${_arg_REGEN_TARGET}
+ DEPENDS ${GENERATED_FILES}
+ COMMENT "Generated cxx bindings for crate ${_arg_CRATE}")
+ endif()
+
+endfunction()
+
+#[=======================================================================[.md:
+ANCHOR: corrosion_cbindgen
+```cmake
+corrosion_cbindgen(
+ TARGET <imported_target_name>
+ HEADER_NAME <output_header_name>
+ [CARGO_PACKAGE <cargo_package_name>]
+ [MANIFEST_DIRECTORY <package_manifest_directory>]
+ [CBINDGEN_VERSION <version>]
+ [FLAGS <flag1> ... <flagN>]
+)
+```
+
+A helper function which uses [cbindgen] to generate C/C++ bindings for a Rust crate.
+If `cbindgen` is not in `PATH` the helper function will automatically try to download
+`cbindgen` and place the built binary into `CMAKE_BINARY_DIR`. The binary is shared
+between multiple invocations of this function.
+
+
+* **TARGET**: The name of an imported Rust library target, for which bindings should be generated.
+ If the target was not previously imported by Corrosion, because the crate only produces an
+ `rlib`, you must additionally specify `MANIFEST_DIRECTORY`.
+
+* **MANIFEST_DIRECTORY**: Directory of the package defining the library crate bindings should be generated for.
+ If you want to avoid specifying `MANIFEST_DIRECTORY` you could add a `staticlib` target to your package
+ manifest as a workaround to make corrosion import the crate.
+
+* **HEADER_NAME**: The name of the generated header file. This will be the name which you include in your C/C++ code
+ (e.g. `#include "myproject/myheader.h" if you specify `HEADER_NAME "myproject/myheader.h"`.
+* **CBINDGEN_VERSION**: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented.
+* **FLAGS**: Arbitrary other flags for `cbindgen`. Run `cbindgen --help` to see the possible flags.
+
+[cbindgen]: https://github.com/eqrion/cbindgen
+
+### Current limitations
+
+- Cbindgens (optional) macro expansion feature internally actually builds the crate / runs the build script.
+ For this to work as expected in all cases, we probably need to set all the same environment variables
+ as when corrosion builds the crate. However the crate is a **library**, so we would need to figure out which
+ target builds it - and if there are multiple, potentially generate bindings per-target?
+ Alternatively we could add support of setting some environment variables on rlibs, and pulling that
+ information in when building the actual corrosion targets
+ Alternatively we could restrict corrosions support of this feature to actual imported staticlib/cdylib targets.
+ANCHOR_END: corrosion_cbindgen
+#]=======================================================================]
+function(corrosion_experimental_cbindgen)
+ set(OPTIONS "")
+ set(ONE_VALUE_KEYWORDS
+ TARGET
+ MANIFEST_DIRECTORY
+ HEADER_NAME
+ CBINDGEN_VERSION)
+ set(MULTI_VALUE_KEYWORDS "FLAGS")
+ cmake_parse_arguments(PARSE_ARGV 0 CCN "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
+
+ set(required_keywords TARGET HEADER_NAME)
+ foreach(keyword ${required_keywords})
+ if(NOT DEFINED "CCN_${keyword}")
+ message(FATAL_ERROR "Missing required parameter `${keyword}`.")
+ elseif("${CCN_${keyword}}" STREQUAL "")
+ message(FATAL_ERROR "Required parameter `${keyword}` may not be set to an empty string.")
+ endif()
+ endforeach()
+ set(rust_target "${CCN_TARGET}")
+ unset(package_manifest_dir)
+
+
+ set(hostbuild_override "$<BOOL:$<TARGET_PROPERTY:${rust_target},${_CORR_PROP_HOST_BUILD}>>")
+ set(cbindgen_target_triple "$<IF:${hostbuild_override},${_CORROSION_RUST_CARGO_HOST_TARGET},${_CORROSION_RUST_CARGO_TARGET}>")
+
+ if(TARGET "${rust_target}")
+ get_target_property(package_manifest_path "${rust_target}" INTERFACE_COR_PACKAGE_MANIFEST_PATH)
+ if(NOT EXISTS "${package_manifest_path}")
+ message(FATAL_ERROR "Internal error: No package manifest found at ${package_manifest_path}")
+ endif()
+ get_filename_component(package_manifest_dir "${package_manifest_path}" DIRECTORY)
+ # todo: as an optimization we could cache the cargo metadata output (but --no-deps makes that slightly more complicated)
+ else()
+ if(NOT DEFINED CCN_MANIFEST_DIRECTORY)
+ message(FATAL_ERROR
+ "`${rust_target}` is not a target imported by corrosion and `MANIFEST_DIRECTORY` was not provided."
+ )
+ else()
+ set(package_manifest_dir "${CCN_MANIFEST_DIRECTORY}")
+ endif()
+ endif()
+
+ get_target_property(rust_cargo_package "${rust_target}" COR_CARGO_PACKAGE_NAME )
+ if(NOT rust_cargo_package)
+ message(FATAL_ERROR "Internal Error: Could not determine cargo package name for cbindgen. "
+ )
+ endif()
+ message(STATUS "Using package ${rust_cargo_package} as crate for cbindgen")
+
+
+ set(output_header_name "${CCN_HEADER_NAME}")
+
+ find_program(installed_cbindgen cbindgen)
+
+ # Install the newest cbindgen version into our build tree.
+ if(installed_cbindgen)
+ set(cbindgen "${installed_cbindgen}")
+ else()
+ set(local_cbindgen_install_dir "${CMAKE_BINARY_DIR}/corrosion/cbindgen")
+ unset(executable_postfix)
+ if(Rust_CARGO_HOST_OS STREQUAL "windows")
+ set(executable_postfix ".exe")
+ endif()
+ set(cbindgen "${local_cbindgen_install_dir}/bin/cbindgen${executable_postfix}")
+ if(NOT TARGET "_corrosion_cbindgen")
+ file(MAKE_DIRECTORY "${local_cbindgen_install_dir}")
+ add_custom_command(OUTPUT "${cbindgen}"
+ COMMAND ${CMAKE_COMMAND}
+ -E env
+ "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
+ ${_CORROSION_CARGO} install
+ cbindgen
+ --root "${local_cbindgen_install_dir}"
+ ${_CORROSION_QUIET_OUTPUT_FLAG}
+ COMMENT "Building cbindgen"
+ )
+ add_custom_target("_corrosion_cbindgen"
+ DEPENDS "${cbindgen}"
+ )
+ endif()
+ endif()
+
+ set(corrosion_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/corrosion_generated")
+ set(generated_dir "${corrosion_generated_dir}/cbindgen/${rust_target}")
+ set(header_placement_dir "${generated_dir}/include/")
+ set(depfile_placement_dir "${generated_dir}/depfile")
+ set(generated_depfile "${depfile_placement_dir}/${output_header_name}.d")
+ set(generated_header "${header_placement_dir}/${output_header_name}")
+ message(STATUS "rust target is ${rust_target}")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.23")
+ target_sources(${rust_target}
+ INTERFACE
+ FILE_SET HEADERS
+ BASE_DIRS "${header_placement_dir}"
+ FILES "${header_placement_dir}/${output_header_name}"
+ )
+ else()
+ # Note: not clear to me how install would best work before CMake 3.23
+ target_include_directories(${rust_target}
+ INTERFACE
+ $<BUILD_INTERFACE:${header_placement_dir}>
+ $<INSTALL_INTERFACE:include>
+ )
+ endif()
+
+ # This may be different from $header_placement_dir since the user specified HEADER_NAME may contain
+ # relative directories.
+ get_filename_component(generated_header_dir "${generated_header}" DIRECTORY)
+ file(MAKE_DIRECTORY "${generated_header_dir}")
+
+ unset(depfile_cbindgen_arg)
+ unset(depfile_cmake_arg)
+ get_filename_component(generated_depfile_dir "${generated_depfile}" DIRECTORY)
+ file(MAKE_DIRECTORY "${generated_depfile_dir}")
+ set(depfile_cbindgen_arg "--depfile=${generated_depfile}")
+
+ add_custom_command(
+ OUTPUT
+ "${generated_header}"
+ COMMAND
+ "${CMAKE_COMMAND}" -E env
+ TARGET="${cbindgen_target_triple}"
+ "${cbindgen}"
+ --output "${generated_header}"
+ --crate "${rust_cargo_package}"
+ ${depfile_cbindgen_arg}
+ ${CCN_FLAGS}
+ COMMENT "Generate cbindgen bindings for package ${rust_cargo_package} and output header ${generated_header}"
+ DEPFILE "${generated_depfile}"
+ COMMAND_EXPAND_LISTS
+ WORKING_DIRECTORY "${package_manifest_dir}"
+ )
+
+ if(NOT installed_cbindgen)
+ add_custom_command(
+ OUTPUT "${generated_header}"
+ APPEND
+ DEPENDS _corrosion_cbindgen
+ )
+ endif()
+
+ if(NOT TARGET "_corrosion_cbindgen_${rust_target}_bindings")
+ add_custom_target(_corrosion_cbindgen_${rust_target}_bindings
+ COMMENT "Generate cbindgen bindings for package ${rust_cargo_package}"
+ )
+ endif()
+ # Users might want to call cbindgen multiple times, e.g. to generate separate C++ and C header files.
+ string(MAKE_C_IDENTIFIER "${output_header_name}" header_identifier )
+ add_custom_target("_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}"
+ DEPENDS "${generated_header}"
+ COMMENT "Generate ${generated_header} for ${rust_target}"
+ )
+ add_dependencies("_corrosion_cbindgen_${rust_target}_bindings" "_corrosion_cbindgen_${rust_target}_bindings_${header_identifier}")
+ add_dependencies(${rust_target} "_corrosion_cbindgen_${rust_target}_bindings")
+endfunction()
+
+# Parse the version of a Rust package from it's package manifest (Cargo.toml)
+function(corrosion_parse_package_version package_manifest_path out_package_version)
+ if(NOT EXISTS "${package_manifest_path}")
+ message(FATAL_ERROR "Package manifest `${package_manifest_path}` does not exist.")
+ endif()
+
+ file(READ "${package_manifest_path}" package_manifest)
+
+ # Find the package table. It may contain arrays, so match until \n\[, which should mark the next
+ # table. Note: backslashes must be doubled to escape the backslash for the bracket. LF is single
+ # backslash however. On windows the line also ends in \n, so matching against \n\[ is sufficient
+ # to detect an opening bracket on a new line.
+ set(package_table_regex "\\[package\\](.*)\n\\[")
+
+ string(REGEX MATCH "${package_table_regex}" _package_table "${package_manifest}")
+
+ if(CMAKE_MATCH_COUNT EQUAL "1")
+ set(package_table "${CMAKE_MATCH_1}")
+ else()
+ message(DEBUG
+ "Failed to find `[package]` table in package manifest `${package_manifest_path}`.\n"
+ "Matches: ${CMAKE_MATCH_COUNT}\n"
+ )
+ set(${out_package_version}
+ "NOTFOUND"
+ PARENT_SCOPE
+ )
+ endif()
+ # Match `version = "0.3.2"`, `"version" = "0.3.2" Contains one matching group for the version
+ set(version_regex "[\r]?\n[\"']?version[\"']?[ \t]*=[ \t]*[\"']([0-9\.]+)[\"']")
+
+ string(REGEX MATCH "${version_regex}" _version "${package_table}")
+
+ if("${package_table}" MATCHES "${version_regex}")
+ set(${out_package_version}
+ "${CMAKE_MATCH_1}"
+ PARENT_SCOPE
+ )
+ else()
+ message(DEBUG "Failed to extract package version from manifest `${package_manifest_path}`.")
+ set(${out_package_version}
+ "NOTFOUND"
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+function(_corrosion_initialize_properties target_name)
+ # Initialize the `<XYZ>_OUTPUT_DIRECTORY` properties based on `CMAKE_<XYZ>_OUTPUT_DIRECTORY`.
+ foreach(output_var RUNTIME_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY)
+ if (DEFINED "CMAKE_${output_var}")
+ set_property(TARGET ${target_name} PROPERTY "${output_var}" "${CMAKE_${output_var}}")
+ endif()
+
+ foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER "${config_type}" config_type_upper)
+ if (DEFINED "CMAKE_${output_var}_${config_type_upper}")
+ set_property(TARGET ${target_name} PROPERTY "${output_var}_${config_type_upper}" "${CMAKE_${output_var}_${config_type_upper}}")
+ endif()
+ endforeach()
+ endforeach()
+endfunction()
+
+# Helper macro to pass through an optional `OPTION` argument parsed via `cmake_parse_arguments`
+# to another function that takes the same OPTION.
+# If the option was set, then the variable <var_name> will be set to the same option name again,
+# otherwise <var_name> will be unset.
+macro(_corrosion_option_passthrough_helper option_name prefix var_name)
+ if(${${prefix}_${option_name}})
+ set("${var_name}" "${option_name}")
+ else()
+ unset("${var_name}")
+ endif()
+endmacro()
+
+# Helper macro to pass through an optional argument with value(s), parsed via `cmake_parse_arguments`,
+# to another function that takes the same keyword + associated values.
+# If the argument was given, then the variable <var_name> will be a list of the argument name and the values,
+# which will be expanded, when calling the function (assuming no quotes).
+macro(_corrosion_arg_passthrough_helper arg_name prefix var_name)
+ if(DEFINED "${prefix}_${arg_name}")
+ set("${var_name}" "${arg_name}" "${${prefix}_${arg_name}}")
+ else()
+ unset("${var_name}")
+ endif()
+endmacro()
+
+list(POP_BACK CMAKE_MESSAGE_CONTEXT)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/cmake/CorrosionConfig.cmake.in Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+@PACKAGE_INIT@
+
+if (Corrosion_FOUND)
+ return()
+endif()
+
+list(APPEND CMAKE_MODULE_PATH "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_DATADIR@/cmake")
+
+include(Corrosion)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/cmake/CorrosionGenerator.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,338 @@
+function(_cargo_metadata out manifest)
+ set(OPTIONS LOCKED FROZEN)
+ set(ONE_VALUE_KEYWORDS "")
+ set(MULTI_VALUE_KEYWORDS "")
+ cmake_parse_arguments(PARSE_ARGV 2 CM "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
+
+ list(APPEND CMAKE_MESSAGE_CONTEXT "_cargo_metadata")
+
+ if(DEFINED CM_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Internal error - unexpected arguments: ${CM_UNPARSED_ARGUMENTS}")
+ elseif(DEFINED CM_KEYWORDS_MISSING_VALUES)
+ message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
+ "${CM_KEYWORDS_MISSING_VALUES}")
+ endif()
+
+ set(cargo_locked "")
+ set(cargo_frozen "")
+ if(LOCKED)
+ set(cargo_locked "--locked")
+ endif()
+ if(FROZEN)
+ set(cargo_frozen "--frozen")
+ endif()
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E env
+ "CARGO_BUILD_RUSTC=${_CORROSION_RUSTC}"
+ "${_CORROSION_CARGO}"
+ metadata
+ --manifest-path "${manifest}"
+ --format-version 1
+ # We don't care about non-workspace dependencies
+ --no-deps
+ ${cargo_locked}
+ ${cargo_frozen}
+
+ OUTPUT_VARIABLE json
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+
+ set(${out} "${json}" PARENT_SCOPE)
+endfunction()
+
+# Add targets (crates) of one package
+function(_generator_add_package_targets)
+ set(OPTIONS NO_LINKER_OVERRIDE)
+ set(ONE_VALUE_KEYWORDS
+ WORKSPACE_MANIFEST_PATH
+ PACKAGE_MANIFEST_PATH
+ PACKAGE_NAME
+ PACKAGE_VERSION
+ TARGETS_JSON
+ OUT_CREATED_TARGETS)
+ set(MULTI_VALUE_KEYWORDS CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS)
+ cmake_parse_arguments(PARSE_ARGV 0 GAPT "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")
+
+ if(DEFINED GAPT_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Internal error - unexpected arguments: ${GAPT_UNPARSED_ARGUMENTS}")
+ elseif(DEFINED GAPT_KEYWORDS_MISSING_VALUES)
+ message(FATAL_ERROR "Internal error - the following keywords had no associated value(s):"
+ "${GAPT_KEYWORDS_MISSING_VALUES}")
+ endif()
+
+ _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GAPT no_linker_override)
+
+ set(workspace_manifest_path "${GAPT_WORKSPACE_MANIFEST_PATH}")
+ set(package_manifest_path "${GAPT_PACKAGE_MANIFEST_PATH}")
+ set(package_name "${GAPT_PACKAGE_NAME}")
+ set(package_version "${GAPT_PACKAGE_VERSION}")
+ set(targets "${GAPT_TARGETS_JSON}")
+ set(out_created_targets "${GAPT_OUT_CREATED_TARGETS}")
+ set(crate_types "${GAPT_CRATE_TYPES}")
+ if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS)
+ list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 0 override_crate_name_list_ref)
+ list(GET GAPT_OVERRIDE_CRATE_TYPE_ARGS 1 override_crate_types_list_ref)
+ endif()
+
+ set(corrosion_targets "")
+
+ file(TO_CMAKE_PATH "${package_manifest_path}" manifest_path)
+
+ string(JSON targets_len LENGTH "${targets}")
+ math(EXPR targets_len-1 "${targets_len} - 1")
+
+ message(DEBUG "Found ${targets_len} targets in package ${package_name}")
+
+ foreach(ix RANGE ${targets_len-1})
+ string(JSON target GET "${targets}" ${ix})
+ string(JSON target_name GET "${target}" "name")
+ string(JSON target_kind GET "${target}" "kind")
+ string(JSON target_kind_len LENGTH "${target_kind}")
+
+ math(EXPR target_kind_len-1 "${target_kind_len} - 1")
+ set(kinds)
+ unset(override_package_crate_type)
+ # OVERRIDE_CRATE_TYPE is more specific than the CRATE_TYPES argument to corrosion_import_crate, and thus takes
+ # priority.
+ if(DEFINED GAPT_OVERRIDE_CRATE_TYPE_ARGS)
+ foreach(override_crate_name override_crate_types IN ZIP_LISTS ${override_crate_name_list_ref} ${override_crate_types_list_ref})
+ if("${override_crate_name}" STREQUAL "${target_name}")
+ message(DEBUG "Forcing crate ${target_name} to crate-type(s): ${override_crate_types}.")
+ # Convert to CMake list
+ string(REPLACE "," ";" kinds "${override_crate_types}")
+ break()
+ endif()
+ endforeach()
+ else()
+ foreach(ix RANGE ${target_kind_len-1})
+ string(JSON kind GET "${target_kind}" ${ix})
+ if(NOT crate_types OR ${kind} IN_LIST crate_types)
+ list(APPEND kinds ${kind})
+ endif()
+ endforeach()
+ endif()
+ if(TARGET "${target_name}"
+ AND ("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds OR "bin" IN_LIST kinds)
+ )
+ message(WARNING "Failed to import Rust crate ${target_name} (kind: `${target_kind}`) because a target "
+ "with the same name already exists. Skipping this target.\n"
+ "Help: If you are importing a package which exposes both a `lib` and "
+ "a `bin` target, please consider explicitly naming the targets in your `Cargo.toml` manifest.\n"
+ "Note: If you have multiple different packages which have targets with the same name, please note that "
+ "this is currently not supported by Corrosion. Feel free to open an issue on Github to request "
+ "supporting this scenario."
+ )
+ # Skip this target to prevent a hard error.
+ continue()
+ endif()
+
+ if("staticlib" IN_LIST kinds OR "cdylib" IN_LIST kinds)
+ # Explicitly set library names have always been forbidden from using dashes (by cargo).
+ # Starting with Rust 1.79, names inherited from the package name will have dashes replaced
+ # by underscores too. Corrosion will thus replace dashes with underscores, to make the target
+ # name consistent independent of the Rust version. `bin` target names are not affected.
+ # See https://github.com/corrosion-rs/corrosion/issues/501 for more details.
+ string(REPLACE "\-" "_" target_name "${target_name}")
+
+ set(archive_byproducts "")
+ set(shared_lib_byproduct "")
+ set(pdb_byproduct "")
+
+ add_library(${target_name} INTERFACE)
+ _corrosion_initialize_properties(${target_name})
+ _corrosion_add_library_target(
+ WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
+ TARGET_NAME "${target_name}"
+ LIB_KINDS ${kinds}
+ OUT_ARCHIVE_OUTPUT_BYPRODUCTS archive_byproducts
+ OUT_SHARED_LIB_BYPRODUCTS shared_lib_byproduct
+ OUT_PDB_BYPRODUCT pdb_byproduct
+ )
+
+ set(byproducts "")
+ list(APPEND byproducts "${archive_byproducts}" "${shared_lib_byproduct}" "${pdb_byproduct}")
+
+ set(cargo_build_out_dir "")
+ _add_cargo_build(
+ cargo_build_out_dir
+ PACKAGE ${package_name}
+ TARGET ${target_name}
+ MANIFEST_PATH "${manifest_path}"
+ WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
+ TARGET_KINDS "${kinds}"
+ BYPRODUCTS "${byproducts}"
+ # Optional
+ ${no_linker_override}
+ )
+ if(archive_byproducts)
+ _corrosion_copy_byproducts(
+ ${target_name} ARCHIVE_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${archive_byproducts}"
+ )
+ endif()
+ if(shared_lib_byproduct)
+ _corrosion_copy_byproducts(
+ ${target_name} LIBRARY_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${shared_lib_byproduct}"
+ )
+ endif()
+ if(pdb_byproduct)
+ _corrosion_copy_byproducts(
+ ${target_name} "PDB_OUTPUT_DIRECTORY;LIBRARY_OUTPUT_DIRECTORY" "${cargo_build_out_dir}" "${pdb_byproduct}"
+ )
+ endif()
+ list(APPEND corrosion_targets ${target_name})
+ set_property(TARGET "${target_name}" PROPERTY COR_CARGO_PACKAGE_NAME "${package_name}" )
+ # Note: "bin" is mutually exclusive with "staticlib/cdylib", since `bin`s are seperate crates from libraries.
+ elseif("bin" IN_LIST kinds)
+ set(bin_byproduct "")
+ set(pdb_byproduct "")
+ add_executable(${target_name} IMPORTED GLOBAL)
+ _corrosion_initialize_properties(${target_name})
+ _corrosion_add_bin_target("${workspace_manifest_path}" "${target_name}"
+ "bin_byproduct" "pdb_byproduct"
+ )
+
+ set(byproducts "")
+ list(APPEND byproducts "${bin_byproduct}" "${pdb_byproduct}")
+
+ set(cargo_build_out_dir "")
+ _add_cargo_build(
+ cargo_build_out_dir
+ PACKAGE "${package_name}"
+ TARGET "${target_name}"
+ MANIFEST_PATH "${manifest_path}"
+ WORKSPACE_MANIFEST_PATH "${workspace_manifest_path}"
+ TARGET_KINDS "bin"
+ BYPRODUCTS "${byproducts}"
+ # Optional
+ ${no_linker_override}
+ )
+ _corrosion_copy_byproducts(
+ ${target_name} RUNTIME_OUTPUT_DIRECTORY "${cargo_build_out_dir}" "${bin_byproduct}"
+ )
+ if(pdb_byproduct)
+ _corrosion_copy_byproducts(
+ ${target_name} "PDB_OUTPUT_DIRECTORY;RUNTIME_OUTPUT_DIRECTORY" "${cargo_build_out_dir}" "${pdb_byproduct}"
+ )
+ endif()
+ list(APPEND corrosion_targets ${target_name})
+ set_property(TARGET "${target_name}" PROPERTY COR_CARGO_PACKAGE_NAME "${package_name}" )
+ else()
+ # ignore other kinds (like examples, tests, build scripts, ...)
+ endif()
+ endforeach()
+
+ if(NOT corrosion_targets)
+ message(DEBUG "No relevant targets found in package ${package_name} - Ignoring")
+ else()
+ set_target_properties(${corrosion_targets} PROPERTIES INTERFACE_COR_PACKAGE_MANIFEST_PATH "${package_manifest_path}")
+ endif()
+ set(${out_created_targets} "${corrosion_targets}" PARENT_SCOPE)
+
+endfunction()
+
+# Add all cargo targets defined in the packages defined in the Cargo.toml manifest at
+# `MANIFEST_PATH`.
+function(_generator_add_cargo_targets)
+ set(options NO_LINKER_OVERRIDE)
+ set(one_value_args MANIFEST_PATH IMPORTED_CRATES)
+ set(multi_value_args CRATES CRATE_TYPES OVERRIDE_CRATE_TYPE_ARGS)
+ cmake_parse_arguments(
+ GGC
+ "${options}"
+ "${one_value_args}"
+ "${multi_value_args}"
+ ${ARGN}
+ )
+ list(APPEND CMAKE_MESSAGE_CONTEXT "_add_cargo_targets")
+
+ _corrosion_option_passthrough_helper(NO_LINKER_OVERRIDE GGC no_linker_override)
+ _corrosion_arg_passthrough_helper(CRATE_TYPES GGC crate_types)
+ _corrosion_arg_passthrough_helper(OVERRIDE_CRATE_TYPE_ARGS GGC override_crate_types)
+
+ _cargo_metadata(json "${GGC_MANIFEST_PATH}")
+ string(JSON packages GET "${json}" "packages")
+ string(JSON workspace_members GET "${json}" "workspace_members")
+
+ string(JSON pkgs_len LENGTH "${packages}")
+ math(EXPR pkgs_len-1 "${pkgs_len} - 1")
+
+ string(JSON ws_mems_len LENGTH ${workspace_members})
+ math(EXPR ws_mems_len-1 "${ws_mems_len} - 1")
+
+ set(created_targets "")
+ set(available_package_names "")
+ foreach(ix RANGE ${pkgs_len-1})
+ string(JSON pkg GET "${packages}" ${ix})
+ string(JSON pkg_id GET "${pkg}" "id")
+ string(JSON pkg_name GET "${pkg}" "name")
+ string(JSON pkg_manifest_path GET "${pkg}" "manifest_path")
+ string(JSON pkg_version GET "${pkg}" "version")
+ list(APPEND available_package_names "${pkg_name}")
+
+ if(DEFINED GGC_CRATES)
+ if(NOT pkg_name IN_LIST GGC_CRATES)
+ continue()
+ endif()
+ endif()
+
+ # probably this loop is not necessary at all, since when using --no-deps, the
+ # contents of packages should already be only workspace members!
+ unset(pkg_is_ws_member)
+ foreach(ix RANGE ${ws_mems_len-1})
+ string(JSON ws_mem GET "${workspace_members}" ${ix})
+ if(ws_mem STREQUAL pkg_id)
+ set(pkg_is_ws_member YES)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT DEFINED pkg_is_ws_member)
+ # Since we pass `--no-deps` to cargo metadata now, I think this situation can't happen, but lets check for
+ # it anyway, just to discover any potential issues.
+ # If nobody complains for a while, it should be safe to remove this check and the previous loop, which
+ # should speed up the configuration process.
+ message(WARNING "The package `${pkg_name}` unexpectedly is not part of the workspace."
+ "Please open an issue at corrosion with some background information on the package"
+ )
+ endif()
+
+ string(JSON targets GET "${pkg}" "targets")
+
+ _generator_add_package_targets(
+ WORKSPACE_MANIFEST_PATH "${GGC_MANIFEST_PATH}"
+ PACKAGE_MANIFEST_PATH "${pkg_manifest_path}"
+ PACKAGE_NAME "${pkg_name}"
+ PACKAGE_VERSION "${pkg_version}"
+ TARGETS_JSON "${targets}"
+ OUT_CREATED_TARGETS curr_created_targets
+ ${no_linker_override}
+ ${crate_types}
+ ${override_crate_types}
+ )
+ list(APPEND created_targets "${curr_created_targets}")
+ endforeach()
+
+ if(NOT created_targets)
+ set(crates_error_message "")
+ if(DEFINED GGC_CRATES)
+ set(crates_error_message "\n`corrosion_import_crate()` was called with the `CRATES` "
+ "parameter set to `${GGC_CRATES}`. Corrosion will only attempt to import packages matching "
+ "names from this list."
+ )
+ endif()
+ message(FATAL_ERROR
+ "Found no targets in ${pkgs_len} packages."
+ ${crates_error_message}.
+ "\nPlease keep in mind that corrosion will only import Rust `bin` targets or"
+ "`staticlib` or `cdylib` library targets."
+ "The following packages were found in the Manifest: ${available_package_names}"
+ )
+ else()
+ message(DEBUG "Corrosion created the following CMake targets: ${created_targets}")
+ endif()
+
+ if(GGC_IMPORTED_CRATES)
+ set(${GGC_IMPORTED_CRATES} "${created_targets}" PARENT_SCOPE)
+ endif()
+endfunction()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/cmake/FindRust.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,900 @@
+#[=======================================================================[.rst:
+FindRust
+--------
+
+Find Rust
+
+This module finds an installed rustc compiler and the cargo build tool. If Rust
+is managed by rustup it determines the available toolchains and returns a
+concrete Rust version, not a rustup proxy.
+
+#]=======================================================================]
+
+cmake_minimum_required(VERSION 3.12)
+
+option(
+ Rust_RUSTUP_INSTALL_MISSING_TARGET
+ "Use Rustup to automatically install missing targets instead of giving up"
+ OFF
+)
+
+# search for Cargo here and set up a bunch of cool flags and stuff
+include(FindPackageHandleStandardArgs)
+
+list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust")
+
+# Print error message and return. Should not be used from inside functions
+macro(_findrust_failed)
+ if("${Rust_FIND_REQUIRED}")
+ message(FATAL_ERROR ${ARGN})
+ elseif(NOT "${Rust_FIND_QUIETLY}")
+ message(WARNING ${ARGN})
+ endif()
+ set(Rust_FOUND "")
+ return()
+endmacro()
+
+# Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package.
+function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK)
+ if(DEFINED Rust_FIND_VERSION_RANGE)
+ if(Rust_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE")
+ set(COMPARSION_OPERATOR "VERSION_LESS_EQUAL")
+ elseif(Rust_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE")
+ set(COMPARSION_OPERATOR "VERSION_LESS")
+ else()
+ message(FATAL_ERROR "Unexpected value in `<PackageName>_FIND_VERSION_RANGE_MAX`: "
+ "`${Rust_FIND_VERSION_RANGE_MAX}`.")
+ endif()
+ if(("${ACTUAL_VERSION}" VERSION_GREATER_EQUAL "${Rust_FIND_VERSION_RANGE_MIN}")
+ AND
+ ( "${ACTUAL_VERSION}" ${COMPARSION_OPERATOR} "${Rust_FIND_VERSION_RANGE_MAX}" )
+ )
+ set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
+ else()
+ set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
+ endif()
+ elseif(DEFINED Rust_FIND_VERSION)
+ if(Rust_VERSION_EXACT)
+ set(COMPARISON_OPERATOR VERSION_EQUAL)
+ else()
+ set(COMPARISON_OPERATOR VERSION_GREATER_EQUAL)
+ endif()
+ if(_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION "${COMPARISON_OPERATOR}" Rust_FIND_VERSION)
+ set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
+ else()
+ set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
+ endif()
+ else()
+ # if no VERSION requirement was specified, the version is always okay.
+ set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_corrosion_strip_target_triple input_triple_or_path output_triple)
+ # If the target_triple is a path to a custom target specification file, then strip everything
+ # except the filename from `target_triple`.
+ get_filename_component(target_triple_ext "${input_triple_or_path}" EXT)
+ set(target_triple "${input_triple_or_path}")
+ if(target_triple_ext)
+ if(target_triple_ext STREQUAL ".json")
+ get_filename_component(target_triple "${input_triple_or_path}" NAME_WE)
+ endif()
+ endif()
+ set(${output_triple} "${target_triple}" PARENT_SCOPE)
+endfunction()
+
+function(_corrosion_parse_target_triple target_triple out_arch out_vendor out_os out_env)
+ _corrosion_strip_target_triple(${target_triple} target_triple)
+
+ # The vendor part may be left out from the target triple, and since `env` is also optional,
+ # we determine if vendor is present by matching against a list of known vendors.
+ set(known_vendors
+ "apple"
+ "esp[a-z0-9]*" # espressif, e.g. riscv32imc-esp-espidf or xtensa-esp32s3-none-elf
+ "fortanix"
+ "kmc"
+ "pc"
+ "nintendo"
+ "nvidia"
+ "openwrt"
+ "alpine"
+ "chimera"
+ "unikraft"
+ "unknown"
+ "uwp" # aarch64-uwp-windows-msvc
+ "wrs" # e.g. aarch64-wrs-vxworks
+ "sony"
+ "sun"
+ )
+ # todo: allow users to add additional vendors to the list via a cmake variable.
+ list(JOIN known_vendors "|" known_vendors_joined)
+ # vendor is optional - We detect if vendor is present by matching against a known list of
+ # vendors. The next field is the OS, which we assume to always be present, while the last field
+ # is again optional and contains the environment.
+ string(REGEX MATCH
+ "^([a-z0-9_\.]+)-((${known_vendors_joined})-)?([a-z0-9_]+)(-([a-z0-9_]+))?$"
+ whole_match
+ "${target_triple}"
+ )
+ if((NOT whole_match) AND (NOT CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED))
+ message(WARNING "Failed to parse target-triple `${target_triple}`."
+ "Corrosion determines some information about the output artifacts based on OS "
+ "specified in the Rust target-triple.\n"
+ "Currently this is relevant for windows and darwin (mac) targets, since file "
+ "extensions differ.\n"
+ "Note: If you are targeting a different OS you can suppress this warning by"
+ " setting the CMake cache variable "
+ "`CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED`."
+ "Please consider opening an issue on github if you you need to add a new vendor to the list."
+ )
+ endif()
+
+ message(DEBUG "Parsed Target triple: arch: ${CMAKE_MATCH_1}, vendor: ${CMAKE_MATCH_3}, "
+ "OS: ${CMAKE_MATCH_4}, env: ${CMAKE_MATCH_6}")
+
+ set("${out_arch}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set("${out_vendor}" "${CMAKE_MATCH_3}" PARENT_SCOPE)
+ set("${out_os}" "${CMAKE_MATCH_4}" PARENT_SCOPE)
+ set("${out_env}" "${CMAKE_MATCH_6}" PARENT_SCOPE)
+endfunction()
+
+function(_corrosion_determine_libs_new target_triple out_libs out_flags)
+ set(package_dir "${CMAKE_BINARY_DIR}/corrosion/required_libs")
+ # Cleanup on reconfigure to get a cleans state (in case we change something in the future)
+ file(REMOVE_RECURSE "${package_dir}")
+ file(MAKE_DIRECTORY "${package_dir}")
+ set(manifest "[package]\nname = \"required_libs\"\nedition = \"2018\"\nversion = \"0.1.0\"\n")
+ string(APPEND manifest "\n[lib]\ncrate-type=[\"staticlib\"]\npath = \"lib.rs\"\n")
+ string(APPEND manifest "\n[workspace]\n")
+ file(WRITE "${package_dir}/Cargo.toml" "${manifest}")
+ file(WRITE "${package_dir}/lib.rs" "pub fn add(left: usize, right: usize) -> usize {left + right}\n")
+
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E env
+ "CARGO_BUILD_RUSTC=${Rust_COMPILER_CACHED}"
+ ${Rust_CARGO_CACHED} rustc --verbose --color never --target=${target_triple} -- --print=native-static-libs
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs"
+ RESULT_VARIABLE cargo_build_result
+ ERROR_VARIABLE cargo_build_error_message
+ )
+ if(cargo_build_result)
+ message(DEBUG "Determining required native libraries - failed: ${cargo_build_result}.")
+ message(TRACE "The cargo build error was: ${cargo_build_error_message}")
+ message(DEBUG "Note: This is expected for Rust targets without std support")
+ return()
+ else()
+ # The pattern starts with `native-static-libs:` and goes to the end of the line.
+ if(cargo_build_error_message MATCHES "native-static-libs: ([^\r\n]+)\r?\n")
+ string(REPLACE " " ";" "libs_list" "${CMAKE_MATCH_1}")
+ set(stripped_lib_list "")
+ set(flag_list "")
+
+ set(was_last_framework OFF)
+ foreach(lib ${libs_list})
+ # merge -framework;lib -> "-framework lib" as CMake does de-duplication of link libraries, and -framework prefix is required
+ if (lib STREQUAL "-framework")
+ set(was_last_framework ON)
+ continue()
+ endif()
+ if (was_last_framework)
+ list(APPEND stripped_lib_list "-framework ${lib}")
+ set(was_last_framework OFF)
+ continue()
+ endif()
+
+ # Flags start with / for MSVC
+ if (lib MATCHES "^/" AND ${target_triple} MATCHES "msvc$")
+ # Windows GNU uses the compiler to invoke the linker, so -Wl, prefix is needed
+ # https://gitlab.kitware.com/cmake/cmake/-/blob/9bed4f4d817f139f0c2e050d7420e1e247949fe4/Modules/Platform/Windows-GNU.cmake#L156
+ if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ list(APPEND flag_list "-Wl,${lib}")
+ else()
+ list(APPEND flag_list "${lib}")
+ endif()
+ else()
+ # Strip leading `-l` (unix) and potential .lib suffix (windows)
+ string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}")
+ string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}")
+ list(APPEND stripped_lib_list "${stripped_lib}")
+ endif()
+ endforeach()
+ set(libs_list "${stripped_lib_list}")
+ # We leave it up to the C/C++ executable that links in the Rust static-library
+ # to determine which version of the msvc runtime library it should select.
+ list(FILTER libs_list EXCLUDE REGEX "^msvcrtd?")
+ list(FILTER flag_list EXCLUDE REGEX "^(-Wl,)?/defaultlib:msvcrtd?")
+ else()
+ message(DEBUG "Determining required native libraries - failed: Regex match failure.")
+ message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`")
+ return()
+ endif()
+ endif()
+ set("${out_libs}" "${libs_list}" PARENT_SCOPE)
+ set("${out_flags}" "${flag_list}" PARENT_SCOPE)
+endfunction()
+
+if (NOT "${Rust_TOOLCHAIN}" STREQUAL "$CACHE{Rust_TOOLCHAIN}")
+ # Promote Rust_TOOLCHAIN to a cache variable if it is not already a cache variable
+ set(Rust_TOOLCHAIN ${Rust_TOOLCHAIN} CACHE STRING "Requested rustup toolchain" FORCE)
+endif()
+
+set(_RESOLVE_RUSTUP_TOOLCHAINS_DESC "Indicates whether to descend into the toolchain pointed to by rustup")
+set(Rust_RESOLVE_RUSTUP_TOOLCHAINS ON CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC})
+
+# This block checks to see if we're prioritizing a rustup-managed toolchain.
+if (DEFINED Rust_TOOLCHAIN)
+ # If the user specifies `Rust_TOOLCHAIN`, then look for `rustup` first, rather than `rustc`.
+ find_program(Rust_RUSTUP rustup PATHS "$ENV{HOME}/.cargo/bin")
+ if(NOT Rust_RUSTUP)
+ if(NOT "${Rust_FIND_QUIETLY}")
+ message(
+ WARNING "CMake variable `Rust_TOOLCHAIN` specified, but `rustup` was not found. "
+ "Ignoring toolchain and looking for a Rust toolchain not managed by rustup.")
+ endif()
+ endif()
+else()
+ # If we aren't definitely using a rustup toolchain, look for rustc first - the user may have
+ # a toolchain installed via a method other than rustup higher in the PATH, which should be
+ # preferred. However, if the first-found rustc is a rustup proxy, then we'll revert to
+ # finding the preferred toolchain via rustup.
+
+ # Uses `Rust_COMPILER` to let user-specified `rustc` win. But we will still "override" the
+ # user's setting if it is pointing to `rustup`. Default rustup install path is provided as a
+ # backup if a toolchain cannot be found in the user's PATH.
+
+ if (DEFINED Rust_COMPILER)
+ set(_Rust_COMPILER_TEST "${Rust_COMPILER}")
+ set(_USER_SPECIFIED_RUSTC ON)
+ if(NOT (EXISTS "${_Rust_COMPILER_TEST}" AND NOT IS_DIRECTORY "${_Rust_COMPILER_TEST}"))
+ set(_ERROR_MESSAGE "Rust_COMPILER was set to `${Rust_COMPILER}`, but this file does "
+ "not exist."
+ )
+ _findrust_failed(${_ERROR_MESSAGE})
+ return()
+ endif()
+ else()
+ find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin")
+ if(NOT EXISTS "${_Rust_COMPILER_TEST}")
+ cmake_path(CONVERT "$ENV{HOME}/.cargo/bin" TO_CMAKE_PATH_LIST _cargo_bin_dir)
+ set(_ERROR_MESSAGE "`rustc` not found in PATH or `${_cargo_bin_dir}`.\n"
+ "Hint: Check if `rustc` is in PATH or manually specify the location "
+ "by setting `Rust_COMPILER` to the path to `rustc`.")
+ _findrust_failed(${_ERROR_MESSAGE})
+ endif()
+ endif()
+
+ # Check if the discovered rustc is actually a "rustup" proxy.
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E env
+ RUSTUP_FORCE_ARG0=rustup
+ "${_Rust_COMPILER_TEST}" --version
+ OUTPUT_VARIABLE _RUSTC_VERSION_RAW
+ ERROR_VARIABLE _RUSTC_VERSION_STDERR
+ RESULT_VARIABLE _RUSTC_VERSION_RESULT
+ )
+
+ if(NOT (_RUSTC_VERSION_RESULT EQUAL "0"))
+ _findrust_failed("`${_Rust_COMPILER_TEST} --version` failed with ${_RUSTC_VERSION_RESULT}\n"
+ "rustc stderr:\n${_RUSTC_VERSION_STDERR}"
+ )
+ endif()
+
+ if (_RUSTC_VERSION_RAW MATCHES "rustup [0-9\\.]+")
+ if (_USER_SPECIFIED_RUSTC)
+ message(
+ WARNING "User-specified Rust_COMPILER pointed to rustup's rustc proxy. Corrosion's "
+ "FindRust will always try to evaluate to an actual Rust toolchain, and so the "
+ "user-specified Rust_COMPILER will be discarded in favor of the default "
+ "rustup-managed toolchain."
+ )
+
+ unset(Rust_COMPILER)
+ unset(Rust_COMPILER CACHE)
+ endif()
+
+ # Get `rustup` next to the `rustc` proxy
+ get_filename_component(_RUST_PROXIES_PATH "${_Rust_COMPILER_TEST}" DIRECTORY)
+ find_program(Rust_RUSTUP rustup HINTS "${_RUST_PROXIES_PATH}" NO_DEFAULT_PATH)
+ endif()
+
+ unset(_Rust_COMPILER_TEST CACHE)
+endif()
+
+# At this point, the only thing we should have evaluated is a path to `rustup` _if that's what the
+# best source for a Rust toolchain was determined to be_.
+if (NOT Rust_RUSTUP)
+ set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC} FORCE)
+endif()
+
+# List of user variables that will override any toolchain-provided setting
+set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET)
+foreach(_VAR ${_Rust_USER_VARS})
+ if (DEFINED "${_VAR}")
+ set(${_VAR}_CACHED "${${_VAR}}" CACHE INTERNAL "Internal cache of ${_VAR}")
+ else()
+ unset(${_VAR}_CACHED CACHE)
+ endif()
+endforeach()
+
+# Discover what toolchains are installed by rustup, if the discovered `rustc` is a proxy from
+# `rustup` and the user hasn't explicitly requested to override this behavior, then select either
+# the default toolchain, or the requested toolchain Rust_TOOLCHAIN
+if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
+ execute_process(
+ COMMAND
+ "${Rust_RUSTUP}" toolchain list --verbose
+ OUTPUT_VARIABLE _TOOLCHAINS_RAW
+ )
+
+ string(REPLACE "\n" ";" _TOOLCHAINS_RAW "${_TOOLCHAINS_RAW}")
+ set(_DISCOVERED_TOOLCHAINS "")
+ set(_DISCOVERED_TOOLCHAINS_RUSTC_PATH "")
+ set(_DISCOVERED_TOOLCHAINS_CARGO_PATH "")
+ set(_DISCOVERED_TOOLCHAINS_VERSION "")
+
+ foreach(_TOOLCHAIN_RAW ${_TOOLCHAINS_RAW})
+ if (_TOOLCHAIN_RAW MATCHES "([a-zA-Z0-9\\._\\-]+)[ \t\r\n]?(\\(default\\) \\(override\\)|\\(default\\)|\\(override\\))?[ \t\r\n]+(.+)")
+ set(_TOOLCHAIN "${CMAKE_MATCH_1}")
+ set(_TOOLCHAIN_TYPE "${CMAKE_MATCH_2}")
+
+ set(_TOOLCHAIN_PATH "${CMAKE_MATCH_3}")
+ set(_TOOLCHAIN_${_TOOLCHAIN}_PATH "${CMAKE_MATCH_3}")
+
+ if (_TOOLCHAIN_TYPE MATCHES ".*\\(default\\).*")
+ set(_TOOLCHAIN_DEFAULT "${_TOOLCHAIN}")
+ endif()
+
+ if (_TOOLCHAIN_TYPE MATCHES ".*\\(override\\).*")
+ set(_TOOLCHAIN_OVERRIDE "${_TOOLCHAIN}")
+ endif()
+
+ execute_process(
+ COMMAND
+ "${_TOOLCHAIN_PATH}/bin/rustc" --version
+ OUTPUT_VARIABLE _TOOLCHAIN_RAW_VERSION
+ )
+ if (_TOOLCHAIN_RAW_VERSION MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
+ list(APPEND _DISCOVERED_TOOLCHAINS "${_TOOLCHAIN}")
+ list(APPEND _DISCOVERED_TOOLCHAINS_RUSTC_PATH "${_TOOLCHAIN_PATH}/bin/rustc")
+ list(APPEND _DISCOVERED_TOOLCHAINS_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+
+ # We need this variable to determine the default toolchain, since `foreach(... IN ZIP_LISTS ...)`
+ # requires CMake 3.17. As a workaround we define this variable to lookup the version when iterating
+ # through the `_DISCOVERED_TOOLCHAINS` lists.
+ set(_TOOLCHAIN_${_TOOLCHAIN}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+ if(CMAKE_MATCH_4)
+ set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "TRUE")
+ else()
+ set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "FALSE")
+ endif()
+ if(EXISTS "${_TOOLCHAIN_PATH}/bin/cargo")
+ list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "${_TOOLCHAIN_PATH}/bin/cargo")
+ else()
+ list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "NOTFOUND")
+ endif()
+ else()
+ message(AUTHOR_WARNING "Unexpected output from `rustc --version` for Toolchain `${_TOOLCHAIN}`: "
+ "`${_TOOLCHAIN_RAW_VERSION}`.\n"
+ "Ignoring this toolchain."
+ )
+ endif()
+ else()
+ message(AUTHOR_WARNING "Didn't recognize toolchain: ${_TOOLCHAIN_RAW}. Ignoring this toolchain.\n"
+ "Rustup toolchain list output( `${Rust_RUSTUP} toolchain list --verbose`):\n"
+ "${_TOOLCHAINS_RAW}"
+ )
+ endif()
+ endforeach()
+
+ # Expose a list of available rustup toolchains.
+ list(LENGTH _DISCOVERED_TOOLCHAINS _toolchain_len)
+ list(LENGTH _DISCOVERED_TOOLCHAINS_RUSTC_PATH _toolchain_rustc_len)
+ list(LENGTH _DISCOVERED_TOOLCHAINS_CARGO_PATH _toolchain_cargo_len)
+ list(LENGTH _DISCOVERED_TOOLCHAINS_VERSION _toolchain_version_len)
+ if(NOT
+ (_toolchain_len EQUAL _toolchain_rustc_len
+ AND _toolchain_cargo_len EQUAL _toolchain_version_len
+ AND _toolchain_len EQUAL _toolchain_cargo_len)
+ )
+ message(FATAL_ERROR "Internal error - list length mismatch."
+ "List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo,"
+ " ${_toolchain_version_len} version. The lengths should be the same."
+ )
+ endif()
+
+ set(Rust_RUSTUP_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}" CACHE INTERNAL "List of available Rustup toolchains")
+ set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH "${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}"
+ CACHE INTERNAL
+ "List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`."
+ )
+ set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH "${_DISCOVERED_TOOLCHAINS_CARGO_PATH}"
+ CACHE INTERNAL
+ "List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \
+ May also be `NOTFOUND` if the toolchain does not have a cargo executable."
+ )
+ set(Rust_RUSTUP_TOOLCHAINS_VERSION "${_DISCOVERED_TOOLCHAINS_VERSION}"
+ CACHE INTERNAL
+ "List of the rust toolchain version corresponding to the toolchain at the same index in \
+ `Rust_RUSTUP_TOOLCHAINS`."
+ )
+
+ # Rust_TOOLCHAIN is preferred over a requested version if it is set.
+ if (NOT DEFINED Rust_TOOLCHAIN)
+ if (NOT DEFINED _TOOLCHAIN_OVERRIDE)
+ set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_DEFAULT}")
+ else()
+ set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_OVERRIDE}")
+ endif()
+ # Check default toolchain first.
+ _findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION" _VERSION_OK)
+ if(NOT "${_VERSION_OK}")
+ foreach(_TOOLCHAIN "${_DISCOVERED_TOOLCHAINS}")
+ _findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN}_VERSION" _VERSION_OK)
+ if("${_VERSION_OK}")
+ set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN}")
+ break()
+ endif()
+ endforeach()
+ # Check if we found a suitable version in the for loop.
+ if(NOT "${_VERSION_OK}")
+ string(REPLACE ";" "\n" _DISCOVERED_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}")
+ _findrust_failed("Failed to find a Rust toolchain matching the version requirements of "
+ "${Rust_FIND_VERSION}. Available toolchains: ${_DISCOVERED_TOOLCHAINS}")
+ endif()
+ endif()
+ endif()
+
+ set(Rust_TOOLCHAIN "${_TOOLCHAIN_SELECTED}" CACHE STRING "The rustup toolchain to use")
+ set_property(CACHE Rust_TOOLCHAIN PROPERTY STRINGS "${_DISCOVERED_TOOLCHAINS}")
+
+ if(NOT Rust_FIND_QUIETLY)
+ message(STATUS "Rust Toolchain: ${Rust_TOOLCHAIN}")
+ endif()
+
+ if (NOT Rust_TOOLCHAIN IN_LIST _DISCOVERED_TOOLCHAINS)
+ # If the precise toolchain wasn't found, try appending the default host
+ execute_process(
+ COMMAND
+ "${Rust_RUSTUP}" show
+ RESULT_VARIABLE _SHOW_RESULT
+ OUTPUT_VARIABLE _SHOW_RAW
+ )
+ if(NOT "${_SHOW_RESULT}" EQUAL "0")
+ _findrust_failed("Command `${Rust_RUSTUP} show` failed")
+ endif()
+
+ if (_SHOW_RAW MATCHES "Default host: ([a-zA-Z0-9_\\-]*)\n")
+ set(_DEFAULT_HOST "${CMAKE_MATCH_1}")
+ else()
+ _findrust_failed("Failed to parse \"Default host\" from `${Rust_RUSTUP} show`. Got: ${_SHOW_RAW}")
+ endif()
+
+ if (NOT "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}" IN_LIST _DISCOVERED_TOOLCHAINS)
+ set(_NOT_FOUND_MESSAGE "Could not find toolchain '${Rust_TOOLCHAIN}'\n"
+ "Available toolchains:\n"
+ )
+ foreach(_TOOLCHAIN ${_DISCOVERED_TOOLCHAINS})
+ list(APPEND _NOT_FOUND_MESSAGE " `${_TOOLCHAIN}`\n")
+ endforeach()
+ _findrust_failed(${_NOT_FOUND_MESSAGE})
+ endif()
+
+ set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}")
+ else()
+ set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}")
+ endif()
+
+ set(_RUST_TOOLCHAIN_PATH "${_TOOLCHAIN_${_RUSTUP_TOOLCHAIN_FULL}_PATH}")
+ if(NOT "${Rust_FIND_QUIETLY}")
+ message(VERBOSE "Rust toolchain ${_RUSTUP_TOOLCHAIN_FULL}")
+ message(VERBOSE "Rust toolchain path ${_RUST_TOOLCHAIN_PATH}")
+ endif()
+
+ # Is overridden if the user specifies `Rust_COMPILER` explicitly.
+ find_program(
+ Rust_COMPILER_CACHED
+ rustc
+ HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
+ NO_DEFAULT_PATH)
+else()
+ message(DEBUG "Rust_RESOLVE_RUSTUP_TOOLCHAINS=OFF and Rust_RUSTUP=${Rust_RUSTUP}")
+ if(Rust_RUSTUP)
+ get_filename_component(_RUSTUP_DIR "${Rust_RUSTUP}" DIRECTORY)
+ find_program(Rust_COMPILER_CACHED rustc HINTS "${_RUSTUP_DIR}")
+ else()
+ find_program(Rust_COMPILER_CACHED rustc)
+ endif()
+ message(DEBUG "find_program rustc: ${Rust_COMPILER_CACHED}")
+ if (EXISTS "${Rust_COMPILER_CACHED}")
+ # rustc is expected to be at `<toolchain_path>/bin/rustc`.
+ get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY)
+ get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
+ endif()
+endif()
+
+if (NOT EXISTS "${Rust_COMPILER_CACHED}")
+ set(_NOT_FOUND_MESSAGE "The rustc executable was not found. "
+ "Rust not installed or ~/.cargo/bin not added to path?\n"
+ "Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`."
+ )
+ _findrust_failed(${_NOT_FOUND_MESSAGE})
+endif()
+
+if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
+ set(_NOT_FOUND_MESSAGE "Rust was detected to be managed by rustup, but failed to find `cargo` "
+ "next to `rustc` in `${_RUST_TOOLCHAIN_PATH}/bin`. This can happen for custom toolchains, "
+ "if cargo was not built. "
+ "Please manually specify the path to a compatible `cargo` by setting `Rust_CARGO`."
+ )
+ find_program(
+ Rust_CARGO_CACHED
+ cargo
+ HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
+ NO_DEFAULT_PATH
+ )
+ # note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
+ # not sure why that is here...
+ if(NOT EXISTS "${Rust_CARGO_CACHED}")
+ _findrust_failed(${_NOT_FOUND_MESSAGE})
+ endif()
+ set(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED TRUE CACHE INTERNAL "" FORCE)
+else()
+ set(_NOT_FOUND_MESSAGE "Failed to find `cargo` in PATH and `${_RUST_TOOLCHAIN_PATH}/bin`.\n"
+ "Please ensure cargo is in PATH or manually specify the path to a compatible `cargo` by "
+ "setting `Rust_CARGO`."
+ )
+ # On some systems (e.g. NixOS) cargo is not managed by rustup and also not next to rustc.
+ find_program(
+ Rust_CARGO_CACHED
+ cargo
+ HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
+ )
+ # note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
+ # not sure why that is here...
+ if(NOT EXISTS "${Rust_CARGO_CACHED}")
+ _findrust_failed(${_NOT_FOUND_MESSAGE})
+ endif()
+endif()
+
+execute_process(
+ COMMAND "${Rust_CARGO_CACHED}" --version --verbose
+ OUTPUT_VARIABLE _CARGO_VERSION_RAW
+ RESULT_VARIABLE _CARGO_VERSION_RESULT
+)
+# todo: check if cargo is a required component!
+if(NOT ( "${_CARGO_VERSION_RESULT}" EQUAL "0" ))
+ _findrust_failed("Failed to get cargo version.\n"
+ "`${Rust_CARGO_CACHED} --version` failed with error: `${_CARGO_VERSION_RESULT}"
+)
+endif()
+
+# todo: don't set cache variables here, but let find_package_handle_standard_args do the promotion
+# later.
+if (_CARGO_VERSION_RAW MATCHES "cargo ([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
+# Workaround for the version strings where the `cargo ` prefix is missing.
+elseif(_CARGO_VERSION_RAW MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
+ set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
+else()
+ _findrust_failed(
+ "Failed to parse cargo version. `cargo --version` evaluated to (${_CARGO_VERSION_RAW}). "
+ "Expected a <Major>.<Minor>.<Patch> version triple."
+ )
+endif()
+
+execute_process(
+ COMMAND "${Rust_COMPILER_CACHED}" --version --verbose
+ OUTPUT_VARIABLE _RUSTC_VERSION_RAW
+ RESULT_VARIABLE _RUSTC_VERSION_RESULT
+)
+
+if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" ))
+ _findrust_failed("Failed to get rustc version.\n"
+ "${Rust_COMPILER_CACHED} --version failed with error: `${_RUSTC_VERSION_RESULT}`")
+endif()
+
+if (_RUSTC_VERSION_RAW MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
+ set(Rust_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
+ set(Rust_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
+ set(Rust_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
+ set(Rust_VERSION "${Rust_VERSION_MAJOR}.${Rust_VERSION_MINOR}.${Rust_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
+ if(CMAKE_MATCH_4)
+ set(Rust_IS_NIGHTLY 1 CACHE INTERNAL "" FORCE)
+ else()
+ set(Rust_IS_NIGHTLY 0 CACHE INTERNAL "" FORCE)
+ endif()
+else()
+ _findrust_failed("Failed to parse rustc version. `${Rust_COMPILER_CACHED} --version --verbose` "
+ "evaluated to:\n`${_RUSTC_VERSION_RAW}`"
+ )
+endif()
+
+if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n")
+ set(Rust_DEFAULT_HOST_TARGET "${CMAKE_MATCH_1}")
+ set(Rust_CARGO_HOST_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Host triple")
+else()
+ _findrust_failed(
+ "Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
+ )
+endif()
+
+if (_RUSTC_VERSION_RAW MATCHES "LLVM version: ([0-9]+)\\.([0-9]+)(\\.([0-9]+))?")
+ set(Rust_LLVM_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
+ set(Rust_LLVM_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
+ # With the Rust toolchain 1.44.1 the reported LLVM version is 9.0, i.e. without a patch version.
+ # Since cmake regex does not support non-capturing groups, just ignore Match 3.
+ set(Rust_LLVM_VERSION_PATCH "${CMAKE_MATCH_4}" CACHE INTERNAL "" FORCE)
+ set(Rust_LLVM_VERSION "${Rust_LLVM_VERSION_MAJOR}.${Rust_LLVM_VERSION_MINOR}.${Rust_LLVM_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
+elseif(NOT Rust_FIND_QUIETLY)
+ message(
+ WARNING
+ "Failed to parse rustc LLVM version. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
+ )
+endif()
+
+if (NOT Rust_CARGO_TARGET_CACHED)
+ unset(_CARGO_ARCH)
+ unset(_CARGO_ABI)
+ if (WIN32)
+ if (CMAKE_VS_PLATFORM_NAME)
+ string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" LOWER_VS_PLATFORM_NAME)
+ if ("${LOWER_VS_PLATFORM_NAME}" STREQUAL "win32")
+ set(_CARGO_ARCH i686)
+ elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "x64")
+ set(_CARGO_ARCH x86_64)
+ elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "arm64")
+ set(_CARGO_ARCH aarch64)
+ else()
+ message(WARNING "VS Platform '${CMAKE_VS_PLATFORM_NAME}' not recognized")
+ endif()
+ endif()
+ # Fallback path
+ if(NOT DEFINED _CARGO_ARCH)
+ # Possible values for windows when not cross-compiling taken from here:
+ # https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
+ # When cross-compiling the user is expected to supply the value, so we match more variants.
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64)$")
+ set(_CARGO_ARCH x86_64)
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ARM64|arm64|aarch64)$")
+ set(_CARGO_ARCH aarch64)
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(X86|x86|i686)$")
+ set(_CARGO_ARCH i686)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i586")
+ set(_CARGO_ARCH i586)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64")
+ message(FATAL_ERROR "No rust target for Intel Itanium.")
+ elseif(NOT "${CMAKE_SYSTEM_PROCESSOR}")
+ message(WARNING "Failed to detect target architecture. Please set `CMAKE_SYSTEM_PROCESSOR`"
+ " to your target architecture or set `Rust_CARGO_TARGET` to your cargo target triple."
+ )
+ else()
+ message(WARNING "Failed to detect target architecture. Please set "
+ "`Rust_CARGO_TARGET` to your cargo target triple."
+ )
+ endif()
+ endif()
+
+ set(_CARGO_VENDOR "pc-windows")
+
+ # The MSVC Generators will always target the msvc ABI.
+ # For other generators we check the compiler ID and compiler target (if present)
+ # If no compiler is set and we are not cross-compiling then we just choose the
+ # default rust host target.
+ if(DEFINED MSVC
+ OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"
+ OR "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC"
+ OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-msvc$"
+ OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$"
+ )
+ set(_CARGO_ABI msvc)
+ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
+ OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"
+ OR (NOT CMAKE_CROSSCOMPILING
+ AND NOT DEFINED CMAKE_CXX_COMPILER_ID
+ AND NOT DEFINED CMAKE_C_COMPILER_ID
+ AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$"
+ )
+ )
+ set(_CARGO_ABI gnu)
+ elseif(("${CMAKE_C_COMPILER_ID}" MATCHES "Clang$" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$")
+ AND ("${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$"
+ OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu(llvm)?$")
+ )
+ if("${Rust_VERSION}" VERSION_GREATER_EQUAL "1.79")
+ set(_CARGO_ABI gnullvm)
+ else()
+ message(WARNING "Your selected C/C++ compilers suggest you want to use the -gnullvm"
+ " rust targets, however your Rust compiler version is ${Rust_VERSION}, which is"
+ " before the promotion of the gnullvm target to tier2."
+ " Please either use a more recent rust compiler or manually choose a target "
+ " triple by specifying `Rust_CARGO_TARGET` manually."
+ )
+ endif()
+ elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$")
+ # We first check if the gnu branches match to ensure this fallback is only used
+ # if no compiler is enabled.
+ set(_CARGO_ABI msvc)
+ else()
+ message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.")
+ endif()
+
+ if(DEFINED _CARGO_ARCH AND DEFINED _CARGO_VENDOR AND DEFINED _CARGO_ABI)
+ set(Rust_CARGO_TARGET_CACHED "${_CARGO_ARCH}-${_CARGO_VENDOR}-${_CARGO_ABI}"
+ CACHE STRING "Target triple")
+ endif()
+ elseif (ANDROID)
+ if (CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a)
+ if (CMAKE_ANDROID_ARM_MODE)
+ set(_Rust_ANDROID_TARGET armv7-linux-androideabi)
+ else ()
+ set(_Rust_ANDROID_TARGET thumbv7neon-linux-androideabi)
+ endif()
+ elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a)
+ set(_Rust_ANDROID_TARGET aarch64-linux-android)
+ elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86)
+ set(_Rust_ANDROID_TARGET i686-linux-android)
+ elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64)
+ set(_Rust_ANDROID_TARGET x86_64-linux-android)
+ endif()
+
+ if (_Rust_ANDROID_TARGET)
+ set(Rust_CARGO_TARGET_CACHED "${_Rust_ANDROID_TARGET}" CACHE STRING "Target triple")
+ endif()
+ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "OHOS")
+ if(CMAKE_OHOS_ARCH_ABI STREQUAL arm64-v8a)
+ set(_RUST_OHOS_TARGET aarch64-unknown-linux-ohos)
+ elseif(CMAKE_OHOS_ARCH_ABI STREQUAL armeabi-v7a)
+ set(_RUST_OHOS_TARGET armv7-unknown-linux-ohos)
+ elseif(CMAKE_OHOS_ARCH_ABI STREQUAL x86_64)
+ set(_RUST_OHOS_TARGET x86_64-unknown-linux-ohos)
+ else()
+ message(WARNING "unrecognized OHOS architecture: ${OHOS_ARCH}")
+ endif()
+ if(_RUST_OHOS_TARGET)
+ set(Rust_CARGO_TARGET_CACHED "${_RUST_OHOS_TARGET}" CACHE STRING "Target triple")
+ endif()
+ endif()
+ # Fallback to the default host target
+ if(NOT Rust_CARGO_TARGET_CACHED)
+ if(CMAKE_CROSSCOMPILING)
+ message(WARNING "CMake is in cross-compiling mode, but the cargo target-triple could not be inferred."
+ "Falling back to the default host target. Please consider manually setting `Rust_CARGO_TARGET`."
+ )
+ endif()
+ set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple")
+ endif()
+
+ message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}")
+endif()
+
+
+if(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED)
+ execute_process(COMMAND rustup target list --toolchain "${Rust_TOOLCHAIN}"
+ OUTPUT_VARIABLE AVAILABLE_TARGETS_RAW
+ )
+ string(REPLACE "\n" ";" AVAILABLE_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
+ string(REPLACE " (installed)" "" "AVAILABLE_TARGETS" "${AVAILABLE_TARGETS_RAW}")
+ set(INSTALLED_TARGETS_RAW "${AVAILABLE_TARGETS_RAW}")
+ list(FILTER INSTALLED_TARGETS_RAW INCLUDE REGEX " \\(installed\\)")
+ string(REPLACE " (installed)" "" "INSTALLED_TARGETS" "${INSTALLED_TARGETS_RAW}")
+ list(TRANSFORM INSTALLED_TARGETS STRIP)
+ if("${Rust_CARGO_TARGET_CACHED}" IN_LIST AVAILABLE_TARGETS)
+ message(DEBUG "Cargo target ${Rust_CARGO_TARGET} is an official target-triple")
+ message(DEBUG "Installed targets: ${INSTALLED_TARGETS}")
+ if(NOT ("${Rust_CARGO_TARGET_CACHED}" IN_LIST INSTALLED_TARGETS))
+ if(Rust_RUSTUP_INSTALL_MISSING_TARGET)
+ message(STATUS "Cargo target ${Rust_CARGO_TARGET_CACHED} is not installed. Installing via rustup.")
+ execute_process(COMMAND "${Rust_RUSTUP}" target add
+ --toolchain ${Rust_TOOLCHAIN}
+ ${Rust_CARGO_TARGET_CACHED}
+ RESULT_VARIABLE target_add_result
+ )
+ if(NOT "${target_add_result}" EQUAL "0")
+ message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain "
+ "${Rust_TOOLCHAIN} and automatically installing failed with ${target_add_result}.\n"
+ "You can try to manually install by running\n"
+ "`rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET}`."
+ )
+ endif()
+ message(STATUS "Installed target ${Rust_CARGO_TARGET_CACHED} successfully.")
+ else()
+ message(FATAL_ERROR "Target ${Rust_CARGO_TARGET_CACHED} is not installed for toolchain ${Rust_TOOLCHAIN}.\n"
+ "Help: Run `rustup target add --toolchain ${Rust_TOOLCHAIN} ${Rust_CARGO_TARGET_CACHED}` to install "
+ "the missing target or configure corrosion with `Rust_RUSTUP_INSTALL_MISSING_TARGET=ON`."
+ )
+ endif()
+ endif()
+ endif()
+endif()
+
+if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET)
+ set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling")
+else()
+ set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling")
+endif()
+
+_corrosion_parse_target_triple("${Rust_CARGO_TARGET_CACHED}" rust_arch rust_vendor rust_os rust_env)
+_corrosion_parse_target_triple("${Rust_CARGO_HOST_TARGET_CACHED}" rust_host_arch rust_host_vendor rust_host_os rust_host_env)
+
+set(Rust_CARGO_TARGET_ARCH "${rust_arch}" CACHE INTERNAL "Target architecture")
+set(Rust_CARGO_TARGET_VENDOR "${rust_vendor}" CACHE INTERNAL "Target vendor")
+set(Rust_CARGO_TARGET_OS "${rust_os}" CACHE INTERNAL "Target Operating System")
+set(Rust_CARGO_TARGET_ENV "${rust_env}" CACHE INTERNAL "Target environment")
+
+set(Rust_CARGO_HOST_ARCH "${rust_host_arch}" CACHE INTERNAL "Host architecture")
+set(Rust_CARGO_HOST_VENDOR "${rust_host_vendor}" CACHE INTERNAL "Host vendor")
+set(Rust_CARGO_HOST_OS "${rust_host_os}" CACHE INTERNAL "Host Operating System")
+set(Rust_CARGO_HOST_ENV "${rust_host_env}" CACHE INTERNAL "Host environment")
+
+if(NOT DEFINED CACHE{Rust_CARGO_TARGET_LINK_NATIVE_LIBS})
+ message(STATUS "Determining required link libraries for target ${Rust_CARGO_TARGET_CACHED}")
+ unset(required_native_libs)
+ _corrosion_determine_libs_new("${Rust_CARGO_TARGET_CACHED}" required_native_libs required_link_flags)
+ if(DEFINED required_native_libs)
+ message(STATUS "Required static libs for target ${Rust_CARGO_TARGET_CACHED}: ${required_native_libs}" )
+ endif()
+ if(DEFINED required_link_flags)
+ message(STATUS "Required link flags for target ${Rust_CARGO_TARGET_CACHED}: ${required_link_flags}" )
+ endif()
+ # In very recent corrosion versions it is possible to override the rust compiler version
+ # per target, so to be totally correct we would need to determine the libraries for
+ # every installed Rust version, that the user could choose from.
+ # In practice there aren't likely going to be any major differences, so we just do it once
+ # for the target and once for the host target (if cross-compiling).
+ set(Rust_CARGO_TARGET_LINK_NATIVE_LIBS "${required_native_libs}" CACHE INTERNAL
+ "Required native libraries when linking Rust static libraries")
+ set(Rust_CARGO_TARGET_LINK_OPTIONS "${required_link_flags}" CACHE INTERNAL
+ "Required link flags when linking Rust static libraries")
+endif()
+
+if(Rust_CROSSCOMPILING AND NOT DEFINED CACHE{Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS})
+ message(STATUS "Determining required link libraries for target ${Rust_CARGO_HOST_TARGET_CACHED}")
+ unset(host_libs)
+ _corrosion_determine_libs_new("${Rust_CARGO_HOST_TARGET_CACHED}" host_libs host_flags)
+ if(DEFINED host_libs)
+ message(STATUS "Required static libs for host target ${Rust_CARGO_HOST_TARGET_CACHED}: ${host_libs}" )
+ endif()
+ set(Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS "${host_libs}" CACHE INTERNAL
+ "Required native libraries when linking Rust static libraries for the host target")
+ set(Rust_CARGO_HOST_TARGET_LINK_OPTIONS "${host_flags}" CACHE INTERNAL
+ "Required linker flags when linking Rust static libraries for the host target")
+endif()
+
+# Set the input variables as non-cache variables so that the variables are available after
+# `find_package`, even if the values were evaluated to defaults.
+foreach(_VAR ${_Rust_USER_VARS})
+ set(${_VAR} "${${_VAR}_CACHED}")
+ # Ensure cached variables have type INTERNAL
+ set(${_VAR}_CACHED "${${_VAR}_CACHED}" CACHE INTERNAL "Internal cache of ${_VAR}")
+endforeach()
+
+find_package_handle_standard_args(
+ Rust
+ REQUIRED_VARS Rust_COMPILER Rust_VERSION Rust_CARGO Rust_CARGO_VERSION Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET
+ VERSION_VAR Rust_VERSION
+)
+
+
+if(NOT TARGET Rust::Rustc)
+ add_executable(Rust::Rustc IMPORTED GLOBAL)
+ set_property(
+ TARGET Rust::Rustc
+ PROPERTY IMPORTED_LOCATION "${Rust_COMPILER_CACHED}"
+ )
+
+ add_executable(Rust::Cargo IMPORTED GLOBAL)
+ set_property(
+ TARGET Rust::Cargo
+ PROPERTY IMPORTED_LOCATION "${Rust_CARGO_CACHED}"
+ )
+ set(Rust_FOUND true)
+endif()
+
+list(POP_BACK CMAKE_MESSAGE_CONTEXT)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/.gitignore Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,1 @@
+book
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/book.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+[book]
+language = "en"
+multilingual = false
+src = "src"
+title = "Corrosion documentation"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/SUMMARY.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+# Summary
+
+- [Introduction](./introduction.md)
+- [Quick Start](./quick_start.md)
+- [Setup Corrosion](./setup_corrosion.md)
+- [Usage](./usage.md)
+- [Advanced](./advanced.md)
+- [FFI binding integrations](./ffi_bindings.md)
+- [Common Issues](./common_issues.md)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/advanced.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,100 @@
+## What does corrosion do?
+
+The specifics of what corrosion does should be regarded as an implementation detail and not relied on
+when writing user code. However, a basic understanding of what corrosion does may be helpful when investigating
+issues.
+
+### FindRust
+
+Corrosion maintains a CMake module `FindRust` which is executed when Corrosion is loaded, i.e. at the time
+of `find_package(corrosion)`, `FetchContent_MakeAvailable(corrosion)` or `add_subdirectory(corrosion)` depending
+on the method used to include Corrosion.
+
+`FindRust` will search for installed rust toolchains, respecting the options prefixed with `Rust_` documented in
+the [Usage](usage.md#corrosion-options) chapter.
+It will select _one_ Rust toolchain to be used for the compilation of Rust code. Toolchains managed by `rustup`
+will be resolved and corrosion will always select a specific toolchain, not a `rustup` proxy.
+
+
+### Importing Rust crates
+
+Corrosion's main function is `corrosion_import_crate`, which internally will call `cargo metadata` to provide
+structured information based on the `Cargo.toml` manifest.
+Corrosion will then iterate over all workspace and/or package members and find all rust crates that are either
+a static (`staticlib`) or shared (`cdylib`) library or a `bin` target and create CMake targets matching the
+crate name. Additionally, a build target is created for each imported target, containing the required build
+command to create the imported artifact. This build command can be influenced by various arguments to
+`corrosion_import_crate` as well as corrosion specific target properties which are documented int the
+[Usage](usage.md) chapter.
+Corrosion adds the necessary dependencies and also copies the target artifacts out of the cargo build tree
+to standard CMake locations, even respecting `OUTPUT_DIRECTORY` target properties if set.
+
+### Linking
+
+Depending on the type of the crate the linker will either be invoked by CMake or by `rustc`.
+Rust `staticlib`s are linked into C/C++ code via `target_link_libraries()` and the linker is
+invoked by CMake.
+For rust `cdylib`s and `bin`s, the linker is invoked via `rustc` and CMake just gets the final artifact.
+
+#### CMake invokes the linker
+
+When CMake invokes the linker, everything is as usual. CMake will call the linker with
+the compiler as the linker driver and users can just use the regular CMake functions to
+modify linking behaviour. `corrosion_set_linker()` has **no effect**.
+As a convenience, `corrosion_link_libraries()` will forward its arguments to `target_link_libraries()`.
+
+#### Rustc invokes the linker
+
+Rust `cdylib`s and `bin`s are linked via `rustc`. Corrosion provides several helper functions
+to influence the linker invocation for such targets.
+
+`corrosion_link_libraries()` is a limited version of `target_link_libraries()`
+for rust `cdylib` or `bin` targets.
+Under the hood this function passes `-l` and `-L` flags to the linker invocation and
+ensures the linked libraries are built first.
+Much of the advanced functionality available in `target_link_libraries()` is not implemented yet,
+but pull-requests are welcome! In the meantime, users may want to use
+`corrosion_add_target_local_rustflags()` to pass customized linking flags.
+
+`corrosion_set_linker()` can be used to specify a custom linker, in case the default one
+chosen by corrosion is not what you want.
+Corrosion currently instructs `rustc` to use the C/C++ compiler as the linker driver.
+This is done because:
+- For C++ code we must link with `libstdc++` or `libc++` (depending on the compiler), so we must
+ either specify the library on the link line or use a `c++` compiler as the linker driver.
+- `Rustc`s default linker selection currently is not so great. For a number of platforms
+ `rustc` will fallback to `cc` as the linker driver. When cross-compiling, this leads
+ to linking failures, since the linker driver is for the host architecture.
+ Corrosion avoids this by specifying the C/C++ compiler as the linker driver.
+
+
+In some cases, especially in older rust versions (pre 1.68), the linker flavor detection
+of `rustc` is also not correct, so when setting a custom linker you may want to pass the
+[`-C linker-flavor`](https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-flavor)
+rustflag via `corrosion_add_target_local_rustflags()`.
+
+## FFI bindings
+
+For interaction between Rust and other languages there need to be some FFI bindings of some sort.
+For simple cases manually defining the interfaces may be sufficient, but in many cases users
+wish to use tools like [bindgen], [cbindgen], [cxx] or [autocxx] to automate the generating of
+bindings.
+
+In principle there are two different ways to generate the bindings:
+- use a `build.rs` script to generate the bindings when cargo is invoked, using
+ library versions of the tools to generate the bindings.
+- use the cli versions of the tools and setup custom CMake targets/commands to
+ generate the bindings. This approach should be preferred if the bindings are needed
+ by the C/C++ side.
+
+Corrosion currently provides 2 experimental functions to integrate cbindgen and cxx into
+the build process. They are not 100% production ready yet, but should work well as a
+template on how to integrate generating bindings into your build process.
+
+Todo: expand this documentation and link to other resources.
+
+[bindgen]: https://rust-lang.github.io/rust-bindgen/
+[cbindgen]: https://github.com/eqrion/cbindgen
+[cxx]: https://cxx.rs/
+[autocxx]: https://google.github.io/autocxx/index.html
+
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/common_issues.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,88 @@
+# Commonly encountered (Non-Corrosion) Issues
+
+## Table of Contents
+
+- [Linking Debug C/C++ libraries into Rust fails on Windows MSVC targets](#linking-debug-cc-libraries-into-rust-fails-on-windows-msvc-targets)
+- [Linking Rust static libraries into Debug C/C++ binaries fails on Windows MSVC targets](#linking-rust-static-libraries-into-debug-cc-binaries-fails-on-windows-msvc-targets)
+- [Missing `soname` on Linux for `cdylibs`](#missing-soname-on-linux-for-cdylibs)
+- [Missing `install_name` on MacOS for `ccdylibs` / Hardcoded references to the build-directory](#missing-installname-on-macos-for-ccdylibs--hardcoded-references-to-the-build-directory)
+
+## Linking Debug C/C++ libraries into Rust fails on Windows MSVC targets
+
+`rustc` always links against the non-debug Windows runtime on `*-msvc` targets.
+This is tracked [in this issue](https://github.com/rust-lang/rust/issues/39016)
+and could be fixed upstream.
+
+A typical error message for this issue is:
+
+```
+ Compiling rust_bin v0.1.0 (D:\a\corrosion\corrosion\test\cxxbridge\cxxbridge_cpp2rust\rust)
+error: linking with `link.exe` failed: exit code: 1319
+[ redacted ]
+ = note: cxxbridge-cpp.lib(lib.cpp.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in libcxx-bafec361a1a30317.rlib(cxx.o)
+
+ cxxbridge-cpp.lib(lib.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in libcxx-bafec361a1a30317.rlib(cxx.o)
+
+ cpp_lib.lib(cpplib.cpp.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in libcxx-bafec361a1a30317.rlib(cxx.o)
+
+ cpp_lib.lib(cpplib.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in libcxx-bafec361a1a30317.rlib(cxx.o)
+
+ msvcrt.lib(initializers.obj) : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
+```
+
+### Solutions
+
+One solution is to also use the non-debug version when building the C/C++ libraries.
+You can set the [MSVC_RUNTIME_LIBRARY] target properties of your C/C++ libraries to the non-debug variants.
+By default you will probably want to select the `MultiThreadedDLL` variant, unless you specified
+[`-Ctarget-feature=+crt-static`](https://rust-lang.github.io/rfcs/1721-crt-static.html) in your
+`RUSTFLAGS`.
+
+
+[MSVC_RUNTIME_LIBRARY]: https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html#prop_tgt:MSVC_RUNTIME_LIBRARY
+
+## Linking Rust static libraries into Debug C/C++ binaries fails on Windows MSVC targets
+
+This issue is quite similar to the previous one, except that this time it's a Rust library being linked
+into a C/C++ target. If it's 100% only Rust code you likely won't even have any issues.
+However, if somewhere in the dependency graph C/C++ code is built and linked into your Rust library,
+you will likely encounter this issue. Please note, that using [cxx] counts as using C++ code and will
+lead to this issue.
+
+The previous solution should also work for this case, but additionally you [may also
+have success](https://github.com/rust-lang/rust/issues/39016#issuecomment-853964918) by using
+`corrosion_set_env_vars(your_rust_lib "CFLAGS=-MDd" "CXXFLAGS=-MDd")` (or `-MTd` for a statically linked
+runtime).
+For debug builds, this is likely to be the preferable solution. It assumes that downstream C/C++ code
+is built by the `cc` crate, which respects the `CFLAGS` and `CXXFLAGS` environment variables.
+
+[cxx]: https://github.com/dtolnay/cxx
+
+
+## Missing `soname` on Linux for `cdylibs`
+
+Cargo doesn't support setting the `soname` field for cdylib, which may cause issues.
+You can set the soname manually by passing a linker-flag such as `-Clink-arg=-Wl,-soname,libyour_crate.so`
+to the linker via `corrosion_add_target_local_rustflags()` and additionally seting the `IMPORTED_SONAME`
+property on the import CMake target:
+```
+set_target_properties(your_crate-shared PROPERTIES IMPORTED_SONAME libyour_crate.so)
+```
+Replace `your_crate` with the name of your shared library as defined in the `[lib]` section of your Cargo.toml
+Manifest file.
+
+Attention: The Linux section may not be entirely correct, maybe `$ORIGIN` needs to be added to the linker arguments.
+Feel free to open a pull-request with corrections.
+
+## Missing `install_name` on MacOS for `ccdylibs` / Hardcoded references to the build-directory
+
+The solution here is essentially the same as in the previous section.
+```
+corrosion_add_target_local_rustflags(your_crate -Clink-arg=-Wl,-install_name,@rpath/libyour_crate.dylib,-current_version,${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR},-compatibility_version,${PROJECT_VERSION_MAJOR}.0)
+set_target_properties(your_crate-shared PROPERTIES IMPORTED_NO_SONAME 0)
+set_target_properties(your_crate-shared PROPERTIES IMPORTED_SONAME libyour_crate.dylib)
+```
+When building binaries using this shared library, you should set the build rpath to the output directory of
+your shared library, e.g. by setting `set(CMAKE_BUILD_RPATH ${YOUR_CUSTOM_OUTPUT_DIRECTORY})` before adding
+executables.
+For a practical example, you may look at [Slint PR 2455](https://github.com/slint-ui/slint/pull/2455).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/ffi_bindings.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,43 @@
+# Integrating Automatically Generated FFI Bindings
+
+There are a number of tools to automatically generate bindings between Rust and different
+foreign languages.
+
+1. [bindgen](#bindgen)
+2. [cbindgen](#cbindgen-integration)
+3. [cxx](#cxx-integration)
+
+## bindgen
+
+[bindgen] is a tool to automatically generate Rust bindings from C headers.
+As such, integrating bindgen [via a build-script](https://rust-lang.github.io/rust-bindgen/library-usage.html)
+works well and their doesn't seem to be a need to create CMake rules for
+generating the bindings.
+
+[bindgen]: https://github.com/rust-lang/rust-bindgen
+
+## cbindgen integration
+
+⚠️⚠️⚠️ **EXPERIMENTAL** ⚠️⚠️⚠️
+
+[cbindgen] is a tool that generates C/C++ headers from Rust code. When compiling C/C++
+code that `#include`s such generated headers the buildsystem must be aware of the dependencies.
+Generating the headers via a build-script is possible, but Corrosion offers no guidance here.
+
+Instead, Corrosion offers an experimental function to add CMake rules using cbindgen to generate
+the headers.
+This is not available on a stable released version yet, and the details are subject to change.
+{{#include ../../cmake/Corrosion.cmake:corrosion_cbindgen}}
+
+### Current limitations
+
+- The current version regenerates the bindings more often then necessary to be on the safe side,
+ but an upstream PR is open to solve this in a future cbindgen version.
+
+## cxx integration
+
+⚠️⚠️⚠️ **EXPERIMENTAL** ⚠️⚠️⚠️
+
+[cxx] is a tool which generates bindings for C++/Rust interop.
+
+{{#include ../../cmake/Corrosion.cmake:corrosion_add_cxxbridge}}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/introduction.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,19 @@
+## About Corrosion
+
+Corrosion, formerly known as cmake-cargo, is a tool for integrating Rust into an existing CMake
+project. Corrosion is capable of automatically importing executables, static libraries, and
+dynamic libraries from a Rust package or workspace as CMake targets.
+
+The imported static and dynamic library types can be linked into C/C++ CMake targets using the usual
+CMake functions such as [`target_link_libraries()`].
+For rust executables and dynamic libraries corrosion provides a `corrosion_link_libraries`
+helper function to conveniently add the necessary flags to link C/C++ libraries into
+the rust target.
+
+## Requirements
+
+- Corrosion supports CMake 3.15 and newer with the v0.5 release. If you are using the v0.5 release, please
+ view [the documentation here](./v0.5/introduction.md)
+- The master branch of Corrosion currently requires CMake 3.22 or newer.
+
+[`target_link_libraries()`]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/quick_start.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,37 @@
+# Quick Start
+
+You can add corrosion to your project via the `FetchContent` CMake module or one of the other methods
+described in the [Setup chapter](setup_corrosion.md).
+Afterwards you can import Rust targets defined in a `Cargo.toml` manifest file by using
+`corrosion_import_crate`. This will add CMake targets with names matching the crate names defined
+in the Cargo.toml manifest. These targets can then subsequently be used, e.g. to link the imported
+target into a regular C/C++ target.
+
+The example below shows how to add Corrosion to your project via `FetchContent`
+and how to import a rust library and link it into a regular C/C++ CMake target.
+
+```cmake
+include(FetchContent)
+
+FetchContent_Declare(
+ Corrosion
+ GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
+ GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
+)
+# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line!
+FetchContent_MakeAvailable(Corrosion)
+
+# Import targets defined in a package or workspace manifest `Cargo.toml` file
+corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml)
+
+add_executable(your_cool_cpp_bin main.cpp)
+
+# In this example the the `Cargo.toml` file passed to `corrosion_import_crate` is assumed to have
+# defined a static (`staticlib`) or shared (`cdylib`) rust library with the name "rust-lib".
+# A target with the same name is now available in CMake and you can use it to link the rust library into
+# your C/C++ CMake target(s).
+target_link_libraries(your_cool_cpp_bin PUBLIC rust-lib)
+```
+
+
+Please see the [Usage chapter](usage.md) for a complete discussion of possible configuration options.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/setup_corrosion.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,89 @@
+# Adding Corrosion to your project
+
+There are two fundamental installation methods that are supported by Corrosion - installation as a
+CMake package or using it as a subdirectory in an existing CMake project. For CMake versions below
+3.19 Corrosion strongly recommends installing the package, either via a package manager or manually
+using CMake's installation facilities.
+If you have CMake 3.19 or newer, we recommend to use either the [FetchContent](#fetchcontent) or the
+[Subdirectory](#subdirectory) method to integrate Corrosion.
+
+## FetchContent
+If you are using CMake >= 3.19 or installation is difficult or not feasible in
+your environment, you can use the
+[FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module to include
+Corrosion. This will download Corrosion and use it as if it were a subdirectory at configure time.
+
+In your CMakeLists.txt:
+```cmake
+include(FetchContent)
+
+FetchContent_Declare(
+ Corrosion
+ GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
+ GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
+)
+# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line!
+FetchContent_MakeAvailable(Corrosion)
+```
+
+## Subdirectory
+Corrosion can also be used directly as a subdirectory. This solution may work well for small
+projects, but it's discouraged for large projects with many dependencies, especially those which may
+themselves use Corrosion. Either copy the Corrosion library into your source tree, being sure to
+preserve the `LICENSE` file, or add this repository as a git submodule:
+```bash
+git submodule add https://github.com/corrosion-rs/corrosion.git
+```
+
+From there, using Corrosion is easy. In your CMakeLists.txt:
+```cmake
+add_subdirectory(path/to/corrosion)
+```
+
+## Installation
+
+
+Installation will pre-build all of Corrosion's native tooling (required only for CMake versions
+below 3.19) and install it together with Corrosions CMake files into a standard location.
+On CMake >= 3.19 installing Corrosion does not offer any speed advantages, unless the native
+tooling option is explicitly enabled.
+
+### Install from source
+
+First, download and install Corrosion:
+```bash
+git clone https://github.com/corrosion-rs/corrosion.git
+# Optionally, specify -DCMAKE_INSTALL_PREFIX=<target-install-path> to specify a
+# custom installation directory
+cmake -Scorrosion -Bbuild -DCMAKE_BUILD_TYPE=Release
+cmake --build build --config Release
+# This next step may require sudo or admin privileges if you're installing to a system location,
+# which is the default.
+cmake --install build --config Release
+```
+
+You'll want to ensure that the install directory is available in your `PATH` or `CMAKE_PREFIX_PATH`
+environment variable. This is likely to already be the case by default on a Unix system, but on
+Windows it will install to `C:\Program Files (x86)\Corrosion` by default, which will not be in your
+`PATH` or `CMAKE_PREFIX_PATH` by default.
+
+Once Corrosion is installed, and you've ensured the package is available in your `PATH`, you
+can use it from your own project like any other package from your CMakeLists.txt:
+```cmake
+find_package(Corrosion REQUIRED)
+```
+
+### Package Manager
+
+#### Homebrew (unofficial)
+
+Corrosion is available via Homebrew and can be installed via
+
+```bash
+brew install corrosion
+```
+
+Please note that this package is community maintained. Please also keep in mind that Corrosion follows
+semantic versioning and minor version bumps (i.e. `0.3` -> `0.4`) may contain breaking changes, while
+Corrosion is still pre `1.0`.
+Please read the release notes when upgrading Corrosion.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/doc/src/usage.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,405 @@
+## Usage
+
+### Automatically import crate targets with `corrosion_import_crate`
+
+In order to integrate a Rust crate into CMake, you first need to import Rust crates from
+a [package] or [workspace]. Corrosion provides `corrosion_import_crate()` to automatically import
+crates defined in a Cargo.toml Manifest file:
+
+{{#include ../../cmake/Corrosion.cmake:corrosion-import-crate}}
+
+Corrosion will use `cargo metadata` to add a cmake target for each crate defined in the Manifest file
+and add the necessary rules to build the targets.
+For Rust executables an [`IMPORTED`] executable target is created with the same name as defined in the `[[bin]]`
+section of the Manifest corresponding to this target.
+If no such name was defined the target name defaults to the Rust package name.
+For Rust library targets an [`INTERFACE`] library target is created with the same name as defined in the `[lib]`
+section of the Manifest. This `INTERFACE` library links an internal corrosion target, which is either a
+`SHARED` or `STATIC` `IMPORTED` library, depending on the Rust crate type (`cdylib` vs `staticlib`).
+
+The created library targets can be linked into other CMake targets by simply using [target_link_libraries].
+
+Corrosion will by default copy the produced Rust artifacts into `${CMAKE_CURRENT_BINARY_DIR}`. The target location
+can be changed by setting the CMake `OUTPUT_DIRECTORY` target properties on the imported Rust targets.
+See the [OUTPUT_DIRECTORY](#cmake-output_directory-target-properties-and-imported_location) section for more details.
+
+Many of the options available for `corrosion_import_crate` can also be individually set per
+target, see [Per Target options](#per-target-options) for details.
+
+[package]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html
+[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
+[`IMPORTED`]: https://cmake.org/cmake/help/latest/prop_tgt/IMPORTED.html
+[`INTERFACE`]: https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries
+[target_link_libraries]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html
+
+### Experimental: Install crate and headers with `corrosion_install`
+
+The default CMake [install commands] do not work correctly with the targets exported from `corrosion_import_crate()`.
+Corrosion provides `corrosion_install` to automatically install relevant files:
+
+{{#include ../../cmake/Corrosion.cmake:corrosion-install}}
+
+The example below shows how to import a rust library and make it available for install through CMake.
+
+```cmake
+include(FetchContent)
+
+FetchContent_Declare(
+ Corrosion
+ GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
+ GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
+)
+# Set any global configuration variables such as `Rust_TOOLCHAIN` before this line!
+FetchContent_MakeAvailable(Corrosion)
+
+# Import targets defined in a package or workspace manifest `Cargo.toml` file
+corrosion_import_crate(MANIFEST_PATH rust-lib/Cargo.toml)
+
+# Add a manually written header file which will be exported
+# Requires CMake >=3.23
+target_sources(rust-lib INTERFACE
+ FILE_SET HEADERS
+ BASE_DIRS include
+ FILES
+ include/rust-lib/rust-lib.h
+)
+
+# OR for CMake <= 3.23
+target_include_directories(is_odd INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:include>
+)
+target_sources(is_odd
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/rust-lib/rust-lib.h>
+ $<INSTALL_INTERFACE:include/rust-lib/rust-lib.h>
+)
+
+# Rust libraries must be installed using `corrosion_install`.
+corrosion_install(TARGETS rust-lib EXPORT RustLibTargets)
+
+# Installs the main target
+install(
+ EXPORT RustLibTargets
+ NAMESPACE RustLib::
+ DESTINATION lib/cmake/RustLib
+)
+
+# Necessary for packaging helper commands
+include(CMakePackageConfigHelpers)
+# Create a file for checking version compatibility
+# Optional
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/RustLibConfigVersion.cmake"
+ VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
+ COMPATIBILITY AnyNewerVersion
+)
+
+# Configures the main config file that cmake loads
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/RustLibConfig.cmake"
+ INSTALL_DESTINATION lib/cmake/RustLib
+ NO_SET_AND_CHECK_MACRO
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+)
+# Config.cmake.in contains
+# @PACKAGE_INIT@
+#
+# include(${CMAKE_CURRENT_LIST_DIR}/RustLibTargetsCorrosion.cmake)
+# include(${CMAKE_CURRENT_LIST_DIR}/RustLibTargets.cmake)
+
+# Install all generated files
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/RustLibConfigVersion.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/RustLibConfig.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/corrosion/RustLibTargetsCorrosion.cmake
+ DESTINATION lib/cmake/RustLib
+)
+```
+
+[install commands]: https://cmake.org/cmake/help/latest/command/install.html
+
+### Per Target options
+
+Some configuration options can be specified individually for each target. You can set them via the
+`corrosion_set_xxx()` functions specified below:
+
+- `corrosion_set_env_vars(<target_name> <key1=value1> [... <keyN=valueN>])`: Define environment variables
+ that should be set during the invocation of `cargo build` for the specified target. Please note that
+ the environment variable will only be set for direct builds of the target via cmake, and not for any
+ build where cargo built the crate in question as a dependency for another target.
+ The environment variables may contain generator expressions.
+- `corrosion_add_target_rustflags(<target_name> <rustflag> [... <rustflagN>])`: When building the target,
+ the `RUSTFLAGS` environment variable will contain the flags added via this function. Please note that any
+ dependencies (built by cargo) will also see these flags. See also: `corrosion_add_target_local_rustflags`.
+- `corrosion_add_target_local_rustflags(target_name rustc_flag [more_flags ...])`: Support setting
+ rustflags for only the main target (crate) and none of its dependencies.
+ This is useful in cases where you only need rustflags on the main-crate, but need to set different
+ flags for different targets. Without "local" Rustflags this would require rebuilds of the
+ dependencies when switching targets.
+- `corrosion_set_hostbuild(<target_name>)`: The target should be compiled for the Host target and ignore any
+ cross-compile configuration.
+- `corrosion_set_features(<target_name> [ALL_FEATURES <Bool>] [NO_DEFAULT_FEATURES] [FEATURES <feature1> ... ])`:
+ For a given target, enable specific features via `FEATURES`, toggle `ALL_FEATURES` on or off or disable all features
+ via `NO_DEFAULT_FEATURES`. For more information on features, please see also the
+ [cargo reference](https://doc.rust-lang.org/cargo/reference/features.html).
+- `corrosion_set_cargo_flags(<target_name> <flag1> ...])`:
+ For a given target, add options and flags at the end of `cargo build` invocation. This will be appended after any
+ arguments passed through the `FLAGS` during the crate import.
+- `corrosion_set_linker(target_name linker)`: Use `linker` to link the target.
+ Please note that this only has an effect for targets where the final linker invocation is done
+ by cargo, i.e. targets where foreign code is linked into rust code and not the other way around.
+ Please also note that if you are cross-compiling and specify a linker such as `clang`, you are
+ responsible for also adding a rustflag which adds the necessary `--target=` argument for the
+ linker.
+
+
+### Global Corrosion Options
+
+#### Selecting the Rust toolchain and target triple
+
+The following variables are evaluated automatically in most cases. In typical cases you
+shouldn't need to alter any of these. If you do want to specify them manually, make sure to set
+them **before** `find_package(Corrosion REQUIRED)`.
+
+- `Rust_TOOLCHAIN:STRING` - Specify a named rustup toolchain to use. Changes to this variable
+ resets all other options. Default: If the first-found `rustc` is a `rustup` proxy, then the default
+ rustup toolchain (see `rustup show`) is used. Otherwise, the variable is unset by default.
+- `Rust_ROOT:STRING` - CMake provided. Path to a Rust toolchain to use. This is an alternative if
+ you want to select a specific Rust toolchain, but it's not managed by rustup. Default: Nothing
+- `Rust_COMPILER:STRING` - Path to `rustc`, which should be used for compiling or for toolchain
+ detection (if it is a `rustup` proxy). Default: The `rustc` in the first-found toolchain, either
+ from `rustup`, or from a toolchain available in the user's `PATH`.
+- `Rust_RESOLVE_RUSTUP_TOOLCHAINS:BOOL` - If the found `rustc` is a `rustup` proxy, resolve a
+ concrete path to a specific toolchain managed by `rustup`, according to the `rustup` toolchain
+ selection rules and other options detailed here. If this option is turned off, the found `rustc`
+ will be used as-is to compile, even if it is a `rustup` proxy, which might increase compilation
+ time. Default: `ON` if the found `rustc` is a rustup proxy or a `rustup` managed toolchain was
+ requested, `OFF` otherwise. Forced `OFF` if `rustup` was not found.
+- `Rust_CARGO:STRING` - Path to `cargo`. Default: the `cargo` installed next to `${Rust_COMPILER}`.
+- `Rust_CARGO_TARGET:STRING` - The default target triple to build for. Alter for cross-compiling.
+ Default: On Visual Studio Generator, the matching triple for `CMAKE_VS_PLATFORM_NAME`. Otherwise,
+ the default target triple reported by `${Rust_COMPILER} --version --verbose`.
+
+#### Enable Convenience Options
+
+The following options are off by default, but may increase convenience:
+
+- `Rust_RUSTUP_INSTALL_MISSING_TARGET:BOOL`: Automatically install a missing target via `rustup` instead of failing.
+
+
+#### Developer/Maintainer Options
+These options are not used in the course of normal Corrosion usage, but are used to configure how
+Corrosion is built and installed. Only applies to Corrosion builds and subdirectory uses.
+
+- `CORROSION_BUILD_TESTS:BOOL` - Build the Corrosion tests. Default: `Off` if Corrosion is a
+ subdirectory, `ON` if it is the top-level project
+
+
+### Information provided by Corrosion
+
+For your convenience, Corrosion sets a number of variables which contain information about the version of the rust
+toolchain. You can use the CMake version comparison operators
+(e.g. [`VERSION_GREATER_EQUAL`](https://cmake.org/cmake/help/latest/command/if.html#version-comparisons)) on the main
+variable (e.g. `if(Rust_VERSION VERSION_GREATER_EQUAL "1.57.0")`), or you can inspect the major, minor and patch
+versions individually.
+- `Rust_VERSION<_MAJOR|_MINOR|_PATCH>` - The version of rustc.
+- `Rust_CARGO_VERSION<_MAJOR|_MINOR|_PATCH>` - The cargo version.
+- `Rust_LLVM_VERSION<_MAJOR|_MINOR|_PATCH>` - The LLVM version used by rustc.
+- `Rust_IS_NIGHTLY` - 1 if a nightly toolchain is used, otherwise 0. Useful for selecting an unstable feature for a
+ crate, that is only available on nightly toolchains.
+- Cache variables containing information based on the target triple for the selected target
+ as well as the default host target:
+ - `Rust_CARGO_TARGET_ARCH`, `Rust_CARGO_HOST_ARCH`: e.g. `x86_64` or `aarch64`
+ - `Rust_CARGO_TARGET_VENDOR`, `Rust_CARGO_HOST_VENDOR`: e.g. `apple`, `pc`, `unknown` etc.
+ - `Rust_CARGO_TARGET_OS`, `Rust_CARGO_HOST_OS`: e.g. `darwin`, `linux`, `windows`, `none`
+ - `Rust_CARGO_TARGET_ENV`, `Rust_CARGO_HOST_ENV`: e.g. `gnu`, `musl`
+
+
+
+
+### Selecting a custom cargo profile
+
+[Rust 1.57](https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html) stabilized the support for custom
+[profiles](https://doc.rust-lang.org/cargo/reference/profiles.html). If you are using a sufficiently new rust toolchain,
+you may select a custom profile by adding the optional argument `PROFILE <profile_name>` to
+`corrosion_import_crate()`. If you do not specify a profile, or you use an older toolchain, corrosion will select
+the standard `dev` profile if the CMake config is either `Debug` or unspecified. In all other cases the `release`
+profile is chosen for cargo.
+
+### Importing C-Style Libraries Written in Rust
+Corrosion makes it completely trivial to import a crate into an existing CMake project. Consider
+a project called [rust2cpp](test/rust2cpp/rust2cpp) with the following file structure:
+```
+rust2cpp/
+ rust/
+ src/
+ lib.rs
+ Cargo.lock
+ Cargo.toml
+ CMakeLists.txt
+ main.cpp
+```
+
+This project defines a simple Rust lib crate, like so, in [`rust2cpp/rust/Cargo.toml`](test/rust2cpp/rust2cpp/rust/Cargo.toml):
+```toml
+[package]
+name = "rust-lib"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib"]
+```
+
+In addition to `"staticlib"`, you can also use `"cdylib"`. In fact, you can define both with a
+single crate and switch between which is used using the standard
+[`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) variable.
+
+This crate defines a simple crate called `rust-lib`. Importing this crate into your
+[CMakeLists.txt](test/rust2cpp/CMakeLists.txt) is trivial:
+```cmake
+# Note: you must have already included Corrosion for `corrosion_import_crate` to be available. See # the `Installation` section above.
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+```
+
+Now that you've imported the crate into CMake, all of the executables, static libraries, and dynamic
+libraries defined in the Rust can be directly referenced. So, merely define your C++ executable as
+normal in CMake and add your crate's library using target_link_libraries:
+```cmake
+add_executable(cpp-exe main.cpp)
+target_link_libraries(cpp-exe PUBLIC rust-lib)
+```
+
+That's it! You're now linking your Rust library to your C++ library.
+
+#### Generate Bindings to Rust Library Automatically
+
+Currently, you must manually declare bindings in your C or C++ program to the exported routines and
+types in your Rust project. You can see boths sides of this in
+[the Rust code](test/rust2cpp/rust2cpp/rust/src/lib.rs) and in [the C++ code](test/rust2cpp/rust2cpp/main.cpp).
+
+Integration with [cbindgen](https://github.com/eqrion/cbindgen) is
+planned for the future.
+
+### Importing Libraries Written in C and C++ Into Rust
+
+The rust targets can be imported with `corrosion_import_crate()` into CMake.
+For targets where the linker should be invoked by Rust corrosion provides
+`corrosion_link_libraries()` to link your C/C++ libraries with the Rust target.
+For additional linker flags you may use `corrosion_add_target_local_rustflags()`
+and pass linker arguments via the `-Clink-args` flag to rustc. These flags will
+only be passed to the final rustc invocation and not affect any rust dependencies.
+
+C bindings can be generated via [bindgen](https://github.com/rust-lang/rust-bindgen).
+Corrosion does not offer any direct integration yet, but you can either generate the
+bindings in the build-script of your crate, or generate the bindings as a CMake build step
+(e.g. a custom target) and add a dependency from `cargo-prebuild_<rust_target>` to your
+custom target for generating the bindings.
+
+Example:
+
+```cmake
+# Import your Rust targets
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+# Link C/C++ libraries with your Rust target
+corrosion_link_libraries(target_name c_library)
+# Optionally explicitly define which linker to use.
+corrosion_set_linker(target_name your_custom_linker)
+# Optionally set linker arguments
+corrosion_add_target_local_rustflags(target_name "-Clink-args=<linker arguments>")
+# Optionally tell CMake that the rust crate depends on another target (e.g. a code generator)
+add_dependencies(cargo-prebuild_<target_name> custom_bindings_target)
+```
+
+### Cross Compiling
+Corrosion attempts to support cross-compiling as generally as possible, though not all
+configurations are tested. Cross-compiling is explicitly supported in the following scenarios.
+
+In all cases, you will need to install the standard library for the Rust target triple. When using
+Rustup, you can use it to install the target standard library:
+
+```bash
+rustup target add <target-rust-triple>
+```
+
+If the target triple is automatically derived, Corrosion will print the target during configuration.
+For example:
+
+```
+-- Rust Target: aarch64-linux-android
+```
+
+#### Windows-to-Windows
+Corrosion supports cross-compiling between arbitrary Windows architectures using the Visual Studio
+Generator. For example, to cross-compile for ARM64 from any platform, simply set the `-A`
+architecture flag:
+
+```bash
+cmake -S. -Bbuild-arm64 -A ARM64
+cmake --build build-arm64
+```
+
+Please note that for projects containing a build-script at least Rust 1.54 is required due to a bug
+in previous cargo versions, which causes the build-script to incorrectly be built for the target
+platform.
+
+#### Linux-to-Linux
+In order to cross-compile on Linux, you will need to install a cross-compiler. For example, on
+Ubuntu, to cross compile for 64-bit Little-Endian PowerPC Little-Endian, install
+`g++-powerpc64le-linux-gnu` from apt-get:
+
+```bash
+sudo apt install g++-powerpc64le-linux-gnu
+```
+
+Currently, Corrosion does not automatically determine the target triple while cross-compiling on
+Linux, so you'll need to specify a matching `Rust_CARGO_TARGET`.
+
+```bash
+cmake -S. -Bbuild-ppc64le -DRust_CARGO_TARGET=powerpc64le-unknown-linux-gnu -DCMAKE_CXX_COMPILER=powerpc64le-linux-gnu-g++
+cmake --build build-ppc64le
+```
+
+#### Android
+
+Cross-compiling for Android is supported on all platforms with the Makefile and Ninja generators,
+and the Rust target triple will automatically be selected. The CMake
+[cross-compiling instructions for Android](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android)
+apply here. For example, to build for ARM64:
+
+```bash
+cmake -S. -Bbuild-android-arm64 -GNinja -DCMAKE_SYSTEM_NAME=Android \
+ -DCMAKE_ANDROID_NDK=/path/to/android-ndk-rxxd -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a
+```
+
+**Important note:** The Android SDK ships with CMake 3.10 at newest, which Android Studio will
+prefer over any CMake you've installed locally. CMake 3.10 is insufficient for using Corrosion,
+which requires a minimum of CMake 3.22. If you're using Android Studio to build your project,
+follow the instructions in the Android Studio documentation for
+[using a specific version of CMake](https://developer.android.com/studio/projects/install-ndk#vanilla_cmake).
+
+
+### CMake `OUTPUT_DIRECTORY` target properties and `IMPORTED_LOCATION`
+
+Corrosion respects the following `OUTPUT_DIRECTORY` target properties:
+- [ARCHIVE_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.html)
+- [LIBRARY_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html)
+- [RUNTIME_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html)
+- [PDB_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html)
+
+If the target property is set (e.g. by defining the `CMAKE_XYZ_OUTPUT_DIRECTORY` variable before calling
+`corrosion_import_crate()`), corrosion will copy the built rust artifacts to the location defined in the
+target property.
+Due to limitations in CMake these target properties are evaluated in a deferred manner, to
+support the user setting the target properties after the call to `corrosion_import_crate()`.
+This has the side effect that the `IMPORTED_LOCATION` property will be set late, and users should not
+use `get_property` to read `IMPORTED_LOCATION` at configure time. Instead, generator expressions
+should be used to get the location of the target artifact.
+If `IMPORTED_LOCATION` is needed at configure time users may use `cmake_language(DEFER CALL ...)` to defer
+evaluation to after the `IMPORTED_LOCATION` property is set.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,188 @@
+# This option is currently used to prevent recursion
+option(CORROSION_TESTS "Enable Corrosion tests" ON)
+mark_as_advanced(CORROSION_TESTS)
+if(NOT CORROSION_TESTS)
+ return()
+endif()
+
+option(CORROSION_TESTS_CXXBRIDGE
+ "Build cxxbridge tests which requires cxxbridge executable being available"
+ OFF)
+option(CORROSION_TESTS_KEEP_BUILDDIRS
+ "By default corrosion tests will cleanup after themselves. This option limits the cleaning up to the
+ target directories and will keep the build directories, which may be useful for caching."
+ OFF)
+mark_as_advanced(CORROSION_TESTS_NO_CLEANUP)
+
+set(test_install_path "${CMAKE_CURRENT_BINARY_DIR}/test-install-corrosion")
+file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.." corrosion_source_dir)
+set(test_header_contents
+ "option(CORROSION_TESTS_FIND_CORROSION \"Use Corrosion as a subdirectory\" OFF)"
+ "if (CORROSION_TESTS_FIND_CORROSION)"
+ " set(CMAKE_PREFIX_PATH \"${test_install_path}\" CACHE INTERNAL \"\" FORCE)"
+ " find_package(Corrosion REQUIRED PATHS \"${test_install_path}\" NO_CMAKE_SYSTEM_PATH)"
+ "else()"
+ " add_subdirectory(\"${corrosion_source_dir}\" corrosion)"
+ "endif()"
+)
+
+string(REPLACE ";" "\n" test_header_contents "${test_header_contents}")
+
+file(WRITE test_header.cmake "${test_header_contents}")
+
+option(CORROSION_TESTS_INSTALL_CORROSION
+ "Install Corrosion to a test directory and let tests use the installed Corrosion"
+ OFF)
+if(CORROSION_TESTS_INSTALL_CORROSION)
+ add_test(NAME "install_corrosion_configure"
+ COMMAND
+ ${CMAKE_COMMAND}
+ -S "${CMAKE_CURRENT_SOURCE_DIR}/.."
+ -B "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion"
+ -DCORROSION_VERBOSE_OUTPUT=ON
+ -DCORROSION_TESTS=OFF
+ -DCMAKE_BUILD_TYPE=Release
+ -G${CMAKE_GENERATOR}
+ "-DCMAKE_INSTALL_PREFIX=${test_install_path}"
+ )
+ add_test(NAME "install_corrosion_build"
+ COMMAND
+ ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release
+ )
+ add_test(NAME "install_corrosion_install"
+ COMMAND
+ ${CMAKE_COMMAND} --install "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release
+ )
+ set_tests_properties("install_corrosion_configure" PROPERTIES FIXTURES_SETUP "fixture_corrosion_configure")
+ set_tests_properties("install_corrosion_build" PROPERTIES FIXTURES_SETUP "fixture_corrosion_build")
+ set_tests_properties("install_corrosion_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_configure")
+ set_tests_properties("install_corrosion_install" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_build")
+ set_tests_properties("install_corrosion_install" PROPERTIES FIXTURES_SETUP "fixture_corrosion_install")
+
+ add_test(NAME "install_corrosion_build_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion")
+ set_tests_properties("install_corrosion_build_cleanup" PROPERTIES
+ FIXTURES_CLEANUP
+ "fixture_corrosion_configure;fixture_corrosion_build"
+ )
+
+ add_test(NAME "install_corrosion_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${test_install_path}")
+ set_tests_properties("install_corrosion_cleanup" PROPERTIES
+ FIXTURES_CLEANUP
+ "fixture_corrosion_configure;fixture_corrosion_build;fixture_corrosion_install"
+ )
+endif()
+
+function(corrosion_tests_add_test test_name bin_names)
+ set(options "IS_HOSTBUILD")
+ set(one_value_kewords "TEST_SRC_DIR")
+ set(multi_value_keywords "")
+ cmake_parse_arguments(PARSE_ARGV 2 TST "${options}" "${one_value_kewords}" "${multi_value_keywords}")
+ set(pass_through_arguments "${TST_UNPARSED_ARGUMENTS}")
+
+# In the future we could add multiple tests here for different configurations (generator, build mode, rust version ...)
+# which would allow us to simplify the github job matrix
+ if(TST_TEST_SRC_DIR)
+ set(test_dir "${TST_TEST_SRC_DIR}")
+ else()
+ set(test_dir "${test_name}")
+ endif()
+
+ set(configure_cmake_args)
+ if(CMAKE_C_COMPILER)
+ list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}")
+ endif()
+ if(CMAKE_CXX_COMPILER)
+ list(APPEND configure_cmake_args "CXX_COMPILER" "${CMAKE_CXX_COMPILER}")
+ endif()
+ if(CMAKE_C_COMPILER_TARGET)
+ list(APPEND configure_cmake_args "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}")
+ endif()
+ if(CMAKE_CXX_COMPILER_TARGET)
+ list(APPEND configure_cmake_args "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}")
+ endif()
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}")
+ endif()
+ if(CMAKE_CROSSCOMPILING)
+ list(APPEND configure_cmake_args SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+ endif()
+ if(CMAKE_OSX_ARCHITECTURES)
+ list(APPEND configure_cmake_args OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
+ endif()
+ if(CMAKE_TOOLCHAIN_FILE)
+ list(APPEND configure_cmake_args TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}")
+ endif()
+
+ add_test(NAME "${test_name}_build"
+ COMMAND
+ ${CMAKE_COMMAND}
+ -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake"
+ SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${test_dir}"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}"
+ GENERATOR "${CMAKE_GENERATOR}"
+ RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
+ CARGO_TARGET "${Rust_CARGO_TARGET}"
+ ${configure_cmake_args}
+ ${pass_through_arguments}
+
+ COMMAND_EXPAND_LISTS
+ )
+ set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_SETUP "build_fixture_${test_name}")
+ if(CORROSION_TESTS_INSTALL_CORROSION)
+ set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install")
+ endif()
+ foreach(bin ${bin_names})
+ if(WIN32)
+ set(bin_filename "${bin}.exe")
+ else()
+ set(bin_filename "${bin}")
+ endif()
+ add_test(NAME "${test_name}_run_${bin}" COMMAND "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/${bin_filename}")
+ set_tests_properties("${test_name}_run_${bin}" PROPERTIES FIXTURES_REQUIRED "build_fixture_${test_name}")
+ # CMAKE_CROSSCOMPILING is not set when cross-compiling with VS (via -A flag).
+ # Todo: We could run x86 binaries on x64 hosts.
+ if((CMAKE_CROSSCOMPILING OR CMAKE_VS_PLATFORM_NAME) AND NOT "${TST_IS_HOSTBUILD}")
+ # Todo: In the future we could potentially run some tests with qemu.
+ set_tests_properties("${test_name}_run_${bin}" PROPERTIES DISABLED TRUE)
+ endif()
+ endforeach()
+
+ if(CORROSION_TESTS_KEEP_BUILDDIRS)
+ add_test(NAME "${test_name}_cleanup_artifacts"
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}" --target clean
+ )
+ add_test(NAME "${test_name}_cleanup_cargo"
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/cargo"
+ )
+ set_tests_properties("${test_name}_cleanup_artifacts" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
+ set_tests_properties("${test_name}_cleanup_cargo" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
+ else()
+ add_test(NAME "${test_name}_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}")
+ set_tests_properties("${test_name}_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
+ endif()
+endfunction()
+
+# Please keep this in alphabetical order.
+add_subdirectory(cargo_flags)
+add_subdirectory(cpp2rust)
+if(Rust_VERSION VERSION_GREATER_EQUAL "1.64.0")
+ # Flag `--crate-type` is only supported since Rust 1.64.0
+ add_subdirectory(crate_type)
+ add_subdirectory(override_crate_type)
+endif()
+add_subdirectory(custom_profiles)
+add_subdirectory(cbindgen)
+add_subdirectory(corrosion_install)
+add_subdirectory(cxxbridge)
+add_subdirectory(envvar)
+add_subdirectory(features)
+add_subdirectory(find_rust)
+add_subdirectory(gensource)
+add_subdirectory(hostbuild)
+add_subdirectory(multitarget)
+add_subdirectory(nostd)
+add_subdirectory("output directory")
+add_subdirectory(parse_target_triple)
+add_subdirectory(rust2cpp)
+add_subdirectory(rustflags)
+add_subdirectory(workspace)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/ConfigureAndBuild.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,118 @@
+# CMake script to configure and build a test project
+
+set(TEST_ARG_LIST)
+
+# Expect actual arguments to start at index 3 (cmake -P <script_name>)
+foreach(ARG_INDEX RANGE 3 ${CMAKE_ARGC})
+ list(APPEND TEST_ARG_LIST "${CMAKE_ARGV${ARG_INDEX}}")
+endforeach()
+
+set(options "USE_INSTALLED_CORROSION")
+set(oneValueArgs
+ SOURCE_DIR
+ BINARY_DIR
+ GENERATOR
+ GENERATOR_PLATFORM
+ RUST_TOOLCHAIN
+ CARGO_TARGET
+ C_COMPILER
+ CXX_COMPILER
+ C_COMPILER_TARGET
+ CXX_COMPILER_TARGET
+ SYSTEM_NAME
+ CARGO_PROFILE
+ OSX_ARCHITECTURES
+ TOOLCHAIN_FILE
+)
+set(multiValueArgs "PASS_THROUGH_ARGS")
+cmake_parse_arguments(TEST "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${TEST_ARG_LIST} )
+
+set(configure_args "")
+if(TEST_CARGO_TARGET)
+ list(APPEND configure_args "-DRust_CARGO_TARGET=${TEST_CARGO_TARGET}")
+endif()
+if(TEST_USE_INSTALLED_CORROSION)
+ list(APPEND configure_args "-DCORROSION_TESTS_FIND_CORROSION=ON")
+endif()
+if(TEST_GENERATOR_PLATFORM)
+ list(APPEND configure_args "-A${TEST_GENERATOR_PLATFORM}")
+endif()
+if(TEST_C_COMPILER)
+ list(APPEND configure_args "-DCMAKE_C_COMPILER=${TEST_C_COMPILER}")
+endif()
+if(TEST_CXX_COMPILER)
+ list(APPEND configure_args "-DCMAKE_CXX_COMPILER=${TEST_CXX_COMPILER}")
+endif()
+if(TEST_C_COMPILER_TARGET)
+ list(APPEND configure_args "-DCMAKE_C_COMPILER_TARGET=${TEST_C_COMPILER_TARGET}")
+endif()
+if(TEST_CXX_COMPILER_TARGET)
+ list(APPEND configure_args "-DCMAKE_CXX_COMPILER_TARGET=${TEST_CXX_COMPILER_TARGET}")
+endif()
+if(TEST_SYSTEM_NAME)
+ list(APPEND configure_args "-DCMAKE_SYSTEM_NAME=${TEST_SYSTEM_NAME}")
+endif()
+if(TEST_OSX_ARCHITECTURES)
+ list(APPEND configure_args "-DCMAKE_OSX_ARCHITECTURES=${TEST_OSX_ARCHITECTURES}")
+endif()
+if(TEST_TOOLCHAIN_FILE)
+ list(APPEND configure_args "-DCMAKE_TOOLCHAIN_FILE=${TEST_TOOLCHAIN_FILE}")
+endif()
+if(TEST_CARGO_PROFILE)
+ list(APPEND configure_args "-DCARGO_PROFILE=${TEST_CARGO_PROFILE}")
+endif()
+
+# Remove old binary directory
+file(REMOVE_RECURSE "${TEST_BINARY_DIR}")
+
+file(MAKE_DIRECTORY "${TEST_BINARY_DIR}")
+
+message(STATUS "TEST_BINARY_DIRECTORY: ${TEST_BINARY_DIR}")
+
+execute_process(
+ COMMAND
+ "${CMAKE_COMMAND}"
+ "-G${TEST_GENERATOR}"
+ "-DRust_TOOLCHAIN=${TEST_RUST_TOOLCHAIN}"
+ --log-level Debug
+ ${configure_args}
+ ${TEST_PASS_THROUGH_ARGS}
+ -S "${TEST_SOURCE_DIR}"
+ -B "${TEST_BINARY_DIR}"
+ COMMAND_ECHO STDOUT
+ RESULT_VARIABLE EXIT_CODE
+)
+
+if (NOT "${EXIT_CODE}" EQUAL 0)
+ message(FATAL_ERROR "Configure step failed. Exit code: `${EXIT_CODE}`")
+endif()
+
+if ("${TEST_GENERATOR}" STREQUAL "Ninja Multi-Config"
+ OR "${TEST_GENERATOR}" MATCHES "Visual Studio"
+ )
+ foreach(config Debug Release RelWithDebInfo)
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}"
+ --build "${TEST_BINARY_DIR}"
+ --config "${config}"
+ COMMAND_ECHO STDOUT
+ RESULT_VARIABLE EXIT_CODE
+ )
+ if (NOT "${EXIT_CODE}" EQUAL 0)
+ message(FATAL_ERROR "Build step failed for config `${config}`. "
+ "Exit code: `${EXIT_CODE}`")
+ endif()
+ endforeach()
+else()
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build "${TEST_BINARY_DIR}"
+ COMMAND_ECHO STDOUT
+ RESULT_VARIABLE EXIT_CODE
+ )
+ if (NOT "${EXIT_CODE}" EQUAL 0)
+ message(FATAL_ERROR "Build step failed. Exit code: `${EXIT_CODE}`")
+ endif()
+endif()
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/README.md Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+# Corrosion Tests
+
+Corrosions tests are run via ctest. The tests themselves utilize CMake script mode
+to configure and build a test project, which allows for great flexibility.
+Using ctest properties such as `PASS_REGULAR_EXPRESSION` or `FAIL_REGULAR_EXPRESSION`
+can be used to confirm that built executable targets run as expected, but can also
+be used to fail tests if Corrosion warnings appear in the configure output.
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cargo_flags/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+corrosion_tests_add_test(cargo_flags "flags-exe")
+
+set_tests_properties("cargo_flags_run_flags-exe" PROPERTIES PASS_REGULAR_EXPRESSION [[Hello, Cxx! I am Rust!]])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cargo_flags/cargo_flags/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml FLAGS --features one)
+
+add_executable(flags-exe main.cpp)
+target_link_libraries(flags-exe PUBLIC flags_lib)
+corrosion_set_cargo_flags(flags_lib --features two)
+corrosion_set_cargo_flags(flags_lib $<TARGET_PROPERTY:flags_lib,more_flags>)
+
+set_property(
+ TARGET flags_lib
+ APPEND
+ PROPERTY more_flags --features three
+)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cargo_flags/cargo_flags/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+extern "C" void rust_function(char const *name);
+
+
+int main(int argc, char **argv) {
+ rust_function("Cxx");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cargo_flags/cargo_flags/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,13 @@
+[package]
+name = "flags-lib"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+crate-type=["staticlib"]
+
+[features]
+
+one = []
+two = []
+three = []
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cargo_flags/cargo_flags/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,14 @@
+use std::os::raw::c_char;
+
+#[no_mangle]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I am Rust!", name);
+
+ #[cfg(not(feature = "one"))]
+ compile_error!("Feature one is not enabled");
+ #[cfg(not(feature = "two"))]
+ compile_error!("Feature two is not enabled");
+ #[cfg(not(feature = "three"))]
+ compile_error!("Feature three is not enabled");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+corrosion_tests_add_test(cbindgen_rust2cpp "cpp-exe" TEST_SRC_DIR rust2cpp)
+
+set_tests_properties(cbindgen_rust2cpp_run_cpp-exe PROPERTIES PASS_REGULAR_EXPRESSION
+ "^add_point Result: Point { x: 100, y: 100 }\r?\n$"
+)
+# Todo: We also should add a cpp2rust test with the following setup:
+# - A rust lib that is used by a rust executable
+# - cbindgen creates bindings for the rust-lib
+# - c++ code uses the rust lib and is used in turn by the rust bin.
+
+# todo: add a test for the DEPFILE and correct regenerating if the sources are touched.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+corrosion_experimental_cbindgen(TARGET rust_lib HEADER_NAME "rust-lib.h")
+
+add_executable(cpp-exe main.cpp)
+set_property(TARGET cpp-exe PROPERTY CXX_STANDARD 11)
+target_link_libraries(cpp-exe PUBLIC rust_lib)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,22 @@
+#include "rust-lib.h"
+#include <cassert>
+
+int main(int argc, char **argv) {
+ assert(is_magic_number(MAGIC_NUMBER));
+ struct Point p1, p2;
+ p1.x = 54;
+ p2.x = 46;
+ p1.y = 34;
+ p2.y = 66;
+ add_point(&p1, &p2);
+ assert(p1.x == 100);
+ assert(p2.x == 46);
+ assert(p1.y == 100);
+ assert(p2.y == 66);
+ add_point(&p1, NULL);
+ assert(p1.x == 100);
+ assert(p1.y == 100);
+
+ assert(OTHER_MOD_MAGIC_NUMBER == 192312312);
+ assert(FFI_MAGIC_NUMBER == 0xFDA00184);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "rust-lib"
+version = "0.1.0"
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/cbindgen.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+language = "C++"
+include_version = true
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/ffi.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+//! Just a module that contains some entries that should be parsed by cbindgen.
+
+pub const FFI_MAGIC_NUMBER: u64 = 0xFDA0_0184;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,33 @@
+pub const MAGIC_NUMBER: u64 = 0xABCD_EFAB;
+
+pub mod ffi;
+pub mod other_mod;
+
+#[derive(Debug)]
+#[repr(C)]
+pub struct Point {
+ x: u64,
+ y: u64,
+}
+
+impl Point {
+ pub(crate) fn add(&mut self, rhs: &Point) {
+ self.x = self.x.wrapping_add(rhs.x);
+ self.y = self.y.wrapping_add(rhs.y);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_point(lhs: Option<&mut Point>, rhs: Option<&Point>) {
+ if let (Some(p1), Some(p2)) = (lhs, rhs) {
+ p1.add(p2);
+ // Print something so we can let Ctest assert the output.
+ println!("add_point Result: {:?}", p1);
+ }
+}
+
+// simple test if the constant was exported by cbindgen correctly
+#[no_mangle]
+pub extern "C" fn is_magic_number(num: u64) -> bool {
+ num == MAGIC_NUMBER
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cbindgen/rust2cpp/rust/src/other_mod/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,1 @@
+pub const OTHER_MOD_MAGIC_NUMBER: u32 = 192312312;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,27 @@
+if(NOT (CMAKE_CROSSCOMPILING AND MSVC))
+ # When using MSVC the cmake build via ExternalProject seems to inherit the target architecture,
+ # which breaks the test. Since we practically don't care about this, and we just want to ensure
+ # that installing an executable works, skipping this test when cross-compiling is fine.
+ corrosion_tests_add_test(install_rust_bin "generated_from_installed_bin")
+
+ set_tests_properties("install_rust_bin_run_generated_from_installed_bin"
+ PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello World! I'm generated code"
+ )
+endif()
+
+# Todo: Fix and re-enable tests on Windows
+if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
+ corrosion_tests_add_test(install_lib "main-static;main-shared")
+
+ set_tests_properties("install_lib_run_main-static" "install_lib_run_main-shared"
+ PROPERTIES PASS_REGULAR_EXPRESSION
+ "The sum is 11"
+ )
+endif()
+
+# Further tests we should add:
+# - Test installing a Rust executable, that requires a (C/C++) shared library at runtime.
+# Note: We should delete the build directory of the subproject
+# before running the installed rust executable, to insure the shared library is loaded from the
+# installed location and not from the build dir.
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(ExternalProject)
+
+add_library(static_lib STATIC IMPORTED)
+add_library(shared_lib SHARED IMPORTED)
+set(install_prefix "${CMAKE_CURRENT_BINARY_DIR}/rust_lib")
+set(static_lib_install_path "${install_prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}rust_lib${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set(shared_lib_install_path "${install_prefix}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}rust_lib${CMAKE_SHARED_LIBRARY_SUFFIX}")
+
+
+set_target_properties(static_lib PROPERTIES
+ IMPORTED_LOCATION
+ "${static_lib_install_path}")
+
+set_target_properties(shared_lib PROPERTIES
+ IMPORTED_LOCATION
+ "${shared_lib_install_path}")
+
+add_executable(main-static main.cpp)
+target_link_libraries(main-static PRIVATE static_lib)
+
+ExternalProject_Add(
+ rust_lib
+ PREFIX "${CMAKE_CURRENT_BINARY_DIR}/rust_lib"
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_lib"
+ CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${install_prefix}"
+ # INSTALL_BYPRODUCTS "${static_lib_install_path}"
+)
+
+# Dummy target since INSTALL_BYPRODUCTS requires CMake 3.26
+add_custom_target(build_rust_project_dummy
+ COMMAND echo dummy
+ BYPRODUCTS "${static_lib_install_path}" "${shared_lib_install_path}"
+ DEPENDS rust_lib)
+
+add_dependencies(main-static build_rust_project_dummy)
+
+set(CMAKE_BUILD_RPATH ${install_prefix}/lib)
+add_executable(main-shared main.cpp)
+target_link_libraries(main-shared
+ PUBLIC shared_lib)
+
+add_dependencies(main-shared build_rust_project_dummy)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+#include <stdint.h>
+#include <assert.h>
+#include <iostream>
+
+extern "C" uint64_t add(uint64_t a, uint64_t b);
+
+int main(int argc, char **argv) {
+ uint64_t sum = add(5, 6);
+ assert(sum == 11);
+ std::cout << "The sum is " << sum << std::endl;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ corrosion_add_target_local_rustflags(rust_lib "-Clink-arg=-Wl,-soname,librust_lib.so")
+ set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.so)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+ corrosion_add_target_local_rustflags(rust_lib -Clink-arg=-Wl,-install_name,@rpath/librust_lib.dylib,-current_version,1.0,-compatibility_version,1.0)
+ set_target_properties(rust_lib-shared PROPERTIES IMPORTED_NO_SONAME 0)
+ set_target_properties(rust_lib-shared PROPERTIES IMPORTED_SONAME librust_lib.dylib)
+endif()
+
+target_sources(rust_lib INTERFACE include/rust_lib/rust_lib.hpp)
+
+corrosion_install(TARGETS rust_lib)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+[package]
+name = "rust_lib"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type = ["staticlib", "cdylib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/include/rust_lib/rust_lib.hpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+#include <cstdint.h>
+
+extern "C" uint64_t add(uint64_t left, uint64_t right);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_lib/rust_lib/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+
+#[no_mangle]
+pub extern "C" fn add(left: u64, right: u64) -> u64 {
+ left + right
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.22)
+project(test_project VERSION 0.1.0)
+
+# Note: Corrosion supports `hostbuild`, so building a Rust binary in a subproject
+# like this doesn't offer any benefit over using the hostbuild option.
+# However, this is a reasonable way to test that installing Rust binaries via
+# corrosion_install works as expected.
+include(ExternalProject)
+
+set(bin_suffix "")
+if(CMAKE_HOST_WIN32)
+ set(bin_suffix ".exe")
+endif()
+set(generator_bin_path "${CMAKE_CURRENT_BINARY_DIR}/rust_bin/bin/my_rust_bin${bin_suffix}")
+
+ExternalProject_Add(
+ rust_bin
+ PREFIX "${CMAKE_CURRENT_BINARY_DIR}/rust_bin"
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_bin"
+ CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/rust_bin"
+)
+
+# This custom command is the main part of the test:
+# We test that corrosion (in the CMake of the ExternalProject) properly installed
+# a Rust executable to the location we specified by running the executable, which generates some cpp code.
+add_custom_command(
+ OUTPUT generated_main.cpp
+ COMMAND "${generator_bin_path}" > "${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp"
+ DEPENDS rust_bin
+)
+
+add_executable(generated_from_installed_bin ${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.22)
+project(test_rust_bin VERSION 0.1.0)
+include(../../../test_header.cmake)
+include(GNUInstallDirs)
+
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+corrosion_install(TARGETS my_rust_bin)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+[package]
+name = "my_rust_bin"
+version = "0.1.0"
+edition = "2018"
+license = "MIT"
+
+[dependencies]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/corrosion_install/install_rust_bin/rust_bin/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+fn main() {
+ println!(
+"#include <iostream>
+int main() {{
+ std::cout << \"Hello World! I'm generated code\";
+ return 0;
+}}"
+ );
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+corrosion_tests_add_test(cpp2rust "rust-exe")
+
+set_tests_properties("cpp2rust_run_rust-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, Rust! I am Cpp!\r?\nHello, Rust! I am Cpp library Number 2!\r?\nHello, Rust! I am Cpp library Number 3!"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+
+add_library(cpp-lib lib.cpp)
+target_compile_features(cpp-lib PRIVATE cxx_std_14)
+set_target_properties(
+ cpp-lib
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+)
+
+add_library(cpp-lib2 lib2.cpp)
+target_compile_features(cpp-lib2 PRIVATE cxx_std_14)
+set_target_properties(
+ cpp-lib2
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+ OUTPUT_NAME cpp-lib-renamed
+)
+
+add_library(cpp-lib3 "path with space/lib3.cpp" )
+target_compile_features(cpp-lib3 PRIVATE cxx_std_14)
+set_target_properties(
+ cpp-lib3
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+)
+
+corrosion_link_libraries(rust-exe cpp-lib cpp-lib2 cpp-lib3)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/lib.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+#include <iostream>
+
+extern "C" void cpp_function(char const *name) {
+ std::cout << "Hello, " << name << "! I am Cpp!\n";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/lib2.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+#include <iostream>
+#include <stdint.h>
+
+extern "C" void cpp_function2(char const *name) {
+ std::cout << "Hello, " << name << "! I am Cpp library Number 2!\n";
+}
+
+extern "C" uint32_t get_42() {
+ uint32_t v = 42;
+ return v;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/path with space/lib3.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+// Check that libraries located at a path containing a space can also be linked.
+
+#include <iostream>
+
+extern "C" void cpp_function3(char const *name) {
+ std::cout << "Hello, " << name << "! I am Cpp library Number 3!\n";
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+[package]
+name = "rust-exe"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+rust-dependency = { path = "rust_dependency" }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/rust/build.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works.
+fn main() {
+ println!("Build-script is running.")
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "rust-dependency"
+version = "0.1.0"
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cpp2rust/cpp2rust/rust/rust_dependency/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+
+extern "C" {
+ fn get_42() -> u32;
+}
+pub fn calls_ffi() {
+ let res = unsafe { get_42()};
+ assert_eq!(res, 42);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+corrosion_tests_add_test(crate_type "cpp-exe")
+
+
+set_tests_properties("crate_type_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello from lib 1!\r?\nHello from lib 2!"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+# Add --crate-type to ensure that only the specified type of library is built and no error is thrown
+corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml CRATE_TYPES staticlib FLAGS --crate-type=staticlib)
+corrosion_import_crate(MANIFEST_PATH proj2/Cargo.toml CRATE_TYPES cdylib FLAGS --crate-type=cdylib)
+
+add_executable(cpp-exe main.cpp)
+target_link_libraries(cpp-exe proj1)
+target_link_libraries(cpp-exe proj2)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+extern "C" void rust_function1();
+extern "C" void rust_function2();
+
+int main() {
+ rust_function1();
+ rust_function2();
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/proj1/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "proj1"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib", "cdylib"]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/proj1/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn rust_function1() {
+ println!("Hello from lib 1!");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/proj2/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+[package]
+name = "proj2"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib", "cdylib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/crate_type/crate_type/proj2/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn rust_function2() {
+ println!("Hello from lib 2!");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,27 @@
+# The tests in this folder test specifying the cargo profile name via the --profile option.
+# The built-in `test` and `bench` profiles are _not_ supported, because they output
+# artifacts to a different location and add a hash to the artifact name.
+if(Rust_VERSION VERSION_GREATER_EQUAL 1.57.0)
+
+ corrosion_tests_add_test(custom_profiles_global "custom-profile-exe" TEST_SRC_DIR custom_profiles)
+ corrosion_tests_add_test(custom_profiles_target_specific "custom-profile-exe"
+ TEST_SRC_DIR custom_profiles
+ PASS_THROUGH_ARGS -DCORROSION_TEST_USE_TARGET_SPECIFIC_OVERRIDE=ON
+ )
+ corrosion_tests_add_test(dev_profile "dev_bin" TEST_SRC_DIR basic_profiles CARGO_PROFILE dev)
+ corrosion_tests_add_test(release_profile "release_bin" TEST_SRC_DIR basic_profiles CARGO_PROFILE release)
+
+ set_tests_properties("custom_profiles_global_run_custom-profile-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+ set_tests_properties("custom_profiles_target_specific_run_custom-profile-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+ set_tests_properties("dev_profile_run_dev_bin" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+ set_tests_properties("release_profile_run_release_bin" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/basic_profiles/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+if(NOT DEFINED CARGO_PROFILE)
+ message(FATAL_ERROR "Test internal error. The test should be called with the CARGO_PROFILE parameter.")
+endif()
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE ${CARGO_PROFILE})
+
+add_executable(${CARGO_PROFILE}_bin main.cpp)
+target_link_libraries(${CARGO_PROFILE}_bin PUBLIC cargo_profiles_lib)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/basic_profiles/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+extern "C" void rust_function(char const *name);
+
+
+int main(int argc, char **argv) {
+ rust_function("Cpp");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/basic_profiles/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+[package]
+name = "cargo-profiles-lib"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type=["staticlib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/basic_profiles/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+use std::os::raw::c_char;
+
+#[no_mangle]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/custom_profiles/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+set(_release_profile $<IF:$<CONFIG:Release>,release-without-dbg,custom-without-dbg>)
+set(custom_profile $<IF:$<CONFIG:Debug>,dev-without-dbg,${_release_profile}>)
+
+if(CORROSION_TEST_USE_TARGET_SPECIFIC_OVERRIDE)
+ # Select "wrong" profile here on purpose.
+ corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE dev)
+ set_target_properties(custom_profiles_lib
+ PROPERTIES
+ INTERFACE_CORROSION_CARGO_PROFILE "${custom_profile}"
+ )
+else()
+ corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml PROFILE ${custom_profile})
+endif()
+
+add_executable(custom-profile-exe main.cpp)
+target_link_libraries(custom-profile-exe PUBLIC custom_profiles_lib)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/custom_profiles/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+extern "C" void rust_function(char const *name);
+
+
+int main(int argc, char **argv) {
+ rust_function("Cpp");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/custom_profiles/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,24 @@
+[package]
+name = "custom-profiles-lib"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type=["staticlib"]
+
+# Test if neither release or debug where selected by only disabling debug-assertions in the inherited profile.
+[profile.release]
+debug-assertions = true
+
+[profile.dev-without-dbg]
+inherits = "dev"
+debug-assertions = false
+
+[profile.release-without-dbg]
+inherits = "release"
+debug-assertions = false
+
+[profile.custom-without-dbg]
+inherits = "release"
+opt-level = 1
+debug-assertions = false
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/custom_profiles/custom_profiles/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+use std::os::raw::c_char;
+
+#[no_mangle]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
+
+
+#[cfg(debug_assertions)]
+const _: () = assert!(false, "Debug assertions where not disabled via custom profile!");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,20 @@
+if(CORROSION_TESTS_CXXBRIDGE)
+ corrosion_tests_add_test(cxxbridge_cpp2rust_1 "rust_bin"
+ TEST_SRC_DIR cxxbridge_cpp2rust
+ PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT1=ON
+ )
+ corrosion_tests_add_test(cxxbridge_cpp2rust_2 "rust_bin"
+ TEST_SRC_DIR cxxbridge_cpp2rust
+ PASS_THROUGH_ARGS -DTEST_CXXBRIDGE_VARIANT2=ON
+ )
+ corrosion_tests_add_test(cxxbridge_rust2cpp "cxxbridge-exe")
+
+ set_tests_properties("cxxbridge_cpp2rust_1_run_rust_bin"
+ PROPERTIES PASS_REGULAR_EXPRESSION
+ "main function"
+ )
+ set_tests_properties("cxxbridge_rust2cpp_run_cxxbridge-exe"
+ PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello cxxbridge from lib.rs! \\[4, 5, 6\\]\r?\nHello cxxbridge from foo/mod.rs! \\[4, 5, 6\\]"
+ )
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0 LANGUAGES CXX)
+include(../../test_header.cmake)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED 1)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+corrosion_add_cxxbridge(cxxbridge-cpp CRATE rust_bin FILES lib.rs)
+target_include_directories(cxxbridge-cpp PRIVATE "include")
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux"
+ OR (CMAKE_SYSTEM_NAME STREQUAL "Windows"
+ AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ )
+)
+ corrosion_add_target_local_rustflags(rust_bin "-Clink-arg=-fuse-ld=lld")
+endif()
+
+if(MSVC)
+ set_target_properties(cxxbridge-cpp PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+endif()
+
+if(TEST_CXXBRIDGE_VARIANT1)
+ # Variant 1: Merge the C++ User sources into the generated library target.
+ target_sources(cxxbridge-cpp PRIVATE cpplib.cpp)
+ corrosion_link_libraries(rust_bin cxxbridge-cpp)
+elseif(TEST_CXXBRIDGE_VARIANT2)
+ # Variant 2: Create a separate C++ library and link both the User library and
+ # the generated library into rust
+ add_library(cpp_lib STATIC cpplib.cpp)
+ target_include_directories(cpp_lib PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include")
+ target_link_libraries(cpp_lib PUBLIC cxxbridge-cpp)
+ corrosion_link_libraries(rust_bin cpp_lib cxxbridge-cpp)
+ if(MSVC)
+ set_target_properties(cpp_lib PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+ endif()
+else()
+ message(FATAL_ERROR "Internal test error - required option not defined")
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/cpplib.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,15 @@
+#include <iostream>
+#include "cpplib.h"
+#include "cxxbridge-cpp/lib.h"
+#include "rust/cxx.h"
+
+RsImage read_image(rust::Str path) {
+ std::cout << "read_image called" << std::endl;
+ std::cout << path << std::endl;
+ Rgba c = { 1.0, 2.0, 3.0, 4.0};
+ RsImage v = { 1, 1, c};
+ return v;
+}
+void write_image(::rust::Str path, ::RsImage const & image) {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/include/cpplib.h Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+#pragma once
+#include "cxxbridge-cpp/lib.h"
+
+::RsImage read_image(::rust::Str path);
+void write_image(::rust::Str path, ::RsImage const & image);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "rust_bin"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+name = "cxxbridge_lib"
+
+[dependencies]
+cxx = "1.0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,26 @@
+#[cxx::bridge]
+pub mod ffi
+{
+ #[derive(Debug, PartialEq)]
+ pub struct Rgba
+ {
+ r: f32,
+ g: f32,
+ b: f32,
+ a: f32,
+ }
+
+ #[derive(Debug,PartialEq)]
+ pub struct RsImage
+ {
+ width: usize,
+ height: usize,
+ raster: Rgba,
+ }
+ unsafe extern "C++"
+ {
+ include!("cpplib.h");
+ pub fn read_image(path: &str) -> RsImage;
+ fn write_image(path: &str, image: &RsImage);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_cpp2rust/rust/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,14 @@
+use cxxbridge_lib::ffi::{RsImage,Rgba,read_image};
+
+fn main() {
+ println!("main function");
+ let expected = RsImage { width: 1, height: 1, raster: Rgba {
+ r: 1.0,
+ g: 2.0,
+ b: 3.0,
+ a: 4.0,
+ }};
+ let actual = read_image("dummy path");
+ println!("returned from C++");
+ assert_eq!(actual, expected)
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_rust2cpp/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED 1)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+corrosion_add_cxxbridge(cxxbridge-cpp CRATE cxxbridge_crate MANIFEST_PATH rust FILES lib.rs foo/mod.rs)
+
+add_executable(cxxbridge-exe main.cpp)
+target_link_libraries(cxxbridge-exe PUBLIC cxxbridge-cpp)
+
+if(MSVC)
+ # Note: This is required because we use `cxx` which uses `cc` to compile and link C++ code.
+ corrosion_set_env_vars(cxxbridge_crate "CFLAGS=-MDd" "CXXFLAGS=-MDd")
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_rust2cpp/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+#include <cxxbridge-cpp/foo/mod.h>
+#include <cxxbridge-cpp/lib.h>
+#include <vector>
+
+int main(int argc, char **argv)
+{
+ std::vector<uint64_t> input = { 4, 5, 6};
+ rust::Slice<const ::std::uint64_t> slice{input.data(), input.size()};
+ lib::print(slice);
+ foo::print(slice);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "cxxbridge-crate"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+cxx = "1.0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/foo/mod.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+#[cxx::bridge(namespace = "foo")]
+mod bridge {
+ extern "Rust" {
+ fn print(slice: &[u64]);
+ }
+}
+
+fn print(slice: &[u64]) {
+ println!("Hello cxxbridge from foo/mod.rs! {:?}", slice);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/cxxbridge/cxxbridge_rust2cpp/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,12 @@
+mod foo;
+
+#[cxx::bridge(namespace = "lib")]
+mod bridge {
+ extern "Rust" {
+ fn print(slice: &[u64]);
+ }
+}
+
+fn print(slice: &[u64]) {
+ println!("Hello cxxbridge from lib.rs! {:?}", slice);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+corrosion_tests_add_test(envvar "program_requiring_rust_lib_with_envvar")
+
+set_tests_properties("envvar_run_program_requiring_rust_lib_with_envvar" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Ok"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/.cargo/config.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,2 @@
+[env]
+COR_CONFIG_TOML_ENV_VAR = "EnvVariableSetViaConfig.toml"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+
+corrosion_set_env_vars(rust_lib_requiring_envvar
+ "ANOTHER_VARIABLE=ANOTHER_VALUE"
+ "$<TARGET_PROPERTY:program_requiring_rust_lib_with_envvar,INDIRECT_VAR_TEST>"
+ "COR_CARGO_VERSION_MAJOR=${Rust_CARGO_VERSION_MAJOR}"
+ "COR_CARGO_VERSION_MINOR=${Rust_CARGO_VERSION_MINOR}"
+)
+
+add_executable(program_requiring_rust_lib_with_envvar main.cpp)
+
+set_property(
+ TARGET program_requiring_rust_lib_with_envvar
+ APPEND
+ PROPERTY INDIRECT_VAR_TEST
+ "REQUIRED_VARIABLE=EXPECTED_VALUE"
+)
+
+target_link_libraries(program_requiring_rust_lib_with_envvar PUBLIC rust_lib_requiring_envvar)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+[package]
+name = "rust-lib-requiring-envvar"
+version = "0.1.0"
+authors = ["Olivier Goffart <ogoffart@sixtyfps.io>"]
+edition = "2018"
+build = "build.rs"
+
+[lib]
+crate-type = [ "lib", "cdylib" ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/build.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,18 @@
+fn main() {
+ assert_eq!(env!("REQUIRED_VARIABLE"), "EXPECTED_VALUE");
+ assert_eq!(std::env::var("ANOTHER_VARIABLE").unwrap(), "ANOTHER_VALUE");
+ let cargo_major = env!("COR_CARGO_VERSION_MAJOR")
+ .parse::<u32>()
+ .expect("Invalid Major version");
+ let cargo_minor = env!("COR_CARGO_VERSION_MINOR")
+ .parse::<u32>()
+ .expect("Invalid Minor version");
+
+ // The `[env]` section in `.cargo/config.toml` was added in version 1.56.
+ if cargo_major > 1 || (cargo_major == 1 && cargo_minor >= 56) {
+ // Check if cargo picks up the config.toml, which sets this additional env variable.
+ let env_value = option_env!("COR_CONFIG_TOML_ENV_VAR")
+ .expect("Test failure! Cargo >= 1.56.0 should set this environment variable");
+ assert_eq!(env_value, "EnvVariableSetViaConfig.toml");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+#include <iostream>
+
+int main() {
+ std::cout << "Ok";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/envvar/envvar/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ assert_eq!(2 + 2, 4);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/features/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+corrosion_tests_add_test(features "features-cpp-exe")
+
+set_tests_properties("features_run_features-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/features/features/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml FEATURES thirdfeature ALL_FEATURES)
+
+add_executable(features-cpp-exe main.cpp)
+target_link_libraries(features-cpp-exe PUBLIC rust_feature_lib)
+
+corrosion_set_features(rust_feature_lib
+ ALL_FEATURES OFF
+ NO_DEFAULT_FEATURES
+ FEATURES
+ $<TARGET_PROPERTY:features-cpp-exe,app_features>
+)
+
+set_property(
+ TARGET features-cpp-exe
+ APPEND
+ PROPERTY app_features myfeature
+)
+set_property(
+ TARGET features-cpp-exe
+ APPEND
+ PROPERTY app_features secondfeature
+)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/features/features/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,13 @@
+extern "C" void rust_function(char const *name);
+extern "C" void rust_second_function(char const *name);
+extern "C" void rust_third_function(char const *name);
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ rust_function("Cpp");
+ rust_second_function("Cpp again");
+ rust_third_function("Cpp again");
+ } else {
+ rust_function(argv[1]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/features/features/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,18 @@
+[package]
+name = "rust-feature-lib"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib"]
+
+[features]
+default = ["compile-breakage"]
+myfeature = []
+secondfeature = []
+thirdfeature = []
+compile-breakage = []
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/features/features/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,26 @@
+#[cfg(feature = "myfeature")]
+use std::os::raw::c_char;
+
+#[no_mangle]
+#[cfg(feature = "myfeature")]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
+
+#[no_mangle]
+#[cfg(feature = "secondfeature")]
+pub extern "C" fn rust_second_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust again!", name);
+}
+
+#[no_mangle]
+#[cfg(feature = "thirdfeature")]
+pub extern "C" fn rust_third_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust again, third time the charm!", name);
+}
+
+#[cfg(feature = "compile-breakage")]
+const _: [(); 1] = [(); 2]; // Trigger a compile error to make sure that we succeeded in de-activating this feature
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/find_rust/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+corrosion_tests_add_test(find_rust "")
+corrosion_tests_add_test(rustup_proxy "")
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/find_rust/find_rust/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+
+cmake_minimum_required(VERSION 3.15)
+project(FindRust LANGUAGES CXX)
+
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../cmake" ${CMAKE_MODULE_PATH})
+
+# make sure find_package(Rust) can be used more than once
+find_package(Rust REQUIRED)
+find_package(Rust REQUIRED)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/find_rust/rustup_proxy/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.15)
+project(RustupProxy LANGUAGES CXX)
+
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../cmake" ${CMAKE_MODULE_PATH})
+
+function(_assert_is_rustup_proxy executable_path)
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E env
+ RUSTUP_FORCE_ARG0=rustup
+ "${executable_path}" --version
+ OUTPUT_VARIABLE _VERSION_RAW
+ ERROR_VARIABLE _VERSION_STDERR
+ RESULT_VARIABLE _VERSION_RESULT
+ )
+
+ if(NOT _VERSION_RESULT EQUAL "0")
+ message(FATAL_ERROR "`${executable_path} --version` failed with ${_VERSION_RESULT}\n"
+ "stderr:\n${_VERSION_STDERR}"
+ )
+ endif()
+
+ if (NOT _VERSION_RAW MATCHES "rustup [0-9\\.]+")
+ message(FATAL_ERROR "`${executable_path} --version` output does not match rustup: ${_VERSION_RAW}\n")
+ endif()
+endfunction()
+
+set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL "" FORCE)
+find_package(Rust REQUIRED)
+
+if (NOT Rust_FOUND)
+ message(FATAL_ERROR "Rustup not found")
+endif()
+
+get_property(
+ RUSTC_EXECUTABLE
+ TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
+)
+
+_assert_is_rustup_proxy(${RUSTC_EXECUTABLE})
+
+get_property(
+ CARGO_EXECUTABLE
+ TARGET Rust::Cargo PROPERTY IMPORTED_LOCATION
+)
+
+_assert_is_rustup_proxy(${CARGO_EXECUTABLE})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+corrosion_tests_add_test(gensource "")
+
+#set_tests_properties("features_run_features-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+# "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!"
+# )
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/.gitignore Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,1 @@
+src/foo.rs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+add_subdirectory(generator)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs"
+ DEPENDS $<TARGET_FILE:srcgen>
+ COMMAND $<TARGET_FILE:srcgen> "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs"
+)
+
+add_custom_target(after_generation DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/foo.rs")
+add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "Config DEBUG: $<TARGET_PROPERTY:srcgen,IMPORTED_LOCATION_DEBUG> Config Release: $<TARGET_PROPERTY:srcgen,IMPORTED_LOCATION_RELEASE> IMPORTED_LOCATION: $<TARGET_PROPERTY:srcgen,IMPORTED_LOCATION>")
+
+corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml)
+add_dependencies(cargo-prebuild_generated after_generation)
+
+# Simple test for corrosion_parse_package_version
+corrosion_parse_package_version("${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml" srcgen_version)
+if (NOT "${srcgen_version}" VERSION_EQUAL "0.1.0")
+ message(FATAL_ERROR "Test failed to parse expected version")
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "generated"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+crate-type = ["lib", "cdylib"]
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/generator/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,2 @@
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+corrosion_set_hostbuild(srcgen)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/generator/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "srcgen"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/generator/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+use std::io::Write;
+fn main() -> Result<(), std::io::Error> {
+ let out_name = std::env::args().skip(1).next().unwrap();
+ let mut out_file = std::fs::File::create(out_name)?;
+ Ok(write!(out_file, "const _: () = ();")?)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/gensource/gensource/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+mod foo;
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ let result = 2 + 2;
+ assert_eq!(result, 4);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+corrosion_tests_add_test(hostbuild "rust-host-program" IS_HOSTBUILD)
+
+set_tests_properties("hostbuild_run_rust-host-program" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^ok\r?\nHello Rust Hostbuild, I am an external C function"
+ )
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/hostbuild/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml)
+
+corrosion_set_hostbuild(rust-host-program)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/hostbuild/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "rust-host-program"
+version = "0.1.0"
+authors = ["Olivier Goffart <ogoffart@sixtyfps.io>"]
+edition = "2018"
+
+[build-dependencies]
+cc = "1.0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/hostbuild/build.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+fn main() {
+ let out_dir = std::env::var("OUT_DIR").unwrap();
+ cc::Build::new()
+ .file("src/lib.c")
+ .compile("hello");
+
+ println!("cargo:rustc-link-search=native={}", out_dir);
+ println!("cargo:rustc-link-lib=hello");
+ println!("cargo:rerun-if-changed=src/lib.c");
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/hostbuild/src/lib.c Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void c_function(char const *name) {
+ printf("Hello %s, I am an external C function\n", name);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/hostbuild/hostbuild/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,13 @@
+use std::os::raw::c_char;
+
+extern "C" {
+ fn c_function(name: *const c_char);
+}
+
+fn main() {
+ println!("ok");
+ let name = b"Rust Hostbuild\0";
+ unsafe {
+ c_function(name.as_ptr() as _);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/multitarget/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,22 @@
+corrosion_tests_add_test(multitarget "bin1;bin2;bin3")
+
+# Don't run this test in parallel with others, since the target directory size may cause issues.
+set_tests_properties("multitarget_build" PROPERTIES RUN_SERIAL TRUE)
+
+set_tests_properties("multitarget_run_bin1" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, world!\r?\nHello, bin1! I'm Cpp!"
+ RUN_SERIAL
+ TRUE
+ )
+
+set_tests_properties("multitarget_run_bin2" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, world!\r?\nHello, bin2! I'm Cpp!"
+ RUN_SERIAL
+ TRUE
+ )
+
+set_tests_properties("multitarget_run_bin3" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, world!\r?\nHello, bin3! I'm Cpp!"
+ RUN_SERIAL
+ TRUE
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/multitarget/multitarget/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+
+add_library(cpp-lib4 lib.cpp)
+target_compile_features(cpp-lib4 PRIVATE cxx_std_14)
+set_property(TARGET cpp-lib4 PROPERTY POSITION_INDEPENDENT_CODE ON)
+corrosion_link_libraries(bin1 cpp-lib4)
+corrosion_link_libraries(bin2 cpp-lib4)
+corrosion_link_libraries(bin3 cpp-lib4)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/multitarget/multitarget/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,19 @@
+[package]
+name = "multitarget-crate"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+name = "multitarget_lib"
+crate-type=["lib", "staticlib", "cdylib"]
+
+[[bin]]
+name = "bin1"
+
+[[bin]]
+name = "bin2"
+
+[[bin]]
+name = "bin3"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/multitarget/multitarget/lib.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+#include <iostream>
+
+extern "C" void cpp_function(char const *name) {
+ std::cout << "Hello, " << name << "! I'm Cpp!\n";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/multitarget/multitarget/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+use std::os::raw::c_char;
+
+pub fn hello_world() {
+ println!("Hello, world!");
+}
+
+extern "C" {
+ pub fn cpp_function(name: *const c_char);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/nostd/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,1 @@
+corrosion_tests_add_test(nostd "")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/nostd/nostd/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml NO_STD)
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostdlib")
+list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_LIBRARIES stdc++)
+
+add_library(nostd-cpp-lib STATIC main.cpp)
+target_link_libraries(nostd-cpp-lib PUBLIC rust-nostd-lib)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/nostd/nostd/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+extern "C" void rust_function();
+
+extern "C" void cpp_function() {
+ // Fail on linking issues
+ rust_function();
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/nostd/nostd/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,17 @@
+[package]
+name = "rust-nostd-lib"
+version = "0.1.0"
+edition = "2015"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib"]
+
+[profile.release]
+panic = "abort"
+
+[profile.dev]
+panic = "abort"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/nostd/nostd/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+#![no_std]
+use core::panic::PanicInfo;
+
+#[no_mangle]
+pub extern "C" fn rust_function() {}
+
+#[panic_handler]
+fn panic(_panic: &PanicInfo<'_>) -> ! {
+ loop {}
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,154 @@
+set(configure_cmake_args)
+if(CMAKE_C_COMPILER)
+ list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}")
+endif()
+if(CMAKE_CXX_COMPILER)
+ list(APPEND configure_cmake_args "CXX_COMPILER" "${CMAKE_CXX_COMPILER}")
+endif()
+if(CMAKE_C_COMPILER_TARGET)
+ list(APPEND configure_cmake_args "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}")
+endif()
+if(CMAKE_CXX_COMPILER_TARGET)
+ list(APPEND configure_cmake_args "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}")
+endif()
+if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}")
+endif()
+if(CMAKE_OSX_ARCHITECTURES)
+ list(APPEND configure_cmake_args OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
+endif()
+if(CMAKE_TOOLCHAIN_FILE)
+ list(APPEND configure_cmake_args TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}")
+endif()
+
+add_test(NAME "output_directory_build"
+ COMMAND
+ ${CMAKE_COMMAND}
+ -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake"
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/output directory"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build"
+ GENERATOR "${CMAKE_GENERATOR}"
+ RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
+ CARGO_TARGET "${Rust_CARGO_TARGET}"
+ SYSTEM_NAME "${CMAKE_SYSTEM_NAME}"
+ ${configure_cmake_args}
+
+ COMMAND_EXPAND_LISTS
+)
+set_tests_properties("output_directory_build" PROPERTIES FIXTURES_SETUP "build_fixture_output_directory")
+if(CORROSION_TESTS_INSTALL_CORROSION)
+ set_tests_properties("output_directory_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install")
+endif()
+
+foreach(output_approach targetprop var targetprop_pdb_fallback)
+ if(output_approach STREQUAL "targetprop")
+ set(rust_proj_suffix "1")
+ elseif(output_approach STREQUAL "var")
+ set(rust_proj_suffix "2")
+ elseif(output_approach STREQUAL "targetprop_pdb_fallback")
+ set(rust_proj_suffix "3")
+ else()
+ message(FATAL_ERROR "specify rust project suffix for new output approach ${output_approach}")
+ endif()
+
+ set(bin_name "rust_bin${rust_proj_suffix}${CMAKE_EXECUTABLE_SUFFIX}")
+
+ add_test(NAME output_directory_bin_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/custom_bin_${output_approach}/${bin_name}"
+ )
+ set_tests_properties("output_directory_bin_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+ set(lib_name "rust_lib${rust_proj_suffix}")
+
+ set(static_lib_name "${CMAKE_STATIC_LIBRARY_PREFIX}${lib_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+
+ add_test(NAME output_directory_staticlib_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/custom_archive_${output_approach}/${static_lib_name}"
+ )
+ set_tests_properties("output_directory_staticlib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+ if(MINGW)
+ # Windows-GNU defines "lib" as prefix for DLLs, but cargo creates foo.dll instead of libfoo.dll
+ set(dynamic_lib_prefix "")
+ else()
+ set(dynamic_lib_prefix "${CMAKE_SHARED_LIBRARY_PREFIX}")
+ endif()
+ set(dynamic_lib_name "${dynamic_lib_prefix}${lib_name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+
+ add_test(NAME output_directory_cdylib_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/custom_lib_${output_approach}/${dynamic_lib_name}"
+ )
+ set_tests_properties("output_directory_cdylib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+ if(WIN32)
+ set(implib_name ${CMAKE_IMPORT_LIBRARY_PREFIX}${lib_name}${CMAKE_IMPORT_LIBRARY_SUFFIX})
+
+ add_test(NAME output_directory_implib_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ # Implib is an ARCHIVE artifact, see:
+ # https://cmake.org/cmake/help/v3.25/manual/cmake-buildsystem.7.html#archive-output-artifacts
+ "${CMAKE_CURRENT_BINARY_DIR}/build/custom_archive_${output_approach}/${implib_name}"
+ )
+ set_tests_properties("output_directory_implib_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+ if(MSVC)
+ if(output_approach STREQUAL "targetprop")
+ set(expected_lib_pdb_path "custom_lib_pdb_targetprop")
+ set(expected_bin_pdb_path "custom_bin_pdb_targetprop")
+ elseif(output_approach STREQUAL "var")
+ # When using a CMAKE_ variable instead of a target property, both targets
+ # end up in the same directory.
+ set(expected_lib_pdb_path "custom_binlib_pdb_var")
+ set(expected_bin_pdb_path "custom_binlib_pdb_var")
+ elseif(output_approach STREQUAL "targetprop_pdb_fallback")
+ set(expected_lib_pdb_path "custom_lib_targetprop_pdb_fallback")
+ set(expected_bin_pdb_path "custom_bin_targetprop_pdb_fallback")
+ else()
+ message(FATAL_ERROR "specify rust project suffix for new output approach ${output_approach}")
+ endif()
+
+ set(lib_pdb_name "${lib_name}.pdb")
+ add_test(NAME output_directory_cdylib_pdb_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/${expected_lib_pdb_path}/${lib_pdb_name}"
+ )
+ set_tests_properties("output_directory_cdylib_pdb_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+ set(bin_pdb_name "rust_bin${rust_proj_suffix}.pdb")
+ add_test(NAME output_directory_bin_pdb_${output_approach}
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/${expected_bin_pdb_path}/${bin_pdb_name}"
+ )
+ set_tests_properties("output_directory_bin_pdb_${output_approach}" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+ endif()
+ endif()
+
+endforeach()
+
+add_test(NAME postbuild_custom_command
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/TestFileExists.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/build/another_dir/moved_bin"
+ )
+set_tests_properties("postbuild_custom_command" PROPERTIES FIXTURES_REQUIRED "build_fixture_output_directory")
+
+add_test(NAME "output_directory_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build")
+set_tests_properties("output_directory_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_output_directory")
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/TestFileExists.cmake Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,13 @@
+# CMake script to test if a file exists. Errors if the file does not exist.
+# Expect actual arguments to start at index 3 (cmake -P <script_name>)
+
+# Expect one argument
+if(NOT (CMAKE_ARGC EQUAL "4"))
+ message(FATAL_ERROR "Test Internal Error: Unexpected ARGC Value: ${CMAKE_ARGC}.")
+endif()
+
+set(FILE_PATH "${CMAKE_ARGV3}")
+
+if(NOT ( EXISTS "${FILE_PATH}" ))
+ message(FATAL_ERROR "Test failed: File `${FILE_PATH}` does not exist.")
+endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml)
+
+# Note: The output directories defined here must be manually kept in sync with the expected test location.
+set_target_properties(rust_bin1
+ PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_targetprop"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_pdb_targetprop"
+
+)
+set_target_properties(rust_lib1 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_targetprop")
+set_target_properties(rust_lib1
+ PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_targetprop"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_pdb_targetprop"
+)
+
+add_custom_command(TARGET cargo-build_rust_bin1 POST_BUILD
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/another_dir"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_PROPERTY:rust_bin1,LOCATION>" "${CMAKE_CURRENT_BINARY_DIR}/another_dir/moved_bin"
+ )
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_var")
+set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_binlib_pdb_var")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_var")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_var")
+
+corrosion_import_crate(MANIFEST_PATH proj2/Cargo.toml)
+
+unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+unset(CMAKE_PDB_OUTPUT_DIRECTORY)
+unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
+unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+unset(CMAKE_PDB_OUTPUT_DIRECTORY)
+
+add_executable(consumer consumer.cpp)
+add_dependencies(consumer cargo-build_rust_lib1 cargo-build_rust_lib2)
+
+target_link_libraries(consumer rust_lib1 rust_lib2)
+
+
+corrosion_import_crate(MANIFEST_PATH proj3/Cargo.toml)
+
+# Note: The output directories defined here must be manually kept in sync with the expected test location.
+set_target_properties(rust_bin3
+ PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_bin_targetprop_pdb_fallback"
+)
+set_target_properties(rust_lib3
+ PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_archive_targetprop_pdb_fallback"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom_lib_targetprop_pdb_fallback"
+)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/consumer.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <cstdlib>
+
+extern "C" unsigned int ret_12();
+
+
+int main(int argc, char *argv[])
+{
+ std::cout << "HI\n";
+ unsigned int a = ret_12();
+ if (a != 12) {
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj1/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+[package]
+name = "rust_package1"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+name = "rust_lib1"
+crate-type=["staticlib", "cdylib"]
+
+[[bin]]
+name = "rust_bin1"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj1/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn ret_12() -> u32 {
+ 12
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj2/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+[package]
+name = "rust_package2"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+name = "rust_lib2"
+crate-type=["staticlib", "cdylib"]
+
+[[bin]]
+name = "rust_bin2"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj2/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn ret_12() -> u32 {
+ 12
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj3/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+[package]
+name = "rust_package3"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+name = "rust_lib3"
+crate-type=["staticlib", "cdylib"]
+
+[[bin]]
+name = "rust_bin3"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/output directory/output directory/proj3/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub extern "C" fn ret_12() -> u32 {
+ 12
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+corrosion_tests_add_test(override_crate_type "cpp-exe;cpp-exe-shared")
+
+set_tests_properties("override_crate_type_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+
+set_tests_properties("override_crate_type_run_cpp-exe-shared" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml OVERRIDE_CRATE_TYPE my_rust_lib=staticlib,cdylib)
+
+add_executable(cpp-exe main.cpp)
+target_link_libraries(cpp-exe PUBLIC my_rust_lib)
+
+add_executable(cpp-exe-shared main.cpp)
+target_link_libraries(cpp-exe-shared
+ PUBLIC my_rust_lib-shared)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+extern "C" void rust_function(char const *name);
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ rust_function("Cpp");
+ } else {
+ rust_function(argv[1]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+[package]
+name = "rust-lib"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+
+[lib]
+name = "my_rust_lib"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/build.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works.
+fn main() {
+ println!("Build-script is running.")
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/override_crate_type/override_crate_type/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+use std::os::raw::c_char;
+
+#[no_mangle]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/parse_target_triple/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+corrosion_tests_add_test(parse_target_triple "")
+corrosion_tests_add_test(parse_target_triple_should_fail "")
+
+set_tests_properties("parse_target_triple_build" PROPERTIES FAIL_REGULAR_EXPRESSION
+ "CMake Warning"
+ )
+
+set_tests_properties("parse_target_triple_should_fail_build" PROPERTIES PASS_REGULAR_EXPRESSION
+ "CMake Warning"
+ )
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/parse_target_triple/parse_target_triple/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,106 @@
+# This test is supposed to ensure that the regex in _corrosion_parse_platform works as expected.
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+# Todo: Test if the output matches expectations.
+_corrosion_parse_target_triple("../../blah/x86_64-unknown-custom-gnu.json" arch vendor os env)
+_corrosion_parse_target_triple("x86_64-unknown-custom-gnu.json" arch vendor os env)
+_corrosion_parse_target_triple("/path/to/x86_64-unknown-custom-musl.json" arch vendor os env)
+_corrosion_parse_target_triple("../../blah/x86_64-custom_os.json" arch vendor os env)
+
+# List of builtin targets aquired via `rustup target list` with rust 1.64 on Linux.
+set(rustup_shipped_targets
+ "aarch64-apple-darwin"
+ "aarch64-apple-ios"
+ "aarch64-apple-ios-sim"
+ "aarch64-fuchsia"
+ "aarch64-linux-android"
+ "aarch64-pc-windows-msvc"
+ "aarch64-unknown-linux-gnu"
+ "aarch64-unknown-linux-musl"
+ "aarch64-unknown-none"
+ "aarch64-unknown-none-softfloat"
+ "arm-linux-androideabi"
+ "arm-unknown-linux-gnueabi"
+ "arm-unknown-linux-gnueabihf"
+ "arm-unknown-linux-musleabi"
+ "arm-unknown-linux-musleabihf"
+ "armebv7r-none-eabi"
+ "armebv7r-none-eabihf"
+ "armv5te-unknown-linux-gnueabi"
+ "armv5te-unknown-linux-musleabi"
+ "armv7-linux-androideabi"
+ "armv7-unknown-linux-gnueabi"
+ "armv7-unknown-linux-gnueabihf"
+ "armv7-unknown-linux-musleabi"
+ "armv7-unknown-linux-musleabihf"
+ "armv7a-none-eabi"
+ "armv7r-none-eabi"
+ "armv7r-none-eabihf"
+ "asmjs-unknown-emscripten"
+ "i586-pc-windows-msvc"
+ "i586-unknown-linux-gnu"
+ "i586-unknown-linux-musl"
+ "i686-linux-android"
+ "i686-pc-windows-gnu"
+ "i686-pc-windows-msvc"
+ "i686-unknown-freebsd"
+ "i686-unknown-linux-gnu"
+ "i686-unknown-linux-musl"
+ "mips-unknown-linux-gnu"
+ "mips-unknown-linux-musl"
+ "mips64-unknown-linux-gnuabi64"
+ "mips64-unknown-linux-muslabi64"
+ "mips64el-unknown-linux-gnuabi64"
+ "mips64el-unknown-linux-muslabi64"
+ "mipsel-unknown-linux-gnu"
+ "mipsel-unknown-linux-musl"
+ "nvptx64-nvidia-cuda"
+ "powerpc-unknown-linux-gnu"
+ "powerpc64-unknown-linux-gnu"
+ "powerpc64le-unknown-linux-gnu"
+ "riscv32i-unknown-none-elf"
+ "riscv32imac-unknown-none-elf"
+ "riscv32imc-unknown-none-elf"
+ "riscv64gc-unknown-linux-gnu"
+ "riscv64gc-unknown-none-elf"
+ "riscv64imac-unknown-none-elf"
+ "s390x-unknown-linux-gnu"
+ "sparc64-unknown-linux-gnu"
+ "sparcv9-sun-solaris"
+ "thumbv6m-none-eabi"
+ "thumbv7em-none-eabi"
+ "thumbv7em-none-eabihf"
+ "thumbv7m-none-eabi"
+ "thumbv7neon-linux-androideabi"
+ "thumbv7neon-unknown-linux-gnueabihf"
+ "thumbv8m.base-none-eabi"
+ "thumbv8m.main-none-eabi"
+ "thumbv8m.main-none-eabihf"
+ "wasm32-unknown-emscripten"
+ "wasm32-unknown-unknown"
+ "wasm32-wasi"
+ "x86_64-apple-darwin"
+ "x86_64-apple-ios"
+ "x86_64-fortanix-unknown-sgx"
+ "x86_64-fuchsia"
+ "x86_64-linux-android"
+ "x86_64-pc-solaris"
+ "x86_64-pc-windows-gnu"
+ "x86_64-pc-windows-msvc"
+ "x86_64-sun-solaris"
+ "x86_64-unknown-freebsd"
+ "x86_64-unknown-illumos"
+ "x86_64-unknown-linux-gnu"
+ "x86_64-unknown-linux-gnux32"
+ "x86_64-unknown-linux-musl"
+ "x86_64-unknown-netbsd"
+ "x86_64-unknown-none"
+ "x86_64-unknown-redox"
+)
+set(other_targets riscv32imc-esp-espidf xtensa-esp32s3-none-elf)
+
+foreach(target ${rustup_shipped_targets} ${other_targets})
+ _corrosion_parse_target_triple("${target}" arch vendor os env)
+endforeach()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/parse_target_triple/parse_target_triple_should_fail/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+# This test is supposed to ensure that the regex in _corrosion_parse_platform works as expected.
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+_corrosion_parse_target_triple("x86_64-unknown-linux-gnu-toomuch" arch vendor os env)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+corrosion_tests_add_test(rust2cpp "cpp-exe;cpp-exe-shared")
+
+set_tests_properties("rust2cpp_run_cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
+
+set_tests_properties("rust2cpp_run_cpp-exe-shared" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Hello, Cpp! I'm Rust!\r?\n$"
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/rust2cpp/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+
+add_executable(cpp-exe main.cpp)
+target_link_libraries(cpp-exe PUBLIC rust_lib)
+
+add_executable(cpp-exe-shared main.cpp)
+target_link_libraries(cpp-exe-shared
+ PUBLIC rust_lib-shared)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/rust2cpp/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,9 @@
+extern "C" void rust_function(char const *name);
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ rust_function("Cpp");
+ } else {
+ rust_function(argv[1]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/rust2cpp/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+[package]
+name = "rust-lib"
+version = "0.1.0"
+authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+
+[lib]
+crate-type=["staticlib", "cdylib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/rust2cpp/rust/build.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+// Build-scripts also need to be linked, so just add a dummy buildscript ensuring this works.
+fn main() {
+ println!("Build-script is running.")
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rust2cpp/rust2cpp/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+use std::os::raw::c_char;
+
+#[no_mangle]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+corrosion_tests_add_test(rustflags "rustflags-cpp-exe")
+
+set_tests_properties("rustflags_run_rustflags-cpp-exe" PROPERTIES PASS_REGULAR_EXPRESSION
+ "Hello, Cpp! I'm Rust!\r?\nHello, Cpp again! I'm Rust in (Debug|Release) mode again!\r?\nHello, Cpp again! I'm Rust again, third time the charm!\r?\n$"
+ )
+
+corrosion_tests_add_test(cargo_config_rustflags "cargo_config_rustflags")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/cargo_config_rustflags/.cargo/config.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,2 @@
+[build]
+rustflags = ["--cfg=some_cargo_config_rustflag"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/cargo_config_rustflags/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH Cargo.toml)
+
+# Do not use `corrosion_add_target_rustflags()` here, since we want to test if the rustflag from `.cargo/config.toml`
+# is picked up.
+
+# Local rustflags should not interfere with `.cargo/config.toml`, so enable one.
+corrosion_add_target_local_rustflags(cargo_config_rustflags "--cfg=local_rustflag")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/cargo_config_rustflags/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+[package]
+name = "cargo_config_rustflags"
+version = "0.1.0"
+edition = "2018"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/cargo_config_rustflags/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,16 @@
+
+#[cfg(some_cargo_config_rustflag)]
+fn print_line() {
+ println!("Rustflag is enabled");
+}
+
+// test that local rustflags don't override global rustflags set via `.cargo/config`
+#[cfg(local_rustflag)]
+fn test_local_rustflag() {
+ println!("local_rustflag was enabled");
+}
+
+fn main() {
+ print_line();
+ test_local_rustflag();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
+
+add_executable(rustflags-cpp-exe main.cpp)
+target_link_libraries(rustflags-cpp-exe PUBLIC rustflag_test_lib)
+
+# Test --cfg=key="value" rustflag.
+corrosion_add_target_rustflags(rustflag_test_lib --cfg=test_rustflag_cfg1="test_rustflag_cfg1_value")
+
+# Test using a generator expression to produce a rustflag and passing multiple rustflags.
+corrosion_add_target_rustflags(rustflag_test_lib
+ --cfg=test_rustflag_cfg2="$<IF:$<OR:$<CONFIG:Debug>,$<CONFIG:>>,debug,release>"
+ "--cfg=test_rustflag_cfg3"
+)
+
+corrosion_add_target_local_rustflags(rustflag_test_lib "--cfg=test_local_rustflag1")
+corrosion_add_target_local_rustflags(rustflag_test_lib --cfg=test_local_rustflag2="value")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,13 @@
+extern "C" void rust_function(char const *name);
+extern "C" void rust_second_function(char const *name);
+extern "C" void rust_third_function(char const *name);
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ rust_function("Cpp");
+ rust_second_function("Cpp again");
+ rust_third_function("Cpp again");
+ } else {
+ rust_function(argv[1]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/rust/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,11 @@
+[package]
+name = "rustflag-test-lib"
+version = "0.1.0"
+license = "MIT"
+edition = "2018"
+
+[dependencies]
+some_dependency = { path = "some_dependency" }
+
+[lib]
+crate-type=["staticlib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/rust/some_dependency/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+[package]
+name = "some_dependency"
+version = "0.1.0"
+license = "MIT"
+edition = "2018"
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/rust/some_dependency/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,10 @@
+//! Test that the local rustflags are only passed to the main crate and not to dependencies.
+#[cfg(test_local_rustflag1)]
+const _: [(); 1] = [(); 2];
+
+#[cfg(test_local_rustflag2 = "value")]
+const _: [(); 1] = [(); 2];
+
+pub fn some_function() -> u32 {
+ 42
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/rustflags/rustflags/rust/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,40 @@
+#[cfg(test_rustflag_cfg1 = "test_rustflag_cfg1_value")]
+use std::os::raw::c_char;
+
+#[no_mangle]
+#[cfg(test_rustflag_cfg1 = "test_rustflag_cfg1_value")]
+pub extern "C" fn rust_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust!", name);
+}
+
+#[no_mangle]
+#[cfg(all(debug_assertions, test_rustflag_cfg2 = "debug"))]
+pub extern "C" fn rust_second_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust in Debug mode again!", name);
+}
+
+#[no_mangle]
+#[cfg(all(not(debug_assertions), test_rustflag_cfg2 = "release"))]
+pub extern "C" fn rust_second_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust in Release mode again!", name);
+}
+
+#[no_mangle]
+#[cfg(test_rustflag_cfg3)]
+pub extern "C" fn rust_third_function(name: *const c_char) {
+ let name = unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() };
+ println!("Hello, {}! I'm Rust again, third time the charm!", name);
+ assert_eq!(some_dependency::some_function(), 42);
+}
+
+#[cfg(not(test_rustflag_cfg3))]
+const _: [(); 1] = [(); 2];
+
+#[cfg(not(test_local_rustflag1))]
+const _: [(); 1] = [(); 2];
+
+#[cfg(not(test_local_rustflag2 = "value"))]
+const _: [(); 1] = [(); 2];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,6 @@
+corrosion_tests_add_test(workspace "my_program")
+
+set_tests_properties("workspace_run_my_program" PROPERTIES PASS_REGULAR_EXPRESSION
+ "^Ok\r?\n$"
+ )
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_project VERSION 0.1.0)
+include(../../test_header.cmake)
+
+corrosion_import_crate(
+ MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml
+ CRATES member1 member2
+ IMPORTED_CRATES imported_crate_list
+)
+
+#NOTE: member3 also contains a binary called my_program, but that shouldn't be a problem since it is not imported
+add_executable(my_program main.cpp)
+target_link_libraries(my_program PUBLIC member1 member2)
+
+# Test that the list of imported crates matches our expectations.
+if(NOT DEFINED imported_crate_list)
+ message(FATAL_ERROR "Corrosion failed to set the variable passed via IMPORTED_CRATES.")
+endif()
+set(expected_crates member1 member2)
+foreach(crate ${expected_crates})
+ if(NOT "${crate}" IN_LIST imported_crate_list)
+ message(FATAL_ERROR "Expected ${crate} to be imported, but it wasn't. Imported crate list:\n"
+ "${imported_crate_list}"
+ )
+ endif()
+endforeach()
+set(additional_crates ${imported_crate_list})
+list(REMOVE_ITEM additional_crates ${expected_crates})
+if(additional_crates)
+ message(FATAL_ERROR "Corrosion unexpectedly imported the following crates: ${additional_crates}")
+endif()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,5 @@
+[workspace]
+members=["member1", "member2", "member3"]
+
+[workspace.package]
+version = "0.1.0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,4 @@
+#include <iostream>
+int main() {
+ std::cout << "Ok";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member1/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "member1"
+version = "0.1.0"
+edition = "2018"
+description = "descr;\"hello\\"
+
+[lib]
+crate-type = [ "lib", "cdylib" ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member1/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ assert_eq!(2 + 2, 4);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member2/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,8 @@
+[package]
+name = "member2"
+version = "0.1.0"
+authors = ["Olivier Goffart <ogoffart@sixtyfps.io>"]
+edition = "2018"
+
+[lib]
+crate-type = ["staticlib"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member2/src/lib.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ assert_eq!(2 + 2, 4);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member3/Cargo.toml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,14 @@
+[package]
+name = "member3"
+version = "0.1.0"
+authors = ["Olivier Goffart <ogoffart@sixtyfps.io>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[[bin]]
+name = "my_program"
+path = "src/main.rs"
+
+[dependencies]
+member1 = { path = "../member1" }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/corrosion/test/workspace/workspace/member3/src/main.rs Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/map_templates_tool/CMakeLists.txt Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(map_templates_tool VERSION 1.0 LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.2 COMPONENTS Quick REQUIRED)
+
+qt_add_executable(appmap_templates_tool
+ main.cpp
+)
+
+qt_add_qml_module(appmap_templates_tool
+ URI map_templates_tool
+ VERSION 1.0
+ QML_FILES main.qml
+)
+
+set_target_properties(appmap_templates_tool PROPERTIES
+ MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+target_link_libraries(appmap_templates_tool
+ PRIVATE Qt6::Quick)
+
+install(TARGETS appmap_templates_tool
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/map_templates_tool/main.cpp Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,19 @@
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ const QUrl url(u"qrc:/map_templates_tool/main.qml"_qs);
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
+ &app, [url](QObject *obj, const QUrl &objUrl) {
+ if (!obj && url == objUrl)
+ QCoreApplication::exit(-1);
+ }, Qt::QueuedConnection);
+ engine.load(url);
+
+ return app.exec();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/map_templates_tool/main.qml Tue Dec 31 15:19:43 2024 +0100
@@ -0,0 +1,258 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Shapes
+
+Window {
+ id: control
+
+ width: 1024
+ height: 768
+ visible: true
+ title: qsTr("Map Templates")
+
+ property bool hasError: false
+
+ Page {
+ id: page
+ anchors.fill: parent
+
+ Rectangle {
+ id: mapContainer
+
+ property int spaceForCode: Math.max(250, parent.height * 0.6)
+ property int mapWidth: 2048
+ property int mapHeight: 1024
+ property real aspectRatio: mapWidth / mapHeight
+ property bool fitWidth: aspectRatio > (parent.width / (parent.height - spaceForCode))
+
+ implicitWidth: fitWidth ? parent.width : (parent.height - spaceForCode) * aspectRatio
+ implicitHeight: fitWidth ? parent.width / aspectRatio : (parent.height - spaceForCode)
+
+ x: (parent.width - width) / 2
+
+ border.width: 2
+ border.color: hasError ? "red" : "black"
+ }
+
+ Shape {
+ id: shape
+
+ anchors.fill: mapContainer
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: mapContainer
+ hoverEnabled: true
+ }
+
+ Label {
+ text: mouseArea.containsMouse ? "(%1, %2)".arg(Math.floor(mouseArea.mouseX / mouseArea.width * mapContainer.mapWidth)).arg(Math.floor(mouseArea.mouseY / mouseArea.height * mapContainer.mapHeight)) : ""
+ }
+
+ Rectangle {
+ anchors.fill: codeInput
+ color: "gray"
+ }
+
+ TextEdit {
+ id: codeInput
+
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: parent.height - mapContainer.height
+
+ text: " -
+ width: 3072
+ height: 1424
+ can_flip: false
+ can_invert: false
+ can_mirror: true
+ is_negative: false
+ put_girders: true
+ max_hedgehogs: 18
+ outline_points:
+ -
+ - {x: 748, y: 1424, w: 1, h: 1}
+ - {x: 636, y: 1252, w: 208, h: 72}
+ - {x: 898, y: 1110, w: 308, h: 60}
+ - {x: 1128, y: 1252, w: 434, h: 40}
+ - {x: 1574, y: 1112, w: 332, h: 40}
+ - {x: 1802, y: 1238, w: 226, h: 36}
+ - {x: 1930, y: 1424, w: 1, h: 1}
+ -
+ - {x: 2060, y: 898, w: 111, h: 111}
+ - {x: 1670, y: 876, w: 34, h: 102}
+ - {x: 1082, y: 814, w: 284, h: 132}
+ - {x: 630, y: 728, w: 126, h: 168}
+ - {x: 810, y: 574, w: 114, h: 100}
+ - {x: 1190, y: 572, w: 352, h: 120}
+ - {x: 1674, y: 528, w: 60, h: 240}
+ - {x: 1834, y: 622, w: 254, h: 116}
+ fill_points:
+ - {x: 1423, y: 0}
+"
+
+ onTextChanged: {
+ const template = parseInput()
+
+ if (template) {
+ mapContainer.mapWidth = Number(template.width)
+ mapContainer.mapHeight = Number(template.height)
+
+ shape.data = renderTemplate(template)
+ }
+ }
+ }
+ }
+
+ function parseInput() {
+ let code = codeInput.text.split('\n')
+
+ if(code[0] !== " -") {
+ hasError = true
+ return
+ }
+
+ code = code.slice(1)
+ code.push("")
+
+ let parsed = ({})
+ let polygonAccumulator = []
+ let pointAccumulator = []
+ let key = ""
+ code.forEach(line => {
+ let newKey
+ if (line === " outline_points:") {
+ newKey = "outline_points"
+ }
+
+ if (line === " walls:") {
+ newKey = "walls"
+ }
+
+ if (line === " fill_points:") {
+ newKey = "fill_points"
+ }
+
+ if (line === "") {
+ newKey = "_"
+ }
+
+ if (key === "fill_points" && line.startsWith(" - {")) {
+ // ignore
+ return
+ }
+
+ if (newKey) {
+ if (key.length > 0) {
+ polygonAccumulator.push(pointAccumulator)
+ parsed[key] = polygonAccumulator
+ }
+
+ key = newKey
+ polygonAccumulator = []
+ pointAccumulator = []
+
+ return
+ }
+
+ if (line === " -") {
+ if (pointAccumulator.length > 0) {
+ polygonAccumulator.push(pointAccumulator)
+ pointAccumulator = []
+ }
+
+ return
+ }
+
+ const matchValue = line.match(/^\s{4}(\w+):\s(.+)$/);
+
+ if (matchValue) {
+ parsed[matchValue[1]] = matchValue[2]
+ return
+ }
+
+ const matchPoint = line.match(/^\s{8}-\s\{([^}]+)\}$/);
+
+ if (matchPoint) {
+ const point = matchPoint[1].split(", ").reduce((obj, pair) => {
+ const [key, value] = pair.split(": ");
+ obj[key] = isNaN(value) ? value : parseInt(value);
+ return obj;
+ }, {})
+ pointAccumulator.push(point)
+ return
+ }
+
+ console.log("Unrecognized: " + JSON.stringify(line))
+ hasError = true
+ throw ""
+ })
+
+ hasError = false
+
+ return parsed
+ }
+
+ Component {
+ id: shapePathComponent
+
+ ShapePath {
+ fillColor: "transparent"
+ scale: Qt.size(mapContainer.width / mapContainer.mapWidth, mapContainer.height / mapContainer.mapHeight)
+ strokeWidth: 3
+ }
+ }
+
+ Component {
+ id: pathLineComponent
+ PathLine {
+ }
+ }
+
+ function polygons2shapes(polygons, lineColor, rectColor) {
+ if (!Array.isArray(polygons)) {
+ return []
+ }
+
+ let rectangles = []
+
+ polygons.forEach(polygon => polygon.forEach(r => {
+ let shapePath = shapePathComponent.createObject(shape)
+ shapePath.strokeWidth = 1
+ shapePath.strokeColor = rectColor
+
+ shapePath.startX = r.x
+ shapePath.startY = r.y
+ shapePath.pathElements = [
+ pathLineComponent.createObject(shapePath, {x: r.x, y: r.y + r.h}),
+ pathLineComponent.createObject(shapePath, {x: r.x + r.w, y: r.y + r.h}),
+ pathLineComponent.createObject(shapePath, {x: r.x + r.w, y: r.y}),
+ pathLineComponent.createObject(shapePath, {x: r.x, y: r.y})
+ ]
+
+ rectangles.push(shapePath)
+ }))
+ let polygonShapes = polygons.map(polygon => {
+ let points = polygon.map(r => ({x: r.x + r.w / 2, y: r.y + r.h / 2}))
+ let shapePath = shapePathComponent.createObject(shape)
+ let start = points[points.length - 1]
+
+ shapePath.strokeColor = lineColor
+ shapePath.startX = start.x
+ shapePath.startY = start.y
+ shapePath.pathElements = points.map(p => pathLineComponent.createObject(shapePath, p))
+
+ return shapePath
+ })
+
+ return rectangles.concat(polygonShapes)
+ }
+
+ function renderTemplate(template) {
+ return polygons2shapes(template.outline_points, "red", "black").concat(polygons2shapes(template.walls, "gray", "gray"))
+ }
+}
--- a/tools/pas2c/PascalParser.hs Sat Sep 28 22:27:13 2024 +0200
+++ b/tools/pas2c/PascalParser.hs Tue Dec 31 15:19:43 2024 +0100
@@ -346,6 +346,7 @@
, try $ string "overload;"
, try $ string "export;"
, try $ string "varargs;"
+ , try $ string "external;"
, try (string' "external") >> comments >> iD >> comments >>
optional (string' "name" >> comments >> stringLiteral pas) >> string' ";" >> return "external;"
]