├── .gitignore ├── Assets ├── Default_1mx1m.png ├── Default_1mx1m.png.import ├── Image_12.jpg ├── Image_12.jpg.import ├── Image_13.png ├── Image_13.png.import ├── Image_15.jpg ├── Image_15.jpg.import ├── Image_16.png ├── Image_16.png.import ├── Image_18.png ├── Image_18.png.import ├── Image_19.png ├── Image_19.png.import ├── Image_2.jpg ├── Image_2.jpg.import ├── Image_21.jpg ├── Image_21.jpg.import ├── Image_22.png ├── Image_22.png.import ├── Image_24.jpg ├── Image_24.jpg.import ├── Image_25.png ├── Image_25.png.import ├── Image_27.jpg ├── Image_27.jpg.import ├── Image_28.png ├── Image_28.png.import ├── Image_30.jpg ├── Image_30.jpg.import ├── Image_31.png ├── Image_31.png.import ├── Image_33.jpg ├── Image_33.jpg.import ├── Image_34.png ├── Image_34.png.import ├── Image_37.jpg ├── Image_37.jpg.import ├── Image_38.png ├── Image_38.png.import ├── Image_39.jpg ├── Image_39.jpg.import ├── Image_40.png ├── Image_40.png.import ├── Image_49.png ├── Image_49.png.import ├── Image_50.png ├── Image_50.png.import ├── Image_66.jpg ├── Image_66.jpg.import ├── Image_67.png ├── Image_67.png.import ├── Image_75.jpg ├── Image_75.jpg.import ├── Image_76.png ├── Image_76.png.import ├── asphalt_01_diff_4k.jpg ├── asphalt_01_diff_4k.jpg.import ├── grass.jpg ├── grass.jpg.import ├── gravel-ballast-roof-2500-mm-architextures.png └── gravel-ballast-roof-2500-mm-architextures.png.import ├── CameraEnvironment.tres ├── GUIMaterials ├── PressedButton.tres └── SelectedTensorField.tres ├── LICENSE ├── Materials ├── BuildingMaterial1.tres ├── BuildingMaterial10.tres ├── BuildingMaterial11.tres ├── BuildingMaterial2.tres ├── BuildingMaterial3.tres ├── BuildingMaterial4.tres ├── BuildingMaterial5.tres ├── BuildingMaterial6.tres ├── BuildingMaterial7.tres ├── BuildingMaterial8.tres ├── BuildingMaterial9.tres ├── BuildingRoofMaterial1.tres ├── FloorMaterial.tres ├── RoadMaterial1.tres └── SidewalkMaterial1.tres ├── Prefabs └── tensorFieldPoint.tscn ├── ProceduralCityGenerator.csproj ├── ProceduralCityGenerator.csproj.old ├── ProceduralCityGenerator.sln ├── ProceduralCityGenerator.sln.DotSettings.user ├── README.md ├── Scenes └── Main.tscn ├── Scripts ├── CameraController.cs ├── DataStructure │ ├── Field.cs │ ├── Grid.cs │ ├── GridStorage.cs │ ├── IPointDrawImmediate.cs │ ├── Integrator.cs │ ├── Intersection.cs │ ├── PolygonGenerator.cs │ ├── Radial.cs │ ├── Segment.cs │ ├── StreamLineIntegration.cs │ ├── StreamLines.cs │ ├── StreamLinesParams.cs │ ├── Tensor.cs │ └── TensorField.cs ├── GUI │ ├── GuiController.cs │ └── PropertiesPointsEdit.cs ├── LineDrawer3D.cs ├── MainBuildings3D.cs ├── MainRoads3D.cs ├── MainScript.cs ├── MainSidewalk3D.cs ├── PointDrawer3D.cs ├── RayCast3D.cs └── Roads.cs ├── default_env.tres ├── icon.png ├── icon.png.import └── project.godot /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/latex,godot,rider,visualstudiocode 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=latex,godot,rider,visualstudiocode 3 | 4 | ### Godot ### 5 | # Godot 4+ specific ignores 6 | .godot/ 7 | .idea/ 8 | 9 | # Godot-specific ignores 10 | .import/ 11 | export.cfg 12 | export_presets.cfg 13 | 14 | # Imported translations (automatically generated from CSV files) 15 | *.translation 16 | 17 | # Mono-specific ignores 18 | .mono/ 19 | data_*/ 20 | mono_crash.*.json 21 | 22 | ### LaTeX ### 23 | ## Core latex/pdflatex auxiliary files: 24 | *.aux 25 | *.lof 26 | *.log 27 | *.lot 28 | *.fls 29 | *.out 30 | *.toc 31 | *.fmt 32 | *.fot 33 | *.cb 34 | *.cb2 35 | .*.lb 36 | 37 | ## Intermediate documents: 38 | *.dvi 39 | *.xdv 40 | *-converted-to.* 41 | # these rules might exclude image files for figures etc. 42 | # *.ps 43 | # *.eps 44 | # *.pdf 45 | 46 | ## Generated if empty string is given at "Please type another file name for output:" 47 | .pdf 48 | 49 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 50 | *.bbl 51 | *.bcf 52 | *.blg 53 | *-blx.aux 54 | *-blx.bib 55 | *.run.xml 56 | 57 | ## Build tool auxiliary files: 58 | *.fdb_latexmk 59 | *.synctex 60 | *.synctex(busy) 61 | *.synctex.gz 62 | *.synctex.gz(busy) 63 | *.pdfsync 64 | 65 | ## Build tool directories for auxiliary files 66 | # latexrun 67 | latex.out/ 68 | 69 | ## Auxiliary and intermediate files from other packages: 70 | # algorithms 71 | *.alg 72 | *.loa 73 | 74 | # achemso 75 | acs-*.bib 76 | 77 | # amsthm 78 | *.thm 79 | 80 | # beamer 81 | *.nav 82 | *.pre 83 | *.snm 84 | *.vrb 85 | 86 | # changes 87 | *.soc 88 | 89 | # comment 90 | *.cut 91 | 92 | # cprotect 93 | *.cpt 94 | 95 | # elsarticle (documentclass of Elsevier journals) 96 | *.spl 97 | 98 | # endnotes 99 | *.ent 100 | 101 | # fixme 102 | *.lox 103 | 104 | # feynmf/feynmp 105 | *.mf 106 | *.mp 107 | *.t[1-9] 108 | *.t[1-9][0-9] 109 | *.tfm 110 | 111 | #(r)(e)ledmac/(r)(e)ledpar 112 | *.end 113 | *.?end 114 | *.[1-9] 115 | *.[1-9][0-9] 116 | *.[1-9][0-9][0-9] 117 | *.[1-9]R 118 | *.[1-9][0-9]R 119 | *.[1-9][0-9][0-9]R 120 | *.eledsec[1-9] 121 | *.eledsec[1-9]R 122 | *.eledsec[1-9][0-9] 123 | *.eledsec[1-9][0-9]R 124 | *.eledsec[1-9][0-9][0-9] 125 | *.eledsec[1-9][0-9][0-9]R 126 | 127 | # glossaries 128 | *.acn 129 | *.acr 130 | *.glg 131 | *.glo 132 | *.gls 133 | *.glsdefs 134 | *.lzo 135 | *.lzs 136 | *.slg 137 | *.slo 138 | *.sls 139 | 140 | # uncomment this for glossaries-extra (will ignore makeindex's style files!) 141 | # *.ist 142 | 143 | # gnuplot 144 | *.gnuplot 145 | *.table 146 | 147 | # gnuplottex 148 | *-gnuplottex-* 149 | 150 | # gregoriotex 151 | *.gaux 152 | *.glog 153 | *.gtex 154 | 155 | # htlatex 156 | *.4ct 157 | *.4tc 158 | *.idv 159 | *.lg 160 | *.trc 161 | *.xref 162 | 163 | # hyperref 164 | *.brf 165 | 166 | # knitr 167 | *-concordance.tex 168 | # TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files 169 | # *.tikz 170 | *-tikzDictionary 171 | 172 | # listings 173 | *.lol 174 | 175 | # luatexja-ruby 176 | *.ltjruby 177 | 178 | # makeidx 179 | *.idx 180 | *.ilg 181 | *.ind 182 | 183 | # minitoc 184 | *.maf 185 | *.mlf 186 | *.mlt 187 | *.mtc[0-9]* 188 | *.slf[0-9]* 189 | *.slt[0-9]* 190 | *.stc[0-9]* 191 | 192 | # minted 193 | _minted* 194 | *.pyg 195 | 196 | # morewrites 197 | *.mw 198 | 199 | # newpax 200 | *.newpax 201 | 202 | # nomencl 203 | *.nlg 204 | *.nlo 205 | *.nls 206 | 207 | # pax 208 | *.pax 209 | 210 | # pdfpcnotes 211 | *.pdfpc 212 | 213 | # sagetex 214 | *.sagetex.sage 215 | *.sagetex.py 216 | *.sagetex.scmd 217 | 218 | # scrwfile 219 | *.wrt 220 | 221 | # svg 222 | svg-inkscape/ 223 | 224 | # sympy 225 | *.sout 226 | *.sympy 227 | sympy-plots-for-*.tex/ 228 | 229 | # pdfcomment 230 | *.upa 231 | *.upb 232 | 233 | # pythontex 234 | *.pytxcode 235 | pythontex-files-*/ 236 | 237 | # tcolorbox 238 | *.listing 239 | 240 | # thmtools 241 | *.loe 242 | 243 | # TikZ & PGF 244 | *.dpth 245 | *.md5 246 | *.auxlock 247 | 248 | # titletoc 249 | *.ptc 250 | 251 | # todonotes 252 | *.tdo 253 | 254 | # vhistory 255 | *.hst 256 | *.ver 257 | 258 | # easy-todo 259 | *.lod 260 | 261 | # xcolor 262 | *.xcp 263 | 264 | # xmpincl 265 | *.xmpi 266 | 267 | # xindy 268 | *.xdy 269 | 270 | # xypic precompiled matrices and outlines 271 | *.xyc 272 | *.xyd 273 | 274 | # endfloat 275 | *.ttt 276 | *.fff 277 | 278 | # Latexian 279 | TSWLatexianTemp* 280 | 281 | ## Editors: 282 | # WinEdt 283 | *.bak 284 | *.sav 285 | 286 | # Texpad 287 | .texpadtmp 288 | 289 | # LyX 290 | *.lyx~ 291 | 292 | # Kile 293 | *.backup 294 | 295 | # gummi 296 | .*.swp 297 | 298 | # KBibTeX 299 | *~[0-9]* 300 | 301 | # TeXnicCenter 302 | *.tps 303 | 304 | # auto folder when using emacs and auctex 305 | ./auto/* 306 | *.el 307 | 308 | # expex forward references with \gathertags 309 | *-tags.tex 310 | 311 | # standalone packages 312 | *.sta 313 | 314 | # Makeindex log files 315 | *.lpz 316 | 317 | # xwatermark package 318 | *.xwm 319 | 320 | # REVTeX puts footnotes in the bibliography by default, unless the nofootinbib 321 | # option is specified. Footnotes are the stored in a file with suffix Notes.bib. 322 | # Uncomment the next line to have this generated file ignored. 323 | #*Notes.bib 324 | 325 | ### LaTeX Patch ### 326 | # LIPIcs / OASIcs 327 | *.vtc 328 | 329 | # glossaries 330 | *.glstex 331 | 332 | ### Rider ### 333 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 334 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 335 | 336 | # User-specific stuff 337 | .idea/**/workspace.xml 338 | .idea/**/tasks.xml 339 | .idea/**/usage.statistics.xml 340 | .idea/**/dictionaries 341 | .idea/**/shelf 342 | 343 | # AWS User-specific 344 | .idea/**/aws.xml 345 | 346 | # Generated files 347 | .idea/**/contentModel.xml 348 | 349 | # Sensitive or high-churn files 350 | .idea/**/dataSources/ 351 | .idea/**/dataSources.ids 352 | .idea/**/dataSources.local.xml 353 | .idea/**/sqlDataSources.xml 354 | .idea/**/dynamic.xml 355 | .idea/**/uiDesigner.xml 356 | .idea/**/dbnavigator.xml 357 | 358 | # Gradle 359 | .idea/**/gradle.xml 360 | .idea/**/libraries 361 | 362 | # Gradle and Maven with auto-import 363 | # When using Gradle or Maven with auto-import, you should exclude module files, 364 | # since they will be recreated, and may cause churn. Uncomment if using 365 | # auto-import. 366 | # .idea/artifacts 367 | # .idea/compiler.xml 368 | # .idea/jarRepositories.xml 369 | # .idea/modules.xml 370 | # .idea/*.iml 371 | # .idea/modules 372 | # *.iml 373 | # *.ipr 374 | 375 | # CMake 376 | cmake-build-*/ 377 | 378 | # Mongo Explorer plugin 379 | .idea/**/mongoSettings.xml 380 | 381 | # File-based project format 382 | *.iws 383 | 384 | # IntelliJ 385 | out/ 386 | 387 | # mpeltonen/sbt-idea plugin 388 | .idea_modules/ 389 | 390 | # JIRA plugin 391 | atlassian-ide-plugin.xml 392 | 393 | # Cursive Clojure plugin 394 | .idea/replstate.xml 395 | 396 | # SonarLint plugin 397 | .idea/sonarlint/ 398 | 399 | # Crashlytics plugin (for Android Studio and IntelliJ) 400 | com_crashlytics_export_strings.xml 401 | crashlytics.properties 402 | crashlytics-build.properties 403 | fabric.properties 404 | 405 | # Editor-based Rest Client 406 | .idea/httpRequests 407 | 408 | # Android studio 3.1+ serialized cache file 409 | .idea/caches/build_file_checksums.ser 410 | 411 | ### VisualStudioCode ### 412 | .vscode/* 413 | !.vscode/settings.json 414 | !.vscode/tasks.json 415 | !.vscode/launch.json 416 | !.vscode/extensions.json 417 | !.vscode/*.code-snippets 418 | 419 | # Local History for Visual Studio Code 420 | .history/ 421 | 422 | # Built Visual Studio Code Extensions 423 | *.vsix 424 | 425 | ### VisualStudioCode Patch ### 426 | # Ignore all local history of files 427 | .history 428 | .ionide 429 | 430 | .directory 431 | 432 | # End of https://www.toptal.com/developers/gitignore/api/latex,godot,rider,visualstudiocode 433 | 434 | -------------------------------------------------------------------------------- /Assets/Default_1mx1m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Default_1mx1m.png -------------------------------------------------------------------------------- /Assets/Default_1mx1m.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dlaaf5sxco1rv" 6 | path.s3tc="res://.godot/imported/Default_1mx1m.png-08571233490fe6dab753208cba39c918.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Default_1mx1m.png" 15 | dest_files=["res://.godot/imported/Default_1mx1m.png-08571233490fe6dab753208cba39c918.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_12.jpg -------------------------------------------------------------------------------- /Assets/Image_12.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dlr1xsa17w7mm" 6 | path.s3tc="res://.godot/imported/Image_12.jpg-3394c66cba0a001614ae414fb6f31ca8.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_12.jpg" 15 | dest_files=["res://.godot/imported/Image_12.jpg-3394c66cba0a001614ae414fb6f31ca8.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_13.png -------------------------------------------------------------------------------- /Assets/Image_13.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cefjkxahm2dqn" 6 | path.s3tc="res://.godot/imported/Image_13.png-5c7c3884f3b30ae12c3f764c7f327de1.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_13.png" 15 | dest_files=["res://.godot/imported/Image_13.png-5c7c3884f3b30ae12c3f764c7f327de1.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_13.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_15.jpg -------------------------------------------------------------------------------- /Assets/Image_15.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dw7h7q8f5emdx" 6 | path.s3tc="res://.godot/imported/Image_15.jpg-302b22144e7b610a0c193d9fbef9231b.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_15.jpg" 15 | dest_files=["res://.godot/imported/Image_15.jpg-302b22144e7b610a0c193d9fbef9231b.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_16.png -------------------------------------------------------------------------------- /Assets/Image_16.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b4qx2qwwlt0yl" 6 | path.s3tc="res://.godot/imported/Image_16.png-ee89cc02e05d1135431961911a70966f.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_16.png" 15 | dest_files=["res://.godot/imported/Image_16.png-ee89cc02e05d1135431961911a70966f.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_16.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_18.png -------------------------------------------------------------------------------- /Assets/Image_18.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cy2fo3gqj6xxs" 6 | path.s3tc="res://.godot/imported/Image_18.png-d6e983d72d9c6fcfaacb8b3a4285e47f.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_18.png" 15 | dest_files=["res://.godot/imported/Image_18.png-d6e983d72d9c6fcfaacb8b3a4285e47f.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_19.png -------------------------------------------------------------------------------- /Assets/Image_19.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bhyll7idn30gw" 6 | path.s3tc="res://.godot/imported/Image_19.png-d6227919b829e88eb60dd469557c93da.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_19.png" 15 | dest_files=["res://.godot/imported/Image_19.png-d6227919b829e88eb60dd469557c93da.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_19.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_2.jpg -------------------------------------------------------------------------------- /Assets/Image_2.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://crohtkl2ogb3t" 6 | path.s3tc="res://.godot/imported/Image_2.jpg-dcc35e2d8ad35228526c226ec9473e78.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_2.jpg" 15 | dest_files=["res://.godot/imported/Image_2.jpg-dcc35e2d8ad35228526c226ec9473e78.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_21.jpg -------------------------------------------------------------------------------- /Assets/Image_21.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dbyb2qf6lrmog" 6 | path.s3tc="res://.godot/imported/Image_21.jpg-6ef58dcde23e8955497cd0c1b45add79.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_21.jpg" 15 | dest_files=["res://.godot/imported/Image_21.jpg-6ef58dcde23e8955497cd0c1b45add79.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_22.png -------------------------------------------------------------------------------- /Assets/Image_22.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bge1yem0n6xue" 6 | path.s3tc="res://.godot/imported/Image_22.png-21de3775cf8271eb8f4fc72bf788f60e.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_22.png" 15 | dest_files=["res://.godot/imported/Image_22.png-21de3775cf8271eb8f4fc72bf788f60e.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_24.jpg -------------------------------------------------------------------------------- /Assets/Image_24.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bdqvjxtybdc7j" 6 | path.s3tc="res://.godot/imported/Image_24.jpg-3c3037fd6d7ddced0b29bdcd85519974.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_24.jpg" 15 | dest_files=["res://.godot/imported/Image_24.jpg-3c3037fd6d7ddced0b29bdcd85519974.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_25.png -------------------------------------------------------------------------------- /Assets/Image_25.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dr7qt8s3tjanf" 6 | path.s3tc="res://.godot/imported/Image_25.png-d73b92c919fab1cb393df01527454794.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_25.png" 15 | dest_files=["res://.godot/imported/Image_25.png-d73b92c919fab1cb393df01527454794.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_25.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_27.jpg -------------------------------------------------------------------------------- /Assets/Image_27.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://e76xhy7kdb6n" 6 | path.s3tc="res://.godot/imported/Image_27.jpg-1df22abbada51efeb4e7954ed50006ac.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_27.jpg" 15 | dest_files=["res://.godot/imported/Image_27.jpg-1df22abbada51efeb4e7954ed50006ac.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_28.png -------------------------------------------------------------------------------- /Assets/Image_28.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://blamqi6hfwsn8" 6 | path.s3tc="res://.godot/imported/Image_28.png-f29b715eb86537648b9a5e71bdf56efd.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_28.png" 15 | dest_files=["res://.godot/imported/Image_28.png-f29b715eb86537648b9a5e71bdf56efd.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_28.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_30.jpg -------------------------------------------------------------------------------- /Assets/Image_30.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cxkpy86hriclc" 6 | path.s3tc="res://.godot/imported/Image_30.jpg-7738c2e489a74e4cd21ed531e550b18c.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_30.jpg" 15 | dest_files=["res://.godot/imported/Image_30.jpg-7738c2e489a74e4cd21ed531e550b18c.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_31.png -------------------------------------------------------------------------------- /Assets/Image_31.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b266paove0s0r" 6 | path.s3tc="res://.godot/imported/Image_31.png-ed3cf00432eac89b80519c837f0ddf51.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_31.png" 15 | dest_files=["res://.godot/imported/Image_31.png-ed3cf00432eac89b80519c837f0ddf51.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_31.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_33.jpg -------------------------------------------------------------------------------- /Assets/Image_33.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b3ls7cf1wj7yl" 6 | path.s3tc="res://.godot/imported/Image_33.jpg-2c72f29f3c16118ef47fe06b179f60b3.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_33.jpg" 15 | dest_files=["res://.godot/imported/Image_33.jpg-2c72f29f3c16118ef47fe06b179f60b3.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_34.png -------------------------------------------------------------------------------- /Assets/Image_34.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dkse7h6mt8f4o" 6 | path.s3tc="res://.godot/imported/Image_34.png-472f0d4fd1e86be25bef9382b7ed8e19.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_34.png" 15 | dest_files=["res://.godot/imported/Image_34.png-472f0d4fd1e86be25bef9382b7ed8e19.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_34.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_37.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_37.jpg -------------------------------------------------------------------------------- /Assets/Image_37.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cvaiir664f3no" 6 | path.s3tc="res://.godot/imported/Image_37.jpg-33b19aece053f499264d5b313a72ab69.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_37.jpg" 15 | dest_files=["res://.godot/imported/Image_37.jpg-33b19aece053f499264d5b313a72ab69.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_38.png -------------------------------------------------------------------------------- /Assets/Image_38.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bgbma1mouwl4w" 6 | path.s3tc="res://.godot/imported/Image_38.png-a5f72e9c84b9c0c9f286f9d100e41f4e.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_38.png" 15 | dest_files=["res://.godot/imported/Image_38.png-a5f72e9c84b9c0c9f286f9d100e41f4e.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_38.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_39.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_39.jpg -------------------------------------------------------------------------------- /Assets/Image_39.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c6jsm27bkpne0" 6 | path.s3tc="res://.godot/imported/Image_39.jpg-083066ced67afa4f6c242333f400d2c8.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_39.jpg" 15 | dest_files=["res://.godot/imported/Image_39.jpg-083066ced67afa4f6c242333f400d2c8.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_40.png -------------------------------------------------------------------------------- /Assets/Image_40.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dnccvrcak1a7b" 6 | path.s3tc="res://.godot/imported/Image_40.png-bcdde4d2e5870daff2934ee4165c882c.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_40.png" 15 | dest_files=["res://.godot/imported/Image_40.png-bcdde4d2e5870daff2934ee4165c882c.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_40.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_49.png -------------------------------------------------------------------------------- /Assets/Image_49.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bhgo1ocdgu58d" 6 | path.s3tc="res://.godot/imported/Image_49.png-7a65d831ee4691c39ffc426d75771fcf.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_49.png" 15 | dest_files=["res://.godot/imported/Image_49.png-7a65d831ee4691c39ffc426d75771fcf.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_50.png -------------------------------------------------------------------------------- /Assets/Image_50.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cu00hhhpe6r1c" 6 | path="res://.godot/imported/Image_50.png-bb238a2a7b8f1086475a94f5152853fe.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://Assets/Image_50.png" 14 | dest_files=["res://.godot/imported/Image_50.png-bb238a2a7b8f1086475a94f5152853fe.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /Assets/Image_66.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_66.jpg -------------------------------------------------------------------------------- /Assets/Image_66.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://xpc42yi268y2" 6 | path.s3tc="res://.godot/imported/Image_66.jpg-4d1140a7aba3191d9008ef9f15cb4b4c.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_66.jpg" 15 | dest_files=["res://.godot/imported/Image_66.jpg-4d1140a7aba3191d9008ef9f15cb4b4c.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_67.png -------------------------------------------------------------------------------- /Assets/Image_67.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://csc3a12il6mxm" 6 | path.s3tc="res://.godot/imported/Image_67.png-091c4a8ea2d68f140cf26b8caa4c3ee8.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_67.png" 15 | dest_files=["res://.godot/imported/Image_67.png-091c4a8ea2d68f140cf26b8caa4c3ee8.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_67.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_75.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_75.jpg -------------------------------------------------------------------------------- /Assets/Image_75.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://828yxtcifo2k" 6 | path.s3tc="res://.godot/imported/Image_75.jpg-d4754d8fb7865d0b2d39599dee616ce8.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_75.jpg" 15 | dest_files=["res://.godot/imported/Image_75.jpg-d4754d8fb7865d0b2d39599dee616ce8.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/Image_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/Image_76.png -------------------------------------------------------------------------------- /Assets/Image_76.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cdjik05nthfl4" 6 | path.s3tc="res://.godot/imported/Image_76.png-befd6311a8f0f3dcd9aebdfd5d984466.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/Image_76.png" 15 | dest_files=["res://.godot/imported/Image_76.png-befd6311a8f0f3dcd9aebdfd5d984466.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=1 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=1 28 | roughness/src_normal="res://Assets/Image_76.png" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/asphalt_01_diff_4k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/asphalt_01_diff_4k.jpg -------------------------------------------------------------------------------- /Assets/asphalt_01_diff_4k.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://demk5w3bmixwx" 6 | path.s3tc="res://.godot/imported/asphalt_01_diff_4k.jpg-ff95bc701e80208ec2b23d6c05989254.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/asphalt_01_diff_4k.jpg" 15 | dest_files=["res://.godot/imported/asphalt_01_diff_4k.jpg-ff95bc701e80208ec2b23d6c05989254.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/grass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/grass.jpg -------------------------------------------------------------------------------- /Assets/grass.jpg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b6x4orqnfp2q6" 6 | path.s3tc="res://.godot/imported/grass.jpg-a807c661017f5cb8ef8de151216c8350.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/grass.jpg" 15 | dest_files=["res://.godot/imported/grass.jpg-a807c661017f5cb8ef8de151216c8350.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /Assets/gravel-ballast-roof-2500-mm-architextures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/Assets/gravel-ballast-roof-2500-mm-architextures.png -------------------------------------------------------------------------------- /Assets/gravel-ballast-roof-2500-mm-architextures.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c76iuhm3exgdf" 6 | path.s3tc="res://.godot/imported/gravel-ballast-roof-2500-mm-architextures.png-6ab1251242678878951030f21b428b05.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://Assets/gravel-ballast-roof-2500-mm-architextures.png" 15 | dest_files=["res://.godot/imported/gravel-ballast-roof-2500-mm-architextures.png-6ab1251242678878951030f21b428b05.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /CameraEnvironment.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=3 format=3 uid="uid://6fklvphu014u"] 2 | 3 | [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_bto4x"] 4 | 5 | [sub_resource type="Sky" id="Sky_ge24j"] 6 | sky_material = SubResource("ProceduralSkyMaterial_bto4x") 7 | 8 | [resource] 9 | background_mode = 2 10 | background_energy_multiplier = 1.2 11 | sky = SubResource("Sky_ge24j") 12 | ambient_light_source = 3 13 | ambient_light_color = Color(0, 0.501961, 0.952941, 1) 14 | ssao_horizon = 0.79 15 | ssil_enabled = true 16 | sdfgi_enabled = true 17 | sdfgi_use_occlusion = true 18 | fog_light_color = Color(0.172549, 0.576471, 0.870588, 1) 19 | fog_density = 0.005 20 | volumetric_fog_enabled = true 21 | volumetric_fog_density = 0.02 22 | -------------------------------------------------------------------------------- /GUIMaterials/PressedButton.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxFlat" format=3 uid="uid://d385yneucsjb5"] 2 | 3 | [resource] 4 | bg_color = Color(0.117647, 0.619608, 1, 1) 5 | border_width_left = 4 6 | border_width_top = 4 7 | border_width_right = 4 8 | border_width_bottom = 4 9 | -------------------------------------------------------------------------------- /GUIMaterials/SelectedTensorField.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxFlat" format=3 uid="uid://khqvj7h7agu1"] 2 | 3 | [resource] 4 | bg_color = Color(0.317647, 0.694118, 0.392157, 1) 5 | border_width_left = 4 6 | border_width_top = 4 7 | border_width_right = 4 8 | border_width_bottom = 4 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial1.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://dlpsns3f767fm"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://cxkpy86hriclc" path="res://Assets/Image_30.jpg" id="1_fvxkf"] 4 | [ext_resource type="Texture2D" uid="uid://b266paove0s0r" path="res://Assets/Image_31.png" id="2_mk312"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_fvxkf") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_mk312") 11 | uv1_scale = Vector3(1.5, 6, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial10.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://by6d738i8uuhc"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://xpc42yi268y2" path="res://Assets/Image_66.jpg" id="1_fjewj"] 4 | [ext_resource type="Texture2D" uid="uid://csc3a12il6mxm" path="res://Assets/Image_67.png" id="2_8u0e1"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_fjewj") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_8u0e1") 11 | uv1_scale = Vector3(2, 7, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial11.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://byevgk7f5k71v"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://828yxtcifo2k" path="res://Assets/Image_75.jpg" id="1_qor1q"] 4 | [ext_resource type="Texture2D" uid="uid://cdjik05nthfl4" path="res://Assets/Image_76.png" id="2_i0xip"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_qor1q") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_i0xip") 11 | uv1_scale = Vector3(2, 7, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial2.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://io6h7j2xgfql"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b3ls7cf1wj7yl" path="res://Assets/Image_33.jpg" id="1_4a687"] 4 | [ext_resource type="Texture2D" uid="uid://dkse7h6mt8f4o" path="res://Assets/Image_34.png" id="2_sua56"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_4a687") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_sua56") 11 | uv1_scale = Vector3(3, 7, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial3.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://qyefq5uofu1b"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://c6jsm27bkpne0" path="res://Assets/Image_39.jpg" id="1_gc3ft"] 4 | [ext_resource type="Texture2D" uid="uid://dnccvrcak1a7b" path="res://Assets/Image_40.png" id="2_1lyto"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_gc3ft") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_1lyto") 11 | uv1_scale = Vector3(2, 8, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial4.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://bcatyh4wyy4qv"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://dlr1xsa17w7mm" path="res://Assets/Image_12.jpg" id="1_jw0s2"] 4 | [ext_resource type="Texture2D" uid="uid://cefjkxahm2dqn" path="res://Assets/Image_13.png" id="2_0crm6"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_jw0s2") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_0crm6") 11 | uv1_scale = Vector3(2, 12, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial5.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://d1cf36ct3xc3b"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://dw7h7q8f5emdx" path="res://Assets/Image_15.jpg" id="1_egisv"] 4 | [ext_resource type="Texture2D" uid="uid://b4qx2qwwlt0yl" path="res://Assets/Image_16.png" id="2_4jhrl"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_egisv") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_4jhrl") 11 | uv1_scale = Vector3(2, 7, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial6.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://c7ni8ykuhulic"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://cy2fo3gqj6xxs" path="res://Assets/Image_18.png" id="1_hqxsj"] 4 | [ext_resource type="Texture2D" uid="uid://bhyll7idn30gw" path="res://Assets/Image_19.png" id="2_wgmis"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_hqxsj") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_wgmis") 11 | uv1_scale = Vector3(2, 8, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial7.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://b6nn5mgt5rph4"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://dbyb2qf6lrmog" path="res://Assets/Image_21.jpg" id="1_3r5at"] 4 | [ext_resource type="Texture2D" uid="uid://bge1yem0n6xue" path="res://Assets/Image_22.png" id="2_rrmev"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_3r5at") 8 | normal_enabled = true 9 | normal_texture = ExtResource("2_rrmev") 10 | uv1_scale = Vector3(2.5, 7, 1) 11 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial8.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://b226obygdsjg4"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://bdqvjxtybdc7j" path="res://Assets/Image_24.jpg" id="1_p2pyk"] 4 | [ext_resource type="Texture2D" uid="uid://dr7qt8s3tjanf" path="res://Assets/Image_25.png" id="2_4by32"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_p2pyk") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_4by32") 11 | uv1_scale = Vector3(2, 5, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingMaterial9.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cdphh522k3dwd"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://e76xhy7kdb6n" path="res://Assets/Image_27.jpg" id="1_tp6mk"] 4 | [ext_resource type="Texture2D" uid="uid://blamqi6hfwsn8" path="res://Assets/Image_28.png" id="2_yfden"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_tp6mk") 8 | metallic_specular = 0.0 9 | normal_enabled = true 10 | normal_texture = ExtResource("2_yfden") 11 | uv1_scale = Vector3(2, 7, 1) 12 | -------------------------------------------------------------------------------- /Materials/BuildingRoofMaterial1.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bhurd24vqoyu5"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://c76iuhm3exgdf" path="res://Assets/gravel-ballast-roof-2500-mm-architextures.png" id="1_wogmt"] 4 | 5 | [resource] 6 | albedo_texture = ExtResource("1_wogmt") 7 | uv1_scale = Vector3(10, 10, 1) 8 | -------------------------------------------------------------------------------- /Materials/FloorMaterial.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dop7fuh6lrt1o"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b6x4orqnfp2q6" path="res://Assets/grass.jpg" id="1_ebr5b"] 4 | 5 | [resource] 6 | albedo_color = Color(0, 0.678431, 0.215686, 1) 7 | albedo_texture = ExtResource("1_ebr5b") 8 | metallic_specular = 0.0 9 | uv1_scale = Vector3(20, 20, 1) 10 | -------------------------------------------------------------------------------- /Materials/RoadMaterial1.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dj4mb4w8fyjx6"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://demk5w3bmixwx" path="res://Assets/asphalt_01_diff_4k.jpg" id="1_mlgm3"] 4 | 5 | [resource] 6 | albedo_texture = ExtResource("1_mlgm3") 7 | metallic_specular = 0.0 8 | texture_filter = 1 9 | -------------------------------------------------------------------------------- /Materials/SidewalkMaterial1.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://c8yleok4yc5fy"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://cvaiir664f3no" path="res://Assets/Image_37.jpg" id="1_lieoa"] 4 | [ext_resource type="Texture2D" uid="uid://bgbma1mouwl4w" path="res://Assets/Image_38.png" id="2_vev34"] 5 | 6 | [resource] 7 | albedo_texture = ExtResource("1_lieoa") 8 | normal_enabled = true 9 | normal_texture = ExtResource("2_vev34") 10 | uv1_scale = Vector3(10, 10, 1) 11 | -------------------------------------------------------------------------------- /Prefabs/tensorFieldPoint.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://c34d65rdo2d2f"] 2 | 3 | [ext_resource type="Script" path="res://Scripts/GUI/PropertiesPointsEdit.cs" id="1_4f8lx"] 4 | [ext_resource type="StyleBox" uid="uid://d385yneucsjb5" path="res://GUIMaterials/PressedButton.tres" id="2_c6q1d"] 5 | [ext_resource type="StyleBox" uid="uid://khqvj7h7agu1" path="res://GUIMaterials/SelectedTensorField.tres" id="3_xobsu"] 6 | 7 | [node name="Point" type="VBoxContainer" node_paths=PackedStringArray("pointButton", "removeButton", "tensorPropertiesContainer", "sliderSize", "textEditSize", "angleEditContainer", "sliderAngle", "textEditAngle", "sliderDecay", "textEditDecay")] 8 | offset_right = 49.0 9 | offset_bottom = 31.0 10 | size_flags_horizontal = 3 11 | script = ExtResource("1_4f8lx") 12 | _selectedStyle = ExtResource("3_xobsu") 13 | _unselectedStyle = ExtResource("2_c6q1d") 14 | pointButton = NodePath("HBoxContainer/PointButton") 15 | removeButton = NodePath("HBoxContainer/Remove") 16 | tensorPropertiesContainer = NodePath("Properties") 17 | sliderSize = NodePath("Properties/SizeContainerProperties/HBoxContainer/HSlider") 18 | textEditSize = NodePath("Properties/SizeContainerProperties/HBoxContainer/LineEdit") 19 | angleEditContainer = NodePath("Properties/AngleContainerProperties") 20 | sliderAngle = NodePath("Properties/AngleContainerProperties/HBoxContainer2/HSlider") 21 | textEditAngle = NodePath("Properties/AngleContainerProperties/HBoxContainer2/LineEdit") 22 | sliderDecay = NodePath("Properties/DecayContainerProperties/HBoxContainer3/HSlider") 23 | textEditDecay = NodePath("Properties/DecayContainerProperties/HBoxContainer3/LineEdit") 24 | 25 | [node name="HBoxContainer" type="HBoxContainer" parent="."] 26 | layout_mode = 2 27 | 28 | [node name="PointButton" type="Button" parent="HBoxContainer"] 29 | layout_mode = 2 30 | size_flags_horizontal = 3 31 | focus_mode = 0 32 | theme_override_styles/pressed = ExtResource("2_c6q1d") 33 | toggle_mode = true 34 | text = "Point" 35 | 36 | [node name="Remove" type="Button" parent="HBoxContainer"] 37 | visible = false 38 | layout_mode = 2 39 | focus_mode = 0 40 | text = "Remove" 41 | 42 | [node name="Properties" type="VBoxContainer" parent="."] 43 | visible = false 44 | layout_mode = 2 45 | 46 | [node name="SizeContainerProperties" type="VBoxContainer" parent="Properties"] 47 | layout_mode = 2 48 | 49 | [node name="Label2" type="Label" parent="Properties/SizeContainerProperties"] 50 | layout_mode = 2 51 | theme_override_font_sizes/font_size = 14 52 | text = "Size" 53 | vertical_alignment = 2 54 | 55 | [node name="HBoxContainer" type="HBoxContainer" parent="Properties/SizeContainerProperties"] 56 | layout_mode = 2 57 | 58 | [node name="LineEdit" type="LineEdit" parent="Properties/SizeContainerProperties/HBoxContainer"] 59 | layout_mode = 2 60 | focus_mode = 1 61 | theme_override_constants/minimum_character_width = 3 62 | text = "5" 63 | max_length = 4 64 | caret_blink = true 65 | 66 | [node name="HSlider" type="HSlider" parent="Properties/SizeContainerProperties/HBoxContainer"] 67 | custom_minimum_size = Vector2(100, 0) 68 | layout_mode = 2 69 | size_flags_horizontal = 3 70 | size_flags_vertical = 4 71 | focus_mode = 0 72 | max_value = 20.0 73 | step = 0.5 74 | value = 5.0 75 | 76 | [node name="AngleContainerProperties" type="VBoxContainer" parent="Properties"] 77 | layout_mode = 2 78 | 79 | [node name="Label3" type="Label" parent="Properties/AngleContainerProperties"] 80 | layout_mode = 2 81 | theme_override_font_sizes/font_size = 14 82 | text = "Angle" 83 | vertical_alignment = 2 84 | 85 | [node name="HBoxContainer2" type="HBoxContainer" parent="Properties/AngleContainerProperties"] 86 | layout_mode = 2 87 | 88 | [node name="LineEdit" type="LineEdit" parent="Properties/AngleContainerProperties/HBoxContainer2"] 89 | layout_mode = 2 90 | focus_mode = 1 91 | theme_override_constants/minimum_character_width = 3 92 | text = "45" 93 | max_length = 3 94 | caret_blink = true 95 | 96 | [node name="HSlider" type="HSlider" parent="Properties/AngleContainerProperties/HBoxContainer2"] 97 | custom_minimum_size = Vector2(100, 0) 98 | layout_mode = 2 99 | size_flags_horizontal = 3 100 | size_flags_vertical = 4 101 | focus_mode = 0 102 | max_value = 360.0 103 | step = 0.5 104 | value = 45.0 105 | 106 | [node name="DecayContainerProperties" type="VBoxContainer" parent="Properties"] 107 | layout_mode = 2 108 | 109 | [node name="Label4" type="Label" parent="Properties/DecayContainerProperties"] 110 | layout_mode = 2 111 | theme_override_font_sizes/font_size = 14 112 | text = "Decay" 113 | vertical_alignment = 2 114 | 115 | [node name="HBoxContainer3" type="HBoxContainer" parent="Properties/DecayContainerProperties"] 116 | layout_mode = 2 117 | 118 | [node name="LineEdit" type="LineEdit" parent="Properties/DecayContainerProperties/HBoxContainer3"] 119 | layout_mode = 2 120 | focus_mode = 1 121 | theme_override_constants/minimum_character_width = 3 122 | text = "2" 123 | max_length = 4 124 | caret_blink = true 125 | 126 | [node name="HSlider" type="HSlider" parent="Properties/DecayContainerProperties/HBoxContainer3"] 127 | custom_minimum_size = Vector2(100, 0) 128 | layout_mode = 2 129 | size_flags_horizontal = 3 130 | size_flags_vertical = 4 131 | focus_mode = 0 132 | min_value = -1.0 133 | max_value = 25.0 134 | value = 2.0 135 | -------------------------------------------------------------------------------- /ProceduralCityGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ProceduralCityGenerator.csproj.old: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | 6 | -------------------------------------------------------------------------------- /ProceduralCityGenerator.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProceduralCityGenerator", "ProceduralCityGenerator.csproj", "{38E7DFD8-1E42-49A2-861F-BABAD9384DE5}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | ExportDebug|Any CPU = ExportDebug|Any CPU 9 | ExportRelease|Any CPU = ExportRelease|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU 15 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU 16 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU 17 | {38E7DFD8-1E42-49A2-861F-BABAD9384DE5}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /ProceduralCityGenerator.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 |  2 | <AssemblyExplorer> 3 | <Assembly Path="/home/carl0scheca/.local/share/godot/mono/GodotNuGetFallbackFolder/godotsharp/4.0.0/lib/net6.0/GodotSharp.dll" /> 4 | </AssemblyExplorer> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Procedural City Generator 2 | 3 | Demo https://www.youtube.com/watch?v=61dwd36fJaE 4 | 5 | This project was developed using Godot. The most recent version of the code has been tested and verified to function properly with Godot Mono 4.2.1. 6 | 7 | This project was developed as part of my Bachelor's Degree Final Project. It was inspired by https://probabletrain.itch.io/city-generator and is based on Chen, Guoning & Esch, Gregory & Wonka, Peter & Müller, Pascal & Zhang, Eugene. (2008). Interactive Procedural Street Modeling. ACM Trans. Graph.. 27. 10.1145/1399504.1360702. 8 | 9 | You can download and try it from the [releases page](https://github.com/Carl0sCheca/Procedural-City-Generator-Godot/releases/tag/v1.0). 10 | 11 | Feel free to fork the repository and make improvements as you see fit. 12 | -------------------------------------------------------------------------------- /Scenes/Main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=12 format=3 uid="uid://cm8a07k34k065"] 2 | 3 | [ext_resource type="Environment" uid="uid://6fklvphu014u" path="res://CameraEnvironment.tres" id="1_m02sb"] 4 | [ext_resource type="Script" path="res://Scripts/CameraController.cs" id="1_tgwq1"] 5 | [ext_resource type="StyleBox" uid="uid://d385yneucsjb5" path="res://GUIMaterials/PressedButton.tres" id="2_pw8xn"] 6 | [ext_resource type="Script" path="res://Scripts/LineDrawer3D.cs" id="3_jelu0"] 7 | [ext_resource type="PackedScene" uid="uid://c34d65rdo2d2f" path="res://Prefabs/tensorFieldPoint.tscn" id="4_3wj43"] 8 | [ext_resource type="Script" path="res://Scripts/PointDrawer3D.cs" id="4_rx5bt"] 9 | [ext_resource type="Script" path="res://Scripts/MainScript.cs" id="4_sxoga"] 10 | [ext_resource type="Environment" uid="uid://dknc6bkcyjc43" path="res://default_env.tres" id="6_lt8wb"] 11 | [ext_resource type="Script" path="res://Scripts/GUI/GuiController.cs" id="7_kas2y"] 12 | [ext_resource type="Material" uid="uid://dop7fuh6lrt1o" path="res://Materials/FloorMaterial.tres" id="7_l5vx1"] 13 | 14 | [sub_resource type="PlaneMesh" id="1"] 15 | 16 | [node name="Root" type="Node3D"] 17 | 18 | [node name="GUI" type="Control" parent="." node_paths=PackedStringArray("_mainScript", "addAllRoads", "addFieldButton", "addMainRoads", "addMajorRoads", "addMinorRoads", "angleEditContainer", "generateBuildings", "generateCity", "hideMenuButton", "listTensorPointsContainer", "mainMenuPanel", "regenerateBuildings", "regenerateTrees", "saveModelButton", "selectGridButton", "selectRadialButton", "showMenuButton", "sliderAngle", "sliderDecay", "sliderSize", "tabBar", "tabContainer1", "tabContainer2", "tensorPropertiesContainer", "textEditAngle", "textEditDecay", "textEditSize")] 19 | layout_mode = 3 20 | anchors_preset = 9 21 | anchor_bottom = 1.0 22 | offset_bottom = 2.0 23 | grow_vertical = 2 24 | mouse_filter = 1 25 | script = ExtResource("7_kas2y") 26 | _mainScript = NodePath("../MainScript") 27 | addAllRoads = NodePath("MainMenu/MenuVBoxContainer/TabMenu/All roads") 28 | addFieldButton = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AddField") 29 | addMainRoads = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Main roads") 30 | addMajorRoads = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Major roads") 31 | addMinorRoads = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Minor roads") 32 | angleEditContainer = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties") 33 | generateBuildings = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Generate buildings") 34 | generateCity = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Generate city 3D") 35 | hideMenuButton = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Hide menu") 36 | listTensorPointsContainer = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/ScrollContainer/Tensorfield points") 37 | mainMenuPanel = NodePath("MainMenu") 38 | regenerateBuildings = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Regenerate buildings") 39 | regenerateTrees = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Regenerate trees") 40 | saveModelButton = NodePath("MainMenu/MenuVBoxContainer/TabMenu/Export model") 41 | selectGridButton = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/SelectGrid") 42 | selectRadialButton = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/SelectRadial") 43 | showMenuButton = NodePath("Show menu") 44 | sliderAngle = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties/HBoxContainer2/HSlider") 45 | sliderDecay = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties/HBoxContainer3/HSlider") 46 | sliderSize = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties/HBoxContainer/HSlider") 47 | tabBar = NodePath("MainMenu/MenuVBoxContainer/TabBar") 48 | tabContainer1 = NodePath("MainMenu/MenuVBoxContainer/TabMenu") 49 | tabContainer2 = NodePath("MainMenu/MenuVBoxContainer/TabMenu2") 50 | tensorPointPrefab = ExtResource("4_3wj43") 51 | tensorPropertiesContainer = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties") 52 | textEditAngle = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties/HBoxContainer2/LineEdit") 53 | textEditDecay = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties/HBoxContainer3/LineEdit") 54 | textEditSize = NodePath("MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties/HBoxContainer/LineEdit") 55 | 56 | [node name="Show menu" type="Button" parent="GUI"] 57 | layout_mode = 2 58 | offset_right = 99.0 59 | offset_bottom = 31.0 60 | focus_mode = 0 61 | text = "Show menu (ESC)" 62 | 63 | [node name="MainMenu" type="PanelContainer" parent="GUI"] 64 | layout_mode = 1 65 | anchors_preset = 1 66 | anchor_left = 1.0 67 | anchor_right = 1.0 68 | offset_left = -200.0 69 | offset_bottom = 650.0 70 | grow_horizontal = 0 71 | 72 | [node name="MenuVBoxContainer" type="VBoxContainer" parent="GUI/MainMenu"] 73 | layout_mode = 2 74 | 75 | [node name="TabBar" type="TabBar" parent="GUI/MainMenu/MenuVBoxContainer"] 76 | clip_contents = true 77 | layout_mode = 2 78 | tab_count = 2 79 | tab_alignment = 1 80 | clip_tabs = false 81 | max_tab_width = 150 82 | tab_0/title = "Roads" 83 | tab_1/title = "Tensor fields" 84 | 85 | [node name="TabMenu" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer"] 86 | layout_mode = 2 87 | 88 | [node name="Hide menu" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 89 | layout_mode = 2 90 | focus_mode = 0 91 | text = "Hide menu (ESC)" 92 | 93 | [node name="Main roads" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 94 | layout_mode = 2 95 | focus_mode = 0 96 | text = "Main roads" 97 | 98 | [node name="Major roads" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 99 | layout_mode = 2 100 | focus_mode = 0 101 | text = "Major roads" 102 | 103 | [node name="Minor roads" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 104 | layout_mode = 2 105 | focus_mode = 0 106 | text = "Minor roads" 107 | 108 | [node name="All roads" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 109 | layout_mode = 2 110 | tooltip_text = "Generate all roads at once" 111 | focus_mode = 0 112 | text = "All roads" 113 | 114 | [node name="Generate buildings" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 115 | layout_mode = 2 116 | tooltip_text = "Generate buildings. 117 | You need to generate at least one road first" 118 | focus_mode = 0 119 | text = "Generate buildings" 120 | 121 | [node name="Generate city 3D" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 122 | layout_mode = 2 123 | focus_mode = 0 124 | text = "Generate city 3D" 125 | 126 | [node name="Regenerate buildings" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 127 | layout_mode = 2 128 | tooltip_text = "Change building height distribution" 129 | focus_mode = 0 130 | text = "Regenerate 3D buildings" 131 | 132 | [node name="Regenerate trees" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 133 | layout_mode = 2 134 | tooltip_text = "Change building tree distribution" 135 | focus_mode = 0 136 | text = "Regenerate trees" 137 | 138 | [node name="Export model" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu"] 139 | layout_mode = 2 140 | focus_mode = 0 141 | text = "Export 3D model" 142 | 143 | [node name="TabMenu2" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer"] 144 | visible = false 145 | layout_mode = 2 146 | size_flags_vertical = 3 147 | 148 | [node name="ScrollContainer" type="ScrollContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2"] 149 | clip_contents = false 150 | custom_minimum_size = Vector2(150, 500) 151 | layout_mode = 2 152 | size_flags_vertical = 3 153 | horizontal_scroll_mode = 0 154 | 155 | [node name="PointContainer" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer"] 156 | clip_contents = true 157 | layout_mode = 2 158 | size_flags_horizontal = 3 159 | size_flags_vertical = 3 160 | 161 | [node name="Label5" type="Label" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 162 | layout_mode = 2 163 | text = "Tensor field type" 164 | horizontal_alignment = 1 165 | 166 | [node name="SelectRadial" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 167 | layout_mode = 2 168 | focus_mode = 0 169 | theme_override_styles/pressed = ExtResource("2_pw8xn") 170 | toggle_mode = true 171 | text = "Radial 172 | " 173 | 174 | [node name="SelectGrid" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 175 | layout_mode = 2 176 | focus_mode = 0 177 | theme_override_styles/pressed = ExtResource("2_pw8xn") 178 | toggle_mode = true 179 | text = "Grid" 180 | 181 | [node name="TensorProperties" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 182 | visible = false 183 | layout_mode = 2 184 | 185 | [node name="Label" type="Label" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties"] 186 | layout_mode = 2 187 | text = "Properties" 188 | horizontal_alignment = 1 189 | vertical_alignment = 2 190 | 191 | [node name="SizeContainerProperties" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties"] 192 | layout_mode = 2 193 | 194 | [node name="Label2" type="Label" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties"] 195 | layout_mode = 2 196 | theme_override_font_sizes/font_size = 14 197 | text = "Size" 198 | vertical_alignment = 2 199 | 200 | [node name="HBoxContainer" type="HBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties"] 201 | layout_mode = 2 202 | 203 | [node name="LineEdit" type="LineEdit" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties/HBoxContainer"] 204 | layout_mode = 2 205 | focus_mode = 1 206 | theme_override_constants/minimum_character_width = 3 207 | text = "5" 208 | max_length = 4 209 | caret_blink = true 210 | 211 | [node name="HSlider" type="HSlider" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/SizeContainerProperties/HBoxContainer"] 212 | custom_minimum_size = Vector2(100, 0) 213 | layout_mode = 2 214 | size_flags_horizontal = 3 215 | size_flags_vertical = 4 216 | focus_mode = 0 217 | max_value = 20.0 218 | step = 0.5 219 | value = 5.0 220 | 221 | [node name="AngleContainerProperties" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties"] 222 | layout_mode = 2 223 | 224 | [node name="Label3" type="Label" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties"] 225 | layout_mode = 2 226 | theme_override_font_sizes/font_size = 14 227 | text = "Angle" 228 | vertical_alignment = 2 229 | 230 | [node name="HBoxContainer2" type="HBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties"] 231 | layout_mode = 2 232 | 233 | [node name="LineEdit" type="LineEdit" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties/HBoxContainer2"] 234 | layout_mode = 2 235 | focus_mode = 1 236 | theme_override_constants/minimum_character_width = 3 237 | text = "45" 238 | max_length = 3 239 | caret_blink = true 240 | 241 | [node name="HSlider" type="HSlider" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/AngleContainerProperties/HBoxContainer2"] 242 | custom_minimum_size = Vector2(100, 0) 243 | layout_mode = 2 244 | size_flags_horizontal = 3 245 | size_flags_vertical = 4 246 | focus_mode = 0 247 | max_value = 360.0 248 | step = 0.5 249 | value = 45.0 250 | 251 | [node name="DecayContainerProperties" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties"] 252 | layout_mode = 2 253 | 254 | [node name="Label4" type="Label" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties"] 255 | layout_mode = 2 256 | theme_override_font_sizes/font_size = 14 257 | text = "Decay" 258 | vertical_alignment = 2 259 | 260 | [node name="HBoxContainer3" type="HBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties"] 261 | layout_mode = 2 262 | 263 | [node name="LineEdit" type="LineEdit" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties/HBoxContainer3"] 264 | layout_mode = 2 265 | focus_mode = 1 266 | theme_override_constants/minimum_character_width = 3 267 | text = "2" 268 | max_length = 4 269 | caret_blink = true 270 | 271 | [node name="HSlider" type="HSlider" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties/DecayContainerProperties/HBoxContainer3"] 272 | custom_minimum_size = Vector2(100, 0) 273 | layout_mode = 2 274 | size_flags_horizontal = 3 275 | size_flags_vertical = 4 276 | focus_mode = 0 277 | min_value = -1.0 278 | max_value = 25.0 279 | value = 2.0 280 | 281 | [node name="AddField" type="Button" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/TensorProperties"] 282 | layout_mode = 2 283 | focus_mode = 0 284 | text = "Add tensor field" 285 | 286 | [node name="HSeparator" type="HSeparator" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 287 | layout_mode = 2 288 | 289 | [node name="ScrollContainer" type="ScrollContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer"] 290 | layout_mode = 2 291 | size_flags_vertical = 3 292 | horizontal_scroll_mode = 0 293 | 294 | [node name="Tensorfield points" type="VBoxContainer" parent="GUI/MainMenu/MenuVBoxContainer/TabMenu2/ScrollContainer/PointContainer/ScrollContainer"] 295 | layout_mode = 2 296 | size_flags_horizontal = 3 297 | size_flags_vertical = 3 298 | 299 | [node name="MainScript" type="Node" parent="." node_paths=PackedStringArray("_guiController")] 300 | script = ExtResource("4_sxoga") 301 | _cameraEnvironment = ExtResource("1_m02sb") 302 | _defaultEnvironment = ExtResource("6_lt8wb") 303 | _guiController = NodePath("../GUI") 304 | 305 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] 306 | transform = Transform3D(0.0906328, -0.96195, -0.257754, 0, -0.258819, 0.965926, -0.995884, -0.0875446, -0.0234575, 0, 4.77529, 0) 307 | shadow_enabled = true 308 | 309 | [node name="Camera3D" type="Camera3D" parent="."] 310 | transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 20, 10, -20) 311 | visible = false 312 | environment = ExtResource("6_lt8wb") 313 | projection = 1 314 | size = 2.0 315 | script = ExtResource("1_tgwq1") 316 | 317 | [node name="Points" type="MeshInstance3D" parent="."] 318 | transform = Transform3D(1, 0, 0, 0, 1.19249e-08, 1, 0, -1, 1.19249e-08, 0, 0, 0) 319 | skeleton = NodePath("../Camera3D") 320 | script = ExtResource("4_rx5bt") 321 | 322 | [node name="Lines" type="MeshInstance3D" parent="."] 323 | transform = Transform3D(1, 0, 0, 0, 1.19249e-08, 1, 0, -1, 1.19249e-08, 0, 0, 0) 324 | skeleton = NodePath("../Camera3D") 325 | script = ExtResource("3_jelu0") 326 | 327 | [node name="Lines2" type="MeshInstance3D" parent="."] 328 | transform = Transform3D(1, 0, 0, 0, -1, 2.38498e-08, 0, -2.38498e-08, -1, 0, 0, 0) 329 | skeleton = NodePath("../Camera3D") 330 | script = ExtResource("3_jelu0") 331 | 332 | [node name="TensorFieldPoints" type="MeshInstance3D" parent="."] 333 | transform = Transform3D(1, 0, 0, 0, 1.19249e-08, 1, 0, -1, 1.19249e-08, 0, 0, 0) 334 | sorting_offset = 1.0 335 | skeleton = NodePath("../Camera3D") 336 | script = ExtResource("4_rx5bt") 337 | 338 | [node name="RoadModel" type="Node3D" parent="."] 339 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20, 0, -20) 340 | 341 | [node name="Roads" type="CSGCombiner3D" parent="RoadModel"] 342 | use_collision = true 343 | 344 | [node name="BuildingsModel" type="Node3D" parent="."] 345 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0, -10) 346 | 347 | [node name="Buildings" type="CSGCombiner3D" parent="BuildingsModel"] 348 | transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -10, 0, 10) 349 | use_collision = true 350 | 351 | [node name="RoadsBuildings" type="CSGCombiner3D" parent="BuildingsModel"] 352 | transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -10, 0, 10) 353 | use_collision = true 354 | 355 | [node name="Floor" type="CSGMesh3D" parent="."] 356 | transform = Transform3D(20, 0, 0, 0, 1, 0, 0, 0, 20, 20, 0, -20) 357 | visible = false 358 | use_collision = true 359 | mesh = SubResource("1") 360 | material = ExtResource("7_l5vx1") 361 | 362 | [node name="Trees" type="Node3D" parent="."] 363 | 364 | [node name="Control" type="Control" parent="."] 365 | layout_mode = 3 366 | anchors_preset = 0 367 | offset_right = 40.0 368 | offset_bottom = 40.0 369 | -------------------------------------------------------------------------------- /Scripts/CameraController.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts; 4 | 5 | public partial class CameraController : Camera3D 6 | { 7 | private const float MouseSensitivity = 0.1f; 8 | private readonly Vector2 _draggingSensitivity = new(200f, 200f); 9 | private Vector2 _actualMousePosition; 10 | 11 | private CameraMovement _cameraMovement; 12 | private Vector3 _cameraSpeed = Vector3.One; 13 | private bool _dragging; 14 | private Vector2 _mouseMovement; 15 | private float _pitch; 16 | private Vector2 _startPoint; 17 | private float _yaw; 18 | 19 | public Vector2 centerScreen; 20 | 21 | public bool mouseCapture; 22 | 23 | public override void _Ready() 24 | { 25 | _startPoint = Vector2.Zero; 26 | _actualMousePosition = Vector2.Zero; 27 | Size = 4; 28 | } 29 | 30 | public override void _Process(double delta) 31 | { 32 | centerScreen = new Vector2(Position.X, Position.Z); 33 | 34 | switch (Projection) 35 | { 36 | case ProjectionType.Orthogonal: 37 | _ProcessOrthogonal(); 38 | break; 39 | case ProjectionType.Perspective: 40 | _ProcessProjection(delta); 41 | break; 42 | } 43 | } 44 | 45 | private void _ProcessOrthogonal() 46 | { 47 | Input.MouseMode = Input.MouseModeEnum.Visible; 48 | 49 | if (!_dragging) return; 50 | 51 | var newPosition = new Vector3( 52 | Position.X + (_startPoint.X - _actualMousePosition.X) / _draggingSensitivity.X, 53 | Position.Y, 54 | Position.Z + (_startPoint.Y - _actualMousePosition.Y) / _draggingSensitivity.Y 55 | ); 56 | Position = newPosition; 57 | _startPoint = _actualMousePosition; 58 | } 59 | 60 | private void _ProcessProjection(double delta) 61 | { 62 | Input.MouseMode = mouseCapture ? Input.MouseModeEnum.Captured : Input.MouseModeEnum.Visible; 63 | _yaw = (_yaw - _mouseMovement.X * MouseSensitivity) % 360; 64 | _pitch = Mathf.Max(Mathf.Min(_pitch - _mouseMovement.Y * MouseSensitivity, 90), -90); 65 | Rotation = new Vector3(Mathf.DegToRad(_pitch), Mathf.DegToRad(_yaw), 0); 66 | if (_cameraMovement.forward) 67 | Position -= GlobalTransform.Basis.Z * _cameraSpeed * (float)delta; 68 | else if (_cameraMovement.backward) Position += GlobalTransform.Basis.Z * _cameraSpeed * (float)delta; 69 | if (_cameraMovement.left) 70 | Position -= GlobalTransform.Basis.X * _cameraSpeed * (float)delta; 71 | else if (_cameraMovement.right) Position += GlobalTransform.Basis.X * _cameraSpeed * (float)delta; 72 | if (_cameraMovement.up) 73 | Position += Vector3.Up * _cameraSpeed * (float)delta; 74 | else if (_cameraMovement.down) Position -= Vector3.Up * _cameraSpeed * (float)delta; 75 | _mouseMovement = Vector2.Zero; 76 | } 77 | 78 | public override void _Input(InputEvent @event) 79 | { 80 | if (@event.IsActionReleased("mouseMiddle")) 81 | _dragging = false; 82 | else if (@event.IsActionPressed("mouseMiddle")) _dragging = true; 83 | 84 | switch (Projection) 85 | { 86 | case ProjectionType.Orthogonal: 87 | _InputOrthogonal(@event); 88 | break; 89 | case ProjectionType.Perspective: 90 | _InputProjection(@event); 91 | break; 92 | } 93 | } 94 | 95 | private void _InputOrthogonal(InputEvent @event) 96 | { 97 | if (@event is InputEventMouseMotion eventMouseMotion) 98 | if (_dragging) 99 | _actualMousePosition = eventMouseMotion.Position; 100 | 101 | if (@event is InputEventMouseButton eventMouseButton) 102 | { 103 | if (@event.IsActionPressed("mouseMiddle")) 104 | { 105 | _startPoint = eventMouseButton.Position; 106 | _actualMousePosition = eventMouseButton.Position; 107 | } 108 | 109 | // Scroll up 110 | if (eventMouseButton.ButtonIndex is MouseButton.WheelUp) 111 | { 112 | if (Size - 1 <= 0) 113 | Size = 1; 114 | else 115 | Size -= 1; 116 | } 117 | // Scroll down 118 | else if (eventMouseButton.ButtonIndex is MouseButton.WheelDown) 119 | { 120 | Size += 1; 121 | } 122 | 123 | // var width = Size * (GetViewport().GetVisibleRect().Size.X / GetViewport().GetVisibleRect().Size.Y); 124 | // GD.Print("Position: ", Position.X - width / 2, ", ", Position.Z - Size / 2); 125 | } 126 | } 127 | 128 | private void _InputProjection(InputEvent @event) 129 | { 130 | if (!mouseCapture) return; 131 | 132 | if (@event is InputEventMouseMotion eventMouseMotion) _mouseMovement = eventMouseMotion.Relative; 133 | 134 | if (@event is InputEventKey inputEventKey) 135 | { 136 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.W) 137 | { 138 | _cameraMovement.forward = true; 139 | } 140 | else if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.S) 141 | { 142 | _cameraMovement.backward = true; 143 | } 144 | else if (inputEventKey.Keycode is Key.W or Key.S) 145 | { 146 | _cameraMovement.forward = false; 147 | _cameraMovement.backward = false; 148 | } 149 | 150 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.A) 151 | { 152 | _cameraMovement.left = true; 153 | } 154 | else if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.D) 155 | { 156 | _cameraMovement.right = true; 157 | } 158 | else if (inputEventKey.Keycode is Key.A or Key.D) 159 | { 160 | _cameraMovement.left = false; 161 | _cameraMovement.right = false; 162 | } 163 | 164 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.E) 165 | { 166 | _cameraMovement.up = true; 167 | } 168 | else if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.Q) 169 | { 170 | _cameraMovement.down = true; 171 | } 172 | else if (inputEventKey.Keycode is Key.Q or Key.E) 173 | { 174 | _cameraMovement.up = false; 175 | _cameraMovement.down = false; 176 | } 177 | 178 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.Shift) 179 | _cameraSpeed = Vector3.One * 4f; 180 | else if (!inputEventKey.IsPressed() && inputEventKey.Keycode == Key.Shift) _cameraSpeed = Vector3.One; 181 | } 182 | } 183 | 184 | private struct CameraMovement 185 | { 186 | public bool forward; 187 | public bool backward; 188 | public bool left; 189 | public bool right; 190 | public bool up; 191 | public bool down; 192 | } 193 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Field.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public abstract class Field 6 | { 7 | public Vector2 center; 8 | public float decay; 9 | public float size; 10 | 11 | protected Field(Vector2 center, float size, float decay) 12 | { 13 | this.center = center; 14 | this.size = size; 15 | this.decay = decay; 16 | } 17 | 18 | public Tensor GetWeightedTensor(Vector2 point) 19 | { 20 | var tensor = GetTensor(point); 21 | tensor.r *= GetTensorWeight(point); 22 | tensor.oldth = true; 23 | 24 | return tensor; 25 | } 26 | 27 | private float GetTensorWeight(Vector2 point) 28 | { 29 | var normDistanceToCenter = (point - center).Length() / size; 30 | 31 | if (decay == 0 && normDistanceToCenter >= 1) return 0; 32 | 33 | return Mathf.Pow(Mathf.Max(0, 1 - normDistanceToCenter), decay); 34 | } 35 | 36 | protected abstract Tensor GetTensor(Vector2 point); 37 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Grid.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public class Grid : Field 6 | { 7 | public float theta; 8 | 9 | public Grid(Vector2 center, float size, float decay, float theta) : base(center, size, decay) 10 | { 11 | this.theta = theta; 12 | } 13 | 14 | protected override Tensor GetTensor(Vector2 point) 15 | { 16 | return new Tensor(1, new[] { Mathf.Cos(2 * theta), Mathf.Sin(2 * theta) }); 17 | } 18 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/GridStorage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace ProceduralCityGenerator.Scripts.DataStructure; 5 | 6 | public class GridStorage 7 | { 8 | private readonly List>> _grid; 9 | private readonly Vector2 _gridDimensions; 10 | private readonly Vector2 _origin; 11 | private readonly float _sep; 12 | private readonly Vector2 _worldDimensions; 13 | 14 | public GridStorage(Vector2 worldDimensions, Vector2 origin, float sep) 15 | { 16 | _grid = new List>>(); 17 | _origin = origin; 18 | _sep = sep; 19 | _worldDimensions = worldDimensions; 20 | _gridDimensions = _worldDimensions / _sep; 21 | 22 | for (var i = 0; i < _gridDimensions.X; i++) 23 | { 24 | _grid.Add(new List>()); 25 | for (var j = 0; j < _gridDimensions.Y; j++) _grid[i].Add(new List()); 26 | } 27 | } 28 | 29 | public void AddAll(GridStorage gridStorage) 30 | { 31 | foreach (var row in gridStorage._grid) 32 | foreach (var cell in row) 33 | foreach (var sample in cell) 34 | AddSample(sample); 35 | } 36 | 37 | public List GetNearbyPoints(Vector2 v, float distance) 38 | { 39 | var radius = (int)Mathf.Ceil(distance / _sep - 0.5f); 40 | var coords = GetSampleCoords(v); 41 | var outVectors = new List(); 42 | 43 | for (var i = -1 * radius; i <= 1 * radius; i++) 44 | for (var j = -1 * radius; j <= 1 * radius; j++) 45 | { 46 | var cell = coords + new Vector2(i, j); 47 | if (!VectorOutOfBounds(cell, _gridDimensions)) 48 | foreach (var v2 in _grid[(int)cell.X][(int)cell.Y]) 49 | outVectors.Add(v2); 50 | } 51 | 52 | return outVectors; 53 | } 54 | 55 | public void AddSample(Vector2 v) 56 | { 57 | var coords = GetSampleCoords(v); 58 | 59 | AddSample(v, coords); 60 | } 61 | 62 | private void AddSample(Vector2 v, Vector2 coords) 63 | { 64 | _grid[(int)coords.X][(int)coords.Y].Add(v); 65 | } 66 | 67 | private Vector2 GetSampleCoords(Vector2 worldV) 68 | { 69 | var v = worldV - _origin; 70 | 71 | if (VectorOutOfBounds(v, _worldDimensions)) return Vector2.Zero; 72 | 73 | return new Vector2(Mathf.Floor(v.X / _sep), Mathf.Floor(v.Y / _sep)); 74 | } 75 | 76 | public bool IsValidSample(Vector2 v, float dSq) 77 | { 78 | var coords = GetSampleCoords(v); 79 | 80 | for (var i = -1; i <= 1; i++) 81 | for (var j = -1; j <= 1; j++) 82 | { 83 | var cell = coords + new Vector2(i, j); 84 | 85 | if (!VectorOutOfBounds(cell, _gridDimensions)) 86 | if (!VectorFarFromVectors(v, _grid[(int)cell.X][(int)cell.Y], dSq)) 87 | return false; 88 | } 89 | 90 | return true; 91 | } 92 | 93 | private static bool VectorFarFromVectors(Vector2 v, List vectors, float dSq) 94 | { 95 | foreach (var sample in vectors) 96 | if (!sample.Equals(v)) 97 | { 98 | var distanceSq = sample.DistanceSquaredTo(v); 99 | 100 | if (distanceSq < dSq) return false; 101 | } 102 | 103 | return true; 104 | } 105 | 106 | private static bool VectorOutOfBounds(Vector2 gridV, Vector2 bounds) 107 | { 108 | return gridV.X < 0 || gridV.Y < 0 || 109 | gridV.X >= bounds.X || gridV.Y >= bounds.Y; 110 | } 111 | 112 | public void AddPolyline(List line) 113 | { 114 | foreach (var v in line) AddSample(v); 115 | } 116 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/IPointDrawImmediate.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public interface IPointDrawImmediate 6 | { 7 | internal struct Point 8 | { 9 | internal Vector3 point; 10 | internal Color color; 11 | } 12 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Integrator.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public class Integrator 6 | { 7 | private readonly float _step; 8 | private readonly TensorField _tensorField; 9 | 10 | public Integrator(TensorField tensorField, float step) 11 | { 12 | _tensorField = tensorField; 13 | _step = step; 14 | } 15 | 16 | private Vector2 SampleFieldVector(Vector2 point, bool major) 17 | { 18 | var tensor = _tensorField.GetPoint(point); 19 | 20 | return major ? tensor.Major : tensor.Minor; 21 | } 22 | 23 | public Vector2 Integrate(Vector2 point, bool major) 24 | { 25 | var k1 = SampleFieldVector(point, major); 26 | var k23 = SampleFieldVector(point + new Vector2(_step / 2f, _step / 2f), major); 27 | var k4 = SampleFieldVector(point + new Vector2(_step, _step), major); 28 | 29 | return (k1 + 4 * k23 + k4) * (_step / 6f); 30 | } 31 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Intersection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace ProceduralCityGenerator.Scripts.DataStructure; 5 | 6 | public struct Intersection 7 | { 8 | public Vector2 point; 9 | public HashSet neighbours; 10 | public List segments; 11 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/PolygonGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Godot; 5 | using NetTopologySuite; 6 | using NetTopologySuite.Geometries; 7 | 8 | namespace ProceduralCityGenerator.Scripts.DataStructure; 9 | 10 | public static class PolygonGenerator 11 | { 12 | private const int MaxLength = 20; 13 | private static readonly GeometryFactory Gf = NtsGeometryServices.Instance.CreateGeometryFactory(); 14 | 15 | public static List> GeneratePolygons(List intersections) 16 | { 17 | var polygons = new List>(); 18 | 19 | foreach (var p in intersections) 20 | if (p.neighbours.Count >= 2) 21 | foreach (var nextPoint in p.neighbours.ToList()) 22 | { 23 | var polygon = GetPolygons(new List { p, nextPoint }); 24 | 25 | if (polygon is { Count: < MaxLength }) 26 | { 27 | RemovePolygonAdjacency(polygon); 28 | polygons.Add(polygon); 29 | polygon.Add(polygon[0]); 30 | } 31 | } 32 | 33 | return polygons; 34 | } 35 | 36 | private static void RemovePolygonAdjacency(IReadOnlyList polygon) 37 | { 38 | for (var i = 0; i < polygon.Count; i++) 39 | { 40 | var current = polygon[i]; 41 | var next = polygon[(i + 1) % polygon.Count]; 42 | 43 | if (current.neighbours.Contains(next)) current.neighbours.Remove(next); 44 | } 45 | } 46 | 47 | private static List GetPolygons(List visited, int count = 0) 48 | { 49 | List output = null; 50 | var continueLoop = true; 51 | while (continueLoop) 52 | if (count >= MaxLength) 53 | { 54 | continueLoop = false; 55 | } 56 | else 57 | { 58 | var nextIntersection = GetRightMostIntersection(visited[^2], visited[^1]); 59 | if (!nextIntersection.HasValue) 60 | { 61 | continueLoop = false; 62 | } 63 | else 64 | { 65 | var visitedIndex = visited.IndexOf(nextIntersection.Value); 66 | if (visitedIndex >= 0) 67 | { 68 | output = visited.GetRange(visitedIndex, visited.Count - visitedIndex); 69 | continueLoop = false; 70 | } 71 | else 72 | { 73 | visited.Add(nextIntersection.Value); 74 | count++; 75 | } 76 | } 77 | } 78 | 79 | return output; 80 | } 81 | 82 | private static Intersection? GetRightMostIntersection(Intersection intersectionFrom, Intersection intersectionTo) 83 | { 84 | if (intersectionTo.neighbours.Count == 0) return null; 85 | 86 | var backwardsDifferenceVector = intersectionFrom.point - intersectionTo.point; 87 | var transformAngle = Mathf.Atan2(backwardsDifferenceVector.Y, backwardsDifferenceVector.X); 88 | 89 | Intersection? rightMostIntersection = null; 90 | var smallestTheta = Mathf.Tau; 91 | 92 | foreach (var nextIntersection in intersectionTo.neighbours) 93 | { 94 | if (nextIntersection.Equals(intersectionFrom)) 95 | continue; 96 | 97 | var nextVector = nextIntersection.point - intersectionTo.point; 98 | var nextAngle = Mathf.Atan2(nextVector.Y, nextVector.X) - transformAngle; 99 | 100 | if (nextAngle < 0) nextAngle += Mathf.Tau; 101 | 102 | if (nextAngle < smallestTheta) 103 | { 104 | smallestTheta = nextAngle; 105 | rightMostIntersection = nextIntersection; 106 | } 107 | } 108 | 109 | return rightMostIntersection; 110 | } 111 | 112 | public static (List>, List>, List>, List) GeneratePlots( 113 | List> polygons) 114 | { 115 | var shrunkPolygons = new List>(); 116 | var sidewalkPolygons = new List>(); 117 | var sidewalkFloorPolygons = new List>(); 118 | var centroidPolygon = new List(); 119 | 120 | var random = new Random(); 121 | 122 | foreach (var polygon in polygons) 123 | { 124 | if (random.Next(0, 1001) - 1 < 5) continue; 125 | 126 | if (polygon.Count <= 2) continue; 127 | 128 | var poly = Gf.CreatePolygon( 129 | Gf.CreateLinearRing(polygon.Select(x => new Coordinate(x.point.X, x.point.Y)) 130 | .ToArray()) 131 | ); 132 | 133 | var plotBuilding = poly.Buffer(GD.RandRange(-0.4d, -0.8d)); 134 | 135 | 136 | if (!plotBuilding.IsSimple || plotBuilding.Area < 1d || plotBuilding.Area > 100d) continue; 137 | 138 | var plotSidewalk = poly.Buffer(-0.25d); 139 | var plotSidewalkRounded = plotSidewalk.Buffer(-0.1d).Buffer(0.1d); 140 | 141 | shrunkPolygons.Add( 142 | plotBuilding.Coordinates.Select(c => new Vector2((float)c.X, (float)c.Y)).ToList() 143 | ); 144 | sidewalkPolygons.Add( 145 | plotSidewalk.Coordinates.Select(c => new Vector2((float)c.X, (float)c.Y)).ToList() 146 | ); 147 | sidewalkFloorPolygons.Add( 148 | plotSidewalkRounded.Coordinates.Select(c => new Vector2((float)c.X, (float)c.Y)).ToList() 149 | ); 150 | centroidPolygon.Add(new Vector2((float)plotBuilding.Centroid.X, (float)plotBuilding.Centroid.Y)); 151 | } 152 | 153 | return (shrunkPolygons, sidewalkPolygons, sidewalkFloorPolygons, centroidPolygon); 154 | } 155 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Radial.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public class Radial : Field 6 | { 7 | public Radial(Vector2 center, float size, float decay) : base(center, size, decay) 8 | { 9 | } 10 | 11 | protected override Tensor GetTensor(Vector2 point) 12 | { 13 | var t = point - center; 14 | var t1 = Mathf.Pow(t.Y, 2) - Mathf.Pow(t.X, 2); 15 | var t2 = -2 * t.X * t.Y; 16 | 17 | return new Tensor(1, new[] { t1, t2 }); 18 | } 19 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Segment.cs: -------------------------------------------------------------------------------- 1 | namespace ProceduralCityGenerator.Scripts.DataStructure; 2 | 3 | public struct Segment 4 | { 5 | public int indexA; 6 | public int indexB; 7 | public int indexStreamline; 8 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/StreamLineIntegration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace ProceduralCityGenerator.Scripts.DataStructure; 5 | 6 | public struct StreamLineIntegration 7 | { 8 | public Vector2 seed; 9 | public Vector2 originalDir; 10 | public List streamline; 11 | public Vector2 previousDirection; 12 | public Vector2 previousPoint; 13 | public bool valid; 14 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/StreamLines.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Godot; 4 | using Simplify.NET; 5 | 6 | namespace ProceduralCityGenerator.Scripts.DataStructure; 7 | 8 | public class StreamLines 9 | { 10 | private readonly List> _allStreamlines = new(); 11 | 12 | private readonly Integrator _integrator; 13 | 14 | private readonly GridStorage _major; 15 | private readonly GridStorage _minor; 16 | private readonly Vector2 _origin; 17 | private readonly StreamLinesParams _parameters; 18 | private readonly List> _streamlinesMajor = new(); 19 | private readonly List> _streamlinesMinor = new(); 20 | private readonly Vector2 _worldDimensions; 21 | private StreamLinesParams _parametersSq; 22 | public List> allStreamlinesSimple = new(); 23 | 24 | public StreamLines(Integrator integrator, Vector2 worldDimensions, Vector2 origin, StreamLinesParams parameters) 25 | { 26 | _integrator = integrator; 27 | _worldDimensions = worldDimensions; 28 | _origin = origin; 29 | _parameters = parameters; 30 | 31 | if (_parameters.step > _parameters.sep) 32 | GD.PrintErr("Distancia de la muestra de linea de flujo más grande que dsep"); 33 | 34 | _parameters.test = Mathf.Min(_parameters.test, _parameters.sep); 35 | 36 | _major = new GridStorage(_worldDimensions, _origin, _parameters.sep); 37 | _minor = new GridStorage(_worldDimensions, _origin, _parameters.sep); 38 | 39 | SetParametersSq(); 40 | } 41 | 42 | private void SetParametersSq() 43 | { 44 | _parametersSq = new StreamLinesParams 45 | { 46 | sep = _parameters.sep * _parameters.sep, 47 | test = _parameters.test * _parameters.test, 48 | step = _parameters.step * _parameters.step, 49 | lookahead = _parameters.lookahead * _parameters.lookahead, 50 | circleJoin = _parameters.circleJoin * _parameters.circleJoin, 51 | joinAngle = _parameters.joinAngle * _parameters.joinAngle, 52 | pathIterations = _parameters.pathIterations * _parameters.pathIterations, 53 | seedTries = _parameters.seedTries * _parameters.seedTries, 54 | simplifyTolerance = _parameters.simplifyTolerance * _parameters.simplifyTolerance, 55 | colliderEarly = _parameters.colliderEarly * _parameters.colliderEarly 56 | }; 57 | } 58 | 59 | public void AddExistingStreamlines(StreamLines streamLines) 60 | { 61 | _major.AddAll(streamLines._major); 62 | _minor.AddAll(streamLines._minor); 63 | } 64 | 65 | public void CreateAllStreamLines() 66 | { 67 | var major = true; 68 | while (CreateStreamLine(major)) major = !major; 69 | 70 | JoinDanglingStreamlines(); 71 | } 72 | 73 | private Vector2? GetBestNextPoint(Vector2 point, Vector2 previousPoint) 74 | { 75 | var nearbyPoints = _major.GetNearbyPoints(point, _parameters.lookahead); 76 | nearbyPoints.AddRange(_minor.GetNearbyPoints(point, _parameters.lookahead)); 77 | var direction = point - previousPoint; 78 | 79 | Vector2? closestSample = null; 80 | var closestDistance = float.PositiveInfinity; 81 | 82 | foreach (var sample in nearbyPoints) 83 | if (!sample.Equals(point) && !sample.Equals(previousPoint)) 84 | { 85 | var differenceVector = sample - point; 86 | var dotDifferenceVector = differenceVector.Dot(direction); 87 | if (dotDifferenceVector < 0) 88 | continue; 89 | 90 | var distanceToSample = point.DistanceSquaredTo(sample); 91 | if (distanceToSample < closestDistance && distanceToSample < 2 * 0.01f * 0.01f) 92 | { 93 | closestDistance = distanceToSample; 94 | closestSample = sample; 95 | continue; 96 | } 97 | 98 | var angleBetween = MathF.Abs(direction.AngleTo(differenceVector)); 99 | 100 | if (angleBetween < _parameters.joinAngle && distanceToSample < closestDistance) 101 | { 102 | closestDistance = distanceToSample; 103 | closestSample = sample; 104 | } 105 | } 106 | 107 | if (closestSample.HasValue) closestSample += direction.Normalized() * _parameters.simplifyTolerance * 4; 108 | 109 | return closestSample; 110 | } 111 | 112 | private void JoinDanglingStreamlines() 113 | { 114 | var dstep = 0.01f; 115 | foreach (var major in new[] { true, false }) 116 | foreach (var streamline in Streamlines(major)) 117 | { 118 | if (streamline[0].Equals(streamline[^1])) continue; 119 | 120 | var newStart = GetBestNextPoint(streamline[0], streamline[4]); 121 | 122 | if (newStart.HasValue) 123 | foreach (var p in PointsBetween(streamline[0], newStart.Value, dstep)) 124 | { 125 | streamline.Insert(0, p); 126 | Grid(major).AddSample(p); 127 | } 128 | 129 | var newEnd = GetBestNextPoint(streamline[^1], streamline[^4]); 130 | 131 | if (newEnd.HasValue) 132 | foreach (var p in PointsBetween(streamline[^1], newEnd.Value, dstep)) 133 | { 134 | streamline.Add(p); 135 | Grid(major).AddSample(p); 136 | } 137 | } 138 | 139 | allStreamlinesSimple = new List>(); 140 | foreach (var s in _allStreamlines) allStreamlinesSimple.Add(SimplifyStreamline(s)); 141 | } 142 | 143 | private List PointsBetween(Vector2 v1, Vector2 v2, float step) 144 | { 145 | var d = v1.DistanceTo(v2); 146 | var nPoints = Mathf.Floor(d / step); 147 | 148 | if (nPoints == 0) return new List(); 149 | 150 | var stepVector = v2 - v1; 151 | 152 | var outVectors = new List(); 153 | 154 | var i = 1; 155 | var next = v1 + stepVector * (i / nPoints); 156 | 157 | for (i = 1; i <= nPoints; i++) 158 | { 159 | if (_integrator.Integrate(next, true).LengthSquared() > 0.001f) 160 | outVectors.Add(next); 161 | else 162 | return outVectors; 163 | 164 | next = v1 + stepVector * (i / nPoints); 165 | } 166 | 167 | return outVectors; 168 | } 169 | 170 | private List> Streamlines(bool major) 171 | { 172 | return major ? _streamlinesMajor : _streamlinesMinor; 173 | } 174 | 175 | private GridStorage Grid(bool major) 176 | { 177 | return major ? _major : _minor; 178 | } 179 | 180 | private Vector2 SamplePoint() 181 | { 182 | return new Vector2(GD.Randf() * _worldDimensions.X, GD.Randf() * _worldDimensions.Y) + _origin; 183 | } 184 | 185 | private Vector2? GetSeed(bool major) 186 | { 187 | var seed = SamplePoint(); 188 | var i = 0; 189 | 190 | while (!IsValidSample(major, seed, _parametersSq.sep)) 191 | { 192 | if (i >= _parameters.seedTries) return null; 193 | 194 | seed = SamplePoint(); 195 | i++; 196 | } 197 | 198 | return seed; 199 | } 200 | 201 | private bool IsValidSample(bool major, Vector2 point, float dSq, bool bothGrids = false) 202 | { 203 | var gridValid = Grid(major).IsValidSample(point, dSq); 204 | 205 | if (bothGrids) gridValid = gridValid && Grid(!major).IsValidSample(point, dSq); 206 | 207 | return gridValid; 208 | } 209 | 210 | private bool CreateStreamLine(bool major) 211 | { 212 | var seed = GetSeed(major); 213 | var isValid = false; 214 | if (seed.HasValue) 215 | { 216 | var streamline = _IntegrateStreamline(seed.Value, major); 217 | if (ValidStreamline(streamline)) 218 | { 219 | Grid(major).AddPolyline(streamline); 220 | Streamlines(major).Add(streamline); 221 | _allStreamlines.Add(streamline); 222 | allStreamlinesSimple.Add(SimplifyStreamline(streamline)); 223 | } 224 | 225 | isValid = true; 226 | } 227 | 228 | return isValid; 229 | } 230 | 231 | private List SimplifyStreamline(List streamline) 232 | { 233 | var simplified = new List(); 234 | 235 | foreach (var point in SimplifyNet.Simplify(Vector2ToPoint(streamline), _parameters.simplifyTolerance)) 236 | simplified.Add(new Vector2((float)point.X, (float)point.Y)); 237 | 238 | return simplified; 239 | } 240 | 241 | private static List Vector2ToPoint(List vector) 242 | { 243 | var points = new List(); 244 | foreach (var point in vector) points.Add(new Point(point.X, point.Y)); 245 | 246 | return points; 247 | } 248 | 249 | private bool ValidStreamline(List streamline) 250 | { 251 | return streamline.Count > 5; 252 | } 253 | 254 | private List _IntegrateStreamline(Vector2 seed, bool major) 255 | { 256 | var count = 0; 257 | var pointsEscaped = false; 258 | 259 | var collideBoth = GD.Randf() < _parameters.colliderEarly; 260 | 261 | var d = _integrator.Integrate(seed, major); 262 | 263 | var forwardParameters = new StreamLineIntegration 264 | { 265 | seed = seed, 266 | originalDir = d, 267 | streamline = new List { seed }, 268 | previousDirection = d, 269 | previousPoint = seed + d, 270 | valid = true 271 | }; 272 | 273 | forwardParameters.valid = PointInBounds(forwardParameters.previousPoint); 274 | 275 | var negD = -d; 276 | var backwardParameters = new StreamLineIntegration 277 | { 278 | seed = seed, 279 | originalDir = negD, 280 | streamline = new List(), 281 | previousDirection = negD, 282 | previousPoint = seed + negD, 283 | valid = true 284 | }; 285 | 286 | backwardParameters.valid = PointInBounds(backwardParameters.previousPoint); 287 | 288 | var finished = false; 289 | while (!finished && count < _parameters.pathIterations && (forwardParameters.valid || backwardParameters.valid)) 290 | { 291 | StreamLineIntegrationStep(ref forwardParameters, major, collideBoth); 292 | StreamLineIntegrationStep(ref backwardParameters, major, collideBoth); 293 | 294 | var sqDistanceBetweenPoints = 295 | forwardParameters.previousPoint 296 | .DistanceSquaredTo(backwardParameters.previousPoint); 297 | 298 | if (!pointsEscaped && sqDistanceBetweenPoints > _parametersSq.circleJoin) pointsEscaped = true; 299 | 300 | if (pointsEscaped && sqDistanceBetweenPoints <= _parametersSq.circleJoin) 301 | { 302 | forwardParameters.streamline.Add(forwardParameters.previousPoint); 303 | forwardParameters.streamline.Add(backwardParameters.previousPoint); 304 | backwardParameters.streamline.Add(backwardParameters.previousPoint); 305 | finished = true; 306 | } 307 | 308 | count++; 309 | } 310 | 311 | backwardParameters.streamline.Reverse(); 312 | backwardParameters.streamline.AddRange(forwardParameters.streamline); 313 | return backwardParameters.streamline; 314 | } 315 | 316 | private void StreamLineIntegrationStep(ref StreamLineIntegration parameters, bool major, bool collideBoth) 317 | { 318 | if (!parameters.valid) return; 319 | 320 | parameters.streamline.Add(parameters.previousPoint); 321 | var nextDirection = _integrator.Integrate(parameters.previousPoint, major); 322 | 323 | if (nextDirection.LengthSquared() < 0.01f) 324 | { 325 | parameters.valid = false; 326 | return; 327 | } 328 | 329 | if (nextDirection.Dot(parameters.previousDirection) < 0) nextDirection *= -1; 330 | 331 | var nextPoint = parameters.previousPoint + nextDirection; 332 | 333 | if (PointInBounds(nextPoint) 334 | && IsValidSample(major, nextPoint, _parametersSq.test, collideBoth) 335 | && !StreamlineTurned(parameters.seed, parameters.originalDir, nextPoint, nextDirection)) 336 | { 337 | parameters.previousPoint = nextPoint; 338 | parameters.previousDirection = nextDirection; 339 | } 340 | else 341 | { 342 | parameters.streamline.Add(nextPoint); 343 | parameters.valid = false; 344 | } 345 | } 346 | 347 | private static bool StreamlineTurned(Vector2 seed, Vector2 originalDir, Vector2 point, Vector2 direction) 348 | { 349 | if (!(originalDir.Dot(direction) < 0)) 350 | return false; 351 | 352 | var perpendicularVector = new Vector2(originalDir.Y, -originalDir.X); 353 | var isLeft = (point - seed).Dot(perpendicularVector) < 0; 354 | var directionUp = direction.Dot(perpendicularVector) > 0; 355 | 356 | return isLeft == directionUp; 357 | } 358 | 359 | private bool PointInBounds(Vector2 v) 360 | { 361 | return v.X >= _origin.X 362 | && v.Y >= _origin.Y 363 | && v.X < _worldDimensions.X + _origin.X 364 | && v.Y < _worldDimensions.Y + _origin.Y; 365 | } 366 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/StreamLinesParams.cs: -------------------------------------------------------------------------------- 1 | namespace ProceduralCityGenerator.Scripts.DataStructure; 2 | 3 | public struct StreamLinesParams 4 | { 5 | public StreamLinesParams SetSep(float sep) 6 | { 7 | this.sep = sep; 8 | return this; 9 | } 10 | 11 | public StreamLinesParams SetLookahead(float lookahead) 12 | { 13 | this.lookahead = lookahead; 14 | return this; 15 | } 16 | 17 | public static StreamLinesParams Default => new() 18 | { 19 | sep = 100f, 20 | test = 50f, 21 | step = 1, 22 | lookahead = 500, 23 | circleJoin = 5000, 24 | joinAngle = 0.1f, 25 | pathIterations = 500, 26 | seedTries = 300, 27 | simplifyTolerance = 0.0125f, 28 | colliderEarly = 0 29 | }; 30 | 31 | public float sep; 32 | public float test; 33 | public float step; 34 | public float lookahead; 35 | public float circleJoin; 36 | public float joinAngle; 37 | public float pathIterations; 38 | public float seedTries; 39 | public float simplifyTolerance; 40 | public float colliderEarly; 41 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/Tensor.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public class Tensor 6 | { 7 | private readonly float[] _m; 8 | private float _theta; 9 | public bool oldth; 10 | 11 | public float r; 12 | 13 | public Tensor(float r, float[] m) 14 | { 15 | this.r = r; 16 | _m = m; 17 | oldth = false; 18 | Theta = CalculateTheta(); 19 | } 20 | 21 | private float Theta 22 | { 23 | get 24 | { 25 | if (oldth) 26 | { 27 | _theta = CalculateTheta(); 28 | oldth = false; 29 | } 30 | 31 | return _theta; 32 | } 33 | init => _theta = value; 34 | } 35 | 36 | public static Tensor Zero 37 | { 38 | get { return new Tensor(0, new float[] { 0, 0 }); } 39 | } 40 | 41 | public Vector2 Major 42 | { 43 | get 44 | { 45 | var vector = Vector2.Zero; 46 | if (r != 0) vector = new Vector2(Mathf.Cos(Theta), Mathf.Sin(Theta)); 47 | 48 | return vector; 49 | } 50 | } 51 | 52 | public Vector2 Minor 53 | { 54 | get 55 | { 56 | var vector = Vector2.Zero; 57 | if (r != 0) 58 | { 59 | var angle = Theta + Mathf.Pi / 2; 60 | vector = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); 61 | } 62 | 63 | return vector; 64 | } 65 | } 66 | 67 | private float CalculateTheta() 68 | { 69 | var theta = 0.0f; 70 | if (r != 0) theta = Mathf.Atan2(_m[1] / r, _m[0] / r) / 2; 71 | 72 | return theta; 73 | } 74 | 75 | public void Add(Tensor tensor) 76 | { 77 | for (var i = 0; i < _m.Length; i++) _m[i] = _m[i] * r + tensor._m[i] * tensor.r; 78 | 79 | r = 2; 80 | oldth = true; 81 | } 82 | } -------------------------------------------------------------------------------- /Scripts/DataStructure/TensorField.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace ProceduralCityGenerator.Scripts.DataStructure; 5 | 6 | public class TensorField 7 | { 8 | private readonly float _diameter; 9 | public readonly List points; 10 | 11 | public TensorField(Vector2 worldDimensions, Vector2 origin) 12 | { 13 | _diameter = 0.1f; 14 | var n = new Vector2(Mathf.Ceil(worldDimensions.X / _diameter) + 1, 15 | Mathf.Ceil(worldDimensions.Y / _diameter) + 1); 16 | 17 | Fields = new List(); 18 | 19 | // Puntos en la rejilla 20 | points = new List(); 21 | for (var i = 1; i < n.X - 1; i++) 22 | for (var j = 1; j < n.Y - 1; j++) 23 | points.Add(new Vector2(origin.X + i * _diameter * 2, origin.Y + j * _diameter * 2)); 24 | } 25 | 26 | public List Fields { get; } 27 | 28 | public Tensor GetPoint(Vector2 p) 29 | { 30 | if (Fields.Count == 0) return new Tensor(1, new float[] { 0, 0 }); 31 | 32 | var tensorAcc = Tensor.Zero; 33 | 34 | foreach (var f in Fields) tensorAcc.Add(f.GetWeightedTensor(p)); 35 | 36 | return tensorAcc; 37 | } 38 | 39 | public List GetTensorLine(Vector2 point, Vector2 tensor) 40 | { 41 | var diff = tensor * _diameter; 42 | var start = point - diff; 43 | var end = point + diff; 44 | 45 | return new List { start, end }; 46 | } 47 | 48 | public void AddRadial(Vector2 center, float size, float decay) 49 | { 50 | AddField(new Radial(center, size, decay)); 51 | } 52 | 53 | public void AddGrid(Vector2 center, float size, float decay, float theta) 54 | { 55 | AddField(new Grid(center, size, decay, theta)); 56 | } 57 | 58 | private void AddField(Field field) 59 | { 60 | Fields.Add(field); 61 | } 62 | } -------------------------------------------------------------------------------- /Scripts/GUI/GuiController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Godot; 4 | 5 | namespace ProceduralCityGenerator.Scripts.GUI; 6 | 7 | public partial class GuiController : Control 8 | { 9 | private bool _angleEdit; 10 | private bool _decayEdit; 11 | 12 | [Export] private MainScript _mainScript; 13 | private bool _sizeEdit; 14 | [Export] public Button addAllRoads; 15 | [Export] public Button addFieldButton; 16 | 17 | [Export] public Button addMainRoads; 18 | [Export] public Button addMajorRoads; 19 | [Export] public Button addMinorRoads; 20 | [Export] public VBoxContainer angleEditContainer; 21 | [Export] public Button generateBuildings; 22 | [Export] public Button generateCity; 23 | [Export] public Button hideMenuButton; 24 | 25 | [Export] public VBoxContainer listTensorPointsContainer; 26 | 27 | [Export] public PanelContainer mainMenuPanel; 28 | [Export] public Button regenerateBuildings; 29 | [Export] public Button regenerateTrees; 30 | [Export] public Button saveModelButton; 31 | [Export] public Button selectGridButton; 32 | 33 | [Export] public Button selectRadialButton; 34 | public bool showMenu; 35 | 36 | [Export] public Button showMenuButton; 37 | [Export] public HSlider sliderAngle; 38 | [Export] public HSlider sliderDecay; 39 | [Export] public HSlider sliderSize; 40 | 41 | [Export] public TabBar tabBar; 42 | [Export] public VBoxContainer tabContainer1; 43 | [Export] public VBoxContainer tabContainer2; 44 | [Export] public PackedScene tensorPointPrefab; 45 | [Export] public VBoxContainer tensorPropertiesContainer; 46 | [Export] public LineEdit textEditAngle; 47 | [Export] public LineEdit textEditDecay; 48 | [Export] public LineEdit textEditSize; 49 | 50 | public override void _Ready() 51 | { 52 | regenerateTrees.Pressed += () => _mainScript.GenerateTrees(); 53 | 54 | regenerateBuildings.Pressed += async () => 55 | { 56 | _mainScript.GenerateBuildings3D(); 57 | 58 | await ToSignal(GetTree(), "process_frame"); 59 | _mainScript.GenerateTrees(); 60 | }; 61 | 62 | generateCity.Pressed += async () => 63 | { 64 | _mainScript.GenerateBuildings3D(); 65 | _mainScript.GenerateRoads3D(); 66 | 67 | await ToSignal(GetTree(), "process_frame"); 68 | _mainScript.GenerateTrees(); 69 | }; 70 | 71 | generateBuildings.Pressed += () => 72 | { 73 | _mainScript.GenerateIntersections(); 74 | _mainScript.GeneratePolygons(); 75 | }; 76 | 77 | textEditDecay.TextChanged += text => 78 | { 79 | try 80 | { 81 | sliderDecay.Value = float.Parse(text); 82 | } 83 | catch (FormatException) 84 | { 85 | // ignored 86 | } 87 | }; 88 | sliderDecay.DragEnded += _ => { _decayEdit = false; }; 89 | sliderDecay.DragStarted += () => { _decayEdit = true; }; 90 | 91 | textEditAngle.TextChanged += text => 92 | { 93 | try 94 | { 95 | sliderAngle.Value = float.Parse(text); 96 | } 97 | catch (FormatException) 98 | { 99 | // ignored 100 | } 101 | }; 102 | sliderAngle.DragEnded += _ => { _angleEdit = false; }; 103 | sliderAngle.DragStarted += () => { _angleEdit = true; }; 104 | 105 | textEditSize.TextChanged += text => 106 | { 107 | try 108 | { 109 | sliderSize.Value = float.Parse(text); 110 | } 111 | catch (FormatException) 112 | { 113 | // ignored 114 | } 115 | }; 116 | sliderSize.DragEnded += _ => { _sizeEdit = false; }; 117 | sliderSize.DragStarted += () => { _sizeEdit = true; }; 118 | 119 | tabBar.TabChanged += index => 120 | { 121 | switch (index) 122 | { 123 | case 0: 124 | tabContainer1.Visible = true; 125 | tabContainer2.Visible = false; 126 | _mainScript.state = MainScript.DrawState.Roads; 127 | break; 128 | case 1: 129 | tabContainer1.Visible = false; 130 | tabContainer2.Visible = true; 131 | _mainScript.SetTensorFieldState(); 132 | break; 133 | } 134 | 135 | MainScript.Redraw(); 136 | }; 137 | 138 | addAllRoads.Pressed += () => 139 | { 140 | _mainScript.GenerateRoads(_mainScript.mainRoads); 141 | _mainScript.GenerateRoads(_mainScript.majorRoads); 142 | _mainScript.GenerateRoads(_mainScript.minorRoads); 143 | }; 144 | 145 | addMainRoads.Pressed += () => 146 | { 147 | if (_mainScript.majorRoads.Streamlines != null) _mainScript.majorRoads.Streamlines = null; 148 | 149 | if (_mainScript.minorRoads.Streamlines != null) _mainScript.minorRoads.Streamlines = null; 150 | 151 | _mainScript.GenerateRoads(_mainScript.mainRoads); 152 | }; 153 | 154 | addMajorRoads.Pressed += () => 155 | { 156 | if (_mainScript.minorRoads.Streamlines != null) _mainScript.minorRoads.Streamlines = null; 157 | 158 | _mainScript.GenerateRoads(_mainScript.majorRoads); 159 | }; 160 | 161 | addMinorRoads.Pressed += () => { _mainScript.GenerateRoads(_mainScript.minorRoads); }; 162 | 163 | addFieldButton.Pressed += () => 164 | { 165 | var position = _mainScript.cameraController.centerScreen; 166 | 167 | if (selectGridButton.ButtonPressed) 168 | MainScript.tensorField.AddGrid(new Vector2(position.X, -position.Y), (float)sliderSize.Value, 169 | (float)sliderDecay.Value, Mathf.DegToRad((float)sliderAngle.Value)); 170 | else if (selectRadialButton.ButtonPressed) 171 | MainScript.tensorField.AddRadial(new Vector2(position.X, -position.Y), (float)sliderSize.Value, 172 | (float)sliderDecay.Value); 173 | 174 | var tensor = tensorPointPrefab.Instantiate(); 175 | tensor.AddField(MainScript.tensorField.Fields[^1]); 176 | listTensorPointsContainer.AddChild(tensor); 177 | 178 | _mainScript.DrawReload(); 179 | }; 180 | 181 | selectGridButton.Pressed += () => 182 | { 183 | selectRadialButton.ButtonPressed = false; 184 | angleEditContainer.Visible = true; 185 | 186 | tensorPropertiesContainer.Visible = selectGridButton.ButtonPressed; 187 | }; 188 | 189 | selectRadialButton.Pressed += () => 190 | { 191 | selectGridButton.ButtonPressed = false; 192 | angleEditContainer.Visible = false; 193 | 194 | tensorPropertiesContainer.Visible = selectRadialButton.ButtonPressed; 195 | }; 196 | 197 | hideMenuButton.Pressed += HideMenu; 198 | 199 | showMenuButton.Pressed += ShowMenu; 200 | 201 | saveModelButton.Pressed += () => 202 | { 203 | var gl = new GltfDocument(); 204 | var state = new GltfState(); 205 | var fileDialog = new FileDialog(); 206 | fileDialog.Access = FileDialog.AccessEnum.Filesystem; 207 | fileDialog.InitialPosition = Window.WindowInitialPosition.CenterMainWindowScreen; 208 | fileDialog.Size = new Vector2I(930, 440); 209 | fileDialog.AddFilter("*.gltf"); 210 | GetNode("/root/Root/GUI").AddChild(fileDialog); 211 | fileDialog.Visible = true; 212 | 213 | fileDialog.FileSelected += path => 214 | { 215 | gl.AppendFromScene(GetTree().CurrentScene, state); 216 | 217 | var err = gl.WriteToFilesystem(state, path); 218 | 219 | if (err == Error.Failed) GD.PrintErr("Ha ocurrido un error"); 220 | }; 221 | }; 222 | } 223 | 224 | public async void ShowMenu() 225 | { 226 | if (showMenu) return; 227 | 228 | showMenu = true; 229 | 230 | showMenuButton.Visible = false; 231 | 232 | var tween = GetTree().CreateTween(); 233 | tween.SetTrans(Tween.TransitionType.Expo); 234 | tween.SetEase(Tween.EaseType.Out); 235 | 236 | mainMenuPanel.Visible = true; 237 | tween.TweenProperty(mainMenuPanel, "position", -mainMenuPanel.Position, 0.5f).AsRelative(); 238 | await ToSignal(tween, Tween.SignalName.Finished); 239 | } 240 | 241 | public async void HideMenu() 242 | { 243 | if (!showMenu) return; 244 | 245 | var tween = GetTree().CreateTween(); 246 | tween.SetTrans(Tween.TransitionType.Expo); 247 | tween.SetEase(Tween.EaseType.Out); 248 | 249 | tween.TweenProperty(mainMenuPanel, "position", new Vector2(-mainMenuPanel.Size.X, mainMenuPanel.Position.Y), 250 | 0.5f).AsRelative(); 251 | showMenuButton.Visible = true; 252 | await ToSignal(tween, Tween.SignalName.Finished); 253 | mainMenuPanel.Visible = false; 254 | showMenu = false; 255 | } 256 | 257 | public override void _Process(double delta) 258 | { 259 | if (_sizeEdit) textEditSize.Text = sliderSize.Value.ToString(CultureInfo.InvariantCulture); 260 | 261 | if (_angleEdit) textEditAngle.Text = sliderAngle.Value.ToString(CultureInfo.InvariantCulture); 262 | 263 | if (_decayEdit) textEditDecay.Text = sliderDecay.Value.ToString(CultureInfo.InvariantCulture); 264 | } 265 | } -------------------------------------------------------------------------------- /Scripts/GUI/PropertiesPointsEdit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Godot; 4 | using ProceduralCityGenerator.Scripts.DataStructure; 5 | 6 | namespace ProceduralCityGenerator.Scripts.GUI; 7 | 8 | public partial class PropertiesPointsEdit : VBoxContainer 9 | { 10 | private bool _angleEdit; 11 | private bool _decayEdit; 12 | 13 | private Field _field; 14 | [Export] private StyleBoxFlat _selectedStyle; 15 | private bool _sizeEdit; 16 | [Export] private StyleBoxFlat _unselectedStyle; 17 | [Export] public VBoxContainer angleEditContainer; 18 | [Export] public Button pointButton; 19 | [Export] public Button removeButton; 20 | [Export] public HSlider sliderAngle; 21 | [Export] public HSlider sliderDecay; 22 | [Export] public HSlider sliderSize; 23 | [Export] public VBoxContainer tensorPropertiesContainer; 24 | [Export] public LineEdit textEditAngle; 25 | [Export] public LineEdit textEditDecay; 26 | [Export] public LineEdit textEditSize; 27 | 28 | public override void _Ready() 29 | { 30 | removeButton.Pressed += () => 31 | { 32 | MainScript.tensorField.Fields.Remove(_field); 33 | MainScript.Redraw(); 34 | QueueFree(); 35 | }; 36 | 37 | pointButton.Pressed += () => 38 | { 39 | tensorPropertiesContainer.Visible = !tensorPropertiesContainer.Visible; 40 | removeButton.Visible = !removeButton.Visible; 41 | }; 42 | 43 | textEditDecay.TextChanged += text => 44 | { 45 | try 46 | { 47 | sliderDecay.Value = float.Parse(text); 48 | } 49 | catch (FormatException) 50 | { 51 | // ignored 52 | } 53 | 54 | if (_field != null) 55 | { 56 | _field.decay = (float)sliderDecay.Value; 57 | MainScript.Redraw(); 58 | } 59 | }; 60 | sliderDecay.DragEnded += _ => { _decayEdit = false; }; 61 | sliderDecay.DragStarted += () => { _decayEdit = true; }; 62 | 63 | textEditAngle.TextChanged += text => 64 | { 65 | try 66 | { 67 | sliderAngle.Value = float.Parse(text); 68 | } 69 | catch (FormatException) 70 | { 71 | // ignored 72 | } 73 | 74 | if (_field is Grid grid) 75 | { 76 | grid.theta = (float)Mathf.DegToRad(sliderAngle.Value); 77 | MainScript.Redraw(); 78 | } 79 | }; 80 | sliderAngle.DragEnded += _ => { _angleEdit = false; }; 81 | sliderAngle.DragStarted += () => { _angleEdit = true; }; 82 | 83 | textEditSize.TextChanged += text => 84 | { 85 | try 86 | { 87 | sliderSize.Value = float.Parse(text); 88 | } 89 | catch (FormatException) 90 | { 91 | // ignored 92 | } 93 | 94 | if (_field != null) 95 | { 96 | _field.size = (float)sliderSize.Value; 97 | MainScript.Redraw(); 98 | } 99 | }; 100 | sliderSize.DragEnded += _ => { _sizeEdit = false; }; 101 | sliderSize.DragStarted += () => { _sizeEdit = true; }; 102 | } 103 | 104 | public override void _Process(double delta) 105 | { 106 | if (_sizeEdit) 107 | { 108 | textEditSize.Text = sliderSize.Value.ToString(CultureInfo.InvariantCulture); 109 | 110 | if (_field != null) 111 | { 112 | _field.size = (float)sliderSize.Value; 113 | MainScript.Redraw(); 114 | } 115 | } 116 | 117 | if (_angleEdit) 118 | { 119 | textEditAngle.Text = sliderAngle.Value.ToString(CultureInfo.InvariantCulture); 120 | 121 | if (_field is Grid grid) 122 | { 123 | grid.theta = (float)Mathf.DegToRad(sliderAngle.Value); 124 | MainScript.Redraw(); 125 | } 126 | } 127 | 128 | if (_decayEdit) 129 | { 130 | textEditDecay.Text = sliderDecay.Value.ToString(CultureInfo.InvariantCulture); 131 | 132 | if (_field != null) 133 | { 134 | _field.decay = (float)sliderDecay.Value; 135 | MainScript.Redraw(); 136 | } 137 | } 138 | 139 | if (_field != null && MainScript.selectedField != null && MainScript.selectedField.Equals(_field)) 140 | { 141 | tensorPropertiesContainer.Visible = true; 142 | removeButton.Visible = true; 143 | pointButton.ButtonPressed = true; 144 | 145 | pointButton.Set("theme_override_styles/pressed", _selectedStyle); 146 | } 147 | else 148 | { 149 | pointButton.Set("theme_override_styles/pressed", _unselectedStyle); 150 | } 151 | } 152 | 153 | public void AddField(Field tensorField) 154 | { 155 | _field = tensorField; 156 | SetValuesInit(); 157 | } 158 | 159 | private void SetValuesInit() 160 | { 161 | if (_field is Grid grid) 162 | { 163 | textEditAngle.Text = Mathf.RadToDeg(grid.theta).ToString(CultureInfo.InvariantCulture); 164 | sliderAngle.Value = Mathf.RadToDeg(grid.theta); 165 | pointButton.Text = "Grid point"; 166 | } 167 | else 168 | { 169 | pointButton.Text = "Radial point"; 170 | angleEditContainer.Visible = false; 171 | } 172 | 173 | textEditDecay.Text = _field.decay.ToString(CultureInfo.InvariantCulture); 174 | sliderDecay.Value = _field.decay; 175 | textEditSize.Text = _field.size.ToString(CultureInfo.InvariantCulture); 176 | sliderSize.Value = _field.size; 177 | } 178 | } -------------------------------------------------------------------------------- /Scripts/LineDrawer3D.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | using ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public partial class LineDrawer3D : MeshInstance3D, IPointDrawImmediate 6 | { 7 | private readonly List _points = new(); 8 | private ImmediateMesh _mesh = new(); 9 | 10 | public void AddLine(Vector3 p1, Vector3 p2, Color color) 11 | { 12 | _points.Add(new IPointDrawImmediate.Point { point = p1, color = color }); 13 | _points.Add(new IPointDrawImmediate.Point { point = p2, color = color }); 14 | } 15 | 16 | public void AddLine(Vector3 p1, Vector3 p2) 17 | { 18 | AddLine(p1, p2, Colors.Red); 19 | } 20 | 21 | public void AddLines(List line) 22 | { 23 | AddLines(line, Colors.Red); 24 | } 25 | 26 | public void AddLines(List line, Color color) 27 | { 28 | if (line.Count < 2) return; 29 | 30 | foreach (var point in line) 31 | _points.Add(new IPointDrawImmediate.Point { point = new Vector3(point.X, point.Y, 0), color = color }); 32 | } 33 | 34 | public override void _Ready() 35 | { 36 | var m = new StandardMaterial3D(); 37 | m.NoDepthTest = true; 38 | m.ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded; 39 | m.VertexColorUseAsAlbedo = true; 40 | m.Transparency = BaseMaterial3D.TransparencyEnum.Alpha; 41 | MaterialOverride = m; 42 | } 43 | 44 | public void Clear() 45 | { 46 | _mesh.ClearSurfaces(); 47 | _points.Clear(); 48 | } 49 | 50 | public override void _Process(double delta) 51 | { 52 | if (_points.Count == 0) return; 53 | 54 | _mesh.ClearSurfaces(); 55 | _mesh.SurfaceBegin(Mesh.PrimitiveType.Lines); 56 | foreach (var t in _points) 57 | { 58 | _mesh.SurfaceSetColor(t.color); 59 | _mesh.SurfaceAddVertex(t.point); 60 | } 61 | 62 | _mesh.SurfaceEnd(); 63 | 64 | Mesh = _mesh; 65 | } 66 | } -------------------------------------------------------------------------------- /Scripts/MainBuildings3D.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Godot; 4 | 5 | namespace ProceduralCityGenerator.Scripts; 6 | 7 | public partial class MainBuildings3D : CsgPolygon3D 8 | { 9 | private MainBuildings3D() 10 | { 11 | } 12 | 13 | public MainBuildings3D(IEnumerable polygon, float height) 14 | { 15 | Mode = ModeEnum.Depth; 16 | Name = "Building"; 17 | Polygon = polygon.Select(v => new Vector2(v.X, -v.Y)).ToArray(); 18 | Scale = new Vector3(Scale.X, Scale.Y, height); 19 | } 20 | 21 | public static MainBuildings3D SetTop(MainBuildings3D building) 22 | { 23 | var top = new MainBuildings3D(); 24 | top.Mode = ModeEnum.Depth; 25 | top.Polygon = building.Polygon.ToArray(); 26 | top.Name = "Building Top"; 27 | top.Scale = new Vector3(building.Scale.X, building.Scale.Y, 0.005f); 28 | top.Position = new Vector3(building.Position.X, building.Position.Y, -building.Scale.Z); 29 | top.Material = (Material)ResourceLoader.Load("res://Materials/BuildingRoofMaterial1.tres"); 30 | return top; 31 | } 32 | } -------------------------------------------------------------------------------- /Scripts/MainRoads3D.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | public partial class MainRoads3D : CsgPolygon3D 5 | { 6 | public override void _Ready() 7 | { 8 | const float width = 0.5f; 9 | const float height = 0.0125f; 10 | const float halfWidth = width * 0.5f; 11 | const float halfHeight = height * 0.5f; 12 | Polygon = new Vector2[] 13 | { 14 | new(-halfWidth, -halfHeight), 15 | new(-halfWidth, height - halfHeight), 16 | new(width - halfWidth, height - halfHeight), 17 | new(width - halfWidth, -halfHeight) 18 | }; 19 | Mode = ModeEnum.Path; 20 | Name = "Road"; 21 | Material = (Material)ResourceLoader.Load("res://Materials/RoadMaterial1.tres"); 22 | PathIntervalType = PathIntervalTypeEnum.Subdivide; 23 | PathInterval = 0.1f; 24 | } 25 | 26 | public void AddPath(List points) 27 | { 28 | var path3d = new Path3D(); 29 | path3d.Name = "Path"; 30 | path3d.Curve = new Curve3D(); 31 | 32 | foreach (var point in points) path3d.Curve.AddPoint(point); 33 | 34 | AddChild(path3d); 35 | PathNode = path3d.GetPath(); 36 | } 37 | } -------------------------------------------------------------------------------- /Scripts/MainScript.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Advanced.Algorithms.Geometry; 5 | using Godot; 6 | using ProceduralCityGenerator.Scripts.DataStructure; 7 | using ProceduralCityGenerator.Scripts.GUI; 8 | using Environment = Godot.Environment; 9 | using Noise = SimplexNoise.Noise; 10 | 11 | namespace ProceduralCityGenerator.Scripts; 12 | 13 | public partial class MainScript : Node 14 | { 15 | public enum DrawState 16 | { 17 | TensorFields, 18 | Roads, 19 | Intersections, 20 | Polygons, 21 | Roads3D 22 | } 23 | 24 | public static TensorField tensorField; 25 | 26 | private static bool _redraw; 27 | 28 | public static Field selectedField; 29 | private readonly Vector2 _origin = Vector2.Zero; 30 | 31 | private readonly Vector2 _worldDimension = Vector2.One * 40; 32 | [Export] private Environment _cameraEnvironment; 33 | [Export] private Environment _defaultEnvironment; 34 | 35 | [Export] private GuiController _guiController; 36 | 37 | private List _intersections; 38 | private LineDrawer3D _line; 39 | private PointDrawer3D _point; 40 | private List> _polygons; 41 | private List _polygonsCentroid; 42 | private List> _polygonsShrunk; 43 | private List> _polygonsSidewalk; 44 | private List> _polygonsSidewalkRounded; 45 | private PointDrawer3D _tensorPoints; 46 | 47 | public CameraController cameraController; 48 | 49 | public Roads mainRoads; 50 | public Roads majorRoads; 51 | public Roads minorRoads; 52 | 53 | public DrawState state; 54 | 55 | public override void _Ready() 56 | { 57 | tensorField = new TensorField(_worldDimension * 0.5f, _origin); 58 | var integrator = new Integrator(tensorField, 1f); 59 | 60 | mainRoads = new Roads(StreamLinesParams.Default, integrator, _worldDimension, _origin); 61 | majorRoads = new Roads(StreamLinesParams.Default.SetSep(5f).SetLookahead(500f), integrator, 62 | _worldDimension, 63 | _origin); 64 | minorRoads = new Roads(StreamLinesParams.Default.SetSep(2.5f).SetLookahead(500f), integrator, 65 | _worldDimension, 66 | _origin); 67 | 68 | minorRoads.SetExistingStreamlines(new List { mainRoads, majorRoads }); 69 | majorRoads.SetExistingStreamlines(new List { mainRoads }); 70 | state = DrawState.TensorFields; 71 | 72 | 73 | cameraController = GetTree().Root.GetNode("Root").GetNode("Camera3D"); 74 | _line = GetTree().Root.GetNode("Root").GetNode("Lines"); 75 | _point = GetTree().Root.GetNode("Root").GetNode("Points"); 76 | _tensorPoints = GetTree().Root.GetNode("Root").GetNode("TensorFieldPoints"); 77 | 78 | DrawReload(); 79 | } 80 | 81 | public override void _Input(InputEvent @event) 82 | { 83 | if (@event is InputEventKey inputEventKey) 84 | { 85 | // Ver las intersecciones y las uniones (DEBUG) 86 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.I && minorRoads.Streamlines != null && 87 | majorRoads.Streamlines != null && mainRoads.Streamlines != null) 88 | GenerateIntersections(true); 89 | 90 | if (inputEventKey.IsPressed() && inputEventKey.Keycode == Key.Escape) 91 | { 92 | if (_guiController.showMenu) 93 | { 94 | _guiController.HideMenu(); 95 | cameraController.mouseCapture = true; 96 | } 97 | else 98 | { 99 | _guiController.ShowMenu(); 100 | cameraController.mouseCapture = false; 101 | } 102 | } 103 | } 104 | 105 | 106 | if (@event is InputEventMouseButton eventMouseButton) 107 | { 108 | var position = cameraController.ProjectPosition(eventMouseButton.Position, 0); 109 | 110 | if (eventMouseButton.Pressed && eventMouseButton.ButtonIndex == MouseButton.Left) 111 | { 112 | foreach (var field in tensorField.Fields) 113 | { 114 | var v1 = field.center; 115 | var v2 = new Vector2(position.X, -position.Z); 116 | const float width = 0.1f; 117 | 118 | if (v2.X >= v1.X - width && v2.X <= v1.X + width && v2.Y >= v1.Y - width && v2.Y <= v1.Y + width) 119 | { 120 | selectedField = field; 121 | break; 122 | } 123 | 124 | selectedField = null; 125 | } 126 | 127 | DrawReload(); 128 | } 129 | } 130 | 131 | if (@event is InputEventMouseMotion eventMouseMotion) 132 | { 133 | var position = cameraController.ProjectPosition(eventMouseMotion.Position, 0); 134 | 135 | if (Input.IsActionPressed("mouseLeft") && selectedField != null) 136 | { 137 | selectedField.center = new Vector2(position.X, -position.Z); 138 | DrawReload(); 139 | } 140 | } 141 | } 142 | 143 | public void GeneratePolygons(bool redraw = true) 144 | { 145 | state = DrawState.Polygons; 146 | while (true) 147 | { 148 | var polygonsGenerated = PolygonGenerator.GeneratePolygons(_intersections); 149 | 150 | if (polygonsGenerated.Count == 0) break; 151 | 152 | _polygons.AddRange(polygonsGenerated); 153 | } 154 | 155 | (_polygonsShrunk, _polygonsSidewalk, _polygonsSidewalkRounded, _polygonsCentroid) = 156 | PolygonGenerator.GeneratePlots(_polygons); 157 | 158 | if (redraw) DrawReload(); 159 | } 160 | 161 | public void GenerateIntersections(bool redraw = false) 162 | { 163 | state = DrawState.Intersections; 164 | 165 | var allStreamlines = new List>(); 166 | 167 | if (minorRoads.Streamlines != null) allStreamlines.AddRange(minorRoads.Streamlines.allStreamlinesSimple); 168 | 169 | if (mainRoads.Streamlines != null) allStreamlines.AddRange(mainRoads.Streamlines.allStreamlinesSimple); 170 | 171 | if (majorRoads.Streamlines != null) allStreamlines.AddRange(majorRoads.Streamlines.allStreamlinesSimple); 172 | 173 | _intersections = new List(); 174 | _polygons = new List>(); 175 | 176 | // Intersección entre todas las streamlines 177 | for (var m = 0; m < allStreamlines.Count - 1; m++) 178 | for (var i = 0; i < allStreamlines[m].Count - 1; i++) 179 | for (var j = i + 1; j < allStreamlines[m].Count; j++) 180 | { 181 | for (var k = m + 1; k < allStreamlines.Count; k++) 182 | for (var l = 0; l < allStreamlines[k].Count - 1; l++) 183 | { 184 | var line1 = new Line( 185 | new Point( 186 | _worldDimension.X + allStreamlines[m][i].X, 187 | _worldDimension.Y + allStreamlines[m][i].Y 188 | ), new Point( 189 | _worldDimension.X + allStreamlines[m][j].X, 190 | _worldDimension.Y + allStreamlines[m][j].Y) 191 | ); 192 | 193 | var line2 = new Line( 194 | new Point( 195 | _worldDimension.X + allStreamlines[k][l].X, 196 | _worldDimension.Y + allStreamlines[k][l].Y 197 | ), new Point( 198 | _worldDimension.X + allStreamlines[k][l + 1].X, 199 | _worldDimension.Y + allStreamlines[k][l + 1].Y) 200 | ); 201 | 202 | var actualIntersections = LineIntersection.Find(line1, line2); 203 | if (actualIntersections != null) 204 | _intersections.Add(new Intersection 205 | { 206 | point = new Vector2((float)actualIntersections.X, 207 | (float)actualIntersections.Y) - 208 | _worldDimension, 209 | neighbours = new HashSet(), 210 | segments = new List 211 | { 212 | new() 213 | { 214 | indexA = i, 215 | indexB = j, 216 | indexStreamline = m 217 | }, 218 | new() 219 | { 220 | indexA = l, 221 | indexB = l + 1, 222 | indexStreamline = k 223 | } 224 | } 225 | }); 226 | } 227 | 228 | i++; 229 | } 230 | 231 | for (var i = 0; i < allStreamlines.Count; i++) 232 | for (var j = 0; j < allStreamlines[i].Count - 2; j++) 233 | { 234 | var line1 = new Line( 235 | new Point( 236 | _worldDimension.X + allStreamlines[i][j].X, 237 | _worldDimension.Y + allStreamlines[i][j].Y 238 | ), new Point( 239 | _worldDimension.X + allStreamlines[i][j + 1].X, 240 | _worldDimension.Y + allStreamlines[i][j + 1].Y) 241 | ); 242 | 243 | var line2 = new Line( 244 | new Point( 245 | _worldDimension.X + allStreamlines[i][j + 1].X, 246 | _worldDimension.Y + allStreamlines[i][j + 1].Y 247 | ), new Point( 248 | _worldDimension.X + allStreamlines[i][j + 2].X, 249 | _worldDimension.Y + allStreamlines[i][j + 2].Y) 250 | ); 251 | 252 | var actualIntersections = LineIntersection.Find(line1, line2); 253 | if (actualIntersections != null) 254 | _intersections.Add(new Intersection 255 | { 256 | point = new Vector2((float)actualIntersections.X, 257 | (float)actualIntersections.Y) - 258 | _worldDimension, 259 | neighbours = new HashSet(), 260 | segments = new List 261 | { 262 | new() 263 | { 264 | indexA = j, 265 | indexB = j + 1, 266 | indexStreamline = i 267 | }, 268 | new() 269 | { 270 | indexA = j + 1, 271 | indexB = j + 2, 272 | indexStreamline = i 273 | } 274 | } 275 | }); 276 | } 277 | 278 | // Eliminar líneas que acaban sin ninguna intersección 279 | var usedStreamlines = new HashSet(); 280 | foreach (var intersection in _intersections) 281 | foreach (var segment in intersection.segments) 282 | { 283 | var selectedStreamlineIndex = segment.indexStreamline; 284 | if (usedStreamlines.Contains(selectedStreamlineIndex)) continue; 285 | usedStreamlines.Add(selectedStreamlineIndex); 286 | 287 | // Buscar todos las intersecciones que se encuentren en esa streamline 288 | var selectedIntersectionsFromStreamline = new List(); 289 | for (var i = 0; i < _intersections.Count; i++) 290 | for (var j = 0; j < _intersections[i].segments.Count; j++) 291 | if (_intersections[i].segments[j].indexStreamline == selectedStreamlineIndex) 292 | selectedIntersectionsFromStreamline.Add(_intersections[i]); 293 | 294 | // Si hay más de 2 intersecciones en esa streamline, buscar cuál es el la más cercana al primer 295 | // punto de la streamline y al último [0] y [^1] 296 | if (selectedIntersectionsFromStreamline.Count >= 2) 297 | { 298 | var distanceA = float.MaxValue; 299 | var distanceB = float.MaxValue; 300 | 301 | var indexPointA = -1; 302 | var indexPointB = -1; 303 | 304 | for (var i = 0; i < selectedIntersectionsFromStreamline.Count; i++) 305 | { 306 | var p = selectedIntersectionsFromStreamline[i].point; 307 | 308 | if (allStreamlines[selectedStreamlineIndex][0].DistanceSquaredTo(p) <= distanceA) 309 | { 310 | indexPointA = i; 311 | distanceA = allStreamlines[selectedStreamlineIndex][0].DistanceSquaredTo(p); 312 | } 313 | 314 | if (allStreamlines[selectedStreamlineIndex][^1].DistanceSquaredTo(p) <= distanceB) 315 | { 316 | indexPointB = i; 317 | distanceB = allStreamlines[selectedStreamlineIndex][^1].DistanceSquaredTo(p); 318 | } 319 | } 320 | 321 | if (indexPointA == indexPointB) continue; 322 | if (indexPointA != -1) 323 | allStreamlines[selectedStreamlineIndex][0] = new Vector2( 324 | selectedIntersectionsFromStreamline[indexPointA].point.X, 325 | selectedIntersectionsFromStreamline[indexPointA].point.Y); 326 | 327 | if (indexPointB != -1) 328 | allStreamlines[selectedStreamlineIndex][^1] = new Vector2( 329 | selectedIntersectionsFromStreamline[indexPointB].point.X, 330 | selectedIntersectionsFromStreamline[indexPointB].point.Y); 331 | } 332 | } 333 | 334 | // Añadir vecinos a cada intersección 335 | foreach (var intersection in _intersections) 336 | foreach (var segment in intersection.segments) 337 | { 338 | var selectedStreamlineIndex = segment.indexStreamline; 339 | var selectedIntersectionsFromStreamline = new List(); 340 | for (var i = 0; i < _intersections.Count; i++) 341 | for (var j = 0; j < _intersections[i].segments.Count; j++) 342 | if (_intersections[i].segments[j].indexStreamline == selectedStreamlineIndex) 343 | selectedIntersectionsFromStreamline.Add(_intersections[i]); 344 | var streamlinesSegments = new Dictionary<(int, int), List>(); 345 | for (var i = 0; i < selectedIntersectionsFromStreamline.Count; i++) 346 | foreach (var s in selectedIntersectionsFromStreamline[i].segments 347 | .Where(s => s.indexStreamline == selectedStreamlineIndex)) 348 | if (streamlinesSegments.ContainsKey((s.indexA, s.indexB))) 349 | streamlinesSegments[(s.indexA, s.indexB)] 350 | .Add(selectedIntersectionsFromStreamline[i]); 351 | else 352 | streamlinesSegments.Add((s.indexA, s.indexB), 353 | new List { selectedIntersectionsFromStreamline[i] }); 354 | 355 | foreach (var kv in streamlinesSegments) 356 | { 357 | var firstPoint = allStreamlines[selectedStreamlineIndex][kv.Key.Item1]; 358 | streamlinesSegments[kv.Key] = 359 | kv.Value.OrderBy(item => item.point.DistanceSquaredTo(firstPoint)).ToList(); 360 | } 361 | 362 | var sortedDict = streamlinesSegments.Keys.OrderBy(item => item.Item1).ToList(); 363 | 364 | var finish = false; 365 | for (var i = 0; i < sortedDict.Count && !finish; i++) 366 | for (var j = 0; j < streamlinesSegments[sortedDict[i]].Count && !finish; j++) 367 | if (streamlinesSegments[sortedDict[i]][j].point == intersection.point) 368 | { 369 | if (j - 1 >= 0) 370 | intersection.neighbours.Add(streamlinesSegments[sortedDict[i]][j - 1]); 371 | else if (i - 1 >= 0) intersection.neighbours.Add(streamlinesSegments[sortedDict[i - 1]][^1]); 372 | 373 | if (j + 1 < streamlinesSegments[sortedDict[i]].Count) 374 | intersection.neighbours.Add(streamlinesSegments[sortedDict[i]][j + 1]); 375 | else if (i + 1 < sortedDict.Count) 376 | intersection.neighbours.Add(streamlinesSegments[sortedDict[i + 1]][0]); 377 | finish = true; 378 | } 379 | } 380 | 381 | foreach (var intersection in _intersections) 382 | foreach (var neighbour in intersection.neighbours) 383 | neighbour.neighbours.Add(intersection); 384 | 385 | if (redraw) 386 | DrawReload(); 387 | } 388 | 389 | public void GenerateRoads(Roads roads, bool redraw = true) 390 | { 391 | roads.GenerateRoads(); 392 | state = DrawState.Roads; 393 | if (redraw) 394 | DrawReload(); 395 | } 396 | 397 | public void DrawReload() 398 | { 399 | _line.Clear(); 400 | _point.Clear(); 401 | _tensorPoints.Clear(); 402 | 403 | switch (state) 404 | { 405 | case DrawState.TensorFields: 406 | foreach (var p in tensorField.points) 407 | { 408 | var tensor = tensorField.GetPoint(p); 409 | _line.AddLines(tensorField.GetTensorLine(p, tensor.Major)); 410 | _line.AddLines(tensorField.GetTensorLine(p, tensor.Minor)); 411 | } 412 | 413 | foreach (var field in tensorField.Fields) 414 | if (selectedField != null && selectedField.Equals(field)) 415 | _tensorPoints.AddPoint(new Vector3(field.center.X, field.center.Y, 0), Colors.GreenYellow); 416 | else 417 | _tensorPoints.AddPoint(new Vector3(field.center.X, field.center.Y, 0), Colors.Yellow); 418 | 419 | break; 420 | case DrawState.Roads: 421 | // Orden de dibujado: MINOR -> MAJOR -> MAIN 422 | // Orden de creación: MAIN -> MAJOR -> MINOR 423 | 424 | minorRoads.DrawLineRoads(_line, Colors.Red); 425 | majorRoads.DrawLineRoads(_line, Colors.Green); 426 | mainRoads.DrawLineRoads(_line, Colors.Blue); 427 | 428 | break; 429 | case DrawState.Intersections: 430 | if (_intersections != null) 431 | foreach (var p in _intersections) 432 | { 433 | _point.AddPoint(new Vector3(p.point.X, p.point.Y, 0), Colors.Red); 434 | 435 | foreach (var neighbour in p.neighbours) 436 | { 437 | var vector1 = new Vector3(p.point.X, p.point.Y, 0); 438 | var vector2 = new Vector3(neighbour.point.X, neighbour.point.Y, 0); 439 | _line.AddLine(vector1, vector2, Colors.Black); 440 | } 441 | } 442 | 443 | break; 444 | case DrawState.Polygons: 445 | if (_intersections != null) 446 | foreach (var p in _intersections) 447 | _point.AddPoint(new Vector3(p.point.X, p.point.Y, 0)); 448 | 449 | if (_polygonsShrunk != null) 450 | { 451 | minorRoads.DrawLineRoads(_line, Colors.Red); 452 | majorRoads.DrawLineRoads(_line, Colors.Green); 453 | mainRoads.DrawLineRoads(_line, Colors.Blue); 454 | 455 | foreach (var plist in _polygonsShrunk) 456 | for (var i = 0; i < plist.Count - 1; i++) 457 | { 458 | var vector1 = new Vector3(plist[i].X, plist[i].Y, 0); 459 | var vector2 = new Vector3(plist[i + 1].X, plist[i + 1].Y, 0); 460 | 461 | _line.AddLine(vector1, vector2, Colors.Chocolate); 462 | } 463 | } 464 | 465 | break; 466 | case DrawState.Roads3D: 467 | var floorNode = GetNode("/root/Root/Floor"); 468 | if (!floorNode.IsVisibleInTree()) floorNode.Visible = true; 469 | 470 | break; 471 | } 472 | } 473 | 474 | public override void _Process(double delta) 475 | { 476 | if (!_redraw) return; 477 | 478 | DrawReload(); 479 | _redraw = false; 480 | } 481 | 482 | public static void Redraw() 483 | { 484 | _redraw = true; 485 | } 486 | 487 | public void GenerateRoads3D() 488 | { 489 | var roadsNode = GetNode("/root/Root/RoadModel/Roads"); 490 | foreach (var child in roadsNode.GetChildren()) child.Free(); 491 | 492 | if (minorRoads.Streamlines != null) 493 | foreach (var plist in minorRoads.Streamlines.allStreamlinesSimple) 494 | { 495 | var roadPolygon = new MainRoads3D(); 496 | roadsNode.AddChild(roadPolygon); 497 | roadPolygon.AddPath(plist 498 | .Select(p => 499 | new Vector3(p.X - _worldDimension.X, 0, p.Y - _worldDimension.Y).Rotated(Vector3.Right, 500 | Mathf.Pi)) 501 | .ToList()); 502 | } 503 | 504 | if (majorRoads.Streamlines != null) 505 | foreach (var plist in majorRoads.Streamlines.allStreamlinesSimple) 506 | { 507 | var roadPolygon = new MainRoads3D(); 508 | roadsNode.AddChild(roadPolygon); 509 | roadPolygon.AddPath(plist 510 | .Select(p => 511 | new Vector3(p.X - _worldDimension.X, 0, p.Y - _worldDimension.Y).Rotated(Vector3.Right, 512 | Mathf.Pi)) 513 | .ToList()); 514 | } 515 | 516 | if (mainRoads.Streamlines != null) 517 | foreach (var plist in mainRoads.Streamlines.allStreamlinesSimple) 518 | { 519 | var roadPolygon = new MainRoads3D(); 520 | roadsNode.AddChild(roadPolygon); 521 | roadPolygon.AddPath(plist 522 | .Select(p => 523 | new Vector3(p.X - _worldDimension.X, 0, p.Y - _worldDimension.Y).Rotated(Vector3.Right, 524 | Mathf.Pi)) 525 | .ToList()); 526 | } 527 | 528 | ChangeCameraToPerspective(); 529 | DrawReload(); 530 | } 531 | 532 | private void ChangeCameraToPerspective() 533 | { 534 | state = DrawState.Roads3D; 535 | cameraController.Projection = Camera3D.ProjectionType.Perspective; 536 | cameraController.Environment = _cameraEnvironment; 537 | } 538 | 539 | public void GenerateBuildings3D() 540 | { 541 | var buildingsNode = GetNode("/root/Root/BuildingsModel/Buildings"); 542 | var roadsNode = GetNode("/root/Root/BuildingsModel/RoadsBuildings"); 543 | foreach (var child in buildingsNode.GetChildren()) child.Free(); 544 | foreach (var child in roadsNode.GetChildren()) child.Free(); 545 | 546 | Noise.Seed = GD.RandRange(0, 100000); 547 | var noiseValues = Noise.Calc2D((int)_worldDimension.X, (int)_worldDimension.Y, 0.01f); 548 | 549 | for (var i = 0; i < _polygonsShrunk.Count; i++) 550 | { 551 | var buildingsPolygon = new MainBuildings3D(_polygonsShrunk[i], 552 | noiseValues[(int)_polygonsCentroid[i].X, (int)_polygonsCentroid[i].Y] / 255 * 553 | (float)GD.RandRange(1f, 10f)); 554 | 555 | var index = GD.RandRange(1, 11); 556 | buildingsPolygon.Material = 557 | (Material)ResourceLoader 558 | .Load($"res://Materials/BuildingMaterial{index}.tres"); 559 | 560 | buildingsNode.AddChild(buildingsPolygon); 561 | buildingsNode.AddChild(MainBuildings3D.SetTop(buildingsPolygon)); 562 | } 563 | 564 | foreach (var plist in _polygonsSidewalkRounded) 565 | { 566 | var sidewalkPolygon = new MainSidewalk3D(plist); 567 | 568 | buildingsNode.AddChild(sidewalkPolygon); 569 | } 570 | 571 | foreach (var plist in _polygonsSidewalk) 572 | { 573 | var sidewalkPolygon = MainSidewalk3D.Bottom(plist); 574 | 575 | roadsNode.AddChild(sidewalkPolygon); 576 | } 577 | 578 | ChangeCameraToPerspective(); 579 | DrawReload(); 580 | } 581 | 582 | public void GenerateTrees() 583 | { 584 | var raycasts = new List(); 585 | foreach (var child in GetTree().Root.GetNode("Root/Trees").GetChildren()) child.Free(); 586 | 587 | for (var i = 0; i < _worldDimension.X; i++) 588 | for (var j = 0; j < _worldDimension.Y; j++) 589 | { 590 | var raycast = new RayCast3D(new Vector3(i, 12, -j)); 591 | GetTree().Root.AddChild(raycast); 592 | raycast.ForceRaycastUpdate(); 593 | if (((Node)raycast.GetCollider()).Name.Equals("Floor")) raycasts.Add(raycast.GetCollisionPoint()); 594 | raycast.Free(); 595 | } 596 | 597 | var random = new Random(); 598 | foreach (var raycast in raycasts) 599 | if (random.Next(0, 101) - 1 <= 30) 600 | { 601 | var tree = new Sprite3D(); 602 | tree.Texture = (Texture2D)ResourceLoader.Load("res://Assets/Image_49.png"); 603 | tree.Position = new Vector3(raycast.X, 0.635f, raycast.Z); 604 | tree.Scale = Vector3.One * 0.25f; 605 | tree.Shaded = true; 606 | tree.RotateY((float)GD.RandRange(0, Mathf.Tau)); 607 | var tree2 = tree.Duplicate(); 608 | ((Node3D)tree2).RotateY(Mathf.Pi * 0.5f); 609 | GetTree().Root.GetNode("Root/Trees").AddChild(tree); 610 | GetTree().Root.GetNode("Root/Trees").AddChild(tree2); 611 | } 612 | } 613 | 614 | public void SetTensorFieldState() 615 | { 616 | state = DrawState.TensorFields; 617 | cameraController.Projection = Camera3D.ProjectionType.Orthogonal; 618 | 619 | cameraController.Position = new Vector3(cameraController.Position.X, 10, cameraController.Position.Z); 620 | cameraController.RotationDegrees = new Vector3(-90, 0, 0); 621 | 622 | cameraController.Environment = _defaultEnvironment; 623 | 624 | var buildingsNode = GetNode("/root/Root/BuildingsModel/Buildings"); 625 | foreach (var child in buildingsNode.GetChildren()) child.Free(); 626 | 627 | var sidewalks = GetNode("/root/Root/BuildingsModel/RoadsBuildings"); 628 | foreach (var child in sidewalks.GetChildren()) child.Free(); 629 | 630 | var roadsNode = GetNode("/root/Root/RoadModel/Roads"); 631 | foreach (var child in roadsNode.GetChildren()) child.Free(); 632 | 633 | var treesNode = GetNode("/root/Root/Trees"); 634 | foreach (var child in treesNode.GetChildren()) child.Free(); 635 | 636 | DrawReload(); 637 | var floorNode = GetNode("/root/Root/Floor"); 638 | floorNode.Visible = false; 639 | } 640 | } -------------------------------------------------------------------------------- /Scripts/MainSidewalk3D.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Godot; 4 | 5 | namespace ProceduralCityGenerator.Scripts; 6 | 7 | public partial class MainSidewalk3D : CsgPolygon3D 8 | { 9 | public MainSidewalk3D(IEnumerable polygon) 10 | { 11 | Mode = ModeEnum.Depth; 12 | Name = "Sidewalk"; 13 | Polygon = polygon.Select(v => new Vector2(v.X, -v.Y)).ToArray(); 14 | Scale = new Vector3(Scale.X, Scale.Y, 0.015f); 15 | Material = (Material)ResourceLoader.Load("res://Materials/SidewalkMaterial1.tres"); 16 | } 17 | 18 | public static MainSidewalk3D Bottom(List polygons) 19 | { 20 | var sidewalk = new MainSidewalk3D(polygons); 21 | sidewalk.Scale = new Vector3(sidewalk.Scale.X, sidewalk.Scale.Y, 0.005f); 22 | sidewalk.Material = (Material)ResourceLoader.Load("res://Materials/RoadMaterial1.tres"); 23 | return sidewalk; 24 | } 25 | } -------------------------------------------------------------------------------- /Scripts/PointDrawer3D.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | using ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | public partial class PointDrawer3D : MeshInstance3D, IPointDrawImmediate 6 | { 7 | private readonly List _points = new(); 8 | private ImmediateMesh _mesh = new(); 9 | 10 | public void AddPoint(Vector3 p) 11 | { 12 | AddPoint(p, Colors.Green); 13 | } 14 | 15 | public void AddPoint(Vector3 p, Color color) 16 | { 17 | _points.Add(new IPointDrawImmediate.Point 18 | { 19 | point = p, 20 | color = color 21 | }); 22 | } 23 | 24 | public void Clear() 25 | { 26 | _mesh.ClearSurfaces(); 27 | _points.Clear(); 28 | } 29 | 30 | public override void _Ready() 31 | { 32 | var m = new StandardMaterial3D(); 33 | m.NoDepthTest = true; 34 | m.ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded; 35 | m.VertexColorUseAsAlbedo = true; 36 | m.Transparency = BaseMaterial3D.TransparencyEnum.Alpha; 37 | MaterialOverride = m; 38 | } 39 | 40 | public override void _Process(double delta) 41 | { 42 | if (_points.Count == 0) return; 43 | 44 | _mesh.ClearSurfaces(); 45 | _mesh.SurfaceBegin(Mesh.PrimitiveType.Triangles); 46 | 47 | var width = 0.1f; 48 | foreach (var t in _points) 49 | { 50 | _mesh.SurfaceSetColor(t.color); 51 | _mesh.SurfaceAddVertex(t.point + new Vector3(-1 * width, 1 * width, 0)); 52 | _mesh.SurfaceAddVertex(t.point + new Vector3(1 * width, -1 * width, 0)); 53 | _mesh.SurfaceAddVertex(t.point + new Vector3(-1 * width, -1 * width, 0)); 54 | 55 | _mesh.SurfaceAddVertex(t.point + new Vector3(-1 * width, 1 * width, 0)); 56 | _mesh.SurfaceAddVertex(t.point + new Vector3(1 * width, 1 * width, 0)); 57 | _mesh.SurfaceAddVertex(t.point + new Vector3(1 * width, -1 * width, 0)); 58 | } 59 | 60 | _mesh.SurfaceEnd(); 61 | 62 | Mesh = _mesh; 63 | } 64 | } -------------------------------------------------------------------------------- /Scripts/RayCast3D.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace ProceduralCityGenerator.Scripts; 4 | 5 | public partial class RayCast3D : Godot.RayCast3D 6 | { 7 | public RayCast3D(Vector3 position) 8 | { 9 | Enabled = true; 10 | Position = position; 11 | CollideWithBodies = true; 12 | TargetPosition = new Vector3(0, -13, 0); 13 | } 14 | } -------------------------------------------------------------------------------- /Scripts/Roads.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | using ProceduralCityGenerator.Scripts.DataStructure; 4 | 5 | namespace ProceduralCityGenerator.Scripts; 6 | 7 | public class Roads 8 | { 9 | private readonly Integrator _integrator; 10 | private readonly Vector2 _origin; 11 | private readonly Vector2 _worldDimension; 12 | 13 | private List _existingStreamlines; 14 | 15 | public Roads(StreamLinesParams streamLinesParams, Integrator integrator, Vector2 worldDimension, Vector2 origin) 16 | { 17 | StreamLinesParams = streamLinesParams; 18 | _integrator = integrator; 19 | _worldDimension = worldDimension; 20 | _origin = origin; 21 | _existingStreamlines = new List(); 22 | } 23 | 24 | private StreamLinesParams StreamLinesParams { get; } 25 | public StreamLines Streamlines { get; set; } 26 | 27 | public void GenerateRoads() 28 | { 29 | Streamlines = new StreamLines(_integrator, _worldDimension, _origin, StreamLinesParams); 30 | 31 | foreach (var road in _existingStreamlines) 32 | if (road.Streamlines != null) 33 | Streamlines.AddExistingStreamlines(road.Streamlines); 34 | 35 | Streamlines.CreateAllStreamLines(); 36 | } 37 | 38 | public void SetExistingStreamlines(List roadsList) 39 | { 40 | _existingStreamlines = roadsList; 41 | } 42 | 43 | public void DrawLineRoads(LineDrawer3D line, Color color) 44 | { 45 | if (Streamlines == null) 46 | return; 47 | 48 | foreach (var plist in Streamlines.allStreamlinesSimple) 49 | for (var i = 0; i < plist.Count - 1; i++) 50 | { 51 | var vector1 = new Vector3(plist[i].X, plist[i].Y, 0); 52 | var vector2 = new Vector3(plist[i + 1].X, plist[i + 1].Y, 0); 53 | line.AddLine(vector1, vector2, color); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" format=3 uid="uid://dknc6bkcyjc43"] 2 | 3 | [resource] 4 | background_mode = 1 5 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carl0sCheca/Procedural-City-Generator-Godot/176277e88729c8fad332bb9432f70ba87ab45598/icon.png -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cxiy2vv8psm85" 6 | path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.png" 14 | dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="ProceduralCityGenerator" 14 | run/main_scene="res://Scenes/Main.tscn" 15 | config/features=PackedStringArray("4.2", "C#") 16 | boot_splash/show_image=false 17 | config/icon="res://icon.png" 18 | 19 | [display] 20 | 21 | window/subwindows/embed_subwindows=false 22 | 23 | [dotnet] 24 | 25 | project/assembly_name="ProceduralCityGenerator" 26 | 27 | [gui] 28 | 29 | common/drop_mouse_on_gui_input_disabled=true 30 | 31 | [input] 32 | 33 | mouseMiddle={ 34 | "deadzone": 0.5, 35 | "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null) 36 | ] 37 | } 38 | mouseLeft={ 39 | "deadzone": 0.5, 40 | "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null) 41 | ] 42 | } 43 | 44 | [mono] 45 | 46 | project/assembly_name="ProceduralCityGenerator" 47 | 48 | [physics] 49 | 50 | common/enable_pause_aware_picking=true 51 | 52 | [rendering] 53 | 54 | environment/defaults/default_environment="res://default_env.tres" 55 | --------------------------------------------------------------------------------