Initial commit.
This commit is contained in:
parent
fc115e3dc6
commit
06832c885e
20
Recast/Build/VC9/Recast.sln
Normal file
20
Recast/Build/VC9/Recast.sln
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Recast", "Recast.vcproj", "{CEF242C5-E9A3-403B-BAFF-99397BDA5730}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CEF242C5-E9A3-403B-BAFF-99397BDA5730}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{CEF242C5-E9A3-403B-BAFF-99397BDA5730}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{CEF242C5-E9A3-403B-BAFF-99397BDA5730}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{CEF242C5-E9A3-403B-BAFF-99397BDA5730}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
BIN
Recast/Build/VC9/Recast.suo
Normal file
BIN
Recast/Build/VC9/Recast.suo
Normal file
Binary file not shown.
275
Recast/Build/VC9/Recast.vcproj
Normal file
275
Recast/Build/VC9/Recast.vcproj
Normal file
@ -0,0 +1,275 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="Recast"
|
||||
ProjectGUID="{CEF242C5-E9A3-403B-BAFF-99397BDA5730}"
|
||||
RootNamespace="Recast"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="..\..\Examples"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\Contrib\SDL\include;..\..\Include;..\..\Examples;$(NOINHERIT)"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="opengl32.lib glu32.lib sdlmain.lib sdl.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\Contrib\SDL\lib"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="..\..\Examples"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="..\..\Contrib\SDL\include;..\..\Include;..\..\Examples;$(NOINHERIT)"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="opengl32.lib glu32.lib sdlmain.lib sdl.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\Contrib\SDL\lib"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\Examples\demo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Examples\glfont.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Examples\imgui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Examples\MeshLoaderObj.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\Recast.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastContour.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastDebugDraw.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastFilter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastLog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastMesh.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastRasterization.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastRegion.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\RecastTimer.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\Examples\glfont.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Examples\imgui.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Examples\MeshLoaderObj.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Include\Recast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Include\RecastDebugDraw.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Include\RecastLog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Include\RecastTimer.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
BIN
Recast/Build/Xcode/English.lproj/InfoPlist.strings
Normal file
BIN
Recast/Build/Xcode/English.lproj/InfoPlist.strings
Normal file
Binary file not shown.
3034
Recast/Build/Xcode/English.lproj/MainMenu.xib
Normal file
3034
Recast/Build/Xcode/English.lproj/MainMenu.xib
Normal file
File diff suppressed because it is too large
Load Diff
28
Recast/Build/Xcode/Info.plist
Normal file
28
Recast/Build/Xcode/Info.plist
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
Recast/Build/Xcode/Recast.xcodeproj/TemplateIcon.icns
Normal file
BIN
Recast/Build/Xcode/Recast.xcodeproj/TemplateIcon.icns
Normal file
Binary file not shown.
250
Recast/Build/Xcode/Recast.xcodeproj/memon.pbxuser
Normal file
250
Recast/Build/Xcode/Recast.xcodeproj/memon.pbxuser
Normal file
@ -0,0 +1,250 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
activeBuildConfigurationName = Debug;
|
||||
activeExecutable = 6B8632970F78114600E2684A /* Recast */;
|
||||
activeTarget = 8D1107260486CEB800E47090 /* Recast */;
|
||||
addToTargets = (
|
||||
8D1107260486CEB800E47090 /* Recast */,
|
||||
);
|
||||
codeSenseManager = 6B8632AA0F78115100E2684A /* Code sense */;
|
||||
executables = (
|
||||
6B8632970F78114600E2684A /* Recast */,
|
||||
);
|
||||
perUserDictionary = {
|
||||
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
|
||||
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||
PBXFileTableDataSourceColumnWidthsKey = (
|
||||
20,
|
||||
625,
|
||||
20,
|
||||
48,
|
||||
43,
|
||||
43,
|
||||
20,
|
||||
);
|
||||
PBXFileTableDataSourceColumnsKey = (
|
||||
PBXFileDataSource_FiletypeID,
|
||||
PBXFileDataSource_Filename_ColumnID,
|
||||
PBXFileDataSource_Built_ColumnID,
|
||||
PBXFileDataSource_ObjectSize_ColumnID,
|
||||
PBXFileDataSource_Errors_ColumnID,
|
||||
PBXFileDataSource_Warnings_ColumnID,
|
||||
PBXFileDataSource_Target_ColumnID,
|
||||
);
|
||||
};
|
||||
PBXPerProjectTemplateStateSaveDate = 259608223;
|
||||
PBXWorkspaceStateSaveDate = 259608223;
|
||||
};
|
||||
perUserProjectItems = {
|
||||
6B68D7640F781974007E6D78 /* PBXTextBookmark */ = 6B68D7640F781974007E6D78 /* PBXTextBookmark */;
|
||||
6B85EA8A0F7970D500780B56 /* PBXTextBookmark */ = 6B85EA8A0F7970D500780B56 /* PBXTextBookmark */;
|
||||
6B8633370F7813A600E2684A /* PBXTextBookmark */ = 6B8633370F7813A600E2684A /* PBXTextBookmark */;
|
||||
6B86333A0F7813A600E2684A /* PBXTextBookmark */ = 6B86333A0F7813A600E2684A /* PBXTextBookmark */;
|
||||
6B86333B0F7813A600E2684A /* PBXTextBookmark */ = 6B86333B0F7813A600E2684A /* PBXTextBookmark */;
|
||||
6B8633780F78173000E2684A /* PBXTextBookmark */ = 6B8633780F78173000E2684A /* PBXTextBookmark */;
|
||||
6B8633790F78173000E2684A /* PBXTextBookmark */ = 6B8633790F78173000E2684A /* PBXTextBookmark */;
|
||||
6B86337C0F78173000E2684A /* PBXTextBookmark */ = 6B86337C0F78173000E2684A /* PBXTextBookmark */;
|
||||
6B86337E0F78173000E2684A /* PBXTextBookmark */ = 6B86337E0F78173000E2684A /* PBXTextBookmark */;
|
||||
6B8633820F78174400E2684A /* PBXTextBookmark */ = 6B8633820F78174400E2684A /* PBXTextBookmark */;
|
||||
6B8633840F78174400E2684A /* PBXTextBookmark */ = 6B8633840F78174400E2684A /* PBXTextBookmark */;
|
||||
};
|
||||
sourceControlManager = 6B8632A90F78115100E2684A /* Source Control */;
|
||||
userBuildSettings = {
|
||||
};
|
||||
};
|
||||
6B68D7640F781974007E6D78 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8632BC0F7811CB00E2684A /* demo.cpp */;
|
||||
name = "demo.cpp: 631";
|
||||
rLen = 0;
|
||||
rLoc = 16040;
|
||||
rType = 0;
|
||||
vrLen = 1544;
|
||||
vrLoc = 15684;
|
||||
};
|
||||
6B85EA8A0F7970D500780B56 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8632BC0F7811CB00E2684A /* demo.cpp */;
|
||||
name = "demo.cpp: 640";
|
||||
rLen = 0;
|
||||
rLoc = 16397;
|
||||
rType = 0;
|
||||
vrLen = 1544;
|
||||
vrLoc = 15684;
|
||||
};
|
||||
6B8632970F78114600E2684A /* Recast */ = {
|
||||
isa = PBXExecutable;
|
||||
activeArgIndices = (
|
||||
);
|
||||
argumentStrings = (
|
||||
);
|
||||
autoAttachOnCrash = 1;
|
||||
breakpointsEnabled = 0;
|
||||
configStateDict = {
|
||||
};
|
||||
customDataFormattersEnabled = 1;
|
||||
debuggerPlugin = GDBDebugging;
|
||||
disassemblyDisplayState = 0;
|
||||
dylibVariantSuffix = "";
|
||||
enableDebugStr = 1;
|
||||
environmentEntries = (
|
||||
);
|
||||
executableSystemSymbolLevel = 0;
|
||||
executableUserSymbolLevel = 0;
|
||||
libgmallocEnabled = 0;
|
||||
name = Recast;
|
||||
sourceDirectories = (
|
||||
);
|
||||
};
|
||||
6B8632A90F78115100E2684A /* Source Control */ = {
|
||||
isa = PBXSourceControlManager;
|
||||
fallbackIsa = XCSourceControlManager;
|
||||
isSCMEnabled = 0;
|
||||
scmConfiguration = {
|
||||
};
|
||||
};
|
||||
6B8632AA0F78115100E2684A /* Code sense */ = {
|
||||
isa = PBXCodeSenseManager;
|
||||
indexTemplatePath = "";
|
||||
};
|
||||
6B8632BA0F78119A00E2684A /* SDLMain.m */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {943, 6016}}";
|
||||
sepNavSelRange = "{4217, 0}";
|
||||
sepNavVisRange = "{3795, 1449}";
|
||||
};
|
||||
};
|
||||
6B8632BC0F7811CB00E2684A /* demo.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {803, 11568}}";
|
||||
sepNavSelRange = "{16397, 0}";
|
||||
sepNavVisRange = "{15684, 1544}";
|
||||
};
|
||||
};
|
||||
6B8633370F7813A600E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8633380F7813A600E2684A /* SDL_events.h */;
|
||||
name = "SDL_events.h: 238";
|
||||
rLen = 0;
|
||||
rLoc = 8641;
|
||||
rType = 0;
|
||||
vrLen = 785;
|
||||
vrLoc = 8262;
|
||||
};
|
||||
6B8633380F7813A600E2684A /* SDL_events.h */ = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = SDL_events.h;
|
||||
path = /Library/Frameworks/SDL.framework/Versions/A/Headers/SDL_events.h;
|
||||
sourceTree = "<absolute>";
|
||||
};
|
||||
6B86333A0F7813A600E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8632BC0F7811CB00E2684A /* demo.cpp */;
|
||||
name = "demo.cpp: 37";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 438;
|
||||
vrLoc = 598;
|
||||
};
|
||||
6B86333B0F7813A600E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B86333C0F7813A600E2684A /* SDL_events.h */;
|
||||
name = "SDL_events.h: 238";
|
||||
rLen = 0;
|
||||
rLoc = 8641;
|
||||
rType = 0;
|
||||
vrLen = 785;
|
||||
vrLoc = 8262;
|
||||
};
|
||||
6B86333C0F7813A600E2684A /* SDL_events.h */ = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = SDL_events.h;
|
||||
path = /Library/Frameworks/SDL.framework/Versions/A/Headers/SDL_events.h;
|
||||
sourceTree = "<absolute>";
|
||||
};
|
||||
6B86335E0F7816FA00E2684A /* Recast.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {803, 4720}}";
|
||||
sepNavSelRange = "{827, 0}";
|
||||
sepNavVisRange = "{441, 1040}";
|
||||
};
|
||||
};
|
||||
6B8633650F7816FA00E2684A /* RecastMesh.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {803, 10768}}";
|
||||
sepNavSelRange = "{1485, 0}";
|
||||
sepNavVisRange = "{667, 687}";
|
||||
};
|
||||
};
|
||||
6B8633780F78173000E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8632BA0F78119A00E2684A /* SDLMain.m */;
|
||||
name = "SDLMain.m: 146";
|
||||
rLen = 0;
|
||||
rLoc = 4217;
|
||||
rType = 0;
|
||||
vrLen = 1449;
|
||||
vrLoc = 3795;
|
||||
};
|
||||
6B8633790F78173000E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B86335E0F7816FA00E2684A /* Recast.cpp */;
|
||||
name = "Recast.cpp: 15";
|
||||
rLen = 0;
|
||||
rLoc = 827;
|
||||
rType = 0;
|
||||
vrLen = 1040;
|
||||
vrLoc = 441;
|
||||
};
|
||||
6B86337C0F78173000E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8632BA0F78119A00E2684A /* SDLMain.m */;
|
||||
name = "SDLMain.m: 146";
|
||||
rLen = 0;
|
||||
rLoc = 4217;
|
||||
rType = 0;
|
||||
vrLen = 1449;
|
||||
vrLoc = 3795;
|
||||
};
|
||||
6B86337E0F78173000E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B86335E0F7816FA00E2684A /* Recast.cpp */;
|
||||
name = "Recast.cpp: 15";
|
||||
rLen = 0;
|
||||
rLoc = 827;
|
||||
rType = 0;
|
||||
vrLen = 1040;
|
||||
vrLoc = 441;
|
||||
};
|
||||
6B8633820F78174400E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8633650F7816FA00E2684A /* RecastMesh.cpp */;
|
||||
name = "RecastMesh.cpp: 42";
|
||||
rLen = 0;
|
||||
rLoc = 1485;
|
||||
rType = 0;
|
||||
vrLen = 687;
|
||||
vrLoc = 667;
|
||||
};
|
||||
6B8633840F78174400E2684A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = 6B8633650F7816FA00E2684A /* RecastMesh.cpp */;
|
||||
name = "RecastMesh.cpp: 42";
|
||||
rLen = 0;
|
||||
rLoc = 1485;
|
||||
rType = 0;
|
||||
vrLen = 687;
|
||||
vrLoc = 667;
|
||||
};
|
||||
8D1107260486CEB800E47090 /* Recast */ = {
|
||||
activeExec = 0;
|
||||
executables = (
|
||||
6B8632970F78114600E2684A /* Recast */,
|
||||
);
|
||||
};
|
||||
}
|
1484
Recast/Build/Xcode/Recast.xcodeproj/memon.perspectivev3
Normal file
1484
Recast/Build/Xcode/Recast.xcodeproj/memon.perspectivev3
Normal file
File diff suppressed because it is too large
Load Diff
364
Recast/Build/Xcode/Recast.xcodeproj/project.pbxproj
Normal file
364
Recast/Build/Xcode/Recast.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,364 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 45;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
|
||||
6B8632BB0F78119A00E2684A /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B8632BA0F78119A00E2684A /* SDLMain.m */; };
|
||||
6B8632BD0F7811CB00E2684A /* demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8632BC0F7811CB00E2684A /* demo.cpp */; };
|
||||
6B8632DA0F78122C00E2684A /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632D90F78122C00E2684A /* SDL.framework */; };
|
||||
6B8632DC0F78123E00E2684A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632DB0F78123E00E2684A /* OpenGL.framework */; };
|
||||
6B86335A0F7816C900E2684A /* glfont.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633540F7816C900E2684A /* glfont.cpp */; };
|
||||
6B86335B0F7816C900E2684A /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633560F7816C900E2684A /* imgui.cpp */; };
|
||||
6B86335C0F7816C900E2684A /* MeshLoaderObj.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633580F7816C900E2684A /* MeshLoaderObj.cpp */; };
|
||||
6B86336A0F7816FA00E2684A /* Recast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B86335E0F7816FA00E2684A /* Recast.cpp */; };
|
||||
6B86336B0F7816FA00E2684A /* RecastContour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B86335F0F7816FA00E2684A /* RecastContour.cpp */; };
|
||||
6B86336C0F7816FA00E2684A /* RecastDebugDraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633600F7816FA00E2684A /* RecastDebugDraw.cpp */; };
|
||||
6B86336D0F7816FA00E2684A /* RecastFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633620F7816FA00E2684A /* RecastFilter.cpp */; };
|
||||
6B86336E0F7816FA00E2684A /* RecastLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633630F7816FA00E2684A /* RecastLog.cpp */; };
|
||||
6B86336F0F7816FA00E2684A /* RecastMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633650F7816FA00E2684A /* RecastMesh.cpp */; };
|
||||
6B8633700F7816FA00E2684A /* RecastRasterization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633660F7816FA00E2684A /* RecastRasterization.cpp */; };
|
||||
6B8633710F7816FA00E2684A /* RecastRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633670F7816FA00E2684A /* RecastRegion.cpp */; };
|
||||
6B8633720F7816FA00E2684A /* RecastTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8633680F7816FA00E2684A /* RecastTimer.cpp */; };
|
||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||
1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
32CA4F630368D1EE00C91783 /* Recast_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Recast_Prefix.pch; sourceTree = "<group>"; };
|
||||
6B68D7620F78196F007E6D78 /* RecastDebugDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecastDebugDraw.h; path = ../../Include/RecastDebugDraw.h; sourceTree = SOURCE_ROOT; };
|
||||
6B68D7630F78196F007E6D78 /* RecastTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecastTimer.h; path = ../../Include/RecastTimer.h; sourceTree = SOURCE_ROOT; };
|
||||
6B8632B90F78119A00E2684A /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLMain.h; path = ../../Examples/SDLMain.h; sourceTree = SOURCE_ROOT; };
|
||||
6B8632BA0F78119A00E2684A /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLMain.m; path = ../../Examples/SDLMain.m; sourceTree = SOURCE_ROOT; };
|
||||
6B8632BC0F7811CB00E2684A /* demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = demo.cpp; path = ../../Examples/demo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8632D90F78122C00E2684A /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = Library/Frameworks/SDL.framework; sourceTree = SDKROOT; };
|
||||
6B8632DB0F78123E00E2684A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
6B8633540F7816C900E2684A /* glfont.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = glfont.cpp; path = ../../Examples/glfont.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633550F7816C900E2684A /* glfont.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glfont.h; path = ../../Examples/glfont.h; sourceTree = SOURCE_ROOT; };
|
||||
6B8633560F7816C900E2684A /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../Examples/imgui.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633570F7816C900E2684A /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = ../../Examples/imgui.h; sourceTree = SOURCE_ROOT; };
|
||||
6B8633580F7816C900E2684A /* MeshLoaderObj.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MeshLoaderObj.cpp; path = ../../Examples/MeshLoaderObj.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633590F7816C900E2684A /* MeshLoaderObj.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MeshLoaderObj.h; path = ../../Examples/MeshLoaderObj.h; sourceTree = SOURCE_ROOT; };
|
||||
6B86335D0F7816ED00E2684A /* Recast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Recast.h; path = ../../Include/Recast.h; sourceTree = SOURCE_ROOT; };
|
||||
6B86335E0F7816FA00E2684A /* Recast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Recast.cpp; path = ../../Source/Recast.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B86335F0F7816FA00E2684A /* RecastContour.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastContour.cpp; path = ../../Source/RecastContour.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633600F7816FA00E2684A /* RecastDebugDraw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastDebugDraw.cpp; path = ../../Source/RecastDebugDraw.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633620F7816FA00E2684A /* RecastFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastFilter.cpp; path = ../../Source/RecastFilter.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633630F7816FA00E2684A /* RecastLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastLog.cpp; path = ../../Source/RecastLog.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633640F7816FA00E2684A /* RecastLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecastLog.h; path = ../../Source/RecastLog.h; sourceTree = SOURCE_ROOT; };
|
||||
6B8633650F7816FA00E2684A /* RecastMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastMesh.cpp; path = ../../Source/RecastMesh.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633660F7816FA00E2684A /* RecastRasterization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastRasterization.cpp; path = ../../Source/RecastRasterization.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633670F7816FA00E2684A /* RecastRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastRegion.cpp; path = ../../Source/RecastRegion.cpp; sourceTree = SOURCE_ROOT; };
|
||||
6B8633680F7816FA00E2684A /* RecastTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastTimer.cpp; path = ../../Source/RecastTimer.cpp; sourceTree = SOURCE_ROOT; };
|
||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8D1107320486CEB800E47090 /* Recast.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Recast.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8D11072E0486CEB800E47090 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
6B8632DA0F78122C00E2684A /* SDL.framework in Frameworks */,
|
||||
6B8632DC0F78123E00E2684A /* OpenGL.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B8633730F7816FE00E2684A /* Recast */,
|
||||
6B8633540F7816C900E2684A /* glfont.cpp */,
|
||||
6B8633550F7816C900E2684A /* glfont.h */,
|
||||
6B8633560F7816C900E2684A /* imgui.cpp */,
|
||||
6B8633570F7816C900E2684A /* imgui.h */,
|
||||
6B8633580F7816C900E2684A /* MeshLoaderObj.cpp */,
|
||||
6B8633590F7816C900E2684A /* MeshLoaderObj.h */,
|
||||
6B8632B90F78119A00E2684A /* SDLMain.h */,
|
||||
6B8632BA0F78119A00E2684A /* SDLMain.m */,
|
||||
6B8632BC0F7811CB00E2684A /* demo.cpp */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B8632D90F78122C00E2684A /* SDL.framework */,
|
||||
6B8632DB0F78123E00E2684A /* OpenGL.framework */,
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */,
|
||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
|
||||
);
|
||||
name = "Other Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
19C28FACFE9D520D11CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8D1107320486CEB800E47090 /* Recast.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97314FDCFA39411CA2CEA /* Recast */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
080E96DDFE201D6D7F000001 /* Classes */,
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||
29B97317FDCFA39411CA2CEA /* Resources */,
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||
);
|
||||
name = Recast;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
32CA4F630368D1EE00C91783 /* Recast_Prefix.pch */,
|
||||
);
|
||||
name = "Other Sources";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8D1107310486CEB800E47090 /* Info.plist */,
|
||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
|
||||
1DDD58140DA1D0A300B32029 /* MainMenu.xib */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
|
||||
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6B8633730F7816FE00E2684A /* Recast */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B68D7620F78196F007E6D78 /* RecastDebugDraw.h */,
|
||||
6B68D7630F78196F007E6D78 /* RecastTimer.h */,
|
||||
6B86335E0F7816FA00E2684A /* Recast.cpp */,
|
||||
6B86335F0F7816FA00E2684A /* RecastContour.cpp */,
|
||||
6B8633600F7816FA00E2684A /* RecastDebugDraw.cpp */,
|
||||
6B8633620F7816FA00E2684A /* RecastFilter.cpp */,
|
||||
6B8633630F7816FA00E2684A /* RecastLog.cpp */,
|
||||
6B8633640F7816FA00E2684A /* RecastLog.h */,
|
||||
6B8633650F7816FA00E2684A /* RecastMesh.cpp */,
|
||||
6B8633660F7816FA00E2684A /* RecastRasterization.cpp */,
|
||||
6B8633670F7816FA00E2684A /* RecastRegion.cpp */,
|
||||
6B8633680F7816FA00E2684A /* RecastTimer.cpp */,
|
||||
6B86335D0F7816ED00E2684A /* Recast.h */,
|
||||
);
|
||||
name = Recast;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8D1107260486CEB800E47090 /* Recast */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Recast" */;
|
||||
buildPhases = (
|
||||
8D1107290486CEB800E47090 /* Resources */,
|
||||
8D11072C0486CEB800E47090 /* Sources */,
|
||||
8D11072E0486CEB800E47090 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Recast;
|
||||
productInstallPath = "$(HOME)/Applications";
|
||||
productName = Recast;
|
||||
productReference = 8D1107320486CEB800E47090 /* Recast.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Recast" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
hasScannedForEncodings = 1;
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* Recast */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8D1107260486CEB800E47090 /* Recast */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8D1107290486CEB800E47090 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8D11072C0486CEB800E47090 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B8632BB0F78119A00E2684A /* SDLMain.m in Sources */,
|
||||
6B8632BD0F7811CB00E2684A /* demo.cpp in Sources */,
|
||||
6B86335A0F7816C900E2684A /* glfont.cpp in Sources */,
|
||||
6B86335B0F7816C900E2684A /* imgui.cpp in Sources */,
|
||||
6B86335C0F7816C900E2684A /* MeshLoaderObj.cpp in Sources */,
|
||||
6B86336A0F7816FA00E2684A /* Recast.cpp in Sources */,
|
||||
6B86336B0F7816FA00E2684A /* RecastContour.cpp in Sources */,
|
||||
6B86336C0F7816FA00E2684A /* RecastDebugDraw.cpp in Sources */,
|
||||
6B86336D0F7816FA00E2684A /* RecastFilter.cpp in Sources */,
|
||||
6B86336E0F7816FA00E2684A /* RecastLog.cpp in Sources */,
|
||||
6B86336F0F7816FA00E2684A /* RecastMesh.cpp in Sources */,
|
||||
6B8633700F7816FA00E2684A /* RecastRasterization.cpp in Sources */,
|
||||
6B8633710F7816FA00E2684A /* RecastRegion.cpp in Sources */,
|
||||
6B8633720F7816FA00E2684A /* RecastTimer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
089C165DFE840E0CC02AAC07 /* English */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
1DDD58150DA1D0A300B32029 /* English */,
|
||||
);
|
||||
name = MainMenu.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C01FCF4B08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CONFIGURATION_BUILD_DIR = ../../Examples;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = Recast_Prefix.pch;
|
||||
HEADER_SEARCH_PATHS = "/Library/Frameworks/SDL.framework/Headers/**";
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
PRODUCT_NAME = Recast;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF4C08A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CONFIGURATION_BUILD_DIR = ../../Examples;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = Recast_Prefix.pch;
|
||||
HEADER_SEARCH_PATHS = "/Library/Frameworks/SDL.framework/Headers/**";
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
PRODUCT_NAME = Recast;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C01FCF4F08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.5;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF5008A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.5;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Recast" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C01FCF4B08A954540054247B /* Debug */,
|
||||
C01FCF4C08A954540054247B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Recast" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C01FCF4F08A954540054247B /* Debug */,
|
||||
C01FCF5008A954540054247B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||
}
|
7
Recast/Build/Xcode/Recast_Prefix.pch
Normal file
7
Recast/Build/Xcode/Recast_Prefix.pch
Normal file
@ -0,0 +1,7 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'Recast' target in the 'Recast' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
1
Recast/Contrib/SDL/readme.txt
Normal file
1
Recast/Contrib/SDL/readme.txt
Normal file
@ -0,0 +1 @@
|
||||
Download SDL Developer Libraries from http://www.libsdl.org and unzip them here.
|
219
Recast/Examples/MeshLoaderObj.cpp
Normal file
219
Recast/Examples/MeshLoaderObj.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include "MeshLoaderObj.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
rcMeshLoaderObj::rcMeshLoaderObj() :
|
||||
m_verts(0),
|
||||
m_normals(0),
|
||||
m_tris(0),
|
||||
m_vertCount(0),
|
||||
m_triCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
rcMeshLoaderObj::~rcMeshLoaderObj()
|
||||
{
|
||||
delete [] m_verts;
|
||||
delete [] m_normals;
|
||||
delete [] m_tris;
|
||||
}
|
||||
|
||||
void rcMeshLoaderObj::addVertex(float x, float y, float z, int& cap)
|
||||
{
|
||||
if (m_vertCount+1 > cap)
|
||||
{
|
||||
cap = !cap ? 8 : cap*2;
|
||||
float* nv = new float[cap*3];
|
||||
if (m_vertCount)
|
||||
memcpy(nv, m_verts, m_vertCount*3*sizeof(float));
|
||||
delete [] m_verts;
|
||||
m_verts = nv;
|
||||
}
|
||||
float* dst = &m_verts[m_vertCount*3];
|
||||
*dst++ = x;
|
||||
*dst++ = y;
|
||||
*dst++ = z;
|
||||
m_vertCount++;
|
||||
}
|
||||
|
||||
void rcMeshLoaderObj::addTriangle(int a, int b, int c, int& cap)
|
||||
{
|
||||
if (m_triCount+1 > cap)
|
||||
{
|
||||
cap = !cap ? 8 : cap*2;
|
||||
int* nv = new int[cap*3];
|
||||
if (m_triCount)
|
||||
memcpy(nv, m_tris, m_triCount*3*sizeof(int));
|
||||
delete [] m_tris;
|
||||
m_tris = nv;
|
||||
}
|
||||
int* dst = &m_tris[m_triCount*3];
|
||||
*dst++ = a;
|
||||
*dst++ = b;
|
||||
*dst++ = c;
|
||||
m_triCount++;
|
||||
}
|
||||
|
||||
static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
{
|
||||
bool cont = false;
|
||||
bool start = true;
|
||||
bool done = false;
|
||||
int n = 0;
|
||||
while (!done && buf < bufEnd)
|
||||
{
|
||||
char c = *buf;
|
||||
buf++;
|
||||
// multirow
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
cont = true; // multirow
|
||||
break;
|
||||
case '\n':
|
||||
if (start) break;
|
||||
done = true;
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
case '\t':
|
||||
case ' ':
|
||||
if (start) break;
|
||||
default:
|
||||
start = false;
|
||||
cont = false;
|
||||
row[n++] = c;
|
||||
if (n >= len-1)
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
row[n] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int parseFace(char* row, int* data, int n, int vcnt)
|
||||
{
|
||||
int j = 0;
|
||||
while (*row != '\0')
|
||||
{
|
||||
// Skip initial white space
|
||||
while (*row != '\0' && (*row == ' ' || *row == '\t'))
|
||||
row++;
|
||||
char* s = row;
|
||||
// Find vertex delimiter and terminated the string there for conversion.
|
||||
while (*row != '\0' && *row != ' ' && *row != '\t')
|
||||
{
|
||||
if (*row == '/') *row = '\0';
|
||||
row++;
|
||||
}
|
||||
if (*s == '\0')
|
||||
continue;
|
||||
int vi = atoi(s);
|
||||
data[j++] = vi < 0 ? vi+vcnt : vi-1;
|
||||
if (j >= n) return j;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
bool rcMeshLoaderObj::load(const char* filename)
|
||||
{
|
||||
char* buf = 0;
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int bufSize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
buf = new char[bufSize];
|
||||
if (!buf)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
char* src = buf;
|
||||
char* srcEnd = buf + bufSize;
|
||||
char row[512];
|
||||
int face[32];
|
||||
float x,y,z;
|
||||
int nv;
|
||||
int vcap = 0;
|
||||
int tcap = 0;
|
||||
|
||||
while (src < srcEnd)
|
||||
{
|
||||
// Parse one row
|
||||
row[0] = '\0';
|
||||
src = parseRow(src, srcEnd, row, sizeof(row)/sizeof(char));
|
||||
// Skip comments
|
||||
if (row[0] == '#') continue;
|
||||
if (row[0] == 'v' && row[1] != 'n' && row[1] != 't')
|
||||
{
|
||||
// Vertex pos
|
||||
sscanf(row+1, "%f %f %f", &x, &y, &z);
|
||||
addVertex(x, y, z, vcap);
|
||||
}
|
||||
if (row[0] == 'f')
|
||||
{
|
||||
// Faces
|
||||
nv = parseFace(row+1, face, 32, m_vertCount);
|
||||
for (int i = 2; i < nv; ++i)
|
||||
addTriangle(face[0], face[i-1], face[i], tcap);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
|
||||
// Calculate normals.
|
||||
m_normals = new float[m_triCount*3];
|
||||
for (int i = 0; i < m_triCount*3; i += 3)
|
||||
{
|
||||
const float* v0 = &m_verts[m_tris[i]*3];
|
||||
const float* v1 = &m_verts[m_tris[i+1]*3];
|
||||
const float* v2 = &m_verts[m_tris[i+2]*3];
|
||||
float e0[3], e1[3];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
e0[j] = v1[j] - v0[j];
|
||||
e1[j] = v2[j] - v0[j];
|
||||
}
|
||||
float* n = &m_normals[i];
|
||||
n[0] = e0[1]*e1[2] - e0[2]*e1[1];
|
||||
n[1] = e0[2]*e1[0] - e0[0]*e1[2];
|
||||
n[2] = e0[0]*e1[1] - e0[1]*e1[0];
|
||||
float d = sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
|
||||
if (d > 0)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
n[0] *= d;
|
||||
n[1] *= d;
|
||||
n[2] *= d;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
48
Recast/Examples/MeshLoaderObj.h
Normal file
48
Recast/Examples/MeshLoaderObj.h
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef MESHLOADER_OBJ
|
||||
#define MESHLOADER_OBJ
|
||||
|
||||
class rcMeshLoaderObj
|
||||
{
|
||||
public:
|
||||
rcMeshLoaderObj();
|
||||
~rcMeshLoaderObj();
|
||||
|
||||
bool load(const char* fileName);
|
||||
|
||||
inline const float* getVerts() const { return m_verts; }
|
||||
inline const float* getNormals() const { return m_normals; }
|
||||
inline const int* getTris() const { return m_tris; }
|
||||
inline int getVertCount() const { return m_vertCount; }
|
||||
inline int getTriCount() const { return m_triCount; }
|
||||
|
||||
private:
|
||||
|
||||
void addVertex(float x, float y, float z, int& cap);
|
||||
void addTriangle(int a, int b, int c, int& cap);
|
||||
|
||||
float* m_verts;
|
||||
int* m_tris;
|
||||
float* m_normals;
|
||||
int m_vertCount;
|
||||
int m_triCount;
|
||||
};
|
||||
|
||||
#endif // MESHLOADER_OBJ
|
15234
Recast/Examples/Meshes/dungeon.obj
Normal file
15234
Recast/Examples/Meshes/dungeon.obj
Normal file
File diff suppressed because it is too large
Load Diff
3506
Recast/Examples/Meshes/nav_test.obj
Normal file
3506
Recast/Examples/Meshes/nav_test.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Recast/Examples/Recast.exe
Normal file
BIN
Recast/Examples/Recast.exe
Normal file
Binary file not shown.
BIN
Recast/Examples/SDL.dll
Normal file
BIN
Recast/Examples/SDL.dll
Normal file
Binary file not shown.
11
Recast/Examples/SDLMain.h
Normal file
11
Recast/Examples/SDLMain.h
Normal file
@ -0,0 +1,11 @@
|
||||
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
|
||||
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
|
||||
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
|
||||
|
||||
Feel free to customize this file to suit your needs
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SDLMain : NSObject
|
||||
@end
|
384
Recast/Examples/SDLMain.m
Normal file
384
Recast/Examples/SDLMain.m
Normal file
@ -0,0 +1,384 @@
|
||||
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
|
||||
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
|
||||
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
|
||||
|
||||
Feel free to customize this file to suit your needs
|
||||
*/
|
||||
|
||||
#import "SDL.h"
|
||||
#import "SDLMain.h"
|
||||
#import <sys/param.h> /* for MAXPATHLEN */
|
||||
#import <unistd.h>
|
||||
|
||||
/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
|
||||
but the method still is there and works. To avoid warnings, we declare
|
||||
it ourselves here. */
|
||||
@interface NSApplication(SDL_Missing_Methods)
|
||||
- (void)setAppleMenu:(NSMenu *)menu;
|
||||
@end
|
||||
|
||||
/* Use this flag to determine whether we use SDLMain.nib or not */
|
||||
#define SDL_USE_NIB_FILE 0
|
||||
|
||||
/* Use this flag to determine whether we use CPS (docking) or not */
|
||||
#define SDL_USE_CPS 1
|
||||
#ifdef SDL_USE_CPS
|
||||
/* Portions of CPS.h */
|
||||
typedef struct CPSProcessSerNum
|
||||
{
|
||||
UInt32 lo;
|
||||
UInt32 hi;
|
||||
} CPSProcessSerNum;
|
||||
|
||||
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
|
||||
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
|
||||
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
|
||||
|
||||
#endif /* SDL_USE_CPS */
|
||||
|
||||
static int gArgc;
|
||||
static char **gArgv;
|
||||
static BOOL gFinderLaunch;
|
||||
static BOOL gCalledAppMainline = FALSE;
|
||||
|
||||
static NSString *getApplicationName(void)
|
||||
{
|
||||
NSDictionary *dict;
|
||||
NSString *appName = 0;
|
||||
|
||||
/* Determine the application name */
|
||||
dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
|
||||
if (dict)
|
||||
appName = [dict objectForKey: @"CFBundleName"];
|
||||
|
||||
if (![appName length])
|
||||
appName = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
return appName;
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
/* A helper category for NSString */
|
||||
@interface NSString (ReplaceSubString)
|
||||
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
|
||||
@end
|
||||
#endif
|
||||
|
||||
@interface SDLApplication : NSApplication
|
||||
@end
|
||||
|
||||
@implementation SDLApplication
|
||||
/* Invoked from the Quit menu item */
|
||||
- (void)terminate:(id)sender
|
||||
{
|
||||
/* Post a SDL_QUIT event */
|
||||
SDL_Event event;
|
||||
event.type = SDL_QUIT;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
@end
|
||||
|
||||
/* The main class of the application, the application's delegate */
|
||||
@implementation SDLMain
|
||||
|
||||
/* Set the working directory to the .app's parent directory */
|
||||
- (void) setupWorkingDirectory:(BOOL)shouldChdir
|
||||
{
|
||||
if (shouldChdir)
|
||||
{
|
||||
char parentdir[MAXPATHLEN];
|
||||
CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
|
||||
if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
|
||||
assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */
|
||||
}
|
||||
CFRelease(url);
|
||||
CFRelease(url2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
|
||||
/* Fix menu to contain the real app name instead of "SDL App" */
|
||||
- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
|
||||
{
|
||||
NSRange aRange;
|
||||
NSEnumerator *enumerator;
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
aRange = [[aMenu title] rangeOfString:@"SDL App"];
|
||||
if (aRange.length != 0)
|
||||
[aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
|
||||
|
||||
enumerator = [[aMenu itemArray] objectEnumerator];
|
||||
while ((menuItem = [enumerator nextObject]))
|
||||
{
|
||||
aRange = [[menuItem title] rangeOfString:@"SDL App"];
|
||||
if (aRange.length != 0)
|
||||
[menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
|
||||
if ([menuItem hasSubmenu])
|
||||
[self fixMenu:[menuItem submenu] withAppName:appName];
|
||||
}
|
||||
[ aMenu sizeToFit ];
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setApplicationMenu(void)
|
||||
{
|
||||
/* warning: this code is very odd */
|
||||
NSMenu *appleMenu;
|
||||
NSMenuItem *menuItem;
|
||||
NSString *title;
|
||||
NSString *appName;
|
||||
|
||||
appName = getApplicationName();
|
||||
appleMenu = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
/* Add menu items */
|
||||
title = [@"About " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
|
||||
|
||||
[appleMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
title = [@"Hide " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
|
||||
|
||||
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
|
||||
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
|
||||
|
||||
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
|
||||
|
||||
[appleMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
title = [@"Quit " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
|
||||
|
||||
/* Put menu into the menubar */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
[menuItem setSubmenu:appleMenu];
|
||||
[[NSApp mainMenu] addItem:menuItem];
|
||||
|
||||
/* Tell the application object that this is now the application menu */
|
||||
[NSApp setAppleMenu:appleMenu];
|
||||
|
||||
/* Finally give up our references to the objects */
|
||||
[appleMenu release];
|
||||
[menuItem release];
|
||||
}
|
||||
|
||||
/* Create a window menu */
|
||||
static void setupWindowMenu(void)
|
||||
{
|
||||
NSMenu *windowMenu;
|
||||
NSMenuItem *windowMenuItem;
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
|
||||
/* "Minimize" item */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
|
||||
[windowMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
||||
/* Put menu into the menubar */
|
||||
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
[[NSApp mainMenu] addItem:windowMenuItem];
|
||||
|
||||
/* Tell the application object that this is now the window menu */
|
||||
[NSApp setWindowsMenu:windowMenu];
|
||||
|
||||
/* Finally give up our references to the objects */
|
||||
[windowMenu release];
|
||||
[windowMenuItem release];
|
||||
}
|
||||
|
||||
/* Replacement for NSApplicationMain */
|
||||
static void CustomApplicationMain (int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
SDLMain *sdlMain;
|
||||
|
||||
/* Ensure the application object is initialised */
|
||||
[SDLApplication sharedApplication];
|
||||
|
||||
#ifdef SDL_USE_CPS
|
||||
{
|
||||
CPSProcessSerNum PSN;
|
||||
/* Tell the dock about us */
|
||||
if (!CPSGetCurrentProcess(&PSN))
|
||||
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
|
||||
if (!CPSSetFrontProcess(&PSN))
|
||||
[SDLApplication sharedApplication];
|
||||
}
|
||||
#endif /* SDL_USE_CPS */
|
||||
|
||||
/* Set up the menubar */
|
||||
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
||||
setApplicationMenu();
|
||||
setupWindowMenu();
|
||||
|
||||
/* Create SDLMain and make it the app delegate */
|
||||
sdlMain = [[SDLMain alloc] init];
|
||||
[NSApp setDelegate:sdlMain];
|
||||
|
||||
/* Start the main event loop */
|
||||
[NSApp run];
|
||||
|
||||
[sdlMain release];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Catch document open requests...this lets us notice files when the app
|
||||
* was launched by double-clicking a document, or when a document was
|
||||
* dragged/dropped on the app's icon. You need to have a
|
||||
* CFBundleDocumentsType section in your Info.plist to get this message,
|
||||
* apparently.
|
||||
*
|
||||
* Files are added to gArgv, so to the app, they'll look like command line
|
||||
* arguments. Previously, apps launched from the finder had nothing but
|
||||
* an argv[0].
|
||||
*
|
||||
* This message may be received multiple times to open several docs on launch.
|
||||
*
|
||||
* This message is ignored once the app's mainline has been called.
|
||||
*/
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
|
||||
{
|
||||
const char *temparg;
|
||||
size_t arglen;
|
||||
char *arg;
|
||||
char **newargv;
|
||||
|
||||
if (!gFinderLaunch) /* MacOS is passing command line args. */
|
||||
return FALSE;
|
||||
|
||||
if (gCalledAppMainline) /* app has started, ignore this document. */
|
||||
return FALSE;
|
||||
|
||||
temparg = [filename UTF8String];
|
||||
arglen = SDL_strlen(temparg) + 1;
|
||||
arg = (char *) SDL_malloc(arglen);
|
||||
if (arg == NULL)
|
||||
return FALSE;
|
||||
|
||||
newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
|
||||
if (newargv == NULL)
|
||||
{
|
||||
SDL_free(arg);
|
||||
return FALSE;
|
||||
}
|
||||
gArgv = newargv;
|
||||
|
||||
SDL_strlcpy(arg, temparg, arglen);
|
||||
gArgv[gArgc++] = arg;
|
||||
gArgv[gArgc] = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Called when the internal event loop has just started running */
|
||||
- (void) applicationDidFinishLaunching: (NSNotification *) note
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Set the working directory to the .app's parent directory */
|
||||
[self setupWorkingDirectory:gFinderLaunch];
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
/* Set the main menu to contain the real app name instead of "SDL App" */
|
||||
[self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
|
||||
#endif
|
||||
|
||||
/* Hand off to main application code */
|
||||
gCalledAppMainline = TRUE;
|
||||
status = SDL_main (gArgc, gArgv);
|
||||
|
||||
/* We're done, thank you for playing */
|
||||
exit(status);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSString (ReplaceSubString)
|
||||
|
||||
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
|
||||
{
|
||||
unsigned int bufferSize;
|
||||
unsigned int selfLen = [self length];
|
||||
unsigned int aStringLen = [aString length];
|
||||
unichar *buffer;
|
||||
NSRange localRange;
|
||||
NSString *result;
|
||||
|
||||
bufferSize = selfLen + aStringLen - aRange.length;
|
||||
buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
|
||||
|
||||
/* Get first part into buffer */
|
||||
localRange.location = 0;
|
||||
localRange.length = aRange.location;
|
||||
[self getCharacters:buffer range:localRange];
|
||||
|
||||
/* Get middle part into buffer */
|
||||
localRange.location = 0;
|
||||
localRange.length = aStringLen;
|
||||
[aString getCharacters:(buffer+aRange.location) range:localRange];
|
||||
|
||||
/* Get last part into buffer */
|
||||
localRange.location = aRange.location + aRange.length;
|
||||
localRange.length = selfLen - localRange.location;
|
||||
[self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
|
||||
|
||||
/* Build output string */
|
||||
result = [NSString stringWithCharacters:buffer length:bufferSize];
|
||||
|
||||
NSDeallocateMemoryPages(buffer, bufferSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
#ifdef main
|
||||
# undef main
|
||||
#endif
|
||||
|
||||
|
||||
/* Main entry point to executable - should *not* be SDL_main! */
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
/* Copy the arguments into a global variable */
|
||||
/* This is passed if we are launched by double-clicking */
|
||||
if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
|
||||
gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
|
||||
gArgv[0] = argv[0];
|
||||
gArgv[1] = NULL;
|
||||
gArgc = 1;
|
||||
gFinderLaunch = YES;
|
||||
} else {
|
||||
int i;
|
||||
gArgc = argc;
|
||||
gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
|
||||
for (i = 0; i <= argc; i++)
|
||||
gArgv[i] = argv[i];
|
||||
gFinderLaunch = NO;
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
[SDLApplication poseAsClass:[NSApplication class]];
|
||||
NSApplicationMain (argc, argv);
|
||||
#else
|
||||
CustomApplicationMain (argc, argv);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
796
Recast/Examples/demo.cpp
Normal file
796
Recast/Examples/demo.cpp
Normal file
@ -0,0 +1,796 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
#include "SDL.h"
|
||||
#include "SDL_Opengl.h"
|
||||
#include "GLFont.h"
|
||||
#include "RecastTimer.h"
|
||||
#include "MeshLoaderObj.h"
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastDebugDraw.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
bool intersectSegmentTriangle(const float* sp, const float* sq,
|
||||
const float* a, const float* b, const float* c,
|
||||
float &t)
|
||||
{
|
||||
float v, w;
|
||||
float ab[3], ac[3], qp[3], ap[3], norm[3], e[3];
|
||||
vsub(ab, b, a);
|
||||
vsub(ac, c, a);
|
||||
vsub(qp, sp, sq);
|
||||
|
||||
// Compute triangle normal. Can be precalculated or cached if
|
||||
// intersecting multiple segments against the same triangle
|
||||
vcross(norm, ab, ac);
|
||||
|
||||
// Compute denominator d. If d <= 0, segment is parallel to or points
|
||||
// away from triangle, so exit early
|
||||
float d = vdot(qp, norm);
|
||||
if (d <= 0.0f) return false;
|
||||
|
||||
// Compute intersection t value of pq with plane of triangle. A ray
|
||||
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
|
||||
// dividing by d until intersection has been found to pierce triangle
|
||||
vsub(ap, sp, a);
|
||||
t = vdot(ap, norm);
|
||||
if (t < 0.0f) return false;
|
||||
if (t > d) return false; // For segment; exclude this code line for a ray test
|
||||
|
||||
// Compute barycentric coordinate components and test if within bounds
|
||||
vcross(e, qp, ap);
|
||||
v = vdot(ac, e);
|
||||
if (v < 0.0f || v > d) return false;
|
||||
w = -vdot(ab, e);
|
||||
if (w < 0.0f || v + w > d) return false;
|
||||
|
||||
// Segment/ray intersects triangle. Perform delayed division
|
||||
t /= d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool raycast(rcMeshLoaderObj& mesh, float* src, float* dst, float& tmin)
|
||||
{
|
||||
float dir[3];
|
||||
vsub(dir, dst, src);
|
||||
|
||||
int nt = mesh.getTriCount();
|
||||
const float* verts = mesh.getVerts();
|
||||
const float* normals = mesh.getNormals();
|
||||
const int* tris = mesh.getTris();
|
||||
tmin = 1.0f;
|
||||
bool hit = false;
|
||||
|
||||
for (int i = 0; i < nt*3; i += 3)
|
||||
{
|
||||
const float* n = &normals[i];
|
||||
if (vdot(dir, n) > 0)
|
||||
continue;
|
||||
|
||||
float t = 1;
|
||||
if (intersectSegmentTriangle(src, dst,
|
||||
&verts[tris[i]*3],
|
||||
&verts[tris[i+1]*3],
|
||||
&verts[tris[i+2]*3], t))
|
||||
{
|
||||
if (t < tmin)
|
||||
tmin = t;
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
struct FileList
|
||||
{
|
||||
static const int MAX_FILES = 256;
|
||||
inline FileList() : size(0) {}
|
||||
inline ~FileList()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (int i = 0; i < size; ++i)
|
||||
delete [] files[i];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void add(const char* path)
|
||||
{
|
||||
if (size >= MAX_FILES)
|
||||
return;
|
||||
int n = strlen(path);
|
||||
files[size] = new char[n+1];
|
||||
strcpy(files[size], path);
|
||||
size++;
|
||||
}
|
||||
|
||||
char* files[MAX_FILES];
|
||||
int size;
|
||||
};
|
||||
|
||||
void scanDirectory(const char* path, const char* ext, FileList& list)
|
||||
{
|
||||
list.clear();
|
||||
|
||||
#ifdef WIN32
|
||||
_finddata_t dir;
|
||||
char pathWithExt[MAX_PATH];
|
||||
long fh;
|
||||
strcpy(pathWithExt, path);
|
||||
strcat(pathWithExt, "/*");
|
||||
strcat(pathWithExt, ext);
|
||||
fh = _findfirst(pathWithExt, &dir);
|
||||
if (fh == -1L)
|
||||
return;
|
||||
do
|
||||
{
|
||||
list.add(dir.name);
|
||||
}
|
||||
while (_findnext(fh, &dir) == 0);
|
||||
_findclose(fh);
|
||||
#else
|
||||
dirent* current = 0;
|
||||
DIR* dp = opendir(path);
|
||||
if (!dp)
|
||||
return;
|
||||
|
||||
while ((current = readdir(dp)) != 0)
|
||||
{
|
||||
int len = strlen(current->d_name);
|
||||
if (len > 4 && strncmp(current->d_name+len-4, ext, 4) == 0)
|
||||
{
|
||||
list.add(current->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
enum DrawMode
|
||||
{
|
||||
DRAWMODE_POLYMESH,
|
||||
DRAWMODE_POLYMESH_TRANS,
|
||||
DRAWMODE_MESH,
|
||||
DRAWMODE_VOXELS,
|
||||
DRAWMODE_VOXELS_WALKABLE,
|
||||
DRAWMODE_COMPACT,
|
||||
DRAWMODE_COMPACT_DISTANCE,
|
||||
DRAWMODE_COMPACT_REGIONS,
|
||||
DRAWMODE_RAW_CONTOURS,
|
||||
DRAWMODE_CONTOURS,
|
||||
MAX_DRAWMODE,
|
||||
};
|
||||
|
||||
|
||||
GLFont g_font;
|
||||
|
||||
void drawText(int x, int y, int dir, const char* text, unsigned int col)
|
||||
{
|
||||
if (dir < 0)
|
||||
g_font.drawText((float)x - g_font.getTextLength(text), (float)y, text, col);
|
||||
else
|
||||
g_font.drawText((float)x, (float)y, text, col);
|
||||
}
|
||||
|
||||
|
||||
rcMeshLoaderObj* g_mesh = 0;
|
||||
unsigned char* g_triangleFlags = 0;
|
||||
rcHeightfield* g_solid = 0;
|
||||
rcCompactHeightfield* g_chf = 0;
|
||||
rcContourSet* g_cset = 0;
|
||||
rcPolyMesh* g_polyMesh = 0;
|
||||
rcConfig g_cfg;
|
||||
rcLog g_log;
|
||||
|
||||
static bool buildNavigation()
|
||||
{
|
||||
delete g_solid;
|
||||
delete g_chf;
|
||||
delete g_cset;
|
||||
delete g_polyMesh;
|
||||
delete [] g_triangleFlags;
|
||||
g_solid = 0;
|
||||
g_chf = 0;
|
||||
g_cset = 0;
|
||||
g_polyMesh = 0;
|
||||
g_triangleFlags = 0;
|
||||
|
||||
g_log.clear();
|
||||
rcSetLog(&g_log);
|
||||
|
||||
if (!g_mesh)
|
||||
{
|
||||
g_log.log(RC_LOG_ERROR, "Input mesh is not valid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
rcCalcBounds(g_mesh->getVerts(), g_mesh->getVertCount(), g_cfg.bmin, g_cfg.bmax);
|
||||
rcCalcGridSize(g_cfg.bmin, g_cfg.bmax, g_cfg.cs, &g_cfg.width, &g_cfg.height);
|
||||
|
||||
g_log.log(RC_LOG_PROGRESS, "Building navigation");
|
||||
g_log.log(RC_LOG_PROGRESS, " - %d x %d", g_cfg.width, g_cfg.height);
|
||||
g_log.log(RC_LOG_PROGRESS, " - %d verts, %d tris", g_mesh->getVertCount(), g_mesh->getTriCount());
|
||||
|
||||
g_triangleFlags = new unsigned char[g_mesh->getTriCount()];
|
||||
memset(g_triangleFlags, 0, g_mesh->getTriCount());
|
||||
rcMarkWalkableTriangles(g_cfg.walkableSlopeAngle,
|
||||
g_mesh->getTris(), g_mesh->getNormals(), g_mesh->getTriCount(),
|
||||
g_triangleFlags);
|
||||
|
||||
g_solid = new rcHeightfield;
|
||||
g_chf = new rcCompactHeightfield;
|
||||
g_cset = new rcContourSet;
|
||||
g_polyMesh = new rcPolyMesh;
|
||||
|
||||
if (!rcBuildNavMesh(g_cfg, g_mesh->getVerts(), g_mesh->getVertCount(),
|
||||
g_mesh->getTris(), g_triangleFlags, g_mesh->getTriCount(),
|
||||
*g_solid, *g_chf, *g_cset, *g_polyMesh))
|
||||
{
|
||||
g_log.log(RC_LOG_ERROR, "Could not build navmesh.");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
g_log.log(RC_LOG_PROGRESS, "Build time: %.1f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
g_log.log(RC_LOG_PROGRESS, "NavMesh");
|
||||
g_log.log(RC_LOG_PROGRESS, " - %d verts, %d polys", g_polyMesh->nverts, g_polyMesh->npolys);
|
||||
const int navMeshDataSize = g_polyMesh->nverts*3*sizeof(unsigned short) +
|
||||
g_polyMesh->npolys*g_polyMesh->nvp*2*sizeof(unsigned short);
|
||||
g_log.log(RC_LOG_PROGRESS, " - Approx data size %.1f kB", (float)navMeshDataSize/1024.f);
|
||||
|
||||
for (int i = 0; i < g_log.getMessageCount(); ++i)
|
||||
{
|
||||
printf("%s\n", g_log.getMessageText(i));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Init SDL
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
|
||||
{
|
||||
printf("Could not initialise SDL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Init OpenGL
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
|
||||
|
||||
int width = 1200;
|
||||
int height = 700;
|
||||
SDL_Surface* screen = SDL_SetVideoMode(width, height, 0, SDL_OPENGL);
|
||||
if (!screen)
|
||||
{
|
||||
printf("Could not initialise SDL opengl\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_WM_SetCaption("Recast Demo", 0);
|
||||
|
||||
if(!g_font.create("font.cfnt"))
|
||||
{
|
||||
printf("Could not load font\n");
|
||||
SDL_Quit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
float cellSize = 0.3f;
|
||||
float cellHeight = 0.2f;
|
||||
float agentHeight = 2.0f;
|
||||
float agentRadius = 0.3f;
|
||||
float agentMaxClimb = 0.9f;
|
||||
float agentMaxSlope = 45.0f;
|
||||
float regionMinSize = 50;
|
||||
float regionMergeSize = 20;
|
||||
float edgeMaxLen = 12.0f;
|
||||
float edgeMaxError = 1.5f;
|
||||
float vertsPerPoly = 6.0f;
|
||||
int drawMode = DRAWMODE_POLYMESH;
|
||||
bool showLevels = false;
|
||||
bool showLog = false;
|
||||
char curLevel[256] = "Choose Level...";
|
||||
bool mouseOverMenu = false;
|
||||
FileList fileList;
|
||||
|
||||
float t = 0.0f;
|
||||
Uint32 lastTime = SDL_GetTicks();
|
||||
int mx = 0, my = 0;
|
||||
float rx = 45;
|
||||
float ry = -45;
|
||||
float moveW = 0, moveS = 0, moveA = 0, moveD = 0;
|
||||
float camx = 0, camy = 0, camz = 0, camr=10;
|
||||
float origrx, origry;
|
||||
int origx, origy;
|
||||
bool rotate = false;
|
||||
float rays[3], raye[3];
|
||||
float spos[3] = {0,0,0};
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
float fogCol[4] = { 0.1f,0.12f,0.14f,1 };
|
||||
glEnable(GL_FOG);
|
||||
glFogi(GL_FOG_MODE, GL_LINEAR);
|
||||
glFogf(GL_FOG_START, 0);
|
||||
glFogf(GL_FOG_END, 10);
|
||||
glFogfv(GL_FOG_COLOR, fogCol);
|
||||
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
// Handle input events.
|
||||
SDL_Event event;
|
||||
while(SDL_PollEvent(&event))
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
// Handle any key presses here.
|
||||
if(event.key.keysym.sym == SDLK_ESCAPE)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
// Handle mouse clicks here.
|
||||
if (!mouseOverMenu)
|
||||
{
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
{
|
||||
// Rotate view
|
||||
rotate = true;
|
||||
origx = mx;
|
||||
origy = my;
|
||||
origrx = rx;
|
||||
origry = ry;
|
||||
}
|
||||
else if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
// Hit test mesh.
|
||||
if (g_mesh)
|
||||
{
|
||||
float t;
|
||||
if (raycast(*g_mesh, rays, raye, t))
|
||||
{
|
||||
spos[0] = rays[0] + (raye[0] - rays[0])*t;
|
||||
spos[1] = rays[1] + (raye[1] - rays[1])*t;
|
||||
spos[2] = rays[2] + (raye[2] - rays[2])*t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
// Handle mouse clicks here.
|
||||
if(event.button.button == SDL_BUTTON_LEFT)
|
||||
{
|
||||
rotate = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
mx = event.motion.x;
|
||||
my = height - 1 - event.motion.y;
|
||||
if (rotate)
|
||||
{
|
||||
int dx = mx - origx;
|
||||
int dy = my - origy;
|
||||
rx = origrx - dy*0.25f;
|
||||
ry = origry + dx*0.25f;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 time = SDL_GetTicks();
|
||||
float dt = (time - lastTime) / 1000.0f;
|
||||
lastTime = time;
|
||||
|
||||
t += dt;
|
||||
|
||||
|
||||
// Update and render
|
||||
glViewport(0, 0, width, height);
|
||||
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
// Render 3d
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(50.0f, (float)width/(float)height, 1.0f, camr);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glRotatef(rx,1,0,0);
|
||||
glRotatef(ry,0,1,0);
|
||||
glTranslatef(-camx, -camy, -camz);
|
||||
|
||||
// Get hit ray position and direction.
|
||||
GLdouble proj[16];
|
||||
GLdouble model[16];
|
||||
GLint view[4];
|
||||
glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX, model);
|
||||
glGetIntegerv(GL_VIEWPORT, view);
|
||||
GLdouble x, y, z;
|
||||
gluUnProject(mx, my, 0.0f, model, proj, view, &x, &y, &z);
|
||||
rays[0] = (float)x; rays[1] = (float)y; rays[2] = (float)z;
|
||||
gluUnProject(mx, my, 1.0f, model, proj, view, &x, &y, &z);
|
||||
raye[0] = (float)x; raye[1] = (float)y; raye[2] = (float)z;
|
||||
|
||||
// Handle keyboard movement.
|
||||
Uint8* keystate = SDL_GetKeyState(NULL);
|
||||
moveW = rcClamp(moveW + dt * 4 * (keystate[SDLK_w] ? 1 : -1), 0.0f, 1.0f);
|
||||
moveS = rcClamp(moveS + dt * 4 * (keystate[SDLK_s] ? 1 : -1), 0.0f, 1.0f);
|
||||
moveA = rcClamp(moveA + dt * 4 * (keystate[SDLK_a] ? 1 : -1), 0.0f, 1.0f);
|
||||
moveD = rcClamp(moveD + dt * 4 * (keystate[SDLK_d] ? 1 : -1), 0.0f, 1.0f);
|
||||
|
||||
float keybSpeed = 22.0f;
|
||||
if (SDL_GetModState() & KMOD_SHIFT)
|
||||
keybSpeed *= 4.0f;
|
||||
|
||||
float movex = (moveD - moveA) * keybSpeed * dt;
|
||||
float movey = (moveS - moveW) * keybSpeed * dt;
|
||||
|
||||
camx += movex * (float)model[0];
|
||||
camy += movex * (float)model[4];
|
||||
camz += movex * (float)model[8];
|
||||
|
||||
camx += movey * (float)model[2];
|
||||
camy += movey * (float)model[6];
|
||||
camz += movey * (float)model[10];
|
||||
|
||||
glEnable(GL_FOG);
|
||||
|
||||
if (drawMode == DRAWMODE_MESH)
|
||||
{
|
||||
if (g_mesh)
|
||||
rcDebugDrawMesh(*g_mesh, g_triangleFlags);
|
||||
}
|
||||
else if (drawMode != DRAWMODE_POLYMESH_TRANS)
|
||||
{
|
||||
if (g_mesh)
|
||||
rcDebugDrawMesh(*g_mesh, 0);
|
||||
}
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
if (drawMode == DRAWMODE_POLYMESH || drawMode == DRAWMODE_POLYMESH_TRANS)
|
||||
{
|
||||
if (g_polyMesh)
|
||||
rcDebugDrawPolyMesh(*g_polyMesh, g_cfg.bmin, g_cfg.cs, g_cfg.ch);
|
||||
}
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
if (drawMode == DRAWMODE_COMPACT)
|
||||
{
|
||||
if (g_chf)
|
||||
rcDebugDrawCompactHeightfieldSolid(*g_chf);
|
||||
}
|
||||
if (drawMode == DRAWMODE_COMPACT_DISTANCE)
|
||||
{
|
||||
if (g_chf)
|
||||
rcDebugDrawCompactHeightfieldDistance(*g_chf);
|
||||
}
|
||||
if (drawMode == DRAWMODE_COMPACT_REGIONS)
|
||||
{
|
||||
if (g_chf)
|
||||
rcDebugDrawCompactHeightfieldRegions(*g_chf);
|
||||
}
|
||||
if (drawMode == DRAWMODE_VOXELS)
|
||||
{
|
||||
if (g_solid)
|
||||
rcDebugDrawHeightfieldSolid(*g_solid, g_cfg.bmin, g_cfg.cs, g_cfg.ch);
|
||||
}
|
||||
if (drawMode == DRAWMODE_VOXELS_WALKABLE)
|
||||
{
|
||||
if (g_solid)
|
||||
rcDebugDrawHeightfieldWalkable(*g_solid, g_cfg.bmin, g_cfg.cs, g_cfg.ch);
|
||||
}
|
||||
if (drawMode == DRAWMODE_RAW_CONTOURS)
|
||||
{
|
||||
if (g_cset)
|
||||
rcDebugDrawRawContours(*g_cset, g_cfg.bmin, g_cfg.cs, g_cfg.ch);
|
||||
}
|
||||
if (drawMode == DRAWMODE_CONTOURS)
|
||||
{
|
||||
if (g_cset)
|
||||
rcDebugDrawContours(*g_cset, g_cfg.bmin, g_cfg.cs, g_cfg.ch);
|
||||
}
|
||||
|
||||
glDisable(GL_FOG);
|
||||
|
||||
if (g_mesh)
|
||||
{
|
||||
// Agent dimensions.
|
||||
const float r = agentRadius;
|
||||
const float h = agentHeight;
|
||||
float col[4];
|
||||
col[0] = 0.6f; col[1] = 0.1f; col[2] = 0.1f; col[3] = 0.75f;
|
||||
rcDebugDrawCylinderWire(spos[0]-r, spos[1]+0.02f, spos[2]-r, spos[0]+r, spos[1]+h, spos[2]+r, col);
|
||||
|
||||
glColor4ub(0,0,0,196);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(spos[0], spos[1]-agentMaxClimb, spos[2]);
|
||||
glVertex3f(spos[0], spos[1]+agentMaxClimb, spos[2]);
|
||||
glVertex3f(spos[0]-r/2, spos[1]+0.02f, spos[2]);
|
||||
glVertex3f(spos[0]+r/2, spos[1]+0.02f, spos[2]);
|
||||
glVertex3f(spos[0], spos[1]+0.02f, spos[2]-r/2);
|
||||
glVertex3f(spos[0], spos[1]+0.02f, spos[2]+r/2);
|
||||
glEnd();
|
||||
|
||||
// Mesh bbox.
|
||||
col[0] = 1.0f; col[1] = 1.0f; col[2] = 1.0f; col[3] = 0.25f;
|
||||
rcDebugDrawBoxWire(g_cfg.bmin[0], g_cfg.bmin[1], g_cfg.bmin[2],
|
||||
g_cfg.bmax[0], g_cfg.bmax[1], g_cfg.bmax[2], col);
|
||||
}
|
||||
|
||||
// Render GUI
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, width, 0, height);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
|
||||
imguiBeginFrame();
|
||||
|
||||
mouseOverMenu = false;
|
||||
|
||||
static int propScroll = 0;
|
||||
if (imguiBeginScrollArea(GENID, "Properties", width - 250 - 10, 10, 250, height-20, &propScroll))
|
||||
mouseOverMenu = true;
|
||||
|
||||
if (imguiButton(GENID, curLevel))
|
||||
{
|
||||
showLevels = true;
|
||||
scanDirectory("meshes", ".obj", fileList);
|
||||
}
|
||||
|
||||
imguiSeparator();
|
||||
|
||||
if (g_mesh)
|
||||
{
|
||||
if (imguiButton(GENID, "Build"))
|
||||
{
|
||||
memset(&g_cfg, 0, sizeof(g_cfg));
|
||||
g_cfg.cs = cellSize;
|
||||
g_cfg.ch = cellHeight;
|
||||
g_cfg.walkableSlopeAngle = agentMaxSlope;
|
||||
g_cfg.walkableHeight = (int)ceilf(agentHeight / g_cfg.ch);
|
||||
g_cfg.walkableClimb = (int)ceilf(agentMaxClimb / g_cfg.ch);
|
||||
g_cfg.walkableRadius = (int)ceilf(agentRadius / g_cfg.cs);
|
||||
g_cfg.maxEdgeLen = (int)(edgeMaxLen / cellSize);
|
||||
g_cfg.maxSimplificationError = edgeMaxError;
|
||||
g_cfg.minRegionSize = (int)rcSqr(regionMinSize);
|
||||
g_cfg.mergeRegionSize = (int)rcSqr(regionMergeSize);
|
||||
g_cfg.maxVertsPerPoly = (int)vertsPerPoly;
|
||||
|
||||
buildNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
imguiSeparator();
|
||||
|
||||
if (imguiCheck(GENID, "Show Log", showLog))
|
||||
showLog = !showLog;
|
||||
|
||||
imguiSeparator();
|
||||
imguiLabel(GENID, "Rasterization");
|
||||
imguiSlider(GENID, "Cell Size", &cellSize, 0.1f, 1.0f, 0.01f);
|
||||
imguiSlider(GENID, "Cell Height", &cellHeight, 0.1f, 1.0f, 0.01f);
|
||||
|
||||
if (g_mesh)
|
||||
{
|
||||
int gw = 0, gh = 0;
|
||||
rcCalcGridSize(g_cfg.bmin, g_cfg.bmax, cellSize, &gw, &gh);
|
||||
char text[64];
|
||||
snprintf(text, 64, "Grid %d x %d", gw, gh);
|
||||
imguiValue(GENID, text);
|
||||
}
|
||||
|
||||
imguiSeparator();
|
||||
imguiLabel(GENID, "Agent");
|
||||
imguiSlider(GENID, "Height", &agentHeight, 0.1f, 5.0f, 0.1f);
|
||||
imguiSlider(GENID, "Ragius", &agentRadius, 0.1f, 5.0f, 0.1f);
|
||||
imguiSlider(GENID, "Max Climb", &agentMaxClimb, 0.1f, 5.0f, 0.1f);
|
||||
imguiSlider(GENID, "Max Slope", &agentMaxSlope, 0.0f, 90.0f, 1.0f);
|
||||
|
||||
imguiSeparator();
|
||||
imguiLabel(GENID, "Region");
|
||||
imguiSlider(GENID, "Min Region Size", ®ionMinSize, 0.0f, 150.0f, 1.0f);
|
||||
imguiSlider(GENID, "Merged Region Size", ®ionMergeSize, 0.0f, 150.0f, 1.0f);
|
||||
|
||||
imguiSeparator();
|
||||
imguiLabel(GENID, "Polygonization");
|
||||
imguiSlider(GENID, "Max Edge Length", &edgeMaxLen, 0.0f, 50.0f, 1.0f);
|
||||
imguiSlider(GENID, "Max Edge Error", &edgeMaxError, 0.1f, 3.0f, 0.1f);
|
||||
imguiSlider(GENID, "Verts Per Poly", &vertsPerPoly, 3.0f, 12.0f, 1.0f);
|
||||
|
||||
imguiSeparator();
|
||||
imguiLabel(GENID, "Draw");
|
||||
if (imguiCheck(GENID, "Input Mesh", drawMode == DRAWMODE_MESH))
|
||||
drawMode = DRAWMODE_MESH;
|
||||
if (imguiCheck(GENID, "Navmesh", drawMode == DRAWMODE_POLYMESH))
|
||||
drawMode = DRAWMODE_POLYMESH;
|
||||
if (imguiCheck(GENID, "Navmesh Trans", drawMode == DRAWMODE_POLYMESH_TRANS))
|
||||
drawMode = DRAWMODE_POLYMESH_TRANS;
|
||||
if (imguiCheck(GENID, "Voxels", drawMode == DRAWMODE_VOXELS))
|
||||
drawMode = DRAWMODE_VOXELS;
|
||||
if (imguiCheck(GENID, "Walkable Voxels", drawMode == DRAWMODE_VOXELS_WALKABLE))
|
||||
drawMode = DRAWMODE_VOXELS_WALKABLE;
|
||||
if (imguiCheck(GENID, "Compact", drawMode == DRAWMODE_COMPACT))
|
||||
drawMode = DRAWMODE_COMPACT;
|
||||
if (imguiCheck(GENID, "Compact Distance", drawMode == DRAWMODE_COMPACT_DISTANCE))
|
||||
drawMode = DRAWMODE_COMPACT_DISTANCE;
|
||||
if (imguiCheck(GENID, "Compact Regions", drawMode == DRAWMODE_COMPACT_REGIONS))
|
||||
drawMode = DRAWMODE_COMPACT_REGIONS;
|
||||
if (imguiCheck(GENID, "Raw Contours", drawMode == DRAWMODE_RAW_CONTOURS))
|
||||
drawMode = DRAWMODE_RAW_CONTOURS;
|
||||
if (imguiCheck(GENID, "Contours", drawMode == DRAWMODE_CONTOURS))
|
||||
drawMode = DRAWMODE_CONTOURS;
|
||||
|
||||
imguiEndScrollArea();
|
||||
|
||||
// Log
|
||||
if (showLog)
|
||||
{
|
||||
static int logScroll = 0;
|
||||
if (imguiBeginScrollArea(GENID, "Log", 10, 10, width - 300, 200, &logScroll))
|
||||
mouseOverMenu = true;
|
||||
for (int i = 0; i < g_log.getMessageCount(); ++i)
|
||||
imguiLabel(GENID1(i), g_log.getMessageText(i));
|
||||
imguiEndScrollArea();
|
||||
}
|
||||
|
||||
// Level selection dialog.
|
||||
if (showLevels)
|
||||
{
|
||||
static int scroll = 0;
|
||||
if (imguiBeginScrollArea(GENID, "Choose Level", width-10-250-10-200, height-10-250, 200, 250, &scroll))
|
||||
mouseOverMenu = true;
|
||||
|
||||
int levelToLoad = -1;
|
||||
for (int i = 0; i < fileList.size; ++i)
|
||||
{
|
||||
if (imguiItem(GENID1(i), fileList.files[i]))
|
||||
levelToLoad = i;
|
||||
}
|
||||
|
||||
if (levelToLoad != -1)
|
||||
{
|
||||
strncpy(curLevel, fileList.files[levelToLoad], sizeof(curLevel));
|
||||
curLevel[sizeof(curLevel)-1] = '\0';
|
||||
showLevels = false;
|
||||
|
||||
delete g_mesh;
|
||||
delete g_solid;
|
||||
delete g_chf;
|
||||
delete g_cset;
|
||||
delete g_polyMesh;
|
||||
delete [] g_triangleFlags;
|
||||
g_mesh = 0;
|
||||
g_solid = 0;
|
||||
g_chf = 0;
|
||||
g_cset = 0;
|
||||
g_polyMesh = 0;
|
||||
g_triangleFlags = 0;
|
||||
|
||||
g_mesh = new rcMeshLoaderObj;
|
||||
|
||||
char path[256];
|
||||
strcpy(path, "meshes/");
|
||||
strcat(path, curLevel);
|
||||
|
||||
if (!g_mesh->load(path))
|
||||
{
|
||||
printf("Could not load mesh\n");
|
||||
delete g_mesh;
|
||||
g_mesh = 0;
|
||||
}
|
||||
|
||||
if (g_mesh)
|
||||
{
|
||||
rcCalcBounds(g_mesh->getVerts(), g_mesh->getVertCount(), g_cfg.bmin, g_cfg.bmax);
|
||||
|
||||
// Reset camera.
|
||||
camr = sqrtf(rcSqr(g_cfg.bmax[0]-g_cfg.bmin[0]) +
|
||||
rcSqr(g_cfg.bmax[1]-g_cfg.bmin[1]) +
|
||||
rcSqr(g_cfg.bmax[2]-g_cfg.bmin[2])) / 2;
|
||||
camx = (g_cfg.bmax[0] + g_cfg.bmin[0]) / 2 + camr;
|
||||
camy = (g_cfg.bmax[1] + g_cfg.bmin[1]) / 2 + camr;
|
||||
camz = (g_cfg.bmax[2] + g_cfg.bmin[2]) / 2 + camr;
|
||||
camr *= 3;
|
||||
rx = 45;
|
||||
ry = -45;
|
||||
|
||||
glFogf(GL_FOG_START, camr*0.5f);
|
||||
glFogf(GL_FOG_END, camr*2.5f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
imguiEndScrollArea();
|
||||
|
||||
}
|
||||
|
||||
imguiEndFrame();
|
||||
imguiRender(&drawText);
|
||||
|
||||
g_font.drawText(10.0f, (float)height-20.0f, "W/S/A/D: Move LMB: Rotate RMB: Place character", GLFont::RGBA(255,255,255,128));
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
SDL_GL_SwapBuffers();
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
delete g_mesh;
|
||||
delete g_solid;
|
||||
delete g_chf;
|
||||
delete g_cset;
|
||||
delete g_polyMesh;
|
||||
delete [] g_triangleFlags;
|
||||
|
||||
return 0;
|
||||
}
|
BIN
Recast/Examples/font.cfnt
Normal file
BIN
Recast/Examples/font.cfnt
Normal file
Binary file not shown.
285
Recast/Examples/glfont.cpp
Normal file
285
Recast/Examples/glfont.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include "GlFont.h"
|
||||
#include <stdio.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <SDL_Opengl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
GLFont::GLFont(int renderVerts) :
|
||||
m_fd(0),
|
||||
m_texId(0),
|
||||
m_verts(0),
|
||||
m_nverts(0),
|
||||
m_maxVerts(renderVerts)
|
||||
{
|
||||
}
|
||||
|
||||
GLFont::~GLFont()
|
||||
{
|
||||
if (m_texId)
|
||||
glDeleteTextures(1, (GLuint*)&m_texId);
|
||||
unsigned char* data = (unsigned char*)m_fd;
|
||||
if (data)
|
||||
free(data);
|
||||
if (m_verts)
|
||||
free(m_verts);
|
||||
}
|
||||
|
||||
bool GLFont::create(const char* fileName)
|
||||
{
|
||||
unsigned char* data = 0;
|
||||
|
||||
FILE* fp = fopen(fileName, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
// Read cache file
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned n = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
data = (unsigned char*)malloc(n);
|
||||
fread(data, n, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (!m_verts)
|
||||
m_verts = (RenderVertex*)malloc(m_maxVerts*sizeof(RenderVertex));
|
||||
|
||||
return createFontFromFontData(data);
|
||||
}
|
||||
|
||||
bool GLFont::createFontFromFontData(unsigned char* data)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
printf("GLFont::createFontFromFontData: No input data!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fd = (FontData*)data;
|
||||
|
||||
// Patch kern pointers.
|
||||
for (int i = 0; i < m_fd->charCount; ++i)
|
||||
m_fd->glyphs[i].kern = (KerningPair*)((int)m_fd->glyphs[i].kernOffset + data);
|
||||
|
||||
unsigned char* texData = data + m_fd->textureOffset;
|
||||
|
||||
// Create textures
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, (GLuint*)&m_texId);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texId);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_fd->texWidth, m_fd->texHeight, 0,
|
||||
GL_ALPHA, GL_UNSIGNED_BYTE, texData);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int GLFont::getFontSize() const
|
||||
{
|
||||
return m_fd ? m_fd->fontSize : 0;
|
||||
}
|
||||
|
||||
int GLFont::getDescender() const
|
||||
{
|
||||
return m_fd ? m_fd->descender : 0;
|
||||
}
|
||||
|
||||
int GLFont::getAscender() const
|
||||
{
|
||||
return m_fd ? m_fd->ascender : 0;
|
||||
}
|
||||
|
||||
float GLFont::getLineHeight() const
|
||||
{
|
||||
return m_fd ? m_fd->lineHeight : 0.0f;
|
||||
}
|
||||
|
||||
float GLFont::getTextLength(const char* text, float size, float tracking)
|
||||
{
|
||||
if (!m_texId) return 0.0f;
|
||||
if (!m_fd) return 0.0f;
|
||||
|
||||
float scale = size < 0 ? 1 : size / (float)m_fd->fontSize;
|
||||
float track = scale * m_fd->ascender * tracking / 1000.0f;
|
||||
|
||||
const unsigned char* src = (const unsigned char*)text;
|
||||
|
||||
int prevc = -1;
|
||||
float len = 0.0f;
|
||||
float tx = 0.0f;
|
||||
|
||||
for (; *src; ++src)
|
||||
{
|
||||
int c = (int)*src - m_fd->charMin;
|
||||
if (c < 0 || c >= m_fd->charCount)
|
||||
{
|
||||
prevc = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
CachedGlyph& cg = m_fd->glyphs[c];
|
||||
if (prevc > 0 && prevc < m_fd->charCount)
|
||||
{
|
||||
CachedGlyph& prevcg = m_fd->glyphs[prevc];
|
||||
if (prevcg.nkern != 0)
|
||||
{
|
||||
for (int i = 0; i < prevcg.nkern; ++i)
|
||||
{
|
||||
if (prevcg.kern[i].c == c)
|
||||
{
|
||||
tx += prevcg.kern[i].dx * scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = tx + (cg.ox + cg.w) * scale;
|
||||
|
||||
tx += cg.adv * scale + track;
|
||||
prevc = c;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void GLFont::drawText(float tx, float ty, const char* text,
|
||||
unsigned int col, float size, float tracking)
|
||||
{
|
||||
if (!m_fd) return;
|
||||
if (!m_texId) return;
|
||||
if (!m_verts) return;
|
||||
|
||||
float scale = size < 0 ? 1 : size / (float)m_fd->fontSize;
|
||||
float track = scale * m_fd->ascender * tracking / 1000.0f;
|
||||
float su = 1.0f / m_fd->texWidth;
|
||||
float sv = 1.0f / m_fd->texHeight;
|
||||
|
||||
const unsigned char* src = (const unsigned char*)text;
|
||||
|
||||
RenderVertex* v = &m_verts[m_nverts];
|
||||
|
||||
int prevc = -1;
|
||||
|
||||
for (; *src; ++src)
|
||||
{
|
||||
int c = (int)*src - m_fd->charMin;
|
||||
if (c == '\n')
|
||||
{
|
||||
ty -= getLineHeight();
|
||||
prevc = -1;
|
||||
continue;
|
||||
}
|
||||
if (c < 0 || c >= m_fd->charCount)
|
||||
{
|
||||
prevc = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
CachedGlyph& cg = m_fd->glyphs[c];
|
||||
if (prevc > 0 && prevc < m_fd->charCount)
|
||||
{
|
||||
CachedGlyph& prevcg = m_fd->glyphs[prevc];
|
||||
if (prevcg.nkern != 0)
|
||||
{
|
||||
for (int i = 0; i < prevcg.nkern; ++i)
|
||||
{
|
||||
if (prevcg.kern[i].c == c)
|
||||
{
|
||||
tx += prevcg.kern[i].dx * scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float x0 = floorf(tx + (cg.ox - 1) * scale + 0.5f);
|
||||
float y0 = floorf(ty + (cg.oy - 1) * scale + 0.5f);
|
||||
float x1 = floorf(x0 + (cg.w + 2) * scale + 0.5f);
|
||||
float y1 = floorf(y0 + (cg.h + 2) * scale + 0.5f);
|
||||
|
||||
float u0 = (cg.tx - 1) * su;
|
||||
float v0 = (cg.ty - 1) * sv;
|
||||
float u1 = (cg.tx + cg.w + 1) * su;
|
||||
float v1 = (cg.ty + cg.h + 1) * sv;
|
||||
|
||||
if (m_nverts+6 > m_maxVerts) break;
|
||||
|
||||
v->set(x0, y0, u0, v0, col); v++;
|
||||
v->set(x1, y0, u1, v0, col); v++;
|
||||
v->set(x1, y1, u1, v1, col); v++;
|
||||
|
||||
v->set(x0, y0, u0, v0, col); v++;
|
||||
v->set(x1, y1, u1, v1, col); v++;
|
||||
v->set(x0, y1, u0, v1, col); v++;
|
||||
|
||||
m_nverts += 6;
|
||||
|
||||
tx += cg.adv * scale + track;
|
||||
prevc = c;
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
void GLFont::render()
|
||||
{
|
||||
if (!m_fd) return;
|
||||
if (!m_texId) return;
|
||||
if (!m_verts) return;
|
||||
|
||||
// Render
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texId);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(RenderVertex), &m_verts[0].x);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(RenderVertex), &m_verts[0].u);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(RenderVertex), &m_verts[0].col);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_nverts);
|
||||
m_nverts = 0;
|
||||
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
unsigned int GLFont::RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return (a<<24) | (b<<16) | (g<<8) | r;
|
||||
/*#ifdef WIN32
|
||||
return (a<<24) | (b<<16) | (g<<8) | r;
|
||||
#else
|
||||
return (r<<24) | (g<<16) | (b<<8) | a;
|
||||
#endif*/
|
||||
}
|
106
Recast/Examples/glfont.h
Normal file
106
Recast/Examples/glfont.h
Normal file
@ -0,0 +1,106 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef GLFONT_H
|
||||
#define GLFONT_H
|
||||
|
||||
class GLFont
|
||||
{
|
||||
public:
|
||||
GLFont(int renderVerts = 4096);
|
||||
~GLFont();
|
||||
|
||||
bool create(const char* fileName);
|
||||
|
||||
int getFontSize() const;
|
||||
int getDescender() const;
|
||||
int getAscender() const;
|
||||
float getLineHeight() const;
|
||||
|
||||
float getTextLength(const char* text, float size = -1, float tracking = 0);
|
||||
void drawText(float x, float y, const char* text,
|
||||
unsigned int col, float size = -1, float tracking = 0);
|
||||
|
||||
void render();
|
||||
|
||||
void debugDraw();
|
||||
|
||||
static unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255);
|
||||
|
||||
private:
|
||||
bool createFontFromFontData(unsigned char* fd);
|
||||
|
||||
struct KerningPair
|
||||
{
|
||||
inline KerningPair() {}
|
||||
inline KerningPair(unsigned char c_, float dx_) : dx(dx_), c(c_) {}
|
||||
inline void Set(unsigned char c_, float dx_) { dx = dx_; c = c_; }
|
||||
float dx;
|
||||
unsigned char c, pad[3];
|
||||
};
|
||||
|
||||
struct CachedGlyph
|
||||
{
|
||||
inline CachedGlyph() : w(0), h(0), ox(0), oy(0), tx(0), ty(0), adv(0.0f), nkern(0), kern(0) {}
|
||||
int w, h;
|
||||
int ox, oy;
|
||||
int tx, ty;
|
||||
float adv;
|
||||
int nkern;
|
||||
union
|
||||
{
|
||||
KerningPair* kern;
|
||||
int kernOffset;
|
||||
};
|
||||
};
|
||||
|
||||
struct FontData
|
||||
{
|
||||
unsigned int endian;
|
||||
unsigned int version;
|
||||
unsigned int dataSize;
|
||||
unsigned int kernOffset;
|
||||
unsigned int textureOffset;
|
||||
int fontSize;
|
||||
unsigned int texWidth;
|
||||
unsigned int texHeight;
|
||||
int numMipmaps;
|
||||
int ascender;
|
||||
int descender;
|
||||
int lineHeight;
|
||||
int charMin;
|
||||
int charCount;
|
||||
CachedGlyph glyphs[1];
|
||||
};
|
||||
|
||||
FontData* m_fd;
|
||||
unsigned int m_texId;
|
||||
|
||||
struct RenderVertex
|
||||
{
|
||||
inline void set(float x_, float y_, float u_, float v_, unsigned int c) { x=x_; y=y_; u=u_; v=v_; col=c; }
|
||||
float x, y, u, v;
|
||||
unsigned int col;
|
||||
};
|
||||
RenderVertex* m_verts;
|
||||
int m_nverts;
|
||||
const int m_maxVerts;
|
||||
};
|
||||
|
||||
|
||||
#endif // GLFONT_H
|
851
Recast/Examples/imgui.cpp
Normal file
851
Recast/Examples/imgui.cpp
Normal file
@ -0,0 +1,851 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "imgui.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_opengl.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
enum GfxCmdType
|
||||
{
|
||||
GFXCMD_RECT,
|
||||
GFXCMD_TRIANGLE,
|
||||
GFXCMD_TEXT,
|
||||
GFXCMD_SCISSOR,
|
||||
};
|
||||
|
||||
struct GfxRect
|
||||
{
|
||||
short x,y,w,h,r;
|
||||
};
|
||||
struct GfxText
|
||||
{
|
||||
short x,y,dir;
|
||||
const char* text;
|
||||
};
|
||||
|
||||
struct GfxCmd
|
||||
{
|
||||
char type;
|
||||
char flags;
|
||||
char pad[2];
|
||||
unsigned int col;
|
||||
union
|
||||
{
|
||||
GfxRect rect;
|
||||
GfxText text;
|
||||
};
|
||||
};
|
||||
|
||||
unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return (r) | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
static const unsigned TEXT_POOL_SIZE = 4096;
|
||||
static char g_textPool[TEXT_POOL_SIZE];
|
||||
static unsigned g_textPoolSize = 0;
|
||||
const char* allocText(const char* text)
|
||||
{
|
||||
unsigned len = strlen(text)+1;
|
||||
if (g_textPoolSize + len >= TEXT_POOL_SIZE)
|
||||
return 0;
|
||||
char* dst = &g_textPool[g_textPoolSize];
|
||||
memcpy(dst, text, len);
|
||||
g_textPoolSize += len;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static const unsigned GFXCMD_QUEUE_SIZE = 1024;
|
||||
static GfxCmd g_gfxCmdQueue[GFXCMD_QUEUE_SIZE];
|
||||
static unsigned g_gfxCmdQueueSize = 0;
|
||||
|
||||
void resetGfxCmdQueue()
|
||||
{
|
||||
g_gfxCmdQueueSize = 0;
|
||||
g_textPoolSize = 0;
|
||||
}
|
||||
|
||||
|
||||
static const unsigned TEMP_COORD_COUNT = 100;
|
||||
static float g_tempCoords[TEMP_COORD_COUNT*2];
|
||||
static float g_tempNormals[TEMP_COORD_COUNT*2];
|
||||
|
||||
static void drawPolygon(const float* coords, unsigned numCoords, float r, unsigned int col)
|
||||
{
|
||||
if (numCoords > TEMP_COORD_COUNT) numCoords = TEMP_COORD_COUNT;
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
const float* v0 = &coords[j*2];
|
||||
const float* v1 = &coords[i*2];
|
||||
float dx = v1[0] - v0[0];
|
||||
float dy = v1[1] - v0[1];
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
g_tempNormals[j*2+0] = dy;
|
||||
g_tempNormals[j*2+1] = -dx;
|
||||
}
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
float dlx0 = g_tempNormals[j*2+0];
|
||||
float dly0 = g_tempNormals[j*2+1];
|
||||
float dlx1 = g_tempNormals[i*2+0];
|
||||
float dly1 = g_tempNormals[i*2+1];
|
||||
float dmx = (dlx0 + dlx1) * 0.5f;
|
||||
float dmy = (dly0 + dly1) * 0.5f;
|
||||
float dmr2 = dmx*dmx + dmy*dmy;
|
||||
if (dmr2 > 0.000001f)
|
||||
{
|
||||
float scale = 1.0f / dmr2;
|
||||
if (scale > 10.0f) scale = 10.0f;
|
||||
dmx *= scale;
|
||||
dmy *= scale;
|
||||
}
|
||||
g_tempCoords[i*2+0] = coords[i*2+0]+dmx*r;
|
||||
g_tempCoords[i*2+1] = coords[i*2+1]+dmy*r;
|
||||
}
|
||||
|
||||
unsigned int colTrans = RGBA(col&0xff, (col>>8)&0xff, (col>>16)&0xff, 0);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
glVertex2fv(&coords[i*2]);
|
||||
glVertex2fv(&coords[j*2]);
|
||||
glColor4ubv((GLubyte*)&colTrans);
|
||||
glVertex2fv(&g_tempCoords[j*2]);
|
||||
|
||||
glVertex2fv(&g_tempCoords[j*2]);
|
||||
glVertex2fv(&g_tempCoords[i*2]);
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
glVertex2fv(&coords[i*2]);
|
||||
}
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
for (unsigned i = 2; i < numCoords; ++i)
|
||||
{
|
||||
glVertex2fv(&coords[0]);
|
||||
glVertex2fv(&coords[(i-1)*2]);
|
||||
glVertex2fv(&coords[i*2]);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static const int CIRCLE_VERTS = 8*4;
|
||||
static float g_circleVerts[CIRCLE_VERTS*2];
|
||||
static bool g_circleVertsInitialized = false;
|
||||
|
||||
const float* getCircleVerts()
|
||||
{
|
||||
if (!g_circleVertsInitialized)
|
||||
{
|
||||
g_circleVertsInitialized = true;
|
||||
for (unsigned i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
float a = (float)i/(float)CIRCLE_VERTS * (float)M_PI*2;
|
||||
g_circleVerts[i*2+0] = cosf(a);
|
||||
g_circleVerts[i*2+1] = sinf(a);
|
||||
}
|
||||
}
|
||||
return g_circleVerts;
|
||||
}
|
||||
|
||||
static void drawRect(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[4*2] =
|
||||
{
|
||||
x, y,
|
||||
x+w, y,
|
||||
x+w, y+h,
|
||||
x, y+h,
|
||||
};
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
static void drawEllipse(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[CIRCLE_VERTS*2];
|
||||
const float* cverts = getCircleVerts();
|
||||
float* v = verts;
|
||||
|
||||
for (unsigned i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
*v++ = x + cverts[i*2]*w;
|
||||
*v++ = y + cverts[i*2+1]*h;
|
||||
}
|
||||
|
||||
drawPolygon(verts, CIRCLE_VERTS, fth, col);
|
||||
}
|
||||
|
||||
static void drawRoundedRect(float x, float y, float w, float h, float r, float fth, unsigned int col)
|
||||
{
|
||||
const unsigned n = CIRCLE_VERTS/4;
|
||||
float verts[(n+1)*4*2];
|
||||
const float* cverts = getCircleVerts();
|
||||
float* v = verts;
|
||||
|
||||
for (unsigned i = 0; i <= n; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n; i <= n*2; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*2; i <= n*3; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*3; i < n*4; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
*v++ = x+w-r + cverts[0]*r;
|
||||
*v++ = y+r + cverts[1]*r;
|
||||
|
||||
drawPolygon(verts, (n+1)*4, fth, col);
|
||||
}
|
||||
|
||||
static void drawLine(float x0, float y0, float x1, float y1, float r, float fth, unsigned int col)
|
||||
{
|
||||
float dx = x1-x0;
|
||||
float dy = y1-y0;
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0.0001f)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
float t = dx;
|
||||
dx = dy;
|
||||
dy = -t;
|
||||
float verts[4*2];
|
||||
r -= fth;
|
||||
r *= 0.5f;
|
||||
if (r < 0.01f) r = 0.01f;
|
||||
dx *= r;
|
||||
dy *= r;
|
||||
|
||||
verts[0] = x0-dx;
|
||||
verts[1] = y0-dy;
|
||||
|
||||
verts[2] = x0+dx;
|
||||
verts[3] = y0+dy;
|
||||
|
||||
verts[4] = x1+dx;
|
||||
verts[5] = y1+dy;
|
||||
|
||||
verts[6] = x1-dx;
|
||||
verts[7] = y1-dy;
|
||||
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
|
||||
void renderGfxCmdQueue(void (*drawText)(int x, int y, int dir, const char* text, unsigned int col))
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
for (unsigned i = 0; i < g_gfxCmdQueueSize; ++i)
|
||||
{
|
||||
const GfxCmd& cmd = g_gfxCmdQueue[i];
|
||||
if (cmd.type == GFXCMD_RECT)
|
||||
{
|
||||
if (cmd.rect.r == 0)
|
||||
{
|
||||
drawRect((float)cmd.rect.x+0.5f, (float)cmd.rect.y+0.5f,
|
||||
(float)cmd.rect.w-1, (float)cmd.rect.h-1,
|
||||
1.0f, cmd.col);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawRoundedRect((float)cmd.rect.x+0.5f, (float)cmd.rect.y+0.5f,
|
||||
(float)cmd.rect.w-1, (float)cmd.rect.h-1,
|
||||
(float)cmd.rect.r, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == GFXCMD_TRIANGLE)
|
||||
{
|
||||
glColor4ub(cmd.col&0xff, (cmd.col>>8)&0xff, (cmd.col>>16)&0xff, (cmd.col>>24)&0xff);
|
||||
if (cmd.flags == 1)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x+0.5f, (float)cmd.rect.y+0.5f,
|
||||
(float)cmd.rect.x+0.5f+(float)cmd.rect.w-1, (float)cmd.rect.y+0.5f+(float)cmd.rect.h/2-0.5f,
|
||||
(float)cmd.rect.x+0.5f, (float)cmd.rect.y+0.5f+(float)cmd.rect.h-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
if (cmd.flags == 2)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x+0.5f, (float)cmd.rect.y+(float)cmd.rect.h-1,
|
||||
(float)cmd.rect.x+0.5f+(float)cmd.rect.w/2-0.5f, (float)cmd.rect.y+0.5f,
|
||||
(float)cmd.rect.x+0.5f+(float)cmd.rect.w-1, (float)cmd.rect.y+0.5f+(float)cmd.rect.h-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == GFXCMD_TEXT)
|
||||
{
|
||||
drawText(cmd.text.x, cmd.text.y, cmd.text.dir, cmd.text.text, cmd.col);
|
||||
}
|
||||
else if (cmd.type == GFXCMD_SCISSOR)
|
||||
{
|
||||
if (cmd.flags)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void addGfxCmdScissor(int x, int y, int w, int h)
|
||||
{
|
||||
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
|
||||
return;
|
||||
GfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
|
||||
cmd.type = GFXCMD_SCISSOR;
|
||||
cmd.flags = x < 0 ? 0 : 1; // on/off flag.
|
||||
cmd.col = 0;
|
||||
cmd.rect.x = (short)x;
|
||||
cmd.rect.y = (short)y;
|
||||
cmd.rect.w = (short)w;
|
||||
cmd.rect.h = (short)h;
|
||||
}
|
||||
|
||||
void addGfxCmdRect(int x, int y, int w, int h, unsigned int color)
|
||||
{
|
||||
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
|
||||
return;
|
||||
GfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
|
||||
cmd.type = GFXCMD_RECT;
|
||||
cmd.flags = 0;
|
||||
cmd.col = color;
|
||||
cmd.rect.x = (short)x;
|
||||
cmd.rect.y = (short)y;
|
||||
cmd.rect.w = (short)w;
|
||||
cmd.rect.h = (short)h;
|
||||
cmd.rect.r = 0;
|
||||
}
|
||||
|
||||
void addGfxCmdRoundedRect(int x, int y, int w, int h, int r, unsigned int color)
|
||||
{
|
||||
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
|
||||
return;
|
||||
GfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
|
||||
cmd.type = GFXCMD_RECT;
|
||||
cmd.flags = 0;
|
||||
cmd.col = color;
|
||||
cmd.rect.x = (short)x;
|
||||
cmd.rect.y = (short)y;
|
||||
cmd.rect.w = (short)w;
|
||||
cmd.rect.h = (short)h;
|
||||
cmd.rect.r = (short)r;
|
||||
}
|
||||
|
||||
void addGfxCmdTriangle(int x, int y, int w, int h, int flags, unsigned int color)
|
||||
{
|
||||
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
|
||||
return;
|
||||
GfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
|
||||
cmd.type = GFXCMD_TRIANGLE;
|
||||
cmd.flags = (char)flags;
|
||||
cmd.col = color;
|
||||
cmd.rect.x = (short)x;
|
||||
cmd.rect.y = (short)y;
|
||||
cmd.rect.w = (short)w;
|
||||
cmd.rect.h = (short)h;
|
||||
}
|
||||
|
||||
void addGfxCmdText(int x, int y, int dir, const char* text, unsigned int color)
|
||||
{
|
||||
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
|
||||
return;
|
||||
GfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
|
||||
cmd.type = GFXCMD_TEXT;
|
||||
cmd.flags = 0;
|
||||
cmd.col = color;
|
||||
cmd.text.x = (short)x;
|
||||
cmd.text.y = (short)y;
|
||||
cmd.text.dir = (short)dir;
|
||||
cmd.text.text = allocText(text);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct GuiState
|
||||
{
|
||||
GuiState() :
|
||||
mbutPressed(false), mbutReleased(false), mbut(false), mx(-1), my(-1),
|
||||
isHot(false), isActive(false), wentActive(false),
|
||||
dragX(0), dragY(0), dragOrig(0),
|
||||
widgetX(0), widgetY(0), widgetW(100),
|
||||
active(0), hot(0), hotToBe(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool mbutPressed, mbutReleased;
|
||||
bool mbut;
|
||||
int mx,my;
|
||||
unsigned int active;
|
||||
unsigned int hot;
|
||||
unsigned int hotToBe;
|
||||
bool isHot;
|
||||
bool isActive;
|
||||
bool wentActive;
|
||||
int dragX, dragY;
|
||||
float dragOrig;
|
||||
int widgetX, widgetY, widgetW;
|
||||
};
|
||||
|
||||
static GuiState g_state;
|
||||
|
||||
inline bool anyActive()
|
||||
{
|
||||
return g_state.active != 0;
|
||||
}
|
||||
|
||||
inline bool isActive(unsigned int id)
|
||||
{
|
||||
return g_state.active == id;
|
||||
}
|
||||
|
||||
inline bool isHot(unsigned int id)
|
||||
{
|
||||
return g_state.hot == id;
|
||||
}
|
||||
|
||||
inline bool inRect(int x, int y, int w, int h)
|
||||
{
|
||||
return g_state.mx >= x && g_state.mx <= x+w && g_state.my >= y && g_state.my <= y+h;
|
||||
}
|
||||
|
||||
void clearInput()
|
||||
{
|
||||
g_state.mbutPressed = false;
|
||||
g_state.mbutReleased = false;
|
||||
}
|
||||
|
||||
void clearActive(void)
|
||||
{
|
||||
g_state.active = 0;
|
||||
// mark all UI for this frame as processed
|
||||
clearInput();
|
||||
}
|
||||
|
||||
void setActive(unsigned int id)
|
||||
{
|
||||
g_state.active = id;
|
||||
g_state.wentActive = true;
|
||||
}
|
||||
|
||||
void setHot(unsigned int id)
|
||||
{
|
||||
g_state.hotToBe = id;
|
||||
}
|
||||
|
||||
|
||||
bool buttonLogic(unsigned int id, bool over)
|
||||
{
|
||||
bool res = false;
|
||||
// process down
|
||||
if (!anyActive())
|
||||
{
|
||||
if (over)
|
||||
setHot(id);
|
||||
if (isHot(id) && g_state.mbutPressed)
|
||||
setActive(id);
|
||||
}
|
||||
|
||||
// if button is active, then react on left up
|
||||
if (isActive(id))
|
||||
{
|
||||
g_state.isActive = true;
|
||||
if (over)
|
||||
setHot(id);
|
||||
if (g_state.mbutReleased)
|
||||
{
|
||||
if (isHot(id))
|
||||
res = true;
|
||||
clearActive();
|
||||
}
|
||||
}
|
||||
|
||||
if (isHot(id))
|
||||
g_state.isHot = true;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void updateInput()
|
||||
{
|
||||
int mx, my;
|
||||
Uint8 state = SDL_GetMouseState(&mx, &my);
|
||||
bool mbut = (state & SDL_BUTTON_LMASK) != 0;
|
||||
SDL_Surface* screen = SDL_GetVideoSurface();
|
||||
my = screen->h-1 - my;
|
||||
|
||||
g_state.mx = mx;
|
||||
g_state.my = my;
|
||||
g_state.mbutPressed = !g_state.mbut && mbut;
|
||||
g_state.mbutReleased = g_state.mbut && !mbut;
|
||||
g_state.mbut = mbut;
|
||||
}
|
||||
|
||||
void imguiBeginFrame()
|
||||
{
|
||||
updateInput();
|
||||
|
||||
g_state.hot = g_state.hotToBe;
|
||||
g_state.hotToBe = 0;
|
||||
|
||||
g_state.wentActive = false;
|
||||
g_state.isActive = false;
|
||||
g_state.isHot = false;
|
||||
|
||||
g_state.widgetX = 0;
|
||||
g_state.widgetY = 0;
|
||||
g_state.widgetW = 0;
|
||||
|
||||
resetGfxCmdQueue();
|
||||
}
|
||||
|
||||
void imguiEndFrame()
|
||||
{
|
||||
clearInput();
|
||||
}
|
||||
|
||||
void imguiRender(void (*drawText)(int x, int y, int dir, const char* text, unsigned int col))
|
||||
{
|
||||
renderGfxCmdQueue(drawText);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static const int BUTTON_HEIGHT = 20;
|
||||
static const int SLIDER_HEIGHT = 20;
|
||||
static const int SLIDER_MARKER_WIDTH = 10;
|
||||
static const int CHECK_SIZE = 8;
|
||||
static const int DEFAULT_SPACING = 4;
|
||||
static const int TEXT_HEIGHT = 8;
|
||||
static const int SCROLL_AREA_PADDING = 6;
|
||||
static const int INTEND_SIZE = 16;
|
||||
static const int AREA_HEADER = 28;
|
||||
|
||||
static int g_scrollTop = 0;
|
||||
static int g_scrollBottom = 0;
|
||||
static int g_scrollRight = 0;
|
||||
static int g_scrollAreaTop = 0;
|
||||
static int* g_scrollVal = 0;
|
||||
static int g_focusTop = 0;
|
||||
static int g_focusBottom = 0;
|
||||
static unsigned int g_scrollId = 0;
|
||||
|
||||
bool imguiBeginScrollArea(unsigned int id, const char* name, int x, int y, int w, int h, int* scroll)
|
||||
{
|
||||
g_scrollId = id;
|
||||
|
||||
g_state.widgetX = x + SCROLL_AREA_PADDING;
|
||||
g_state.widgetY = y+h-AREA_HEADER + (*scroll);
|
||||
g_state.widgetW = w - SCROLL_AREA_PADDING*4;
|
||||
g_scrollTop = y-AREA_HEADER+h;
|
||||
g_scrollBottom = y+SCROLL_AREA_PADDING;
|
||||
g_scrollRight = x+w - SCROLL_AREA_PADDING*3;
|
||||
g_scrollVal = scroll;
|
||||
|
||||
g_scrollAreaTop = g_state.widgetY;
|
||||
|
||||
g_focusTop = y-AREA_HEADER;
|
||||
g_focusBottom = y-AREA_HEADER+h;
|
||||
|
||||
addGfxCmdRoundedRect(x, y, w, h, 6, RGBA(0,0,0,192));
|
||||
|
||||
addGfxCmdText(x+AREA_HEADER/2, y+h-AREA_HEADER/2-TEXT_HEIGHT/2, 1, name, RGBA(255,255,255,128));
|
||||
|
||||
addGfxCmdScissor(x+SCROLL_AREA_PADDING, y+SCROLL_AREA_PADDING, w-SCROLL_AREA_PADDING*4, h-AREA_HEADER-SCROLL_AREA_PADDING);
|
||||
|
||||
return inRect(x, y, w, h);
|
||||
}
|
||||
|
||||
void imguiEndScrollArea()
|
||||
{
|
||||
// Disable scissoring.
|
||||
addGfxCmdScissor(-1,-1,-1,-1);
|
||||
|
||||
// Draw scroll bar
|
||||
int x = g_scrollRight+SCROLL_AREA_PADDING/2;
|
||||
int y = g_scrollBottom;
|
||||
int w = SCROLL_AREA_PADDING*2;
|
||||
int h = g_scrollTop - g_scrollBottom;
|
||||
|
||||
int stop = g_scrollAreaTop;
|
||||
int sbot = g_state.widgetY;
|
||||
int sh = stop - sbot; // The scrollable area height.
|
||||
|
||||
float barHeight = (float)h/(float)sh;
|
||||
|
||||
if (barHeight < 1)
|
||||
{
|
||||
float barY = (float)(y - sbot)/(float)sh;
|
||||
if (barY < 0) barY = 0;
|
||||
if (barY > 1) barY = 1;
|
||||
|
||||
// Handle scroll bar logic.
|
||||
unsigned int hid = g_scrollId;
|
||||
int hx = x;
|
||||
int hy = y + (int)(barY*h);
|
||||
int hw = w;
|
||||
int hh = (int)(barHeight*h);
|
||||
|
||||
const int range = h - (hh-1);
|
||||
bool over = inRect(hx, hy, hw, hh);
|
||||
buttonLogic(hid, over);
|
||||
if (isActive(hid))
|
||||
{
|
||||
float u = (float)(hy-y) / (float)range;
|
||||
if (g_state.wentActive)
|
||||
{
|
||||
g_state.dragY = g_state.my;
|
||||
g_state.dragOrig = u;
|
||||
}
|
||||
if (g_state.dragY != g_state.my)
|
||||
{
|
||||
u = g_state.dragOrig + (g_state.my - g_state.dragY) / (float)range;
|
||||
if (u < 0) u = 0;
|
||||
if (u > 1) u = 1;
|
||||
*g_scrollVal = (int)((1-u) * (sh - h));
|
||||
}
|
||||
}
|
||||
|
||||
// BG
|
||||
addGfxCmdRoundedRect(x, y, w, h, w/2-1, RGBA(0,0,0,196));
|
||||
// Bar
|
||||
if (isActive(hid))
|
||||
addGfxCmdRoundedRect(hx, hy, hw, hh, w/2-1, RGBA(255,196,0,196));
|
||||
else
|
||||
addGfxCmdRoundedRect(hx, hy, hw, hh, w/2-1, isHot(hid) ? RGBA(255,196,0,96) : RGBA(255,255,255,64));
|
||||
}
|
||||
}
|
||||
|
||||
bool imguiButton(unsigned int id, const char* text)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
int w = g_state.widgetW;
|
||||
int h = BUTTON_HEIGHT;
|
||||
g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
|
||||
|
||||
bool over = inRect(x, y, w, h);
|
||||
bool res = buttonLogic(id, over);
|
||||
|
||||
addGfxCmdRoundedRect(x, y, w, h, BUTTON_HEIGHT/2-1, RGBA(128,128,128, isActive(id)?196:96));
|
||||
addGfxCmdText(x+BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, 1, text, isHot(id) ? RGBA(255,196,0,255) : RGBA(255,255,255,200));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool imguiItem(unsigned int id, const char* text)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
int w = g_state.widgetW;
|
||||
int h = BUTTON_HEIGHT;
|
||||
g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
|
||||
|
||||
bool over = inRect(x, y, w, h);
|
||||
bool res = buttonLogic(id, over);
|
||||
|
||||
if (isHot(id))
|
||||
addGfxCmdRoundedRect(x, y, w, h, 2, RGBA(255,196,0,isActive(id)?196:96));
|
||||
addGfxCmdText(x+BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, 1, text, RGBA(255,255,255,200));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool imguiCheck(unsigned int id, const char* text, bool checked)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
int w = g_state.widgetW;
|
||||
int h = BUTTON_HEIGHT;
|
||||
g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
|
||||
|
||||
bool over = inRect(x, y, w, h);
|
||||
bool res = buttonLogic(id, over);
|
||||
|
||||
const int cx = x+BUTTON_HEIGHT/2-CHECK_SIZE/2;
|
||||
const int cy = y+BUTTON_HEIGHT/2-CHECK_SIZE/2;
|
||||
addGfxCmdRoundedRect(cx-3, cy-3, CHECK_SIZE+6, CHECK_SIZE+6, 4, RGBA(128,128,128, isActive(id)?196:96));
|
||||
if (checked)
|
||||
addGfxCmdRoundedRect(cx, cy, CHECK_SIZE, CHECK_SIZE, CHECK_SIZE/2-1, RGBA(255,255,255,isActive(id)?255:200));
|
||||
|
||||
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, 1, text, isHot(id) ? RGBA(255,196,0,255) : RGBA(255,255,255,200));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool imguiCollapse(unsigned int id, const char* text, bool checked)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
int w = g_state.widgetW;
|
||||
int h = BUTTON_HEIGHT;
|
||||
g_state.widgetY -= BUTTON_HEIGHT; // + DEFAULT_SPACING;
|
||||
|
||||
const int cx = x+BUTTON_HEIGHT/2-CHECK_SIZE/2;
|
||||
const int cy = y+BUTTON_HEIGHT/2-CHECK_SIZE/2;
|
||||
|
||||
bool over = inRect(x, y, w, h);
|
||||
bool res = buttonLogic(id, over);
|
||||
|
||||
if (checked)
|
||||
addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 1, RGBA(255,255,255,isActive(id)?255:200));
|
||||
else
|
||||
addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 2, RGBA(255,255,255,isActive(id)?255:200));
|
||||
|
||||
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, 1, text, isHot(id) ? RGBA(255,196,0,255) : RGBA(255,255,255,200));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void imguiLabel(unsigned int /*id*/, const char* text)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
g_state.widgetY -= BUTTON_HEIGHT;
|
||||
addGfxCmdText(x, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, 1, text, RGBA(255,255,255,255));
|
||||
}
|
||||
|
||||
void imguiValue(unsigned int /*id*/, const char* text)
|
||||
{
|
||||
const int x = g_state.widgetX;
|
||||
const int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
const int w = g_state.widgetW;
|
||||
g_state.widgetY -= BUTTON_HEIGHT;
|
||||
|
||||
addGfxCmdText(x+w-BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, -1, text, RGBA(255,255,255,200));
|
||||
}
|
||||
|
||||
bool imguiSlider(unsigned int id, const char* text, float* val, float vmin, float vmax, float vinc)
|
||||
{
|
||||
int x = g_state.widgetX;
|
||||
int y = g_state.widgetY - BUTTON_HEIGHT;
|
||||
int w = g_state.widgetW;
|
||||
int h = SLIDER_HEIGHT;
|
||||
g_state.widgetY -= SLIDER_HEIGHT + DEFAULT_SPACING;
|
||||
|
||||
addGfxCmdRoundedRect(x, y, w, h, 4, RGBA(0,0,0,128));
|
||||
|
||||
const int range = w - SLIDER_MARKER_WIDTH;
|
||||
|
||||
float u = (*val - vmin) / (vmax-vmin);
|
||||
if (u < 0) u = 0;
|
||||
if (u > 1) u = 1;
|
||||
int m = (int)(u * range);
|
||||
|
||||
bool over = inRect(x+m, y, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT);
|
||||
bool res = buttonLogic(id, over);
|
||||
bool valChanged = false;
|
||||
|
||||
if (isActive(id))
|
||||
{
|
||||
if (g_state.wentActive)
|
||||
{
|
||||
g_state.dragX = g_state.mx;
|
||||
g_state.dragOrig = u;
|
||||
}
|
||||
if (g_state.dragX != g_state.mx)
|
||||
{
|
||||
u = g_state.dragOrig + (float)(g_state.mx - g_state.dragX) / (float)range;
|
||||
if (u < 0) u = 0;
|
||||
if (u > 1) u = 1;
|
||||
*val = vmin + u*(vmax-vmin);
|
||||
*val = floorf(*val / vinc)*vinc; // Snap to vinc
|
||||
m = (int)(u * range);
|
||||
valChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isActive(id))
|
||||
addGfxCmdRoundedRect(x+m, y, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT, 4, RGBA(255,255,255,255));
|
||||
else
|
||||
addGfxCmdRoundedRect(x+m, y, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT, 4, isHot(id) ? RGBA(255,196,0,128) : RGBA(255,255,255,64));
|
||||
|
||||
int digits = (int)(ceilf(log10f(vinc)));
|
||||
char fmt[16];
|
||||
snprintf(fmt, 16, "%%.%df", digits >= 0 ? 0 : -digits);
|
||||
char msg[128];
|
||||
snprintf(msg, 128, fmt, *val);
|
||||
|
||||
addGfxCmdText(x+SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, 1, text, isHot(id) ? RGBA(255,196,0,255) : RGBA(255,255,255,200));
|
||||
addGfxCmdText(x+w-SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, -1, msg, isHot(id) ? RGBA(255,196,0,255) : RGBA(255,255,255,200));
|
||||
|
||||
return res || valChanged;
|
||||
}
|
||||
|
||||
|
||||
void imguiIndent()
|
||||
{
|
||||
g_state.widgetX += INTEND_SIZE;
|
||||
g_state.widgetW -= INTEND_SIZE;
|
||||
}
|
||||
|
||||
void imguiUnindent()
|
||||
{
|
||||
g_state.widgetX -= INTEND_SIZE;
|
||||
g_state.widgetW += INTEND_SIZE;
|
||||
}
|
||||
|
||||
void imguiSeparator()
|
||||
{
|
||||
g_state.widgetY -= DEFAULT_SPACING*3;
|
||||
}
|
45
Recast/Examples/imgui.h
Normal file
45
Recast/Examples/imgui.h
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef IMGUI_H
|
||||
#define IMGUI_H
|
||||
|
||||
#define GENID ((__LINE__) << 16)
|
||||
#define GENID1(x) ((__LINE__) << 16 | (x))
|
||||
|
||||
void imguiBeginFrame();
|
||||
void imguiEndFrame();
|
||||
void imguiRender(void (*drawText)(int x, int y, int dir, const char* text, unsigned int col));
|
||||
|
||||
bool imguiBeginScrollArea(unsigned int id, const char* name, int x, int y, int w, int h, int* scroll);
|
||||
void imguiEndScrollArea();
|
||||
|
||||
void imguiIndent();
|
||||
void imguiUnindent();
|
||||
void imguiSeparator();
|
||||
|
||||
bool imguiButton(unsigned int id, const char* text);
|
||||
bool imguiItem(unsigned int id, const char* text);
|
||||
bool imguiCheck(unsigned int id, const char* text, bool checked);
|
||||
bool imguiCollapse(unsigned int id, const char* text, bool checked);
|
||||
void imguiLabel(unsigned int id, const char* text);
|
||||
void imguiValue(unsigned int id, const char* text);
|
||||
bool imguiSlider(unsigned int id, const char* text, float* val, float vmin, float vmax, float vinc);
|
||||
|
||||
|
||||
#endif // IMGUI_H
|
390
Recast/Include/Recast.h
Normal file
390
Recast/Include/Recast.h
Normal file
@ -0,0 +1,390 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef RECAST_H
|
||||
#define RECAST_H
|
||||
|
||||
struct rcConfig
|
||||
{
|
||||
int width, height; // Dimensions of the rasterized heighfield
|
||||
float cs, ch; // Grid cell size and height.
|
||||
float bmin[3], bmax[3]; // Grid bounds.
|
||||
float walkableSlopeAngle; // Maximum walkble slope angle in degrees.
|
||||
int walkableHeight; // Minimum height where the agent can still walk.
|
||||
int walkableClimb; // Maximum height between grid cells the agent can climb.
|
||||
int walkableRadius; // Radius of the agent in cells.
|
||||
int maxEdgeLen; // Maximum contour edge length in cells.
|
||||
float maxSimplificationError; // Maximum distance error from contour to cells.
|
||||
int minRegionSize; // Minimum regions size. Smaller regions will be deleted.
|
||||
int mergeRegionSize; // Minimum regions size. Smaller regions will be merged.
|
||||
int maxVertsPerPoly; // Max number of vertices per polygon.
|
||||
};
|
||||
|
||||
struct rcSpan
|
||||
{
|
||||
unsigned int smin : 15; // Span min height.
|
||||
unsigned int smax : 15; // Span max height.
|
||||
unsigned int flags : 2; // Span flags.
|
||||
rcSpan* next;
|
||||
};
|
||||
|
||||
struct rcSpanPool
|
||||
{
|
||||
rcSpanPool* next;
|
||||
rcSpan items[1];
|
||||
};
|
||||
|
||||
struct rcHeightfield
|
||||
{
|
||||
inline rcHeightfield() : width(0), height(0), spans(0), pools(0), freelist(0) {}
|
||||
inline ~rcHeightfield()
|
||||
{
|
||||
delete [] spans;
|
||||
while (pools)
|
||||
{
|
||||
rcSpanPool* next = pools->next;
|
||||
delete [] reinterpret_cast<unsigned char*>(pools);
|
||||
pools = next;
|
||||
}
|
||||
}
|
||||
int width, height;
|
||||
rcSpan** spans;
|
||||
rcSpanPool* pools;
|
||||
rcSpan* freelist;
|
||||
};
|
||||
|
||||
struct rcCompactCell
|
||||
{
|
||||
unsigned int index : 24;
|
||||
unsigned int count : 8;
|
||||
};
|
||||
|
||||
struct rcCompactSpan
|
||||
{
|
||||
unsigned short y;
|
||||
unsigned short reg;
|
||||
unsigned short dist;
|
||||
unsigned short con;
|
||||
unsigned char h;
|
||||
unsigned char flags;
|
||||
};
|
||||
|
||||
struct rcCompactHeightfield
|
||||
{
|
||||
inline rcCompactHeightfield() : cells(0), spans(0), maxDistance(0), maxRegions(0) {}
|
||||
inline ~rcCompactHeightfield() { delete [] cells; delete [] spans; }
|
||||
int width, height;
|
||||
int spanCount;
|
||||
int walkableHeight, walkableClimb;
|
||||
unsigned short maxDistance;
|
||||
unsigned short maxRegions;
|
||||
float minx, miny, minz;
|
||||
float maxx, maxy, maxz;
|
||||
float cs, ch;
|
||||
rcCompactCell* cells;
|
||||
rcCompactSpan* spans;
|
||||
};
|
||||
|
||||
struct rcContour
|
||||
{
|
||||
inline rcContour() : verts(0), nverts(0), rverts(0), nrverts(0), cx(0), cy(0), cz(0) { }
|
||||
inline ~rcContour() { delete [] verts; delete [] rverts; }
|
||||
int* verts;
|
||||
int nverts;
|
||||
int* rverts;
|
||||
int nrverts;
|
||||
int cx,cy,cz;
|
||||
unsigned short reg;
|
||||
};
|
||||
|
||||
struct rcContourSet
|
||||
{
|
||||
inline rcContourSet() : conts(0), nconts(0) {}
|
||||
inline ~rcContourSet() { delete [] conts; }
|
||||
rcContour* conts;
|
||||
int nconts;
|
||||
};
|
||||
|
||||
struct rcPolyMesh
|
||||
{
|
||||
inline rcPolyMesh() : verts(0), polys(0), nverts(0), npolys(0), nvp(3) {}
|
||||
inline ~rcPolyMesh() { delete [] verts; delete [] polys; }
|
||||
unsigned short* verts;
|
||||
unsigned short* polys;
|
||||
int nverts;
|
||||
int npolys;
|
||||
int nvp;
|
||||
};
|
||||
|
||||
class rcIntArray
|
||||
{
|
||||
int* m_data;
|
||||
int m_size, m_cap;
|
||||
public:
|
||||
inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
|
||||
inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(n) { m_data = new int[n]; }
|
||||
inline ~rcIntArray() { delete [] m_data; }
|
||||
void resize(int n);
|
||||
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||
inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
|
||||
inline const int& operator[](int i) const { return m_data[i]; }
|
||||
inline int& operator[](int i) { return m_data[i]; }
|
||||
inline int size() const { return m_size; }
|
||||
};
|
||||
|
||||
enum rcSpanFlags
|
||||
{
|
||||
RC_WALKABLE = 0x01,
|
||||
RC_REACHABLE = 0x02,
|
||||
};
|
||||
|
||||
// Comppact span neighbour helpers.
|
||||
inline int rcGetCon(const rcCompactSpan& s, int dir)
|
||||
{
|
||||
return (s.con >> (dir*4)) & 0xf;
|
||||
}
|
||||
|
||||
inline int rcGetDirOffsetX(int dir)
|
||||
{
|
||||
const int offset[4] = { -1, 0, 1, 0, };
|
||||
return offset[dir&0x03];
|
||||
}
|
||||
|
||||
inline int rcGetDirOffsetY(int dir)
|
||||
{
|
||||
const int offset[4] = { 0, 1, 0, -1 };
|
||||
return offset[dir&0x03];
|
||||
}
|
||||
|
||||
// Common helper functions
|
||||
template<class T> inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
template<class T> inline T rcMin(T a, T b) { return a < b ? a : b; }
|
||||
template<class T> inline T rcMax(T a, T b) { return a > b ? a : b; }
|
||||
template<class T> inline T rcAbs(T a) { return a < 0 ? -a : a; }
|
||||
template<class T> inline T rcSqr(T a) { return a*a; }
|
||||
template<class T> inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
||||
|
||||
// Common vector helper functions.
|
||||
inline void vcross(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
inline float vdot(const float* v1, const float* v2)
|
||||
{
|
||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||
}
|
||||
|
||||
inline void vsub(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[0]-v2[0];
|
||||
dest[1] = v1[1]-v2[1];
|
||||
dest[2] = v1[2]-v2[2];
|
||||
}
|
||||
|
||||
inline void vmin(float* mn, const float* v)
|
||||
{
|
||||
mn[0] = rcMin(mn[0], v[0]);
|
||||
mn[1] = rcMin(mn[1], v[1]);
|
||||
mn[2] = rcMin(mn[2], v[2]);
|
||||
}
|
||||
|
||||
inline void vmax(float* mx, const float* v)
|
||||
{
|
||||
mx[0] = rcMax(mx[0], v[0]);
|
||||
mx[1] = rcMax(mx[1], v[1]);
|
||||
mx[2] = rcMax(mx[2], v[2]);
|
||||
}
|
||||
|
||||
inline void vcopy(float* dest, const float* v)
|
||||
{
|
||||
dest[0] = v[0];
|
||||
dest[1] = v[1];
|
||||
dest[2] = v[2];
|
||||
}
|
||||
|
||||
inline float vdistSqr(const float* v1, const float* v2)
|
||||
{
|
||||
float dx = v2[0] - v1[0];
|
||||
float dy = v2[1] - v1[1];
|
||||
float dz = v2[2] - v1[2];
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
inline void vnormalize(float* v)
|
||||
{
|
||||
float d = 1.0f / sqrtf(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2]));
|
||||
v[0] *= d;
|
||||
v[1] *= d;
|
||||
v[2] *= d;
|
||||
}
|
||||
|
||||
inline bool vequal(const float* p0, const float* p1)
|
||||
{
|
||||
static const float thr = rcSqr(1.0f/16384.0f);
|
||||
const float d = vdistSqr(p0, p1);
|
||||
return d < thr;
|
||||
}
|
||||
|
||||
|
||||
// Calculated bounding box of array of vertices.
|
||||
// Params:
|
||||
// verts - (in) array of vertices
|
||||
// nv - (in) vertex count
|
||||
// bmin, bmax - (out) bounding box
|
||||
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax);
|
||||
|
||||
// Calculates grid size based on bounding box and grid cell size.
|
||||
// Params:
|
||||
// bmin, bmax - (in) bounding box
|
||||
// cs - (in) grid cell size
|
||||
// w - (out) grid width
|
||||
// h - (out) grid height
|
||||
void rcCalcGridSize(float* bmin, float* bmax, float cs, int* w, int* h);
|
||||
|
||||
// Creates and initializes new heightfield.
|
||||
// Params:
|
||||
// hf - (in/out) heightfield to initialize.
|
||||
// width - (in) width of the heightfield.
|
||||
// height - (in) height of the heightfield.
|
||||
bool rcCreateHeightfield(rcHeightfield& hf, int width, int height);
|
||||
|
||||
// Sets the WALKABLE flag for every triangle whose slope is below
|
||||
// the maximun walkable slope angle.
|
||||
// Params:
|
||||
// walkableSlopeAngle - (in) maximun slope angle in degrees.
|
||||
// tris - (in) array of triangle vertex indices
|
||||
// norms - (in) array of triangle normals
|
||||
// nt - (in) triangle count
|
||||
// flags - (out) array of triangle flags
|
||||
void rcMarkWalkableTriangles(const float walkableSlopeAngle,
|
||||
const int* tris, const float* norms, int nt,
|
||||
unsigned char* flags);
|
||||
|
||||
// Rasterizes the triangles into heightfield spans.
|
||||
// Params:
|
||||
// bmin, bmax - (in) bounding box of the heightfield
|
||||
// cs - (in) grid cell size
|
||||
// ch - (in) grid cell height
|
||||
// verts - (in) array of vertices
|
||||
// nv - (in) vertex count
|
||||
// tris - (in) array of triangle vertex indices
|
||||
// norms - (in) array of triangle normals
|
||||
// flags - (in) array of triangle flags (uses WALKABLE)
|
||||
// nt - (in) triangle count
|
||||
// solid - (in) heighfield where the triangles are rasterized
|
||||
void rcRasterizeTriangles(const float* bmin, const float* bmax,
|
||||
float cs, float ch,
|
||||
const float* verts, int nv,
|
||||
const int* tris, const unsigned char* flags, int nt,
|
||||
rcHeightfield& solid);
|
||||
|
||||
void rcFilterWalkableBorderSpans(const int walkableHeight,
|
||||
const int walkableClimb,
|
||||
rcHeightfield& solid);
|
||||
|
||||
// Removes WALKABLE flag from all spans which have smaller than
|
||||
// 'walkableHeight' clearane above them.
|
||||
// Params:
|
||||
// walkableHeight - (in) minimum height where the agent can still walk
|
||||
// solid - (in/out) heightfield describing the solid space
|
||||
void rcFilterWalkableLowHeightSpans(int walkableHeight,
|
||||
rcHeightfield& solid);
|
||||
|
||||
// Marks spans which are reachable from any of the topmost spans.
|
||||
// Params:
|
||||
// walkableHeight - (in) minimum height where the agent can still walk
|
||||
// walkableClimb - (in) maximum height between grid cells the agent can climb
|
||||
// solid - (in/out) heightfield describing the solid space
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcMarkReachableSpans(const int walkableHeight,
|
||||
const int walkableClimb,
|
||||
rcHeightfield& solid);
|
||||
|
||||
// Builds compact representation of the heightfield.
|
||||
// Params:
|
||||
// bmin, bmax - (in) bounding box of the heightfield
|
||||
// cs - (in) grid cell size
|
||||
// ch - (in) grid cell height
|
||||
// walkableHeight - (in) minimum height where the agent can still walk
|
||||
// walkableClimb - (in) maximum height between grid cells the agent can climb
|
||||
// hf - (in) heightfield to be compacted
|
||||
// chf - (out) compact heightfield representing the open space.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildCompactHeightfield(const float* bmin, const float* bmax,
|
||||
const float cs, const float ch,
|
||||
const int walkableHeight, const int walkableClimb,
|
||||
unsigned char flags,
|
||||
rcHeightfield& hf,
|
||||
rcCompactHeightfield& chf);
|
||||
|
||||
// Builds distance field and stores it into the combat heightfield.
|
||||
// Params:
|
||||
// chf - (in/out) compact heightfield representing the open space.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildDistanceField(rcCompactHeightfield& chf);
|
||||
|
||||
// Divides the walkable heighfied into simple regions.
|
||||
// Each region has only one contour and no overlaps.
|
||||
// The regions are stored in the compact heightfield 'reg' field.
|
||||
// The regions will be shrinked by the radius of the agent.
|
||||
// The process sometimes creates small regions. The parameter
|
||||
// 'minRegionSize' specifies the smallest allowed regions size.
|
||||
// If the area of a regions is smaller than allowed, the regions is
|
||||
// removed or merged to neighbour region.
|
||||
// Params:
|
||||
// chf - (in/out) compact heightfield representing the open space.
|
||||
// walkableRadius - (in) the radius of the agent.
|
||||
// minRegionSize - (in) the smallest allowed regions size.
|
||||
// maxMergeRegionSize - (in) the largest allowed regions size which can be merged.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
int walkableRadius, int minRegionSize, int mergeRegionSize);
|
||||
|
||||
// Builds simplified contours from the regions outlines.
|
||||
// Params:
|
||||
// chf - (in) compact heightfield which has regions set.
|
||||
// maxError - (in) maximum allowed distance between simplified countour and cells.
|
||||
// maxEdgeLen - (in) maximum allowed contour edge length in cells.
|
||||
// cset - (out) Resulting contour set.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
float maxError, int maxEdgeLen,
|
||||
rcContourSet& cset);
|
||||
|
||||
// Builds connected convex polygon mesh from contour polygons.
|
||||
// Params:
|
||||
// cset - (in) contour set.
|
||||
// mesh - (out) poly mesh.
|
||||
// nvp - (int) maximum number of vertices per polygon.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildPolyMesh(rcContourSet& cset, rcPolyMesh& mesh, int nvp);
|
||||
|
||||
|
||||
bool rcBuildNavMesh(const rcConfig& cfg,
|
||||
const float* verts, const int nverts,
|
||||
const int* tris, const unsigned char* tflags, const int ntris,
|
||||
rcHeightfield& solid,
|
||||
rcCompactHeightfield& chf,
|
||||
rcContourSet& cset,
|
||||
rcPolyMesh& polyMesh);
|
||||
|
||||
|
||||
#endif // RECAST_H
|
59
Recast/Include/RecastDebugDraw.h
Normal file
59
Recast/Include/RecastDebugDraw.h
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef RECAST_DEBUGDRAW_H
|
||||
#define RECAST_DEBUGDRAW_H
|
||||
|
||||
inline int bit(int a, int b)
|
||||
{
|
||||
return (a & (1 << b)) >> b;
|
||||
}
|
||||
|
||||
inline void intToCol(int i, float* col)
|
||||
{
|
||||
int r = bit(i, 0) + bit(i, 3) * 2 + 1;
|
||||
int g = bit(i, 1) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 2) + bit(i, 5) * 2 + 1;
|
||||
col[0] = 1 - r*63.0f/255.0f;
|
||||
col[1] = 1 - g*63.0f/255.0f;
|
||||
col[2] = 1 - b*63.0f/255.0f;
|
||||
}
|
||||
|
||||
void rcDebugDrawHeightfieldSolid(const struct rcHeightfield& hf,
|
||||
const float* orig, float cs, float ch);
|
||||
|
||||
void rcDebugDrawHeightfieldWalkable(const struct rcHeightfield& hf,
|
||||
const float* orig, float cs, float ch);
|
||||
|
||||
void rcDebugDrawMesh(const class rcMeshLoaderObj& mesh, const unsigned char* flags);
|
||||
|
||||
void rcDebugDrawCompactHeightfieldSolid(const struct rcCompactHeightfield& chf);
|
||||
void rcDebugDrawCompactHeightfieldRegions(const struct rcCompactHeightfield& chf);
|
||||
void rcDebugDrawCompactHeightfieldDistance(const struct rcCompactHeightfield& chf);
|
||||
|
||||
void rcDebugDrawRawContours(const struct rcContourSet& cset, const float* orig, float cs, float ch);
|
||||
void rcDebugDrawContours(const struct rcContourSet& cset, const float* orig, float cs, float ch);
|
||||
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh, const float* orig, float cs, float ch);
|
||||
|
||||
void rcDebugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col);
|
||||
void rcDebugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col);
|
||||
void rcDebugDrawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz,
|
||||
const float* col1, const float* col2);
|
||||
|
||||
|
||||
#endif // RECAST_DEBUGDRAW_H
|
53
Recast/Include/RecastLog.h
Normal file
53
Recast/Include/RecastLog.h
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef RECAST_LOG_H
|
||||
#define RECAST_LOG_H
|
||||
|
||||
enum rcLogCategory
|
||||
{
|
||||
RC_LOG_PROGRESS = 1,
|
||||
RC_LOG_WARNING,
|
||||
RC_LOG_ERROR,
|
||||
};
|
||||
|
||||
class rcLog
|
||||
{
|
||||
public:
|
||||
rcLog();
|
||||
~rcLog();
|
||||
|
||||
void log(rcLogCategory category, const char* format, ...);
|
||||
inline void clear() { m_messageCount = 0; m_textPoolSize = 0; }
|
||||
inline int getMessageCount() const { return m_messageCount; }
|
||||
inline char getMessageType(int i) const { return *m_messages[i]; }
|
||||
inline const char* getMessageText(int i) const { return m_messages[i]+1; }
|
||||
|
||||
private:
|
||||
static const int MAX_MESSAGES = 1000;
|
||||
const char* m_messages[MAX_MESSAGES];
|
||||
int m_messageCount;
|
||||
static const int TEXT_POOL_SIZE = 8000;
|
||||
char m_textPool[TEXT_POOL_SIZE];
|
||||
int m_textPoolSize;
|
||||
};
|
||||
|
||||
void rcSetLog(rcLog* log);
|
||||
rcLog* rcGetLog();
|
||||
|
||||
#endif // RECAST_LOG_H
|
38
Recast/Include/RecastTimer.h
Normal file
38
Recast/Include/RecastTimer.h
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
#ifndef RECAST_TIMER_H
|
||||
#define RECAST_TIMER_H
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
//#include <stdint.h>
|
||||
typedef __int64 rcTimeVal;
|
||||
rcTimeVal rcGetPerformanceTimer();
|
||||
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end);
|
||||
|
||||
#else
|
||||
|
||||
// OSX
|
||||
#include <stdint.h>
|
||||
typedef uint64_t rcTimeVal;
|
||||
rcTimeVal rcGetPerformanceTimer();
|
||||
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // RECAST_TIMER_H
|
18
Recast/License.txt
Normal file
18
Recast/License.txt
Normal file
@ -0,0 +1,18 @@
|
||||
Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
13
Recast/Readme.txt
Normal file
13
Recast/Readme.txt
Normal file
@ -0,0 +1,13 @@
|
||||
Detour Version 1.0
|
||||
|
||||
Welcome to Detour!
|
||||
|
||||
Detour is a navigation system for games. The system comes with two parts: 1) Automatic preprocess which generates navmesh automatically from a polygon soup and, 2) runtime library which allows to do spatic queries and pathfinding on the navmesh.
|
||||
|
||||
The project files with this distribution with with Microsoft Visual C++ 2008 (you can download it for free) and XCode 3.1.
|
||||
|
||||
You can find examples how to use the preprocess and runtime on the Examples directory.
|
||||
|
||||
|
||||
Mikko Mononen
|
||||
memon@inside.org
|
302
Recast/Source/Recast.cpp
Normal file
302
Recast/Source/Recast.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include <float.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastTimer.h"
|
||||
|
||||
|
||||
void rcIntArray::resize(int n)
|
||||
{
|
||||
if (n > m_cap)
|
||||
{
|
||||
if (!m_cap) m_cap = 8;
|
||||
while (m_cap < n) m_cap *= 2;
|
||||
int* newData = new int[m_cap];
|
||||
if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
|
||||
delete [] m_data;
|
||||
m_data = newData;
|
||||
}
|
||||
m_size = n;
|
||||
}
|
||||
|
||||
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
|
||||
{
|
||||
// Calculate bounding box.
|
||||
vcopy(bmin, verts);
|
||||
vcopy(bmax, verts);
|
||||
for (int i = 1; i < nv; ++i)
|
||||
{
|
||||
const float* v = &verts[i*3];
|
||||
vmin(bmin, v);
|
||||
vmax(bmax, v);
|
||||
}
|
||||
}
|
||||
|
||||
void rcCalcGridSize(float* bmin, float* bmax, float cs, int* w, int* h)
|
||||
{
|
||||
*w = (int)((bmax[0] - bmin[0])/cs+0.5f);
|
||||
*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
|
||||
}
|
||||
|
||||
bool rcCreateHeightfield(rcHeightfield& hf, int width, int height)
|
||||
{
|
||||
hf.width = width;
|
||||
hf.height = height;
|
||||
hf.spans = new rcSpan*[hf.width*hf.height];
|
||||
if (!hf.spans)
|
||||
return false;
|
||||
memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
void rcMarkWalkableTriangles(const float walkableSlopeAngle,
|
||||
const int* tris, const float* norms, int nt,
|
||||
unsigned char* flags)
|
||||
{
|
||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI);
|
||||
|
||||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
// Check if the face is walkable.
|
||||
if (norms[i*3+1] > walkableThr)
|
||||
flags[i] |= RC_WALKABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static int getSpanCount(unsigned char flags, rcHeightfield& hf)
|
||||
{
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
int spanCount = 0;
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
|
||||
{
|
||||
if (s->flags == flags)
|
||||
spanCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spanCount;
|
||||
}
|
||||
|
||||
inline void setCon(rcCompactSpan& s, int dir, int i)
|
||||
{
|
||||
s.con &= ~(0xf << (dir*4));
|
||||
s.con |= (i&0xf) << (dir*4);
|
||||
}
|
||||
|
||||
bool rcBuildCompactHeightfield(const float* bmin, const float* bmax,
|
||||
const float cs, const float ch,
|
||||
const int walkableHeight, const int walkableClimb,
|
||||
unsigned char flags, rcHeightfield& hf,
|
||||
rcCompactHeightfield& chf)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
const int spanCount = getSpanCount(flags, hf);
|
||||
|
||||
// Fill in header.
|
||||
chf.width = w;
|
||||
chf.height = h;
|
||||
chf.spanCount = spanCount;
|
||||
chf.walkableHeight = walkableHeight;
|
||||
chf.walkableClimb = walkableClimb;
|
||||
chf.maxRegions = 0;
|
||||
chf.minx = bmin[0];
|
||||
chf.miny = bmin[1];
|
||||
chf.minz = bmin[2];
|
||||
chf.maxx = bmax[0];
|
||||
chf.maxy = bmax[1] + walkableHeight*ch;
|
||||
chf.maxz = bmax[2];
|
||||
chf.cs = cs;
|
||||
chf.ch = ch;
|
||||
chf.cells = new rcCompactCell[w*h];
|
||||
if (!chf.cells)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
|
||||
return false;
|
||||
}
|
||||
memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
|
||||
chf.spans = new rcCompactSpan[spanCount];
|
||||
if (!chf.spans)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
|
||||
return false;
|
||||
}
|
||||
memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
|
||||
|
||||
const int MAX_HEIGHT = 0xffff;
|
||||
|
||||
// Fill in cells and spans.
|
||||
int idx = 0;
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcSpan* s = hf.spans[x + y*w];
|
||||
// If there are no spans at this cell, just leave the data to index=0, count=0.
|
||||
if (!s) continue;
|
||||
rcCompactCell& c = chf.cells[x+y*w];
|
||||
c.index = idx;
|
||||
c.count = 0;
|
||||
while (s)
|
||||
{
|
||||
if (s->flags == flags)
|
||||
{
|
||||
const int bot = (int)s->smax;
|
||||
const int top = (int)s->next ? (int)s->next->smin : MAX_HEIGHT;
|
||||
chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
|
||||
chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
|
||||
idx++;
|
||||
c.count++;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find neighbour connections.
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
rcCompactSpan& s = chf.spans[i];
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
setCon(s, dir, 0xf);
|
||||
const int nx = x + rcGetDirOffsetX(dir);
|
||||
const int ny = y + rcGetDirOffsetY(dir);
|
||||
// First check that the neighbour cell is in bounds.
|
||||
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
|
||||
continue;
|
||||
// Iterate over all neighbour spans and check if any of the is
|
||||
// accessible from current cell.
|
||||
const rcCompactCell& nc = chf.cells[nx+ny*w];
|
||||
for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
|
||||
{
|
||||
const rcCompactSpan& ns = chf.spans[k];
|
||||
const int bot = rcMax(s.y, ns.y);
|
||||
const int top = rcMin(s.y+s.h, ns.y+ns.h);
|
||||
|
||||
// Check that the gap between the spans is walkable,
|
||||
// and that the climb height between the gaps is not too high.
|
||||
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
|
||||
{
|
||||
// Mark direction as walkable.
|
||||
setCon(s, dir, k - (int)nc.index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Build compact: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rcBuildNavMesh(const rcConfig& cfg,
|
||||
const float* verts, const int nverts,
|
||||
const int* tris, const unsigned char* tflags, const int ntris,
|
||||
rcHeightfield& solid,
|
||||
rcCompactHeightfield& chf,
|
||||
rcContourSet& cset,
|
||||
rcPolyMesh& polyMesh)
|
||||
{
|
||||
if (!rcCreateHeightfield(solid, cfg.width, cfg.height))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not create solid heightfield.");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcRasterizeTriangles(cfg.bmin, cfg.bmax, cfg.cs, cfg.ch,
|
||||
verts, nverts, tris, tflags, ntris, solid);
|
||||
|
||||
rcFilterWalkableBorderSpans(cfg.walkableHeight, cfg.walkableClimb, solid);
|
||||
|
||||
rcFilterWalkableLowHeightSpans(cfg.walkableHeight, solid);
|
||||
|
||||
if (!rcMarkReachableSpans(cfg.walkableHeight, cfg.walkableClimb, solid))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build navigable heightfield.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rcBuildCompactHeightfield(cfg.bmin, cfg.bmax, cfg.cs, cfg.ch,
|
||||
cfg.walkableHeight, cfg.walkableClimb,
|
||||
RC_WALKABLE|RC_REACHABLE, solid, chf))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build compact data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rcBuildDistanceField(chf))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build distance fields.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rcBuildRegions(chf, cfg.walkableRadius, cfg.minRegionSize, cfg.mergeRegionSize))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build regions.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rcBuildContours(chf, cfg.maxSimplificationError, cfg.maxEdgeLen, cset))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not create contours.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rcBuildPolyMesh(cset, polyMesh, cfg.maxVertsPerPoly))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not triangulate contours.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
665
Recast/Source/RecastContour.cpp
Normal file
665
Recast/Source/RecastContour.cpp
Normal file
@ -0,0 +1,665 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastTimer.h"
|
||||
|
||||
|
||||
static int getCornerHeight(int x, int y, int i, int dir,
|
||||
const rcCompactHeightfield& chf)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
int ch = (int)s.y;
|
||||
int dirp = (dir+1) & 0x3;
|
||||
if (rcGetCon(s, dir) != 0xf)
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
ch = rcMax(ch, (int)as.y);
|
||||
if (rcGetCon(as, dirp) != 0xf)
|
||||
{
|
||||
const int ax2 = ax + rcGetDirOffsetX(dirp);
|
||||
const int ay2 = ay + rcGetDirOffsetY(dirp);
|
||||
const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dirp);
|
||||
const rcCompactSpan& as2 = chf.spans[ai2];
|
||||
ch = rcMax(ch, (int)as2.y);
|
||||
}
|
||||
}
|
||||
if (rcGetCon(s, dirp) != 0xf)
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dirp);
|
||||
const int ay = y + rcGetDirOffsetY(dirp);
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dirp);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
ch = rcMax(ch, (int)as.y);
|
||||
if (rcGetCon(as, dir) != 0xf)
|
||||
{
|
||||
const int ax2 = ax + rcGetDirOffsetX(dir);
|
||||
const int ay2 = ay + rcGetDirOffsetY(dir);
|
||||
const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dir);
|
||||
const rcCompactSpan& as2 = chf.spans[ai2];
|
||||
ch = rcMax(ch, (int)as2.y);
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void walkContour(int x, int y, int i,
|
||||
rcCompactHeightfield& chf,
|
||||
unsigned char* flags, rcIntArray& points)
|
||||
{
|
||||
// Choose the first non-connected edge
|
||||
unsigned char dir = 0;
|
||||
while ((flags[i] & (1 << dir)) == 0)
|
||||
dir++;
|
||||
|
||||
unsigned char startDir = dir;
|
||||
int starti = i;
|
||||
|
||||
int iter = 0;
|
||||
while (++iter < 40000)
|
||||
{
|
||||
if (flags[i] & (1 << dir))
|
||||
{
|
||||
// Choose the edge corner
|
||||
int px = x;
|
||||
int py = getCornerHeight(x, y, i, dir, chf);
|
||||
int pz = y;
|
||||
switch(dir)
|
||||
{
|
||||
case 0: pz++; break;
|
||||
case 1: px++; pz++; break;
|
||||
case 2: px++; break;
|
||||
}
|
||||
int r = 0;
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (rcGetCon(s, dir) != 0xf)
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
r = (int)as.reg;
|
||||
}
|
||||
|
||||
points.push(px);
|
||||
points.push(py);
|
||||
points.push(pz);
|
||||
points.push(r);
|
||||
|
||||
flags[i] &= ~(1 << dir); // Remove visited edges
|
||||
dir = (dir+1) & 0x3; // Rotate CW
|
||||
}
|
||||
else
|
||||
{
|
||||
int ni = -1;
|
||||
const int nx = x + rcGetDirOffsetX(dir);
|
||||
const int ny = y + rcGetDirOffsetY(dir);
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (rcGetCon(s, dir) != 0xf)
|
||||
{
|
||||
const rcCompactCell& nc = chf.cells[nx+ny*chf.width];
|
||||
ni = (int)nc.index + rcGetCon(s, dir);
|
||||
}
|
||||
if (ni == -1)
|
||||
{
|
||||
// Should not happen.
|
||||
return;
|
||||
}
|
||||
x = nx;
|
||||
y = ny;
|
||||
i = ni;
|
||||
dir = (dir+3) & 0x3; // Rotate CCW
|
||||
}
|
||||
|
||||
if (starti == i && startDir == dir)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float distancePtSeg(int x, int y, int z,
|
||||
int px, int py, int pz,
|
||||
int qx, int qy, int qz)
|
||||
{
|
||||
float pqx = (float)(qx - px);
|
||||
float pqy = (float)(qy - py);
|
||||
float pqz = (float)(qz - pz);
|
||||
float dx = (float)(x - px);
|
||||
float dy = (float)(y - py);
|
||||
float dz = (float)(z - pz);
|
||||
float d = pqx*pqx + pqy*pqy + pqz*pqz;
|
||||
float t = pqx*dx + pqy*dy + pqz*dz;
|
||||
if (d > 0)
|
||||
t /= d;
|
||||
if (t < 0)
|
||||
t = 0;
|
||||
else if (t > 1)
|
||||
t = 1;
|
||||
|
||||
dx = px + t*pqx - x;
|
||||
dy = py + t*pqy - y;
|
||||
dz = pz + t*pqz - z;
|
||||
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float maxError, int maxEdgeLen)
|
||||
{
|
||||
// Add initial points.
|
||||
bool noConnections = true;
|
||||
for (int i = 0; i < points.size(); i += 4)
|
||||
{
|
||||
if (points[i+3] != 0)
|
||||
{
|
||||
noConnections = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (noConnections)
|
||||
{
|
||||
// If there is no connections at all,
|
||||
// create some initial points for the simplification process.
|
||||
// Find lower-left and upper-right vertices of the contour.
|
||||
int llx = points[0];
|
||||
int lly = points[1];
|
||||
int llz = points[2];
|
||||
int lli = 0;
|
||||
int urx = points[0];
|
||||
int ury = points[1];
|
||||
int urz = points[2];
|
||||
int uri = 0;
|
||||
for (int i = 0; i < points.size(); i += 4)
|
||||
{
|
||||
int x = points[i+0];
|
||||
int y = points[i+1];
|
||||
int z = points[i+2];
|
||||
if (x < llx || (x == llx && z < llz))
|
||||
{
|
||||
llx = x;
|
||||
lly = y;
|
||||
llz = z;
|
||||
lli = i/4;
|
||||
}
|
||||
if (x >= urx || (x == urx && z > urz))
|
||||
{
|
||||
urx = x;
|
||||
ury = y;
|
||||
urz = z;
|
||||
uri = i/4;
|
||||
}
|
||||
}
|
||||
simplified.push(llx);
|
||||
simplified.push(lly);
|
||||
simplified.push(llz);
|
||||
simplified.push(lli);
|
||||
|
||||
simplified.push(urx);
|
||||
simplified.push(ury);
|
||||
simplified.push(urz);
|
||||
simplified.push(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The contour has some portals to other regions.
|
||||
// Add a new point to every location where the region changes.
|
||||
for (int i = 0, ni = points.size()/4; i < ni; ++i)
|
||||
{
|
||||
int ii = (i+1) % ni;
|
||||
if (points[i*4+3] != points[ii*4+3])
|
||||
{
|
||||
simplified.push(points[i*4+0]);
|
||||
simplified.push(points[i*4+1]);
|
||||
simplified.push(points[i*4+2]);
|
||||
simplified.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add points until all raw points are within
|
||||
// error tolerance to the simplified shape.
|
||||
const int pn = points.size()/4;
|
||||
for (int i = 0; i < simplified.size()/4; )
|
||||
{
|
||||
int ii = (i+1) % (simplified.size()/4);
|
||||
|
||||
int ax = simplified[i*4+0];
|
||||
int ay = simplified[i*4+1];
|
||||
int az = simplified[i*4+2];
|
||||
int ai = simplified[i*4+3];
|
||||
|
||||
int bx = simplified[ii*4+0];
|
||||
int by = simplified[ii*4+1];
|
||||
int bz = simplified[ii*4+2];
|
||||
int bi = simplified[ii*4+3];
|
||||
|
||||
// Find maximum deviation from the segment.
|
||||
float maxd = 0;
|
||||
int maxi = -1;
|
||||
int ci = (ai+1) % pn;
|
||||
|
||||
// Tesselate only outer edges.
|
||||
if (points[ci*4+3] == 0)
|
||||
{
|
||||
while (ci != bi)
|
||||
{
|
||||
float d = distancePtSeg(points[ci*4+0], points[ci*4+1]/4, points[ci*4+2],
|
||||
ax, ay/4, az, bx, by/4, bz);
|
||||
if (d > maxd)
|
||||
{
|
||||
maxd = d;
|
||||
maxi = ci;
|
||||
}
|
||||
ci = (ci+1) % pn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the max deviation is larger than accepted error,
|
||||
// add new point, else continue to next segment.
|
||||
if (maxi != -1 && maxd > (maxError*maxError))
|
||||
{
|
||||
// Add space for the new point.
|
||||
simplified.resize(simplified.size()+4);
|
||||
int n = simplified.size()/4;
|
||||
for (int j = n-1; j > i; --j)
|
||||
{
|
||||
simplified[j*4+0] = simplified[(j-1)*4+0];
|
||||
simplified[j*4+1] = simplified[(j-1)*4+1];
|
||||
simplified[j*4+2] = simplified[(j-1)*4+2];
|
||||
simplified[j*4+3] = simplified[(j-1)*4+3];
|
||||
}
|
||||
// Add the point.
|
||||
simplified[(i+1)*4+0] = points[maxi*4+0];
|
||||
simplified[(i+1)*4+1] = points[maxi*4+1];
|
||||
simplified[(i+1)*4+2] = points[maxi*4+2];
|
||||
simplified[(i+1)*4+3] = maxi;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Split too long edges.
|
||||
if (maxEdgeLen > 0)
|
||||
{
|
||||
for (int i = 0; i < simplified.size()/4; )
|
||||
{
|
||||
int ii = (i+1) % (simplified.size()/4);
|
||||
|
||||
int ax = simplified[i*4+0];
|
||||
int az = simplified[i*4+2];
|
||||
int ai = simplified[i*4+3];
|
||||
|
||||
int bx = simplified[ii*4+0];
|
||||
int bz = simplified[ii*4+2];
|
||||
int bi = simplified[ii*4+3];
|
||||
|
||||
// Find maximum deviation from the segment.
|
||||
int maxi = -1;
|
||||
int ci = (ai+1) % pn;
|
||||
|
||||
// Tesselate only outer edges.
|
||||
if (points[ci*4+3] == 0)
|
||||
{
|
||||
int dx = bx - ax;
|
||||
int dz = bz - az;
|
||||
if (dx*dx + dz*dz > maxEdgeLen*maxEdgeLen)
|
||||
{
|
||||
int n = bi < ai ? (bi+pn - ai) : (bi - ai);
|
||||
maxi = (ai + n/2) % pn;
|
||||
}
|
||||
}
|
||||
|
||||
// If the max deviation is larger than accepted error,
|
||||
// add new point, else continue to next segment.
|
||||
if (maxi != -1)
|
||||
{
|
||||
// Add space for the new point.
|
||||
simplified.resize(simplified.size()+4);
|
||||
int n = simplified.size()/4;
|
||||
for (int j = n-1; j > i; --j)
|
||||
{
|
||||
simplified[j*4+0] = simplified[(j-1)*4+0];
|
||||
simplified[j*4+1] = simplified[(j-1)*4+1];
|
||||
simplified[j*4+2] = simplified[(j-1)*4+2];
|
||||
simplified[j*4+3] = simplified[(j-1)*4+3];
|
||||
}
|
||||
// Add the point.
|
||||
simplified[(i+1)*4+0] = points[maxi*4+0];
|
||||
simplified[(i+1)*4+1] = points[maxi*4+1];
|
||||
simplified[(i+1)*4+2] = points[maxi*4+2];
|
||||
simplified[(i+1)*4+3] = maxi;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < simplified.size()/4; ++i)
|
||||
{
|
||||
int ai = (simplified[i*4+3]+1) % pn;
|
||||
simplified[i*4+3] = points[ai*4+3];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void removeDegenerateSegments(rcIntArray& simplified)
|
||||
{
|
||||
// Remove adjacent vertices which are equal on xz-plane,
|
||||
// or else the triangulator will get confused.
|
||||
for (int i = 0; i < simplified.size()/4; ++i)
|
||||
{
|
||||
int ni = i+1;
|
||||
if (ni >= (simplified.size()/4))
|
||||
ni = 0;
|
||||
|
||||
if (simplified[i*4+0] == simplified[ni*4+0] &&
|
||||
simplified[i*4+2] == simplified[ni*4+2])
|
||||
{
|
||||
// Degenerate segment, remove.
|
||||
for (int j = i; j < simplified.size()/4-1; ++j)
|
||||
{
|
||||
simplified[j*4+0] = simplified[(j+1)*4+0];
|
||||
simplified[j*4+1] = simplified[(j+1)*4+1];
|
||||
simplified[j*4+2] = simplified[(j+1)*4+2];
|
||||
simplified[j*4+3] = simplified[(j+1)*4+3];
|
||||
}
|
||||
simplified.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int calcAreaOfPolygon2D(const int* verts, const int nverts)
|
||||
{
|
||||
int area = 0;
|
||||
for (int i = 0, j = nverts-1; i < nverts; j=i++)
|
||||
{
|
||||
const int* vi = &verts[i*4];
|
||||
const int* vj = &verts[j*4];
|
||||
area += vi[0] * vj[2] - vj[0] * vi[2];
|
||||
}
|
||||
return (area+1) / 2;
|
||||
}
|
||||
|
||||
static void getClosestIndices(const int* vertsa, const int nvertsa,
|
||||
const int* vertsb, const int nvertsb,
|
||||
int& ia, int& ib)
|
||||
{
|
||||
int closestDist = 0xfffffff;
|
||||
for (int i = 0; i < nvertsa; ++i)
|
||||
{
|
||||
const int* va = &vertsa[i*4];
|
||||
for (int j = 0; j < nvertsb; ++j)
|
||||
{
|
||||
const int* vb = &vertsb[j*4];
|
||||
const int dx = vb[0] - va[0];
|
||||
const int dz = vb[2] - va[2];
|
||||
const int d = dx*dx + dz*dz;
|
||||
if (d < closestDist)
|
||||
{
|
||||
ia = i;
|
||||
ib = j;
|
||||
closestDist = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
||||
{
|
||||
const int maxVerts = ca.nverts + cb.nverts + 2;
|
||||
int* verts = new int[maxVerts*4];
|
||||
if (!verts)
|
||||
return false;
|
||||
|
||||
int nv = 0;
|
||||
|
||||
// Copy contour A.
|
||||
for (int i = 0; i <= ca.nverts; ++i)
|
||||
{
|
||||
int* dst = &verts[nv*4];
|
||||
const int* src = &ca.verts[((ia+i)%ca.nverts)*4];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
nv++;
|
||||
}
|
||||
|
||||
// Copy contour B
|
||||
for (int i = 0; i <= cb.nverts; ++i)
|
||||
{
|
||||
int* dst = &verts[nv*4];
|
||||
const int* src = &cb.verts[((ib+i)%cb.nverts)*4];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
nv++;
|
||||
}
|
||||
|
||||
delete [] ca.verts;
|
||||
ca.verts = verts;
|
||||
ca.nverts = nv;
|
||||
|
||||
delete [] cb.verts;
|
||||
cb.verts = 0;
|
||||
cb.nverts = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
float maxError, int maxEdgeLen,
|
||||
rcContourSet& cset)
|
||||
{
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int maxContours = chf.maxRegions*2;
|
||||
cset.conts = new rcContour[maxContours];
|
||||
if (!cset.conts)
|
||||
return false;
|
||||
cset.nconts = 0;
|
||||
|
||||
unsigned char* flags = new unsigned char[chf.spanCount];
|
||||
if (!flags)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcTimeVal boundaryStartTime = rcGetPerformanceTimer();
|
||||
|
||||
// Mark boundaries.
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
unsigned char res = 0;
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (s.reg == 0)
|
||||
{
|
||||
flags[i] = 0;
|
||||
continue;
|
||||
}
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
unsigned short r = 0;
|
||||
if (rcGetCon(s, dir) != 0xf)
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
r = as.reg;
|
||||
}
|
||||
if (r == s.reg)
|
||||
res |= (1 << dir);
|
||||
}
|
||||
flags[i] = res ^ 0xf; // Inverse, mark non connected edges.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rcTimeVal boundaryEndTime = rcGetPerformanceTimer();
|
||||
|
||||
rcTimeVal contourStartTime = rcGetPerformanceTimer();
|
||||
|
||||
rcIntArray verts(256);
|
||||
rcIntArray simplified(64);
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (flags[i] == 0 || flags[i] == 0xf)
|
||||
{
|
||||
flags[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
verts.resize(0);
|
||||
simplified.resize(0);
|
||||
walkContour(x, y, i, chf, flags, verts);
|
||||
simplifyContour(verts, simplified, maxError, maxEdgeLen);
|
||||
removeDegenerateSegments(simplified);
|
||||
|
||||
// Store region->contour remap info.
|
||||
unsigned short reg = chf.spans[i].reg;
|
||||
// Create contour.
|
||||
if (simplified.size()/4 >= 3)
|
||||
{
|
||||
if (cset.nconts >= maxContours)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Too many contours %d, max %d.", cset.nconts, maxContours);
|
||||
return false;
|
||||
}
|
||||
|
||||
rcContour* cont = &cset.conts[cset.nconts++];
|
||||
|
||||
cont->nverts = simplified.size()/4;
|
||||
cont->verts = new int[cont->nverts*4];
|
||||
memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
|
||||
|
||||
cont->nrverts = verts.size()/4;
|
||||
cont->rverts = new int[cont->nrverts*4];
|
||||
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
|
||||
|
||||
cont->cx = cont->cy = cont->cz = 0;
|
||||
for (int i = 0; i < cont->nverts; ++i)
|
||||
{
|
||||
cont->cx += cont->verts[i*4+0];
|
||||
cont->cy += cont->verts[i*4+1];
|
||||
cont->cz += cont->verts[i*4+2];
|
||||
}
|
||||
cont->cx /= cont->nverts;
|
||||
cont->cy /= cont->nverts;
|
||||
cont->cz /= cont->nverts;
|
||||
|
||||
cont->reg = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check and merge droplings.
|
||||
// Sometimes the previous algorithms can fail and create several countours
|
||||
// per area. This pass will try to merge the holes into the main region.
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
rcContour& cont = cset.conts[i];
|
||||
// Check if the contour is would backwards.
|
||||
if (calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
|
||||
{
|
||||
// Find another contour which has the same region ID.
|
||||
int mergeIdx = -1;
|
||||
for (int j = 0; j < cset.nconts; ++j)
|
||||
{
|
||||
if (i == j) continue;
|
||||
if (cset.conts[j].nverts && cset.conts[j].reg == cont.reg)
|
||||
{
|
||||
// Make sure the polygon is correctly oriented.
|
||||
if (calcAreaOfPolygon2D(cset.conts[j].verts, cset.conts[j].nverts))
|
||||
{
|
||||
mergeIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mergeIdx == -1)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcContour& mcont = cset.conts[mergeIdx];
|
||||
// Merge by closest points.
|
||||
int ia, ib;
|
||||
getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib);
|
||||
if (!mergeContours(mcont, cont, ia, ib))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rcTimeVal contourEndTime = rcGetPerformanceTimer();
|
||||
|
||||
// Delete vertices.
|
||||
delete [] flags;
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
{
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Create contours: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, " - boundary: %.3f ms", rcGetDeltaTimeUsec(boundaryStartTime, boundaryEndTime)/1000.0f);
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, " - contour: %.3f ms", rcGetDeltaTimeUsec(contourStartTime, contourEndTime)/1000.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
491
Recast/Source/RecastDebugDraw.cpp
Normal file
491
Recast/Source/RecastDebugDraw.cpp
Normal file
@ -0,0 +1,491 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "RecastDebugDraw.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_Opengl.h"
|
||||
#include "MeshLoaderObj.h"
|
||||
#include "Recast.h"
|
||||
|
||||
void rcDebugDrawMesh(const rcMeshLoaderObj& mesh, const unsigned char* flags)
|
||||
{
|
||||
int nt = mesh.getTriCount();
|
||||
const float* verts = mesh.getVerts();
|
||||
const float* normals = mesh.getNormals();
|
||||
const int* tris = mesh.getTris();
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (int i = 0; i < nt*3; i += 3)
|
||||
{
|
||||
float a = (2+normals[i+0]+normals[i+1])/4;
|
||||
if (flags && !flags[i/3])
|
||||
glColor3f(a,a*0.3f,a*0.1f);
|
||||
else
|
||||
glColor3f(a,a,a);
|
||||
glVertex3fv(&verts[tris[i]*3]);
|
||||
glVertex3fv(&verts[tris[i+1]*3]);
|
||||
glVertex3fv(&verts[tris[i+2]*3]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void drawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col)
|
||||
{
|
||||
glColor4fv(col);
|
||||
|
||||
// Top
|
||||
glVertex3f(minx, miny, minz);
|
||||
glVertex3f(maxx, miny, minz);
|
||||
glVertex3f(maxx, miny, minz);
|
||||
glVertex3f(maxx, miny, maxz);
|
||||
glVertex3f(maxx, miny, maxz);
|
||||
glVertex3f(minx, miny, maxz);
|
||||
glVertex3f(minx, miny, maxz);
|
||||
glVertex3f(minx, miny, minz);
|
||||
|
||||
// bottom
|
||||
glVertex3f(minx, maxy, minz);
|
||||
glVertex3f(maxx, maxy, minz);
|
||||
glVertex3f(maxx, maxy, minz);
|
||||
glVertex3f(maxx, maxy, maxz);
|
||||
glVertex3f(maxx, maxy, maxz);
|
||||
glVertex3f(minx, maxy, maxz);
|
||||
glVertex3f(minx, maxy, maxz);
|
||||
glVertex3f(minx, maxy, minz);
|
||||
|
||||
// Sides
|
||||
glVertex3f(minx, miny, minz);
|
||||
glVertex3f(minx, maxy, minz);
|
||||
glVertex3f(maxx, miny, minz);
|
||||
glVertex3f(maxx, maxy, minz);
|
||||
glVertex3f(maxx, miny, maxz);
|
||||
glVertex3f(maxx, maxy, maxz);
|
||||
glVertex3f(minx, miny, maxz);
|
||||
glVertex3f(minx, maxy, maxz);
|
||||
}
|
||||
|
||||
void drawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz,
|
||||
const float* col1, const float* col2)
|
||||
{
|
||||
float verts[8*3] =
|
||||
{
|
||||
minx, miny, minz,
|
||||
maxx, miny, minz,
|
||||
maxx, miny, maxz,
|
||||
minx, miny, maxz,
|
||||
minx, maxy, minz,
|
||||
maxx, maxy, minz,
|
||||
maxx, maxy, maxz,
|
||||
minx, maxy, maxz,
|
||||
};
|
||||
static const float dim[6] =
|
||||
{
|
||||
0.95f, 0.55f, 0.65f, 0.85f, 0.65f, 0.85f,
|
||||
};
|
||||
static const unsigned char inds[6*5] =
|
||||
{
|
||||
0, 7, 6, 5, 4,
|
||||
1, 0, 1, 2, 3,
|
||||
2, 1, 5, 6, 2,
|
||||
3, 3, 7, 4, 0,
|
||||
4, 2, 6, 7, 3,
|
||||
5, 0, 4, 5, 1,
|
||||
};
|
||||
|
||||
const unsigned char* in = inds;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
float d = dim[*in]; in++;
|
||||
if (i == 0)
|
||||
glColor4f(d*col2[0],d*col2[1],d*col2[2], col2[3]);
|
||||
else
|
||||
glColor4f(d*col1[0],d*col1[1],d*col1[2], col1[3]);
|
||||
glVertex3fv(&verts[*in*3]); in++;
|
||||
glVertex3fv(&verts[*in*3]); in++;
|
||||
glVertex3fv(&verts[*in*3]); in++;
|
||||
glVertex3fv(&verts[*in*3]); in++;
|
||||
}
|
||||
}
|
||||
|
||||
void rcDebugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col)
|
||||
{
|
||||
static const int NUM_SEG = 16;
|
||||
float dir[NUM_SEG*2];
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*(float)M_PI*2;
|
||||
dir[i*2] = cosf(a);
|
||||
dir[i*2+1] = sinf(a);
|
||||
}
|
||||
|
||||
const float cx = (maxx + minx)/2;
|
||||
const float cz = (maxz + minz)/2;
|
||||
const float rx = (maxx - minx)/2;
|
||||
const float rz = (maxz - minz)/2;
|
||||
|
||||
glColor4fv(col);
|
||||
glBegin(GL_LINES);
|
||||
for (int i = 0, j=NUM_SEG-1; i < NUM_SEG; j=i++)
|
||||
{
|
||||
glVertex3f(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz);
|
||||
glVertex3f(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz);
|
||||
glVertex3f(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz);
|
||||
glVertex3f(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz);
|
||||
}
|
||||
for (int i = 0; i < NUM_SEG; i += NUM_SEG/4)
|
||||
{
|
||||
glVertex3f(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz);
|
||||
glVertex3f(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col)
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
drawBoxWire(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz,
|
||||
const float* col1, const float* col2)
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
drawBox(minx, miny, minz, maxx, maxy, maxz, col1, col2);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void rcDebugDrawHeightfieldSolid(const rcHeightfield& hf,
|
||||
const float* orig, float cs, float ch)
|
||||
{
|
||||
static const float col0[4] = { 1,1,1,1 };
|
||||
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
float fx = orig[0] + x*cs;
|
||||
float fz = orig[2] + y*cs;
|
||||
const rcSpan* s = hf.spans[x + y*w];
|
||||
while (s)
|
||||
{
|
||||
drawBox(fx, orig[1]+s->smin*ch, fz, fx+cs, orig[1] + s->smax*ch, fz+cs, col0, col0);
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawHeightfieldWalkable(const rcHeightfield& hf,
|
||||
const float* orig, float cs, float ch)
|
||||
{
|
||||
static const float col0[4] = { 1,1,1,1 };
|
||||
static const float col1[4] = { 0.25f,0.44f,0.5f,1 };
|
||||
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
float fx = orig[0] + x*cs;
|
||||
float fz = orig[2] + y*cs;
|
||||
const rcSpan* s = hf.spans[x + y*w];
|
||||
while (s)
|
||||
{
|
||||
bool csel = (s->flags & 0x2) == 0;
|
||||
drawBox(fx, orig[1]+s->smin*ch, fz, fx+cs, orig[1] + s->smax*ch, fz+cs, col0, csel ? col0 : col1);
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawCompactHeightfieldSolid(const rcCompactHeightfield& chf)
|
||||
{
|
||||
const float cs = chf.cs;
|
||||
const float ch = chf.ch;
|
||||
|
||||
glColor3ub(64,112,128);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for (int y = 0; y < chf.height; ++y)
|
||||
{
|
||||
for (int x = 0; x < chf.width; ++x)
|
||||
{
|
||||
const float fx = chf.minx + x*cs;
|
||||
const float fz = chf.minz + y*cs;
|
||||
const rcCompactCell& c = chf.cells[x+y*chf.width];
|
||||
|
||||
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
const float fy = chf.miny + (s.y+1)*ch;
|
||||
glVertex3f(fx, fy, fz);
|
||||
glVertex3f(fx, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawCompactHeightfieldRegions(const rcCompactHeightfield& chf)
|
||||
{
|
||||
const float cs = chf.cs;
|
||||
const float ch = chf.ch;
|
||||
|
||||
float col[4] = { 1,1,1,1 };
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for (int y = 0; y < chf.height; ++y)
|
||||
{
|
||||
for (int x = 0; x < chf.width; ++x)
|
||||
{
|
||||
const float fx = chf.minx + x*cs;
|
||||
const float fz = chf.minz + y*cs;
|
||||
const rcCompactCell& c = chf.cells[x+y*chf.width];
|
||||
|
||||
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (s.reg)
|
||||
{
|
||||
intToCol(s.reg, col);
|
||||
glColor4fv(col);
|
||||
}
|
||||
else
|
||||
glColor4ub(0,0,0,128);
|
||||
const float fy = chf.miny + (s.y+1)*ch;
|
||||
glVertex3f(fx, fy, fz);
|
||||
glVertex3f(fx, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void rcDebugDrawCompactHeightfieldDistance(const rcCompactHeightfield& chf)
|
||||
{
|
||||
const float cs = chf.cs;
|
||||
const float ch = chf.ch;
|
||||
|
||||
float maxd = chf.maxDistance;
|
||||
if (maxd < 1.0f) maxd = 1;
|
||||
float dscale = 1.0f / maxd;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for (int y = 0; y < chf.height; ++y)
|
||||
{
|
||||
for (int x = 0; x < chf.width; ++x)
|
||||
{
|
||||
const float fx = chf.minx + x*cs;
|
||||
const float fz = chf.minz + y*cs;
|
||||
const rcCompactCell& c = chf.cells[x+y*chf.width];
|
||||
|
||||
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
const float fy = chf.miny + (s.y+1)*ch;
|
||||
float cd = (float)s.dist * dscale;
|
||||
glColor3f(cd, cd, cd);
|
||||
glVertex3f(fx, fy, fz);
|
||||
glVertex3f(fx, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz+cs);
|
||||
glVertex3f(fx+cs, fy, fz);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void rcDebugDrawRawContours(const rcContourSet& cset, const float* orig, float cs, float ch)
|
||||
{
|
||||
float col[4] = { 1,1,1,1 };
|
||||
glLineWidth(3.0f);
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
const rcContour& c = cset.conts[i];
|
||||
intToCol(c.reg, col);
|
||||
glColor4fv(col);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (int j = 0; j < c.nrverts; ++j)
|
||||
{
|
||||
const int* v = &c.rverts[j*4];
|
||||
float fx = orig[0] + v[0]*cs;
|
||||
float fy = orig[1] + (v[1]+1+(i&1))*ch;
|
||||
float fz = orig[2] + v[2]*cs;
|
||||
glVertex3f(fx,fy,fz);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
glLineWidth(1.0f);
|
||||
}
|
||||
|
||||
void rcDebugDrawContours(const rcContourSet& cset, const float* orig, float cs, float ch)
|
||||
{
|
||||
float col[4] = { 1,1,1,1 };
|
||||
glLineWidth(3.0f);
|
||||
glPointSize(4.0f);
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
const rcContour& c = cset.conts[i];
|
||||
intToCol(c.reg, col);
|
||||
glColor4fv(col);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const int* v = &c.verts[j*4];
|
||||
float fx = orig[0] + v[0]*cs;
|
||||
float fy = orig[1] + (v[1]+1+(i&1))*ch;
|
||||
float fz = orig[2] + v[2]*cs;
|
||||
glVertex3f(fx,fy,fz);
|
||||
}
|
||||
glEnd();
|
||||
glColor4ub(0,0,0,128);
|
||||
glBegin(GL_POINTS);
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const int* v = &c.verts[j*4];
|
||||
float fx = orig[0] + v[0]*cs;
|
||||
float fy = orig[1] + (v[1]+1+(i&1))*ch;
|
||||
float fz = orig[2] + v[2]*cs;
|
||||
glVertex3f(fx,fy,fz);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
glLineWidth(1.0f);
|
||||
glPointSize(1.0f);
|
||||
}
|
||||
|
||||
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh, const float* orig, float cs, float ch)
|
||||
{
|
||||
const int nvp = mesh.nvp;
|
||||
glColor4ub(0,196,255,64);
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &mesh.polys[i*nvp*2];
|
||||
unsigned short vi[3];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == 0xffff) break;
|
||||
vi[0] = p[0];
|
||||
vi[1] = p[j-1];
|
||||
vi[2] = p[j];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
const unsigned short* v = &mesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+2)*ch;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
glVertex3f(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Draw tri boundaries
|
||||
glColor4ub(0,0,0,64);
|
||||
glLineWidth(1.0f);
|
||||
glBegin(GL_LINES);
|
||||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* poly = &mesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (poly[j] == 0xffff) break;
|
||||
if (poly[nvp+j] == 0xffff) continue;
|
||||
int vi[2];
|
||||
vi[0] = poly[j];
|
||||
if (j+1 >= nvp || poly[j+1] == 0xffff)
|
||||
vi[1] = poly[0];
|
||||
else
|
||||
vi[1] = poly[j+1];
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &mesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+2)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
glVertex3f(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Draw boundaries
|
||||
glLineWidth(3.0f);
|
||||
glColor4ub(0,0,0,128);
|
||||
glBegin(GL_LINES);
|
||||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* poly = &mesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (poly[j] == 0xffff) break;
|
||||
if (poly[nvp+j] != 0xffff) continue;
|
||||
int vi[2];
|
||||
vi[0] = poly[j];
|
||||
if (j+1 >= nvp || poly[j+1] == 0xffff)
|
||||
vi[1] = poly[0];
|
||||
else
|
||||
vi[1] = poly[j+1];
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &mesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+2)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
glVertex3f(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
glLineWidth(1.0f);
|
||||
|
||||
glPointSize(4.0f);
|
||||
glColor4ub(0,0,0,128);
|
||||
glBegin(GL_POINTS);
|
||||
for (int i = 0; i < mesh.nverts; ++i)
|
||||
{
|
||||
const unsigned short* v = &mesh.verts[i*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+2)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
glVertex3f(x, y, z);
|
||||
}
|
||||
glEnd();
|
||||
glPointSize(1.0f);
|
||||
}
|
232
Recast/Source/RecastFilter.cpp
Normal file
232
Recast/Source/RecastFilter.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastTimer.h"
|
||||
|
||||
|
||||
void rcFilterWalkableBorderSpans(const int walkableHeight,
|
||||
const int walkableClimb,
|
||||
rcHeightfield& solid)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
const int MAX_HEIGHT = 0xffff;
|
||||
|
||||
// Mark border spans.
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
|
||||
{
|
||||
// Skip non walkable spans.
|
||||
if ((s->flags & RC_WALKABLE) == 0)
|
||||
continue;
|
||||
|
||||
// The span is valid only if it has four neighbours.
|
||||
int neighbourCount = 0;
|
||||
|
||||
const int bot = (int)s->smax;
|
||||
const int top = (int)s->next ? (int)s->next->smin : MAX_HEIGHT;
|
||||
|
||||
// Visit neighbours in all 4 directions.
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
int dx = x + rcGetDirOffsetX(dir);
|
||||
int dy = y + rcGetDirOffsetY(dir);
|
||||
// Skip neighbours which are out of bounds.
|
||||
if (dx < 0 || dy < 0 || dx >= w || dy >= h)
|
||||
continue;
|
||||
for (rcSpan* ns = solid.spans[dx + dy*w]; ns; ns = ns->next)
|
||||
{
|
||||
const int nbot = (int)ns->smax;
|
||||
const int ntop = (int)ns->next ? (int)ns->next->smin : MAX_HEIGHT;
|
||||
// Skip neightbour if the gap between the spans is too small.
|
||||
if (rcMin(top,ntop) - rcMax(bot,nbot) <= walkableHeight)
|
||||
continue;
|
||||
// Skip neightbour if the climb height to the neighbour is too high.
|
||||
if (rcAbs(nbot - bot) >= walkableClimb)
|
||||
continue;
|
||||
// This neighbour is reachable.
|
||||
neighbourCount++;
|
||||
}
|
||||
}
|
||||
// Remove walkable flag.
|
||||
if (neighbourCount != 4)
|
||||
s->flags &= ~RC_WALKABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Filter border: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
}
|
||||
|
||||
void rcFilterWalkableLowHeightSpans(int walkableHeight,
|
||||
rcHeightfield& solid)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
const int MAX_HEIGHT = 0xffff;
|
||||
|
||||
// Remove walkable flag from spans which do not have enough
|
||||
// space above them for the agent to stand there.
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
|
||||
{
|
||||
const int bot = (int)s->smax;
|
||||
const int top = (int)s->next ? (int)s->next->smin : MAX_HEIGHT;
|
||||
if ((top - bot) <= walkableHeight)
|
||||
s->flags &= ~RC_WALKABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Filter walkable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
}
|
||||
|
||||
struct rcReachableSeed
|
||||
{
|
||||
inline void set(int ix, int iy, rcSpan* is)
|
||||
{
|
||||
x = (unsigned short)ix;
|
||||
y = (unsigned short)iy;
|
||||
s = is;
|
||||
}
|
||||
unsigned short x, y;
|
||||
rcSpan* s;
|
||||
};
|
||||
|
||||
bool rcMarkReachableSpans(const int walkableHeight,
|
||||
const int walkableClimb,
|
||||
rcHeightfield& solid)
|
||||
{
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
const int MAX_HEIGHT = 0xffff;
|
||||
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
// Build navigable space.
|
||||
const int MAX_SEEDS = w*h;
|
||||
rcReachableSeed* stack = new rcReachableSeed[MAX_SEEDS];
|
||||
if (!stack)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcMarkReachableSpans: Out of memory 'stack' (%d).", MAX_SEEDS);
|
||||
return false;
|
||||
}
|
||||
int stackSize = 0;
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
rcSpan* topSpan = solid.spans[x + y*w];
|
||||
if (!topSpan)
|
||||
continue;
|
||||
while (topSpan->next)
|
||||
topSpan = topSpan->next;
|
||||
|
||||
// If the span is not walkable, skip it.
|
||||
if ((topSpan->flags & RC_WALKABLE) == 0)
|
||||
continue;
|
||||
// If the span has been visited already, skip it.
|
||||
if (topSpan->flags & RC_REACHABLE)
|
||||
continue;
|
||||
|
||||
// Start flood fill.
|
||||
topSpan->flags |= RC_REACHABLE;
|
||||
stackSize = 0;
|
||||
stack[stackSize].set(x, y, topSpan);
|
||||
stackSize++;
|
||||
|
||||
while (stackSize)
|
||||
{
|
||||
// Pop a seed from the stack.
|
||||
stackSize--;
|
||||
rcReachableSeed cur = stack[stackSize];
|
||||
|
||||
const int bot = (int)cur.s->smax;
|
||||
const int top = (int)cur.s->next ? (int)cur.s->next->smin : MAX_HEIGHT;
|
||||
|
||||
// Visit neighbours in all 4 directions.
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
int dx = (int)cur.x + rcGetDirOffsetX(dir);
|
||||
int dy = (int)cur.y + rcGetDirOffsetY(dir);
|
||||
// Skip neighbour which are out of bounds.
|
||||
if (dx < 0 || dy < 0 || dx >= w || dy >= h)
|
||||
continue;
|
||||
for (rcSpan* ns = solid.spans[dx + dy*w]; ns; ns = ns->next)
|
||||
{
|
||||
// Skip neighbour if it is not walkable.
|
||||
if ((ns->flags & RC_WALKABLE) == 0)
|
||||
continue;
|
||||
// Skip the neighbour if it has been visited already.
|
||||
if (ns->flags & RC_REACHABLE)
|
||||
continue;
|
||||
|
||||
const int nbot = (int)ns->smax;
|
||||
const int ntop = (int)ns->next ? (int)ns->next->smin : MAX_HEIGHT;
|
||||
// Skip neightbour if the gap between the spans is too small.
|
||||
if (rcMin(top,ntop) - rcMax(bot,nbot) < walkableHeight)
|
||||
continue;
|
||||
// Skip neightbour if the climb height to the neighbour is too high.
|
||||
if (rcAbs(nbot - bot) >= walkableClimb)
|
||||
continue;
|
||||
|
||||
// This neighbour has not been visited yet.
|
||||
// Mark it as reachable and add it to the seed stack.
|
||||
ns->flags |= RC_REACHABLE;
|
||||
if (stackSize < MAX_SEEDS)
|
||||
{
|
||||
stack[stackSize].set(dx, dy, ns);
|
||||
stackSize++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] stack;
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Mark reachable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
|
||||
return true;
|
||||
}
|
66
Recast/Source/RecastLog.cpp
Normal file
66
Recast/Source/RecastLog.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include "RecastLog.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static rcLog* g_log = 0;
|
||||
|
||||
rcLog::rcLog() :
|
||||
m_messageCount(0),
|
||||
m_textPoolSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
rcLog::~rcLog()
|
||||
{
|
||||
if (g_log == this)
|
||||
g_log = 0;
|
||||
}
|
||||
|
||||
void rcLog::log(rcLogCategory category, const char* format, ...)
|
||||
{
|
||||
if (m_messageCount >= MAX_MESSAGES)
|
||||
return;
|
||||
char* dst = &m_textPool[m_textPoolSize];
|
||||
int n = TEXT_POOL_SIZE - m_textPoolSize;
|
||||
if (n < 2)
|
||||
return;
|
||||
// Store category
|
||||
*dst = (char)category;
|
||||
n--;
|
||||
// Store message
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int ret = vsnprintf(dst+1, n-1, format, ap);
|
||||
va_end(ap);
|
||||
if (ret > 0)
|
||||
m_textPoolSize += ret+2;
|
||||
m_messages[m_messageCount++] = dst;
|
||||
}
|
||||
|
||||
void rcSetLog(rcLog* log)
|
||||
{
|
||||
g_log = log;
|
||||
}
|
||||
|
||||
rcLog* rcGetLog()
|
||||
{
|
||||
return g_log;
|
||||
}
|
699
Recast/Source/RecastMesh.cpp
Normal file
699
Recast/Source/RecastMesh.cpp
Normal file
@ -0,0 +1,699 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastTimer.h"
|
||||
|
||||
|
||||
struct rcEdge
|
||||
{
|
||||
unsigned short vert[2];
|
||||
unsigned short polyEdge[2];
|
||||
unsigned short poly[2];
|
||||
};
|
||||
|
||||
static bool buildMeshAdjacency(unsigned short* polys, const int npolys,
|
||||
const int nverts, const int vertsPerPoly)
|
||||
{
|
||||
// Based on code by Eric Lengyel from:
|
||||
// http://www.terathon.com/code/edges.php
|
||||
|
||||
int maxEdgeCount = npolys*vertsPerPoly;
|
||||
unsigned short* firstEdge = new unsigned short[nverts + maxEdgeCount];
|
||||
if (!firstEdge)
|
||||
return false;
|
||||
unsigned short* nextEdge = firstEdge + nverts;
|
||||
int edgeCount = 0;
|
||||
|
||||
rcEdge* edges = new rcEdge[maxEdgeCount];
|
||||
if (!edges)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < nverts; i++)
|
||||
firstEdge[i] = 0xffff;
|
||||
|
||||
// Invalida indices are marked as 0xffff, the following code
|
||||
// handles them just fine.
|
||||
|
||||
for (int i = 0; i < npolys; ++i)
|
||||
{
|
||||
unsigned short* t = &polys[i*vertsPerPoly*2];
|
||||
for (int j = 0; j < vertsPerPoly; ++j)
|
||||
{
|
||||
unsigned short v0 = t[j];
|
||||
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == 0xffff) ? t[0] : t[j+1];
|
||||
if (v0 < v1)
|
||||
{
|
||||
rcEdge& edge = edges[edgeCount];
|
||||
edge.vert[0] = v0;
|
||||
edge.vert[1] = v1;
|
||||
edge.poly[0] = (unsigned short)i;
|
||||
edge.polyEdge[0] = (unsigned short)j;
|
||||
edge.poly[1] = (unsigned short)i;
|
||||
edge.polyEdge[1] = 0;
|
||||
// Insert edge
|
||||
nextEdge[edgeCount] = firstEdge[v0];
|
||||
firstEdge[v0] = edgeCount;
|
||||
edgeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < npolys; ++i)
|
||||
{
|
||||
unsigned short* t = &polys[i*vertsPerPoly*2];
|
||||
for (int j = 0; j < vertsPerPoly; ++j)
|
||||
{
|
||||
unsigned short v0 = t[j];
|
||||
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == 0xffff) ? t[0] : t[j+1];
|
||||
if (v0 > v1)
|
||||
{
|
||||
for (unsigned short e = firstEdge[v1]; e != 0xffff; e = nextEdge[e])
|
||||
{
|
||||
rcEdge& edge = edges[e];
|
||||
if (edge.vert[1] == v0 && edge.poly[0] == edge.poly[1])
|
||||
{
|
||||
edge.poly[1] = (unsigned short)i;
|
||||
edge.polyEdge[1] = (unsigned short)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store adjacency
|
||||
for (int i = 0; i < edgeCount; ++i)
|
||||
{
|
||||
const rcEdge& e = edges[i];
|
||||
if (e.poly[0] != e.poly[1])
|
||||
{
|
||||
unsigned short* p0 = &polys[e.poly[0]*vertsPerPoly*2];
|
||||
unsigned short* p1 = &polys[e.poly[1]*vertsPerPoly*2];
|
||||
p0[vertsPerPoly + e.polyEdge[0]] = e.poly[1];
|
||||
p1[vertsPerPoly + e.polyEdge[1]] = e.poly[0];
|
||||
}
|
||||
}
|
||||
|
||||
delete [] firstEdge;
|
||||
delete [] edges;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const int VERTEX_BUCKET_COUNT = (1<<12);
|
||||
|
||||
inline int computeVertexHash(int x, int y, int z)
|
||||
{
|
||||
const unsigned int h1 = 0x8da6b343; // Large multiplicative constants;
|
||||
const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
const unsigned int h3 = 0xcb1ab31f;
|
||||
unsigned int n = h1 * x + h2 * y + h3 * z;
|
||||
return (int)(n & (VERTEX_BUCKET_COUNT-1));
|
||||
}
|
||||
|
||||
static int addVertex(unsigned short x, unsigned short y, unsigned short z,
|
||||
unsigned short* verts, int* firstVert, int* nextVert, int& nv)
|
||||
{
|
||||
int bucket = computeVertexHash(x, y, z);
|
||||
int i = firstVert[bucket];
|
||||
|
||||
while (i != -1)
|
||||
{
|
||||
const unsigned short* v = &verts[i*3];
|
||||
if (v[0] == x && v[1] == y && v[2] == z)
|
||||
return i;
|
||||
i = nextVert[i]; // next
|
||||
}
|
||||
|
||||
// Could not find, create new.
|
||||
i = nv; nv++;
|
||||
unsigned short* v = &verts[i*3];
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
nextVert[i] = firstVert[bucket];
|
||||
firstVert[bucket] = i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
|
||||
inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
|
||||
|
||||
inline int area2(const int* a, const int* b, const int* c)
|
||||
{
|
||||
return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
|
||||
}
|
||||
|
||||
// Exclusive or: true iff exactly one argument is true.
|
||||
// The arguments are negated to ensure that they are 0/1
|
||||
// values. Then the bitwise Xor operator may apply.
|
||||
// (This idea is due to Michael Baldwin.)
|
||||
inline bool xorb(bool x, bool y)
|
||||
{
|
||||
return !x ^ !y;
|
||||
}
|
||||
|
||||
// Returns true iff c is strictly to the left of the directed
|
||||
// line through a to b.
|
||||
inline bool left(const int* a, const int* b, const int* c)
|
||||
{
|
||||
return area2(a, b, c) < 0;
|
||||
}
|
||||
|
||||
inline bool leftOn(const int* a, const int* b, const int* c)
|
||||
{
|
||||
return area2(a, b, c) <= 0;
|
||||
}
|
||||
|
||||
inline bool collinear(const int* a, const int* b, const int* c)
|
||||
{
|
||||
return area2(a, b, c) == 0;
|
||||
}
|
||||
|
||||
// Returns true iff ab properly intersects cd: they share
|
||||
// a point interior to both segments. The properness of the
|
||||
// intersection is ensured by using strict leftness.
|
||||
bool intersectProp(const int* a, const int* b, const int* c, const int* d)
|
||||
{
|
||||
// Eliminate improper cases.
|
||||
if (collinear(a,b,c) || collinear(a,b,d) ||
|
||||
collinear(c,d,a) || collinear(c,d,b))
|
||||
return false;
|
||||
|
||||
return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b));
|
||||
}
|
||||
|
||||
// Returns T iff (a,b,c) are collinear and point c lies
|
||||
// on the closed segement ab.
|
||||
static bool between(const int* a, const int* b, const int* c)
|
||||
{
|
||||
if (!collinear(a, b, c))
|
||||
return false;
|
||||
// If ab not vertical, check betweenness on x; else on y.
|
||||
if (a[0] != b[0])
|
||||
return ((a[0] <= c[0]) && (c[0] <= b[0])) || ((a[0] >= c[0]) && (c[0] >= b[0]));
|
||||
else
|
||||
return ((a[2] <= c[2]) && (c[2] <= b[2])) || ((a[2] >= c[2]) && (c[2] >= b[2]));
|
||||
}
|
||||
|
||||
// Returns true iff segments ab and cd intersect, properly or improperly.
|
||||
static bool intersect(const int* a, const int* b, const int* c, const int* d)
|
||||
{
|
||||
if (intersectProp(a, b, c, d))
|
||||
return true;
|
||||
else if (between(a, b, c) || between(a, b, d) ||
|
||||
between(c, d, a) || between(c, d, b))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool vequal(const int* a, const int* b)
|
||||
{
|
||||
return a[0] == b[0] && a[2] == b[2];
|
||||
}
|
||||
|
||||
// Returns T iff (v_i, v_j) is a proper internal *or* external
|
||||
// diagonal of P, *ignoring edges incident to v_i and v_j*.
|
||||
static bool diagonalie(int i, int j, int n, const int* verts, int* indices)
|
||||
{
|
||||
const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||
const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4];
|
||||
|
||||
// For each edge (k,k+1) of P
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int k1 = next(k, n);
|
||||
// Skip edges incident to i or j
|
||||
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
|
||||
{
|
||||
const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4];
|
||||
const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4];
|
||||
|
||||
if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
|
||||
continue;
|
||||
|
||||
if (intersect(d0, d1, p0, p1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true iff the diagonal (i,j) is strictly internal to the
|
||||
// polygon P in the neighborhood of the i endpoint.
|
||||
static bool inCone(int i, int j, int n, const int* verts, int* indices)
|
||||
{
|
||||
const int* pi = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||
const int* pj = &verts[(indices[j] & 0x0fffffff) * 4];
|
||||
const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4];
|
||||
const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4];
|
||||
|
||||
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
|
||||
if (leftOn(pin1, pi, pi1))
|
||||
return left(pi, pj, pin1) && left(pj, pi, pi1);
|
||||
// Assume (i-1,i,i+1) not collinear.
|
||||
// else P[i] is reflex.
|
||||
return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
|
||||
}
|
||||
|
||||
// Returns T iff (v_i, v_j) is a proper internal
|
||||
// diagonal of P.
|
||||
static bool diagonal(int i, int j, int n, const int* verts, int* indices)
|
||||
{
|
||||
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
|
||||
}
|
||||
|
||||
int triangulate(int n, const int* verts, int* indices, int* tris)
|
||||
{
|
||||
int ntris = 0;
|
||||
int* dst = tris;
|
||||
|
||||
// The last bit of the index is used to indicate if the vertex can be removed.
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
if (diagonal(i, i2, n, verts, indices))
|
||||
indices[i1] |= 0x80000000;
|
||||
}
|
||||
|
||||
while (n > 3)
|
||||
{
|
||||
int minLen = -1;
|
||||
int mini = -1;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int i1 = next(i, n);
|
||||
if (indices[i1] & 0x80000000)
|
||||
{
|
||||
const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||
const int* p2 = &verts[(indices[next(i1, n)] & 0x0fffffff) * 4];
|
||||
|
||||
int dx = p2[0] - p0[0];
|
||||
int dy = p2[2] - p0[2];
|
||||
int len = dx*dx + dy*dy;
|
||||
|
||||
if (minLen < 0 || len < minLen)
|
||||
{
|
||||
minLen = len;
|
||||
mini = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mini == -1)
|
||||
{
|
||||
// Should not happen.
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_WARNING, "triangulate: Failed to triangulate polygon.");
|
||||
/* printf("mini == -1 ntris=%d n=%d\n", ntris, n);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
printf("%d ", indices[i] & 0x0fffffff);
|
||||
}
|
||||
printf("\n");*/
|
||||
return -ntris;
|
||||
}
|
||||
|
||||
int i = mini;
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
|
||||
*dst++ = indices[i] & 0x0fffffff;
|
||||
*dst++ = indices[i1] & 0x0fffffff;
|
||||
*dst++ = indices[i2] & 0x0fffffff;
|
||||
ntris++;
|
||||
|
||||
// Removes P[i1] by copying P[i+1]...P[n-1] left one index.
|
||||
n--;
|
||||
for (int k = i1; k < n; k++)
|
||||
indices[k] = indices[k+1];
|
||||
|
||||
if (i1 >= n) i1 = 0;
|
||||
i = prev(i1,n);
|
||||
// Update diagonal flags.
|
||||
if (diagonal(prev(i, n), i1, n, verts, indices))
|
||||
indices[i] |= 0x80000000;
|
||||
else
|
||||
indices[i] &= 0x0fffffff;
|
||||
|
||||
if (diagonal(i, next(i1, n), n, verts, indices))
|
||||
indices[i1] |= 0x80000000;
|
||||
else
|
||||
indices[i1] &= 0x0fffffff;
|
||||
}
|
||||
|
||||
// Append the remaining triangle.
|
||||
*dst++ = indices[0] & 0x0fffffff;
|
||||
*dst++ = indices[1] & 0x0fffffff;
|
||||
*dst++ = indices[2] & 0x0fffffff;
|
||||
ntris++;
|
||||
|
||||
return ntris;
|
||||
}
|
||||
|
||||
static int countPolyVerts(const unsigned short* p, const int nvp)
|
||||
{
|
||||
for (int i = 0; i < nvp; ++i)
|
||||
if (p[i] == 0xffff)
|
||||
return i;
|
||||
return nvp;
|
||||
}
|
||||
|
||||
inline bool uleftOn(const unsigned short* a, const unsigned short* b, const unsigned short* c)
|
||||
{
|
||||
return ((int)b[0] - (int)a[0]) * ((int)c[2] - (int)a[2]) -
|
||||
((int)c[0] - (int)a[0]) * ((int)b[2] - (int)a[2]) <= 0;
|
||||
}
|
||||
|
||||
static int getPolyMergeValue(unsigned short* pa, unsigned short* pb,
|
||||
const unsigned short* verts, int& ea, int& eb,
|
||||
const int nvp)
|
||||
{
|
||||
const int na = countPolyVerts(pa, nvp);
|
||||
const int nb = countPolyVerts(pb, nvp);
|
||||
|
||||
// If the merged polygon would be too big, do not merge.
|
||||
if (na+nb-2 > nvp)
|
||||
return -1;
|
||||
|
||||
// Check if the polygons share an edge.
|
||||
ea = -1;
|
||||
eb = -1;
|
||||
|
||||
for (int i = 0; i < na; ++i)
|
||||
{
|
||||
unsigned short va0 = pa[i];
|
||||
unsigned short va1 = pa[(i+1) % na];
|
||||
if (va0 > va1)
|
||||
rcSwap(va0, va1);
|
||||
for (int j = 0; j < nb; ++j)
|
||||
{
|
||||
unsigned short vb0 = pb[j];
|
||||
unsigned short vb1 = pb[(j+1) % nb];
|
||||
if (vb0 > vb1)
|
||||
rcSwap(vb0, vb1);
|
||||
if (va0 == vb0 && va1 == vb1)
|
||||
{
|
||||
ea = i;
|
||||
eb = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No common edge, cannot merge.
|
||||
if (ea == -1 || eb == -1)
|
||||
return -1;
|
||||
|
||||
// Check to see if the merged polygon would be convex.
|
||||
unsigned short va, vb, vc;
|
||||
|
||||
va = pa[(ea+na-1) % na];
|
||||
vb = pa[ea];
|
||||
vc = pb[(eb+2) % nb];
|
||||
if (!uleftOn(&verts[va*3], &verts[vb*3], &verts[vc*3]))
|
||||
return -1;
|
||||
|
||||
va = pb[(eb+nb-1) % nb];
|
||||
vb = pb[eb];
|
||||
vc = pa[(ea+2) % na];
|
||||
if (!uleftOn(&verts[va*3], &verts[vb*3], &verts[vc*3]))
|
||||
return -1;
|
||||
|
||||
va = pa[ea];
|
||||
vb = pa[(ea+1)%na];
|
||||
|
||||
int dx = (int)verts[va*3+0] - (int)verts[vb*3+0];
|
||||
int dy = (int)verts[va*3+2] - (int)verts[vb*3+2];
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static void mergePolys(unsigned short* pa, unsigned short* pb,
|
||||
const unsigned short* verts, int ea, int eb,
|
||||
unsigned short* tmp, const int nvp)
|
||||
{
|
||||
const int na = countPolyVerts(pa, nvp);
|
||||
const int nb = countPolyVerts(pb, nvp);
|
||||
|
||||
// Merge polygons.
|
||||
memset(tmp, 0xff, sizeof(unsigned short)*nvp);
|
||||
int n = 0;
|
||||
// Add pa
|
||||
for (int i = 0; i < na-1; ++i)
|
||||
tmp[n++] = pa[(ea+1+i) % na];
|
||||
// Add pb
|
||||
for (int i = 0; i < nb-1; ++i)
|
||||
tmp[n++] = pb[(eb+1+i) % nb];
|
||||
|
||||
memcpy(pa, tmp, sizeof(unsigned short)*nvp);
|
||||
}
|
||||
|
||||
bool rcBuildPolyMesh(rcContourSet& cset, rcPolyMesh& mesh, const int nvp)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
int maxVertices = 0;
|
||||
int maxTris = 0;
|
||||
int maxVertsPerCont = 0;
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
maxVertices += cset.conts[i].nverts;
|
||||
maxTris += cset.conts[i].nverts - 2;
|
||||
maxVertsPerCont = rcMax(maxVertsPerCont, cset.conts[i].nverts);
|
||||
}
|
||||
|
||||
if (maxVertices >= 0xfffe)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh.verts = new unsigned short[maxVertices*3];
|
||||
if (!mesh.verts)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
|
||||
return false;
|
||||
}
|
||||
mesh.polys = new unsigned short[maxTris*nvp*2];
|
||||
if (!mesh.polys)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxTris*nvp);
|
||||
return false;
|
||||
}
|
||||
mesh.nverts = 0;
|
||||
mesh.npolys = 0;
|
||||
mesh.nvp = nvp;
|
||||
|
||||
memset(mesh.verts, 0, sizeof(unsigned short)*maxVertices*3);
|
||||
memset(mesh.polys, 0xff, sizeof(unsigned short)*maxTris*nvp*2);
|
||||
|
||||
int* nextVert = new int[maxVertices];
|
||||
if (!nextVert)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
|
||||
return false;
|
||||
}
|
||||
memset(nextVert, 0, sizeof(int)*maxVertices);
|
||||
|
||||
int* firstVert = new int[VERTEX_BUCKET_COUNT];
|
||||
if (!firstVert)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
|
||||
firstVert[i] = -1;
|
||||
|
||||
int* indices = new int[maxVertsPerCont];
|
||||
if (!indices)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
|
||||
return false;
|
||||
}
|
||||
int* tris = new int[maxVertsPerCont*3];
|
||||
if (!tris)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
|
||||
return false;
|
||||
}
|
||||
unsigned short* polys = new unsigned short[maxVertsPerCont*nvp];
|
||||
if (!polys)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
|
||||
return false;
|
||||
}
|
||||
unsigned short* tmpPoly = new unsigned short[nvp];
|
||||
if (!tmpPoly)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tmpPoly' (%d).", nvp);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
rcContour& cont = cset.conts[i];
|
||||
|
||||
// Skip empty contours.
|
||||
if (cont.nverts < 3)
|
||||
continue;
|
||||
|
||||
// Triangulate contour
|
||||
for (int j = 0; j < cont.nverts; ++j)
|
||||
indices[j] = j;
|
||||
|
||||
int ntris = triangulate(cont.nverts, cont.verts, &indices[0], &tris[0]);
|
||||
if (ntris <= 0)
|
||||
{
|
||||
// Bad triangulation, should not happen.
|
||||
/* for (int k = 0; k < cont.nverts; ++k)
|
||||
{
|
||||
const int* v = &cont.verts[k*4];
|
||||
printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]);
|
||||
if (nBadPos < 100)
|
||||
{
|
||||
badPos[nBadPos*3+0] = v[0];
|
||||
badPos[nBadPos*3+1] = v[1];
|
||||
badPos[nBadPos*3+2] = v[2];
|
||||
nBadPos++;
|
||||
}
|
||||
}*/
|
||||
ntris = -ntris;
|
||||
}
|
||||
// Add and merge vertices.
|
||||
for (int j = 0; j < cont.nverts; ++j)
|
||||
{
|
||||
const int* v = &cont.verts[j*4];
|
||||
indices[j] = addVertex((unsigned short)v[0], (unsigned short)v[1], (unsigned short)v[2],
|
||||
mesh.verts, firstVert, nextVert, mesh.nverts);
|
||||
}
|
||||
|
||||
// Build initial polygons.
|
||||
int npolys = 0;
|
||||
memset(polys, 0xff, maxVertsPerCont*nvp*sizeof(unsigned short));
|
||||
for (int j = 0; j < ntris; ++j)
|
||||
{
|
||||
int* t = &tris[j*3];
|
||||
if (t[0] != t[1] && t[0] != t[2] && t[1] != t[2])
|
||||
{
|
||||
polys[npolys*nvp+0] = (unsigned short)indices[t[0]];
|
||||
polys[npolys*nvp+1] = (unsigned short)indices[t[1]];
|
||||
polys[npolys*nvp+2] = (unsigned short)indices[t[2]];
|
||||
npolys++;
|
||||
}
|
||||
}
|
||||
if (!npolys)
|
||||
continue;
|
||||
|
||||
// Merge polygons.
|
||||
if (nvp > 3)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Find best polygons to merge.
|
||||
int bestMergeVal = 0;
|
||||
int bestPa, bestPb, bestEa, bestEb;
|
||||
|
||||
for (int j = 0; j < npolys-1; ++j)
|
||||
{
|
||||
unsigned short* pj = &polys[j*nvp];
|
||||
for (int k = j+1; k < npolys; ++k)
|
||||
{
|
||||
unsigned short* pk = &polys[k*nvp];
|
||||
int ea, eb;
|
||||
int v = getPolyMergeValue(pj, pk, mesh.verts, ea, eb, nvp);
|
||||
if (v > bestMergeVal)
|
||||
{
|
||||
bestMergeVal = v;
|
||||
bestPa = j;
|
||||
bestPb = k;
|
||||
bestEa = ea;
|
||||
bestEb = eb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestMergeVal > 0)
|
||||
{
|
||||
// Found best, merge.
|
||||
unsigned short* pa = &polys[bestPa*nvp];
|
||||
unsigned short* pb = &polys[bestPb*nvp];
|
||||
mergePolys(pa, pb, mesh.verts, bestEa, bestEb, tmpPoly, nvp);
|
||||
memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
|
||||
npolys--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could not merge any polygons, stop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Store polygons.
|
||||
for (int j = 0; j < npolys; ++j)
|
||||
{
|
||||
unsigned short* p = &mesh.polys[mesh.npolys*nvp*2];
|
||||
unsigned short* q = &polys[j*nvp];
|
||||
for (int k = 0; k < nvp; ++k)
|
||||
p[k] = q[k];
|
||||
mesh.npolys++;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] tmpPoly;
|
||||
delete [] firstVert;
|
||||
delete [] nextVert;
|
||||
delete [] indices;
|
||||
delete [] tris;
|
||||
|
||||
// Calculate adjacency.
|
||||
if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp))
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "Build polymesh: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
|
||||
return true;
|
||||
}
|
295
Recast/Source/RecastRasterization.cpp
Normal file
295
Recast/Source/RecastRasterization.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastTimer.h"
|
||||
#include "RecastLog.h"
|
||||
|
||||
inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
inline bool overlapInterval(unsigned short amin, unsigned short amax,
|
||||
unsigned short bmin, unsigned short bmax)
|
||||
{
|
||||
if (amax < bmin) return false;
|
||||
if (amin > bmax) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static rcSpan* allocSpan(rcHeightfield& hf)
|
||||
{
|
||||
static const int SPANS_PER_POOL = 2048;
|
||||
// If running out of memory, allocate new page and update the freelist.
|
||||
if (!hf.freelist || !hf.freelist->next)
|
||||
{
|
||||
// Create new page.
|
||||
// Allocate memory for the new pool.
|
||||
const int size = (sizeof(rcSpanPool)-sizeof(rcSpan)) + sizeof(rcSpan)*SPANS_PER_POOL;
|
||||
rcSpanPool* pool = reinterpret_cast<rcSpanPool*>(new unsigned char[size]);
|
||||
if (!pool) return 0;
|
||||
pool->next = 0;
|
||||
// Add the pool into the list of pools.
|
||||
pool->next = hf.pools;
|
||||
hf.pools = pool;
|
||||
// Add new items to the free list.
|
||||
rcSpan* freelist = hf.freelist;
|
||||
rcSpan* head = &pool->items[0];
|
||||
rcSpan* it = &pool->items[SPANS_PER_POOL];
|
||||
do
|
||||
{
|
||||
--it;
|
||||
it->next = freelist;
|
||||
freelist = it;
|
||||
}
|
||||
while (it != head);
|
||||
hf.freelist = it;
|
||||
}
|
||||
|
||||
// Pop item from in front of the free list.
|
||||
rcSpan* it = hf.freelist;
|
||||
hf.freelist = hf.freelist->next;
|
||||
return it;
|
||||
}
|
||||
|
||||
static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
|
||||
{
|
||||
if (!ptr) return;
|
||||
// Add the node in front of the free list.
|
||||
ptr->next = hf.freelist;
|
||||
hf.freelist = ptr;
|
||||
}
|
||||
|
||||
static void addSpan(rcHeightfield& hf, int x, int y,
|
||||
unsigned short smin, unsigned short smax,
|
||||
unsigned short flags)
|
||||
{
|
||||
int idx = x + y*hf.width;
|
||||
|
||||
rcSpan* s = allocSpan(hf);
|
||||
s->smin = smin;
|
||||
s->smax = smax;
|
||||
s->flags = flags;
|
||||
s->next = 0;
|
||||
|
||||
// Empty cell, add he first span.
|
||||
if (!hf.spans[idx])
|
||||
{
|
||||
hf.spans[idx] = s;
|
||||
return;
|
||||
}
|
||||
rcSpan* prev = 0;
|
||||
rcSpan* cur = hf.spans[idx];
|
||||
|
||||
// Insert and merge spans.
|
||||
while (cur)
|
||||
{
|
||||
if (cur->smin > s->smax)
|
||||
{
|
||||
// Current span is further than the new span, break.
|
||||
break;
|
||||
}
|
||||
else if (cur->smax < s->smin)
|
||||
{
|
||||
// Current span is before the new span advance.
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Merge spans.
|
||||
if (cur->smin < s->smin)
|
||||
s->smin = cur->smin;
|
||||
if (cur->smax > s->smax)
|
||||
s->smax = cur->smax;
|
||||
|
||||
// Merge flags.
|
||||
// if (s->smax == cur->smax)
|
||||
if (rcAbs((int)s->smax - (int)cur->smax) <= 1)
|
||||
s->flags |= cur->flags;
|
||||
|
||||
// Remove current span.
|
||||
rcSpan* next = cur->next;
|
||||
freeSpan(hf, cur);
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else
|
||||
hf.spans[idx] = next;
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new span.
|
||||
if (prev)
|
||||
{
|
||||
s->next = prev->next;
|
||||
prev->next = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->next = hf.spans[idx];
|
||||
hf.spans[idx] = s;
|
||||
}
|
||||
}
|
||||
|
||||
static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
|
||||
{
|
||||
float d[12];
|
||||
for (int i = 0; i < n; ++i)
|
||||
d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
|
||||
|
||||
int m = 0;
|
||||
for (int i = 0, j = n-1; i < n; j=i, ++i)
|
||||
{
|
||||
bool ina = d[j] >= 0;
|
||||
bool inb = d[i] >= 0;
|
||||
if (ina != inb)
|
||||
{
|
||||
float s = d[j] / (d[j] - d[i]);
|
||||
out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
|
||||
out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
|
||||
out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
||||
m++;
|
||||
}
|
||||
if (inb)
|
||||
{
|
||||
out[m*3+0] = in[i*3+0];
|
||||
out[m*3+1] = in[i*3+1];
|
||||
out[m*3+2] = in[i*3+2];
|
||||
m++;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
unsigned char flags, rcHeightfield& hf,
|
||||
const float* bmin, const float* bmax,
|
||||
const float cs, const float ics, const float ich)
|
||||
{
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
float tmin[3], tmax[3];
|
||||
const float by = bmax[1] - bmin[1];
|
||||
|
||||
// Calculate the bounding box of the triangle.
|
||||
vcopy(tmin, v0);
|
||||
vcopy(tmax, v0);
|
||||
vmin(tmin, v1);
|
||||
vmin(tmin, v2);
|
||||
vmax(tmax, v1);
|
||||
vmax(tmax, v2);
|
||||
|
||||
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
|
||||
if (!overlapBounds(bmin, bmax, tmin, tmax))
|
||||
return;
|
||||
|
||||
// Calculate the footpring of the triangle on the grid.
|
||||
int x0 = (int)((tmin[0] - bmin[0])*ics);
|
||||
int y0 = (int)((tmin[2] - bmin[2])*ics);
|
||||
int x1 = (int)((tmax[0] - bmin[0])*ics);
|
||||
int y1 = (int)((tmax[2] - bmin[2])*ics);
|
||||
x0 = rcClamp(x0, 0, w-1);
|
||||
y0 = rcClamp(y0, 0, h-1);
|
||||
x1 = rcClamp(x1, 0, w-1);
|
||||
y1 = rcClamp(y1, 0, h-1);
|
||||
|
||||
// Clip the triangle into all grid cells it touches.
|
||||
float in[7*3], out[7*3], inrow[7*3];
|
||||
|
||||
for (int y = y0; y <= y1; ++y)
|
||||
{
|
||||
// Clip polygon to row.
|
||||
vcopy(&in[0], v0);
|
||||
vcopy(&in[1*3], v1);
|
||||
vcopy(&in[2*3], v2);
|
||||
int nvrow = 3;
|
||||
const float cz = bmin[2] + y*cs;
|
||||
nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
|
||||
if (nvrow < 3) continue;
|
||||
nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
|
||||
if (nvrow < 3) continue;
|
||||
|
||||
for (int x = x0; x <= x1; ++x)
|
||||
{
|
||||
// Clip polygon to column.
|
||||
int nv = nvrow;
|
||||
const float cx = bmin[0] + x*cs;
|
||||
nv = clipPoly(inrow, nv, out, 1, 0, -cx);
|
||||
if (nv < 3) continue;
|
||||
nv = clipPoly(out, nv, in, -1, 0, cx+cs);
|
||||
if (nv < 3) continue;
|
||||
|
||||
// Calculate min and max of the span.
|
||||
float smin = in[1], smax = in[1];
|
||||
for (int i = 1; i < nv; ++i)
|
||||
{
|
||||
smin = rcMin(smin, in[i*3+1]);
|
||||
smax = rcMax(smax, in[i*3+1]);
|
||||
}
|
||||
smin -= bmin[1];
|
||||
smax -= bmin[1];
|
||||
// Skip the span if it is outside the heightfield bbox
|
||||
if (smax < 0.0f) continue;
|
||||
if (smin > by) continue;
|
||||
// Clamp the span to the heightfield bbox.
|
||||
if (smin < 0.0f) smin = bmin[1];
|
||||
if (smax > by) smax = bmax[1];
|
||||
|
||||
// Snap the span to the heightfield height grid.
|
||||
unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, 0x7fff);
|
||||
unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), 0, 0x7fff);
|
||||
|
||||
addSpan(hf, x, y, ismin, ismax, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rcRasterizeTriangles(const float* bmin, const float* bmax, const float cs, const float ch,
|
||||
const float* verts, int nv,
|
||||
const int* tris, const unsigned char* flags, int nt,
|
||||
rcHeightfield& solid)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const float ics = 1.0f/cs;
|
||||
const float ich = 1.0f/ch;
|
||||
// Rasterize triangles.
|
||||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
const float* v0 = &verts[tris[i*3+0]*3];
|
||||
const float* v1 = &verts[tris[i*3+1]*3];
|
||||
const float* v2 = &verts[tris[i*3+2]*3];
|
||||
// Rasterize.
|
||||
rasterizeTri(v0, v1, v2, flags[i], solid, bmin, bmax, cs, ics, ich);
|
||||
}
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
|
||||
}
|
1037
Recast/Source/RecastRegion.cpp
Normal file
1037
Recast/Source/RecastRegion.cpp
Normal file
File diff suppressed because it is too large
Load Diff
43
Recast/Source/RecastTimer.cpp
Normal file
43
Recast/Source/RecastTimer.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "RecastTimer.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
rcTimeVal rcGetPerformanceTimer()
|
||||
{
|
||||
__int64 count;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
|
||||
{
|
||||
static __int64 freq = 0;
|
||||
if (freq == 0)
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
__int64 elapsed = end - start;
|
||||
return (int)(elapsed*1000000 / freq);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
|
||||
rcTimeVal rcGetPerformanceTimer()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
|
||||
{
|
||||
static mach_timebase_info_data_t timebaseInfo;
|
||||
if (timebaseInfo.denom == 0)
|
||||
mach_timebase_info(&timebaseInfo);
|
||||
uint64_t elapsed = end - start;
|
||||
uint64_t nanosec = elapsed * timebaseInfo.numer / timebaseInfo.denom;
|
||||
return (int)(nanosec / 1000);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user