WIP sources and TODOs.
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -152,3 +152,6 @@ cython_debug/
 | 
				
			|||||||
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
 | 
					#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
 | 
				
			||||||
#.idea/
 | 
					#.idea/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# RK
 | 
				
			||||||
 | 
					*.blend1
 | 
				
			||||||
 | 
					*.rkar
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								BUILDING
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					Submodules:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git submodule update --init
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Building engine:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					make -C engine all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Building resources:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					python3 -m game.obj2rkar data/rk_island.rkar data/tiles/tiles.obj data/tests.obj
 | 
				
			||||||
							
								
								
									
										3
									
								
								DEPENDENCIES
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					Python (3.8+) modules:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- png
 | 
				
			||||||
							
								
								
									
										2
									
								
								data/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					CC BY-NC-SA 4.0
 | 
				
			||||||
 | 
					https://creativecommons.org/licenses/by-nc-sa/4.0/
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 109 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 108 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump1.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 107 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/sea_bump2.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tests.blend
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										32
									
								
								data/tests.mtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					# Blender 3.2.1 MTL File: 'tests.blend'
 | 
				
			||||||
 | 
					# www.blender.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl blob
 | 
				
			||||||
 | 
					Ns 1000.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 1.000000 0.278396 0.454914
 | 
				
			||||||
 | 
					Ks 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl clouds
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Ks 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl cube
 | 
				
			||||||
 | 
					Ns 562.500000
 | 
				
			||||||
 | 
					Ka 0.750000 0.750000 0.750000
 | 
				
			||||||
 | 
					Kd 1.000000 0.886007 0.495536
 | 
				
			||||||
 | 
					Ks 0.250000 0.250000 0.250000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.500000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 3
 | 
				
			||||||
							
								
								
									
										26258
									
								
								data/tests.obj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/forest.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/forest.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/forest_r.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 207 B  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/forest_r.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/grass.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 11 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/grass.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/lava.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/lava.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/mud.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/mud.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/rock.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/rock.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/sand.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/sand.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								data/tiles/tiles.blend
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										5
									
								
								data/tiles/tiles.hacks
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					water = _water mesh grass
 | 
				
			||||||
 | 
					sand = _sand mesh grass
 | 
				
			||||||
 | 
					rock = _rock mesh grass
 | 
				
			||||||
 | 
					mud = _mud mesh grass
 | 
				
			||||||
 | 
					lava = _lava mesh grass
 | 
				
			||||||
							
								
								
									
										80
									
								
								data/tiles/tiles.mtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					# Blender 3.2.2 MTL File: 'tiles.blend'
 | 
				
			||||||
 | 
					# www.blender.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl forest
 | 
				
			||||||
 | 
					Ns 10.000005
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.100000 0.100000 0.100000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd forest.png
 | 
				
			||||||
 | 
					map_Ns forest_r.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl grass
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.100000 0.100000 0.100000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd grass.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl lava
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.200000 0.200000 0.200000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd lava.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl mud
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.100000 0.100000 0.100000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd mud.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl rock
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.100000 0.100000 0.100000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd rock.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl sand
 | 
				
			||||||
 | 
					Ns 0.000000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 0.100000 0.100000 0.100000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd sand.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newmtl water
 | 
				
			||||||
 | 
					Ns 62.500000
 | 
				
			||||||
 | 
					Ka 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Kd 0.800000 0.800000 0.800000
 | 
				
			||||||
 | 
					Ks 1.000000 1.000000 1.000000
 | 
				
			||||||
 | 
					Ke 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					Ni 0.000000
 | 
				
			||||||
 | 
					d 1.000000
 | 
				
			||||||
 | 
					illum 2
 | 
				
			||||||
 | 
					map_Kd water.png
 | 
				
			||||||
							
								
								
									
										395
									
								
								data/tiles/tiles.obj
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,395 @@
 | 
				
			|||||||
 | 
					# Blender 3.2.2
 | 
				
			||||||
 | 
					# www.blender.org
 | 
				
			||||||
 | 
					mtllib tiles.mtl
 | 
				
			||||||
 | 
					o grass
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v 0.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					v 0.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 0.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -2.000000 -2.000000 0.000000
 | 
				
			||||||
 | 
					v 2.000000 -2.000000 0.000000
 | 
				
			||||||
 | 
					v -2.000000 2.000000 0.000000
 | 
				
			||||||
 | 
					v 2.000000 2.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.500000 0.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 0.500000
 | 
				
			||||||
 | 
					vt 0.500000 0.500000
 | 
				
			||||||
 | 
					vt 1.000000 0.500000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.500000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.250000 0.250000
 | 
				
			||||||
 | 
					vt 0.750000 0.250000
 | 
				
			||||||
 | 
					vt 0.250000 0.750000
 | 
				
			||||||
 | 
					vt 0.750000 0.750000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl grass
 | 
				
			||||||
 | 
					f 2/2/1 3/3/1 11/11/1
 | 
				
			||||||
 | 
					f 4/4/1 5/5/1 12/12/1
 | 
				
			||||||
 | 
					f 5/5/1 6/6/1 13/13/1
 | 
				
			||||||
 | 
					f 1/1/1 2/2/1 10/10/1
 | 
				
			||||||
 | 
					f 2/2/1 5/5/1 10/10/1
 | 
				
			||||||
 | 
					f 5/5/1 4/4/1 10/10/1
 | 
				
			||||||
 | 
					f 4/4/1 1/1/1 10/10/1
 | 
				
			||||||
 | 
					f 3/3/1 6/6/1 11/11/1
 | 
				
			||||||
 | 
					f 6/6/1 5/5/1 11/11/1
 | 
				
			||||||
 | 
					f 5/5/1 2/2/1 11/11/1
 | 
				
			||||||
 | 
					f 5/5/1 8/8/1 12/12/1
 | 
				
			||||||
 | 
					f 8/8/1 7/7/1 12/12/1
 | 
				
			||||||
 | 
					f 7/7/1 4/4/1 12/12/1
 | 
				
			||||||
 | 
					f 6/6/1 9/9/1 13/13/1
 | 
				
			||||||
 | 
					f 9/9/1 8/8/1 13/13/1
 | 
				
			||||||
 | 
					f 8/8/1 5/5/1 13/13/1
 | 
				
			||||||
 | 
					o _water
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl water
 | 
				
			||||||
 | 
					f 16/16/2 14/14/2 15/15/2
 | 
				
			||||||
 | 
					f 16/16/2 15/15/2 17/17/2
 | 
				
			||||||
 | 
					o _sand
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl sand
 | 
				
			||||||
 | 
					f 20/20/3 18/18/3 19/19/3
 | 
				
			||||||
 | 
					f 20/20/3 19/19/3 21/21/3
 | 
				
			||||||
 | 
					o _rock
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl rock
 | 
				
			||||||
 | 
					f 24/24/4 22/22/4 23/23/4
 | 
				
			||||||
 | 
					f 24/24/4 23/23/4 25/25/4
 | 
				
			||||||
 | 
					o _mud
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl mud
 | 
				
			||||||
 | 
					f 28/28/5 26/26/5 27/27/5
 | 
				
			||||||
 | 
					f 28/28/5 27/27/5 29/29/5
 | 
				
			||||||
 | 
					o _lava
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl lava
 | 
				
			||||||
 | 
					f 31/31/6 32/32/6 30/30/6
 | 
				
			||||||
 | 
					f 31/31/6 33/33/6 32/32/6
 | 
				
			||||||
 | 
					o forest
 | 
				
			||||||
 | 
					v -4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v 0.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 -4.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 0.000000 0.000000
 | 
				
			||||||
 | 
					v -4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 0.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v 4.000000 4.000000 0.000000
 | 
				
			||||||
 | 
					v -1.362234 -1.413421 0.000000
 | 
				
			||||||
 | 
					v 0.300244 -1.447442 -0.000000
 | 
				
			||||||
 | 
					v 2.000000 2.000000 -0.000000
 | 
				
			||||||
 | 
					v -2.500000 -2.500000 -0.000000
 | 
				
			||||||
 | 
					v -0.492377 -3.454313 -0.000000
 | 
				
			||||||
 | 
					v 2.000000 -2.000000 -0.000000
 | 
				
			||||||
 | 
					v -2.000000 2.000000 0.000000
 | 
				
			||||||
 | 
					v 2.067242 -0.486847 -0.000000
 | 
				
			||||||
 | 
					v -0.500000 -1.818340 0.740029
 | 
				
			||||||
 | 
					v 0.818340 -0.500000 0.563972
 | 
				
			||||||
 | 
					v -1.818340 -0.500000 0.563972
 | 
				
			||||||
 | 
					v -0.500000 0.818340 0.683588
 | 
				
			||||||
 | 
					v 0.575498 -0.487720 3.437187
 | 
				
			||||||
 | 
					v -0.507330 -1.421268 3.375877
 | 
				
			||||||
 | 
					v -0.512277 0.339565 3.328456
 | 
				
			||||||
 | 
					v -1.427362 -0.522726 3.423728
 | 
				
			||||||
 | 
					v 2.886405 -0.483161 5.390676
 | 
				
			||||||
 | 
					v -0.487300 -3.870228 5.409079
 | 
				
			||||||
 | 
					v -0.469270 2.809886 5.425605
 | 
				
			||||||
 | 
					v -4.131104 -0.500174 5.195535
 | 
				
			||||||
 | 
					v 2.312899 -0.687081 9.665462
 | 
				
			||||||
 | 
					v -0.505750 -3.461892 9.618814
 | 
				
			||||||
 | 
					v -0.244152 2.336861 9.637057
 | 
				
			||||||
 | 
					v -3.688147 -0.482677 9.398805
 | 
				
			||||||
 | 
					v -3.115998 -3.115998 8.130575
 | 
				
			||||||
 | 
					v -3.110920 2.110920 6.971905
 | 
				
			||||||
 | 
					v 2.082467 2.063153 8.144089
 | 
				
			||||||
 | 
					v 2.240869 -3.240869 6.971905
 | 
				
			||||||
 | 
					v -0.502522 -0.497707 10.881164
 | 
				
			||||||
 | 
					v -1.198718 0.104834 3.915295
 | 
				
			||||||
 | 
					v -1.328801 -1.139141 4.040936
 | 
				
			||||||
 | 
					v -3.441890 -0.495848 -0.000000
 | 
				
			||||||
 | 
					v -1.496232 0.385397 -0.000000
 | 
				
			||||||
 | 
					v -0.500000 2.662470 -0.000000
 | 
				
			||||||
 | 
					v 0.191434 0.532933 -0.000000
 | 
				
			||||||
 | 
					v 0.311519 -1.083752 4.188119
 | 
				
			||||||
 | 
					v 0.218048 0.042459 3.963527
 | 
				
			||||||
 | 
					vn -0.0000 -0.0000 1.0000
 | 
				
			||||||
 | 
					vn -0.0201 0.0161 0.9997
 | 
				
			||||||
 | 
					vn -0.0167 0.0210 0.9996
 | 
				
			||||||
 | 
					vn -0.0009 0.0032 1.0000
 | 
				
			||||||
 | 
					vn 0.0244 0.0111 0.9996
 | 
				
			||||||
 | 
					vn 0.0019 0.0045 1.0000
 | 
				
			||||||
 | 
					vn -0.0161 -0.0201 0.9997
 | 
				
			||||||
 | 
					vn 0.0022 0.0009 1.0000
 | 
				
			||||||
 | 
					vn 0.0235 -0.0145 0.9996
 | 
				
			||||||
 | 
					vn -0.0013 -0.0031 1.0000
 | 
				
			||||||
 | 
					vn 0.0145 0.0235 0.9996
 | 
				
			||||||
 | 
					vn 0.0019 -0.0045 1.0000
 | 
				
			||||||
 | 
					vn -0.0222 -0.0167 0.9996
 | 
				
			||||||
 | 
					vn -0.0022 0.0009 1.0000
 | 
				
			||||||
 | 
					vn 0.0167 -0.0222 0.9996
 | 
				
			||||||
 | 
					vn 0.0098 -0.7987 0.6016
 | 
				
			||||||
 | 
					vn -0.6002 -0.5408 0.5893
 | 
				
			||||||
 | 
					vn 0.0044 -0.4121 0.9111
 | 
				
			||||||
 | 
					vn 0.7681 -0.0085 0.6403
 | 
				
			||||||
 | 
					vn 0.6329 -0.5379 0.5569
 | 
				
			||||||
 | 
					vn 0.4115 0.0013 0.9114
 | 
				
			||||||
 | 
					vn -0.7225 -0.0072 0.6914
 | 
				
			||||||
 | 
					vn -0.5435 0.5132 0.6643
 | 
				
			||||||
 | 
					vn -0.3281 -0.0009 0.9446
 | 
				
			||||||
 | 
					vn 0.0396 0.7635 0.6445
 | 
				
			||||||
 | 
					vn 0.6430 0.5228 0.5597
 | 
				
			||||||
 | 
					vn 0.0118 0.3475 0.9376
 | 
				
			||||||
 | 
					vn 0.0112 -0.9310 -0.3649
 | 
				
			||||||
 | 
					vn -0.0190 -0.0189 0.9996
 | 
				
			||||||
 | 
					vn 0.0255 -0.0085 0.9996
 | 
				
			||||||
 | 
					vn -0.0021 0.0025 1.0000
 | 
				
			||||||
 | 
					vn -0.0059 0.0251 0.9997
 | 
				
			||||||
 | 
					vn 0.0258 -0.0005 0.9997
 | 
				
			||||||
 | 
					vn -0.0242 0.0132 0.9996
 | 
				
			||||||
 | 
					vn 0.0084 -0.0263 0.9996
 | 
				
			||||||
 | 
					vn 0.0013 0.0020 1.0000
 | 
				
			||||||
 | 
					vn -0.0255 0.0110 0.9996
 | 
				
			||||||
 | 
					vn 0.0047 -0.0013 1.0000
 | 
				
			||||||
 | 
					vn 0.0163 0.0225 0.9996
 | 
				
			||||||
 | 
					vn -0.0405 0.9454 -0.3235
 | 
				
			||||||
 | 
					vn -0.8888 -0.0010 -0.4582
 | 
				
			||||||
 | 
					vn -0.5741 0.5901 -0.5676
 | 
				
			||||||
 | 
					vn 0.9300 0.0097 -0.3674
 | 
				
			||||||
 | 
					vn 0.0432 0.9043 -0.4247
 | 
				
			||||||
 | 
					vn -0.8888 -0.0140 -0.4582
 | 
				
			||||||
 | 
					vn -0.6604 0.7507 -0.0172
 | 
				
			||||||
 | 
					vn -0.5551 -0.6008 -0.5753
 | 
				
			||||||
 | 
					vn 0.8903 0.0610 -0.4513
 | 
				
			||||||
 | 
					vn 0.7025 0.6869 0.1860
 | 
				
			||||||
 | 
					vn -0.0339 -0.8975 -0.4397
 | 
				
			||||||
 | 
					vn 0.7100 -0.7018 -0.0587
 | 
				
			||||||
 | 
					vn 0.0210 -0.7749 0.6317
 | 
				
			||||||
 | 
					vn 0.7640 -0.0622 0.6422
 | 
				
			||||||
 | 
					vn -0.0221 0.0118 0.9997
 | 
				
			||||||
 | 
					vn -0.0259 -0.0071 0.9996
 | 
				
			||||||
 | 
					vn 0.0113 -0.0243 0.9996
 | 
				
			||||||
 | 
					vn 0.0108 0.0234 0.9997
 | 
				
			||||||
 | 
					vn 0.0154 -0.0207 0.9997
 | 
				
			||||||
 | 
					vn 0.0042 0.0024 1.0000
 | 
				
			||||||
 | 
					vn -0.0167 0.0220 0.9996
 | 
				
			||||||
 | 
					vn -0.0033 -0.0001 1.0000
 | 
				
			||||||
 | 
					vn -0.0233 -0.0149 0.9996
 | 
				
			||||||
 | 
					vn -0.0083 0.0265 0.9996
 | 
				
			||||||
 | 
					vn 0.0268 0.0073 0.9996
 | 
				
			||||||
 | 
					vn -0.0005 0.0023 1.0000
 | 
				
			||||||
 | 
					vn -0.6682 -0.7164 0.2005
 | 
				
			||||||
 | 
					vn -0.7942 0.0579 0.6049
 | 
				
			||||||
 | 
					vn 0.0056 0.7710 0.6368
 | 
				
			||||||
 | 
					vn 0.5913 -0.6605 -0.4628
 | 
				
			||||||
 | 
					vn 0.6398 -0.1352 -0.7566
 | 
				
			||||||
 | 
					vn 0.4614 -0.4637 -0.7564
 | 
				
			||||||
 | 
					vn 0.0956 -0.6354 -0.7663
 | 
				
			||||||
 | 
					vn 0.5767 0.6707 -0.4664
 | 
				
			||||||
 | 
					vn 0.0524 0.6458 -0.7617
 | 
				
			||||||
 | 
					vn 0.4830 0.4998 -0.7190
 | 
				
			||||||
 | 
					vn -0.5477 -0.0500 -0.8352
 | 
				
			||||||
 | 
					vn -0.4291 0.5258 -0.7344
 | 
				
			||||||
 | 
					vn -0.4247 -0.5067 -0.7503
 | 
				
			||||||
 | 
					vt 0.000000 0.000000
 | 
				
			||||||
 | 
					vt 0.500000 0.000000
 | 
				
			||||||
 | 
					vt 1.000000 0.000000
 | 
				
			||||||
 | 
					vt -0.000000 0.500000
 | 
				
			||||||
 | 
					vt 1.000000 0.500000
 | 
				
			||||||
 | 
					vt 0.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.500000 1.000000
 | 
				
			||||||
 | 
					vt 1.000000 1.000000
 | 
				
			||||||
 | 
					vt 0.273438 0.289062
 | 
				
			||||||
 | 
					vt 0.046875 0.046875
 | 
				
			||||||
 | 
					vt 0.726923 0.289572
 | 
				
			||||||
 | 
					vt 0.953125 0.046875
 | 
				
			||||||
 | 
					vt 0.750000 0.750000
 | 
				
			||||||
 | 
					vt 0.250000 0.250000
 | 
				
			||||||
 | 
					vt 0.492188 0.070312
 | 
				
			||||||
 | 
					vt 0.140625 -0.000000
 | 
				
			||||||
 | 
					vt 0.859375 -0.000000
 | 
				
			||||||
 | 
					vt 0.750000 0.250000
 | 
				
			||||||
 | 
					vt 0.250000 0.750000
 | 
				
			||||||
 | 
					vt 0.929688 0.492188
 | 
				
			||||||
 | 
					vt 1.000000 0.093750
 | 
				
			||||||
 | 
					vt 1.000000 0.906250
 | 
				
			||||||
 | 
					vt 0.492188 0.085938
 | 
				
			||||||
 | 
					vt 0.914062 0.492188
 | 
				
			||||||
 | 
					vt 0.085938 0.492188
 | 
				
			||||||
 | 
					vt 0.492188 0.898438
 | 
				
			||||||
 | 
					vt 0.882812 0.492188
 | 
				
			||||||
 | 
					vt 0.492188 0.117188
 | 
				
			||||||
 | 
					vt 0.492188 0.867188
 | 
				
			||||||
 | 
					vt 0.117188 0.492188
 | 
				
			||||||
 | 
					vt 0.742188 0.492188
 | 
				
			||||||
 | 
					vt 0.835938 0.492188
 | 
				
			||||||
 | 
					vt 0.492188 0.164062
 | 
				
			||||||
 | 
					vt 0.492188 0.257812
 | 
				
			||||||
 | 
					vt 0.492188 0.742188
 | 
				
			||||||
 | 
					vt 0.492188 0.835938
 | 
				
			||||||
 | 
					vt 0.257812 0.492188
 | 
				
			||||||
 | 
					vt 0.164062 0.492188
 | 
				
			||||||
 | 
					vt 0.601562 0.492188
 | 
				
			||||||
 | 
					vt 0.492188 0.382812
 | 
				
			||||||
 | 
					vt 0.492188 0.617188
 | 
				
			||||||
 | 
					vt 0.382812 0.492188
 | 
				
			||||||
 | 
					vt 0.398438 0.398438
 | 
				
			||||||
 | 
					vt 0.398438 0.585938
 | 
				
			||||||
 | 
					vt 0.585938 0.585938
 | 
				
			||||||
 | 
					vt 0.585938 0.398438
 | 
				
			||||||
 | 
					vt 0.492188 0.492188
 | 
				
			||||||
 | 
					vt 0.335938 0.664062
 | 
				
			||||||
 | 
					vt 0.304688 0.710938
 | 
				
			||||||
 | 
					vt 0.335938 0.335938
 | 
				
			||||||
 | 
					vt 0.289062 0.289062
 | 
				
			||||||
 | 
					vt 0.070312 0.492188
 | 
				
			||||||
 | 
					vt 0.000000 0.109375
 | 
				
			||||||
 | 
					vt 0.000000 0.875000
 | 
				
			||||||
 | 
					vt 0.289062 0.710938
 | 
				
			||||||
 | 
					vt 0.046875 0.953125
 | 
				
			||||||
 | 
					vt 0.492188 0.914062
 | 
				
			||||||
 | 
					vt 0.125000 1.000000
 | 
				
			||||||
 | 
					vt 0.875000 1.000000
 | 
				
			||||||
 | 
					vt 0.726562 0.695312
 | 
				
			||||||
 | 
					vt 0.953125 0.953125
 | 
				
			||||||
 | 
					vt 0.664062 0.335938
 | 
				
			||||||
 | 
					vt 0.710938 0.289062
 | 
				
			||||||
 | 
					vt 0.664062 0.664062
 | 
				
			||||||
 | 
					vt 0.710938 0.695312
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					usemtl forest
 | 
				
			||||||
 | 
					f 35/35/7 36/36/7 47/51/8
 | 
				
			||||||
 | 
					f 34/34/7 35/35/7 45/47/9
 | 
				
			||||||
 | 
					f 37/37/10 34/34/7 45/47/11
 | 
				
			||||||
 | 
					f 36/36/7 38/38/12 47/51/13
 | 
				
			||||||
 | 
					f 40/40/14 39/39/7 48/52/15
 | 
				
			||||||
 | 
					f 39/39/7 37/37/16 48/52/17
 | 
				
			||||||
 | 
					f 38/38/18 41/41/7 44/46/19
 | 
				
			||||||
 | 
					f 41/41/7 40/40/20 44/46/21
 | 
				
			||||||
 | 
					s 1
 | 
				
			||||||
 | 
					f 50/56/22 42/42/23 46/48/24
 | 
				
			||||||
 | 
					f 51/57/25 43/44/26 49/53/27
 | 
				
			||||||
 | 
					f 52/58/28 74/88/29 73/85/30
 | 
				
			||||||
 | 
					f 53/59/31 74/88/29 52/58/28
 | 
				
			||||||
 | 
					f 53/59/31 76/93/32 75/90/33
 | 
				
			||||||
 | 
					f 50/56/22 46/48/24 43/44/26
 | 
				
			||||||
 | 
					f 51/57/25 50/56/22 43/44/26
 | 
				
			||||||
 | 
					f 51/57/25 49/53/27 76/93/32
 | 
				
			||||||
 | 
					f 53/59/31 51/57/25 76/93/32
 | 
				
			||||||
 | 
					f 53/59/31 75/90/33 74/88/29
 | 
				
			||||||
 | 
					f 52/58/28 73/85/30 42/42/23
 | 
				
			||||||
 | 
					f 52/58/28 42/42/23 50/56/22
 | 
				
			||||||
 | 
					f 51/57/25 55/61/34 50/56/22
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					f 45/47/35 46/49/7 42/43/7
 | 
				
			||||||
 | 
					f 45/47/36 73/86/7 37/37/37
 | 
				
			||||||
 | 
					f 47/51/38 46/50/7 35/35/7
 | 
				
			||||||
 | 
					f 47/51/39 49/54/7 43/45/7
 | 
				
			||||||
 | 
					f 48/52/40 73/87/7 74/89/7
 | 
				
			||||||
 | 
					f 48/52/41 75/91/7 40/40/42
 | 
				
			||||||
 | 
					f 44/46/43 49/55/7 38/38/44
 | 
				
			||||||
 | 
					f 44/46/45 75/92/7 76/94/7
 | 
				
			||||||
 | 
					s 1
 | 
				
			||||||
 | 
					f 56/62/46 57/63/47 71/82/48
 | 
				
			||||||
 | 
					f 53/59/31 54/60/49 51/57/25
 | 
				
			||||||
 | 
					f 52/58/28 56/62/46 53/59/31
 | 
				
			||||||
 | 
					f 50/56/22 57/63/47 52/58/28
 | 
				
			||||||
 | 
					f 60/68/50 61/70/51 67/77/52
 | 
				
			||||||
 | 
					f 57/63/47 55/61/34 72/84/53
 | 
				
			||||||
 | 
					f 58/64/54 60/68/50 68/78/55
 | 
				
			||||||
 | 
					f 59/67/56 58/64/54 69/79/57
 | 
				
			||||||
 | 
					f 63/73/58 62/72/59 70/80/60
 | 
				
			||||||
 | 
					s 0
 | 
				
			||||||
 | 
					f 45/47/61 35/35/7 46/49/7
 | 
				
			||||||
 | 
					f 45/47/62 42/43/7 73/86/7
 | 
				
			||||||
 | 
					f 47/51/63 43/45/7 46/50/7
 | 
				
			||||||
 | 
					f 47/51/64 38/38/65 49/54/7
 | 
				
			||||||
 | 
					f 48/52/66 37/37/67 73/87/7
 | 
				
			||||||
 | 
					f 48/52/68 74/89/7 75/91/7
 | 
				
			||||||
 | 
					f 44/46/69 76/94/7 49/55/7
 | 
				
			||||||
 | 
					f 44/46/70 40/40/71 75/92/7
 | 
				
			||||||
 | 
					s 1
 | 
				
			||||||
 | 
					f 61/70/51 59/67/56 66/76/72
 | 
				
			||||||
 | 
					f 59/67/56 63/73/58 66/76/72
 | 
				
			||||||
 | 
					f 63/73/58 65/75/73 66/76/72
 | 
				
			||||||
 | 
					f 65/75/73 61/70/51 66/76/72
 | 
				
			||||||
 | 
					f 61/70/51 65/75/73 67/77/52
 | 
				
			||||||
 | 
					f 65/75/73 64/74/74 67/77/52
 | 
				
			||||||
 | 
					f 64/74/74 60/68/50 67/77/52
 | 
				
			||||||
 | 
					f 60/68/50 64/74/74 68/78/55
 | 
				
			||||||
 | 
					f 64/74/74 62/72/59 68/78/55
 | 
				
			||||||
 | 
					f 62/72/59 58/64/54 68/78/55
 | 
				
			||||||
 | 
					f 58/64/54 62/72/59 69/79/57
 | 
				
			||||||
 | 
					f 62/72/59 63/73/58 69/79/57
 | 
				
			||||||
 | 
					f 63/73/58 59/67/56 69/79/57
 | 
				
			||||||
 | 
					f 62/72/59 64/74/74 70/80/60
 | 
				
			||||||
 | 
					f 64/74/74 65/75/73 70/80/60
 | 
				
			||||||
 | 
					f 65/75/73 63/73/58 70/80/60
 | 
				
			||||||
 | 
					f 55/61/34 54/60/49 77/96/75
 | 
				
			||||||
 | 
					f 54/60/49 58/65/76 77/96/75
 | 
				
			||||||
 | 
					f 58/64/54 59/67/56 77/95/77
 | 
				
			||||||
 | 
					f 59/66/78 55/61/34 77/96/75
 | 
				
			||||||
 | 
					f 54/60/49 56/62/46 78/98/79
 | 
				
			||||||
 | 
					f 56/62/46 60/69/80 78/98/79
 | 
				
			||||||
 | 
					f 60/68/50 58/64/54 78/97/81
 | 
				
			||||||
 | 
					f 58/65/76 54/60/49 78/98/79
 | 
				
			||||||
 | 
					f 57/63/47 61/71/82 71/82/48
 | 
				
			||||||
 | 
					f 61/70/51 60/68/50 71/81/83
 | 
				
			||||||
 | 
					f 60/69/80 56/62/46 71/82/48
 | 
				
			||||||
 | 
					f 55/61/34 59/66/78 72/84/53
 | 
				
			||||||
 | 
					f 59/67/56 61/70/51 72/83/84
 | 
				
			||||||
 | 
					f 61/71/82 57/63/47 72/84/53
 | 
				
			||||||
 | 
					f 51/57/25 54/60/49 55/61/34
 | 
				
			||||||
 | 
					f 53/59/31 56/62/46 54/60/49
 | 
				
			||||||
 | 
					f 52/58/28 57/63/47 56/62/46
 | 
				
			||||||
 | 
					f 50/56/22 55/61/34 57/63/47
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								data/tiles/water.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/tiles/water.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								docs/tiling.odg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								game/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										60
									
								
								game/batch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from engine import (
 | 
				
			||||||
 | 
					    INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, BATCH_ORIENTATION_FORMAT_NONE, create_batch, draw_batch, destroy_batch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Batch:
 | 
				
			||||||
 | 
					    __slots__ = '_batch', 'max_size', 'flags', 'texlevels', 'meshes', 'translations', 'orientations'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, max_size, translation_format, orientation_format):
 | 
				
			||||||
 | 
					        assert max_size <= BATCH_MAX_SIZE
 | 
				
			||||||
 | 
					        self._batch = create_batch(max_size, translation_format, orientation_format)
 | 
				
			||||||
 | 
					        self.max_size = max_size
 | 
				
			||||||
 | 
					        self.flags = array('B')
 | 
				
			||||||
 | 
					        self.texlevels = array('H')
 | 
				
			||||||
 | 
					        self.meshes = array('I')
 | 
				
			||||||
 | 
					        self.translations = array('f')
 | 
				
			||||||
 | 
					        if orientation_format != BATCH_ORIENTATION_FORMAT_NONE:
 | 
				
			||||||
 | 
					            self.orientations = array('f')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.orientations = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __del__(self):
 | 
				
			||||||
 | 
					        destroy_batch(self._batch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def append(self, flags, texlevel, mesh, translation, orientation):
 | 
				
			||||||
 | 
					        assert len(translation) == 3
 | 
				
			||||||
 | 
					        assert orientation is None or len(orientation) == 3
 | 
				
			||||||
 | 
					        index = len(self.flags)
 | 
				
			||||||
 | 
					        assert index < self.max_size
 | 
				
			||||||
 | 
					        self.flags.append(flags | INSTANCE_FLAG_SPAWNED)
 | 
				
			||||||
 | 
					        self.texlevels.append(texlevel)
 | 
				
			||||||
 | 
					        self.meshes.append(mesh)
 | 
				
			||||||
 | 
					        self.translations.extend(translation)
 | 
				
			||||||
 | 
					        if self.orientations is not None:
 | 
				
			||||||
 | 
					            self.orientations.extend(orientation)
 | 
				
			||||||
 | 
					        return index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_translation(self, index, translation):
 | 
				
			||||||
 | 
					        self.translations[index * 3 : index * 3 + 3] = translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_orientation(self, index, orientation):
 | 
				
			||||||
 | 
					        self.orientations[index * 3 : index * 3 + 3] = orientation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def draw(self):
 | 
				
			||||||
 | 
					        draw_batch(self._batch, self.flags, self.texlevels, self.meshes, self.translations, self.orientations)
 | 
				
			||||||
							
								
								
									
										88
									
								
								game/environment.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from math import radians, cos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from engine import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game.math import vec3_add, vec3_sub, vec3_scale, vec3_mul, vec3_dot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _angles(start, end):
 | 
				
			||||||
 | 
					    cmin = round(cos(radians(start)), 6)
 | 
				
			||||||
 | 
					    cmax = round(cos(radians(end)), 6)
 | 
				
			||||||
 | 
					    return (cmin, cmax, 1.0 / (cmax - cmin))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _floats(a, b):
 | 
				
			||||||
 | 
					    return (a, b - a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _colors(a, b):
 | 
				
			||||||
 | 
					    return (a, vec3_sub(b, a))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_light_color = (
 | 
				
			||||||
 | 
					    (_angles(180.0, 0.0), _colors((1.0, 1.0, 1.0), (1.0, 1.0, 1.0))),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_horizon_color = (
 | 
				
			||||||
 | 
					    (_angles(180.0, 0.0), _colors((0.75, 0.75, 1.0), (0.75, 0.75, 1.0))),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_sky_color = (
 | 
				
			||||||
 | 
					    (_angles(180.0, 0.0), _colors((0.0, 0.0, 0.5), (0.0, 0.0, 0.5))),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_sun_color = (
 | 
				
			||||||
 | 
					    (_angles(180.0, 0.0), _colors((8.0, 8.0, 4.0), (8.0, 8.0, 4.0))),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_light_power = (
 | 
				
			||||||
 | 
					    (_angles(180.0, 90.0), _floats(0.0, 0.0)),
 | 
				
			||||||
 | 
					    (_angles( 90.0,  0.0), _floats(0.0, 1.0))
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _resolve(ranges, c):
 | 
				
			||||||
 | 
					    for (cmin, cmax, crng), ab in ranges:
 | 
				
			||||||
 | 
					        if c >= cmin and c <= cmax:
 | 
				
			||||||
 | 
					            return ((c - cmin) * crng, ab)
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _resolve_float(ranges, c):
 | 
				
			||||||
 | 
					    w, (a, b) = _resolve(ranges, c)
 | 
				
			||||||
 | 
					    return a + (b * w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _resolve_color(ranges, c):
 | 
				
			||||||
 | 
					    w, (a, b) = _resolve(ranges, c)
 | 
				
			||||||
 | 
					    return vec3_add(a, vec3_scale(b, w))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def resolve_inputs():
 | 
				
			||||||
 | 
					    light_direction = resolve_input(b'u_light_direction')
 | 
				
			||||||
 | 
					    light_color = resolve_input(b'u_light_color')
 | 
				
			||||||
 | 
					    horizon_color = resolve_input(b'u_horizon_color')
 | 
				
			||||||
 | 
					    sky_color = resolve_input(b'u_sky_color')
 | 
				
			||||||
 | 
					    sun_color = resolve_input(b'u_sun_color')
 | 
				
			||||||
 | 
					    return (light_direction, light_color, horizon_color, sky_color, sun_color)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def from_sun(sun_direction, sun_power):
 | 
				
			||||||
 | 
					    c = vec3_dot(sun_direction, vec3_up)
 | 
				
			||||||
 | 
					    light_power = _resolve_float(_light_power, c) * sun_power
 | 
				
			||||||
 | 
					    light_color = vec3_scale(_resolve_color(_light_color, c), sun_power) # vec3_scale(_resolve_color(_light_color, c), light_power)
 | 
				
			||||||
 | 
					    horizon_color = vec3_mul(_resolve_color(_horizon_color, c), light_color)
 | 
				
			||||||
 | 
					    sky_color = vec3_mul(_resolve_color(_sky_color, c), light_color)
 | 
				
			||||||
 | 
					    sun_color = _resolve_color(_sun_color, c)
 | 
				
			||||||
 | 
					    return (vec3(sun_direction), vec3(light_color), vec3(horizon_color), vec3(sky_color), vec3(sun_color))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_modes = (INPUT_VIEW_ORIENTATION, INPUT_IDENTITY, INPUT_IDENTITY, INPUT_IDENTITY, INPUT_IDENTITY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def set_inputs(inputs, values):
 | 
				
			||||||
 | 
					    list(map(set_input_vec3, inputs, values, _modes))
 | 
				
			||||||
							
								
								
									
										251
									
								
								game/game.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,251 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					from math import pi, tau, dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from engine import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game import math, resources, batch, triangles, generator, environment, sea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    print("Generating terrain...")
 | 
				
			||||||
 | 
					    gen_begin = time.process_time()
 | 
				
			||||||
 | 
					    generated = generator.Generator(256)
 | 
				
			||||||
 | 
					    gen_end = time.process_time()
 | 
				
			||||||
 | 
					    print("Done: ", round(gen_end - gen_begin, 2), "seconds")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Initializing...")
 | 
				
			||||||
 | 
					    window = initialize(b'RK Island')
 | 
				
			||||||
 | 
					    terrain_shader = load_shader(b'game/shaders/terrain')
 | 
				
			||||||
 | 
					    sky_shader = load_shader(b'game/shaders/sky')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Loading resources...")
 | 
				
			||||||
 | 
					    select_shader(terrain_shader)
 | 
				
			||||||
 | 
					    archive = resources.RuntimeArchive.load('data/rk_island.rkar')
 | 
				
			||||||
 | 
					    tiles_texture = archive.get_texture('tiles')
 | 
				
			||||||
 | 
					    tiles_vertices = archive.get_vertices('tiles')
 | 
				
			||||||
 | 
					    water = archive.get_model('water')
 | 
				
			||||||
 | 
					    sand = archive.get_model('sand')
 | 
				
			||||||
 | 
					    grass = archive.get_model('grass')
 | 
				
			||||||
 | 
					    forest = archive.get_model('forest')
 | 
				
			||||||
 | 
					    rock = archive.get_model('rock')
 | 
				
			||||||
 | 
					    mud = archive.get_model('mud')
 | 
				
			||||||
 | 
					    lava = archive.get_model('lava')
 | 
				
			||||||
 | 
					    heightmap = create_texture(1, b'u_height_sampler',
 | 
				
			||||||
 | 
					        TEXTURE_FORMAT_32F, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR,
 | 
				
			||||||
 | 
					        generated.packed_heights)
 | 
				
			||||||
 | 
					    normalmap = create_texture(2, b'u_normal_sampler',
 | 
				
			||||||
 | 
					        TEXTURE_FORMAT_RGB10_A2, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR,
 | 
				
			||||||
 | 
					        generated.packed_normals)
 | 
				
			||||||
 | 
					    select_vertices(tiles_vertices)
 | 
				
			||||||
 | 
					    terrain_batch = batch.Batch(
 | 
				
			||||||
 | 
					        generated.size ** 2, BATCH_TRANSLATION_FORMAT_SHORT, BATCH_ORIENTATION_FORMAT_NONE)
 | 
				
			||||||
 | 
					    unselect_vertices(tiles_vertices)
 | 
				
			||||||
 | 
					    terrain_environment_inputs = environment.resolve_inputs()
 | 
				
			||||||
 | 
					    tests_texture = archive.get_texture('tests')
 | 
				
			||||||
 | 
					    tests_vertices = archive.get_vertices('tests')
 | 
				
			||||||
 | 
					    blob = archive.get_model('blob')
 | 
				
			||||||
 | 
					    cube = archive.get_model('cube')
 | 
				
			||||||
 | 
					    clouds = archive.get_model('clouds')
 | 
				
			||||||
 | 
					    select_vertices(tests_vertices)
 | 
				
			||||||
 | 
					    tests_batch = batch.Batch(3, BATCH_TRANSLATION_FORMAT_FLOAT, BATCH_ORIENTATION_FORMAT_FLOAT)
 | 
				
			||||||
 | 
					    unselect_vertices(tests_vertices)
 | 
				
			||||||
 | 
					    unselect_shader(terrain_shader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #TODO: generator & for real
 | 
				
			||||||
 | 
					    print("Building tiles...")
 | 
				
			||||||
 | 
					    vc = generated.volcano_c
 | 
				
			||||||
 | 
					    vr = generated.volcano_r
 | 
				
			||||||
 | 
					    for my, mx in generated.map_coords:
 | 
				
			||||||
 | 
					        vd = dist((mx + 0.5, my + 0.5), vc)
 | 
				
			||||||
 | 
					        nx, ny, nz, h = generated.unpack(my, mx)
 | 
				
			||||||
 | 
					        r = generated.rivers[my * generated.size + mx]
 | 
				
			||||||
 | 
					        if h == 0.0:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        if r > 0.0:
 | 
				
			||||||
 | 
					            model = water
 | 
				
			||||||
 | 
					        elif h < 2.0:
 | 
				
			||||||
 | 
					            model = sand
 | 
				
			||||||
 | 
					        elif h < 180:
 | 
				
			||||||
 | 
					            if nz > 0.9:
 | 
				
			||||||
 | 
					                if ny < -0.01 and nz > 0.93:
 | 
				
			||||||
 | 
					                    model = forest
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    model = grass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                model = rock
 | 
				
			||||||
 | 
					        elif vd < vr - 3.0 and nz > 0.999:
 | 
				
			||||||
 | 
					            model = lava
 | 
				
			||||||
 | 
					        elif vd < vr + 2.0:
 | 
				
			||||||
 | 
					            model = mud
 | 
				
			||||||
 | 
					        elif vd < vr + 6.0 and nz < 0.67:
 | 
				
			||||||
 | 
					            model = mud
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            model = rock
 | 
				
			||||||
 | 
					        model.spawn(terrain_batch, (float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0), None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    blob_translation = vec3((-100.0, -500.0, 0.0))
 | 
				
			||||||
 | 
					    cube_translation = vec3((100.0, -500.0, 0.0))
 | 
				
			||||||
 | 
					    cube_orientation = vec3(vec3_forward)
 | 
				
			||||||
 | 
					    clouds_orientation = vec3(vec3_forward)
 | 
				
			||||||
 | 
					    blob_id = blob.spawn(tests_batch, blob_translation)
 | 
				
			||||||
 | 
					    cube_id = cube.spawn(tests_batch, cube_translation, cube_orientation)
 | 
				
			||||||
 | 
					    clouds_id = clouds.spawn(tests_batch, (0.0, 0.0, 32.0), clouds_orientation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    proj_hfov = pi * 0.25
 | 
				
			||||||
 | 
					    proj_ratio = 16.0 / 9.0
 | 
				
			||||||
 | 
					    proj_near_z = 8.0
 | 
				
			||||||
 | 
					    proj_far_z = 3000.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    select_shader(sky_shader)
 | 
				
			||||||
 | 
					    sky_environment_inputs = environment.resolve_inputs()
 | 
				
			||||||
 | 
					    sea_phase = resolve_input(b'u_sea_phase')
 | 
				
			||||||
 | 
					    sea_polar_textures = sea.load_polar_textures(('data/sea_bump1.png', 'data/sea_bump2.png'))
 | 
				
			||||||
 | 
					    sea_detail_texture = sea.load_detail_texture('data/sea_bump.png')
 | 
				
			||||||
 | 
					    sky_triangles = create_triangles(triangles.sky_triangles(64, proj_far_z - 0.1, proj_ratio))
 | 
				
			||||||
 | 
					    unselect_shader(sky_shader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sun_direction = vec3(math.vec3_normalize((1.0, 0.0, 1.0)))
 | 
				
			||||||
 | 
					    sun_power = 1.0
 | 
				
			||||||
 | 
					    camera = vec3((0.0, -1200.0, 500.0))
 | 
				
			||||||
 | 
					    lookat = vec3((0.0,  500.0, -500.0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    start_time = time.monotonic()
 | 
				
			||||||
 | 
					    current_time = 0.0
 | 
				
			||||||
 | 
					    up = vec3(vec3_up)
 | 
				
			||||||
 | 
					    _rotation = mat3()
 | 
				
			||||||
 | 
					    _camera = vec3()
 | 
				
			||||||
 | 
					    _lookat = vec3()
 | 
				
			||||||
 | 
					    _blob_translation = vec3()
 | 
				
			||||||
 | 
					    _cube_translation = vec3()
 | 
				
			||||||
 | 
					    _cube_orientation = vec3()
 | 
				
			||||||
 | 
					    _clouds_orientation = vec3()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Running...")
 | 
				
			||||||
 | 
					    frame_min = 10000.0
 | 
				
			||||||
 | 
					    frame_max = 0.0
 | 
				
			||||||
 | 
					    frame_avg = 0.0
 | 
				
			||||||
 | 
					    draw_min = 10000.0
 | 
				
			||||||
 | 
					    draw_max = 0.0
 | 
				
			||||||
 | 
					    draw_avg = 0.0
 | 
				
			||||||
 | 
					    perf_count = 0
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        for x in range(10000):
 | 
				
			||||||
 | 
					            current_time = time.monotonic() - start_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            begin_frame()
 | 
				
			||||||
 | 
					            frame_begin = time.thread_time()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mat3_rotation(_rotation, up, (current_time * 0.05) % tau)
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_camera, _rotation, camera)
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_lookat, _rotation, lookat)
 | 
				
			||||||
 | 
					            set_view(_camera, _lookat)
 | 
				
			||||||
 | 
					            set_projection(proj_hfov, proj_ratio, proj_near_z, proj_far_z)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mat3_rotation(_rotation, up, (current_time * 0.21) % tau)
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_blob_translation, _rotation, blob_translation)
 | 
				
			||||||
 | 
					            tests_batch.set_translation(blob_id, _blob_translation)
 | 
				
			||||||
 | 
					            tests_batch.set_orientation(blob_id, vec3(math.vec3_normalize((sun_direction[0], sun_direction[1], 0.0))))
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_cube_translation, _rotation, cube_translation)
 | 
				
			||||||
 | 
					            tests_batch.set_translation(cube_id, _cube_translation)
 | 
				
			||||||
 | 
					            mat3_rotation(_rotation, up, (current_time * 0.43) % tau)
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_cube_orientation, _rotation, cube_orientation)
 | 
				
			||||||
 | 
					            tests_batch.set_orientation(cube_id, _cube_orientation)
 | 
				
			||||||
 | 
					            mat3_rotation(_rotation, up, (current_time * -0.037) % tau)
 | 
				
			||||||
 | 
					            mat3_mul_vec3(_clouds_orientation, _rotation, clouds_orientation)
 | 
				
			||||||
 | 
					            tests_batch.set_orientation(clouds_id, _clouds_orientation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            environment_values = environment.from_sun(sun_direction, sun_power)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            select_shader(terrain_shader)
 | 
				
			||||||
 | 
					            select_texture(heightmap)
 | 
				
			||||||
 | 
					            select_texture(normalmap)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            environment.set_inputs(terrain_environment_inputs, environment_values)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            select_texture(tiles_texture)
 | 
				
			||||||
 | 
					            select_vertices(tiles_vertices)
 | 
				
			||||||
 | 
					            draw_begin = time.thread_time()
 | 
				
			||||||
 | 
					            terrain_batch.draw()
 | 
				
			||||||
 | 
					            draw_end = time.thread_time()
 | 
				
			||||||
 | 
					            unselect_vertices(tiles_vertices)
 | 
				
			||||||
 | 
					            unselect_texture(tiles_texture)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            select_texture(tests_texture)
 | 
				
			||||||
 | 
					            select_vertices(tests_vertices)
 | 
				
			||||||
 | 
					            tests_batch.draw()
 | 
				
			||||||
 | 
					            unselect_vertices(tests_vertices)
 | 
				
			||||||
 | 
					            unselect_texture(tests_texture)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            unselect_texture(normalmap)
 | 
				
			||||||
 | 
					            unselect_texture(heightmap)
 | 
				
			||||||
 | 
					            unselect_shader(terrain_shader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            select_shader(sky_shader)
 | 
				
			||||||
 | 
					            environment.set_inputs(sky_environment_inputs, environment_values)
 | 
				
			||||||
 | 
					            set_input_float(sea_phase, (current_time * 0.023) % 1.0)
 | 
				
			||||||
 | 
					            select_texture(sea_polar_textures)
 | 
				
			||||||
 | 
					            select_texture(sea_detail_texture)
 | 
				
			||||||
 | 
					            draw_triangles(sky_triangles)
 | 
				
			||||||
 | 
					            unselect_texture(sea_detail_texture)
 | 
				
			||||||
 | 
					            unselect_texture(sea_polar_textures)
 | 
				
			||||||
 | 
					            unselect_shader(sky_shader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            frame_end = time.thread_time()
 | 
				
			||||||
 | 
					            end_frame()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            draw_ms = draw_end - draw_begin
 | 
				
			||||||
 | 
					            draw_min = min(draw_min, draw_ms)
 | 
				
			||||||
 | 
					            draw_max = max(draw_max, draw_ms)
 | 
				
			||||||
 | 
					            draw_avg += draw_ms
 | 
				
			||||||
 | 
					            frame_ms = frame_end - frame_begin
 | 
				
			||||||
 | 
					            frame_min = min(frame_min, frame_ms)
 | 
				
			||||||
 | 
					            frame_max = max(frame_max, frame_ms)
 | 
				
			||||||
 | 
					            frame_avg += frame_ms
 | 
				
			||||||
 | 
					            perf_count += 1
 | 
				
			||||||
 | 
					    except KeyboardInterrupt:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("\rDraw  *", perf_count,
 | 
				
			||||||
 | 
					        ": min =", round(draw_min * 1000.0, 2),
 | 
				
			||||||
 | 
					        ", max =", round(draw_max * 1000.0, 2),
 | 
				
			||||||
 | 
					        ", avg =", round((draw_avg / perf_count) * 1000.0, 2), "ms")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("\rFrame *", perf_count,
 | 
				
			||||||
 | 
					        ": min =", round(frame_min * 1000.0, 2),
 | 
				
			||||||
 | 
					        ", max =", round(frame_max * 1000.0, 2),
 | 
				
			||||||
 | 
					        ", avg =", round((frame_avg / perf_count) * 1000.0, 2), "ms")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # seed 666
 | 
				
			||||||
 | 
					    # camera = vec3((0.0, -1200.0, 500.0))
 | 
				
			||||||
 | 
					    # lookat = vec3((0.0,  500.0, -500.0))
 | 
				
			||||||
 | 
					    # for x in range(10000)
 | 
				
			||||||
 | 
					    # current_time = 0
 | 
				
			||||||
 | 
					    # Draw  * 10000 : min = 0.11 , max = 1.52 , avg = 0.18 ms
 | 
				
			||||||
 | 
					    # Draw  * 10000 : min = 0.12 , max = 1.74 , avg = 0.18 ms
 | 
				
			||||||
 | 
					    # Draw  * 10000 : min = 0.12 , max = 1.92 , avg = 0.18 ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Quitting...")
 | 
				
			||||||
 | 
					    del tests_batch
 | 
				
			||||||
 | 
					    del terrain_batch
 | 
				
			||||||
 | 
					    destroy_texture(sea_polar_textures)
 | 
				
			||||||
 | 
					    destroy_texture(sea_detail_texture)
 | 
				
			||||||
 | 
					    destroy_texture(heightmap)
 | 
				
			||||||
 | 
					    destroy_triangles(sky_triangles)
 | 
				
			||||||
 | 
					    archive.destroy()
 | 
				
			||||||
 | 
					    destroy_shader(terrain_shader)
 | 
				
			||||||
 | 
					    destroy_shader(sky_shader)
 | 
				
			||||||
 | 
					    terminate()
 | 
				
			||||||
							
								
								
									
										223
									
								
								game/generator.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,223 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from os import urandom
 | 
				
			||||||
 | 
					from operator import mul
 | 
				
			||||||
 | 
					from itertools import product, combinations, chain, starmap, repeat
 | 
				
			||||||
 | 
					from math import prod, sqrt, floor, ceil, dist, hypot, pi, cos, sin
 | 
				
			||||||
 | 
					from random import seed as set_seed, random, uniform, triangular, sample
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					from struct import unpack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game.math import vec3_normal_rgb10a2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Generator:
 | 
				
			||||||
 | 
					    def __init__(self, size):
 | 
				
			||||||
 | 
					        seed = unpack('I', urandom(4))[0] # 666 # 2749145609 #
 | 
				
			||||||
 | 
					        print("Seed =", seed)
 | 
				
			||||||
 | 
					        set_seed(seed)
 | 
				
			||||||
 | 
					        self.size = size
 | 
				
			||||||
 | 
					        self.map_coords = tuple(product(range(size), repeat = 2))
 | 
				
			||||||
 | 
					        self.field_coords = tuple(starmap(lambda y, x: (y + 0.5, x + 0.5), self.map_coords))
 | 
				
			||||||
 | 
					        self.generate_field()
 | 
				
			||||||
 | 
					        self.generate_heights()
 | 
				
			||||||
 | 
					        self.generate_rivers()
 | 
				
			||||||
 | 
					        self.smooth_heights()
 | 
				
			||||||
 | 
					        self.generate_normals()
 | 
				
			||||||
 | 
					        self.smooth_normals()
 | 
				
			||||||
 | 
					        self.pack()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def weighted_samples(self, radius):
 | 
				
			||||||
 | 
					        samples = []
 | 
				
			||||||
 | 
					        smin = floor(radius)
 | 
				
			||||||
 | 
					        tw = 0.0
 | 
				
			||||||
 | 
					        for y, x in product(range(-smin, smin + 1), repeat = 2):
 | 
				
			||||||
 | 
					            w = 1.0 - hypot(y, x) / radius
 | 
				
			||||||
 | 
					            if w > 0.0:
 | 
				
			||||||
 | 
					                tw += w
 | 
				
			||||||
 | 
					                samples.append([y, x, w])
 | 
				
			||||||
 | 
					        iw = 1.0 / tw
 | 
				
			||||||
 | 
					        for sample in samples:
 | 
				
			||||||
 | 
					            sample[2] *= iw
 | 
				
			||||||
 | 
					        return samples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_field(self):
 | 
				
			||||||
 | 
					        half = self.size // 2
 | 
				
			||||||
 | 
					        vhalf = (half, half)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rmin = self.size / 16
 | 
				
			||||||
 | 
					        rmax = self.size / 8
 | 
				
			||||||
 | 
					        vrad = self.size / 32
 | 
				
			||||||
 | 
					        cones = [(vhalf, vrad, 0.2)]
 | 
				
			||||||
 | 
					        for _ in range(180):
 | 
				
			||||||
 | 
					            r = uniform(rmin, rmax)
 | 
				
			||||||
 | 
					            d = uniform(r, half + r)
 | 
				
			||||||
 | 
					            a = uniform(-pi, pi)
 | 
				
			||||||
 | 
					            p = d / half
 | 
				
			||||||
 | 
					            cones.append(((d * cos(a) + half, d * sin(a) + half), r, p))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def height(_position):
 | 
				
			||||||
 | 
					            def influence(_center, _radius, _power):
 | 
				
			||||||
 | 
					                d = dist(_position, _center)
 | 
				
			||||||
 | 
					                return ((_radius ** 2.0) / (d ** 2.0) if d > _radius else (d ** 2.0) / (_radius ** 2.0)) * _power
 | 
				
			||||||
 | 
					            return sum(starmap(influence, cones))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        heights = list(map(height, self.field_coords))
 | 
				
			||||||
 | 
					        heights = list(map(mul, heights, repeat(1.0 / max(heights))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.volcano_c = vhalf
 | 
				
			||||||
 | 
					        self.volcano_r = vrad
 | 
				
			||||||
 | 
					        self.cones = cones
 | 
				
			||||||
 | 
					        self.heights = heights
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_heights(self):
 | 
				
			||||||
 | 
					        size = self.size
 | 
				
			||||||
 | 
					        half = size // 2
 | 
				
			||||||
 | 
					        vhalf = (half, half)
 | 
				
			||||||
 | 
					        heights = self.heights
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def shape(_position, _height):
 | 
				
			||||||
 | 
					            d = dist(vhalf, _position) / half
 | 
				
			||||||
 | 
					            return max(0.0, _height - d) ** 2.5
 | 
				
			||||||
 | 
					        heights = list(map(shape, self.field_coords, heights))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vy, vx = self.volcano_c
 | 
				
			||||||
 | 
					        vrad = self.volcano_r
 | 
				
			||||||
 | 
					        vmin = ceil(vrad)
 | 
				
			||||||
 | 
					        vmax = vrad - 2.0
 | 
				
			||||||
 | 
					        addrs = []
 | 
				
			||||||
 | 
					        hmin = 1.0
 | 
				
			||||||
 | 
					        for y, x in product(range(-vmin, vmin), repeat = 2):
 | 
				
			||||||
 | 
					            if hypot(y + 0.5, x + 0.5) < vmax:
 | 
				
			||||||
 | 
					                addr = (y + vy) * size + (x + vx)
 | 
				
			||||||
 | 
					                addrs.append(addr)
 | 
				
			||||||
 | 
					                hmin = min(hmin, heights[addr])
 | 
				
			||||||
 | 
					        hmin -= 8.0 / 255.0
 | 
				
			||||||
 | 
					        for addr in addrs:
 | 
				
			||||||
 | 
					            heights[addr] = hmin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.heights = list(map(mul, heights, repeat(255.0 / max(heights))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_rivers(self):
 | 
				
			||||||
 | 
					        size = self.size
 | 
				
			||||||
 | 
					        heights = self.heights
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cw = 1.0 / sqrt(2.0)
 | 
				
			||||||
 | 
					        offsets = (
 | 
				
			||||||
 | 
					            # y   x   w      y  x   w      y  x   w
 | 
				
			||||||
 | 
					            (-1, -1,  cw), (-1, 0, 1.0), (-1, 1,  cw),
 | 
				
			||||||
 | 
					            ( 0, -1, 1.0),               ( 0, 1, 1.0),
 | 
				
			||||||
 | 
					            ( 1, -1,  cw), ( 1, 0, 1.0), ( 1, 1,  cw))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def river(_ry, _rx):
 | 
				
			||||||
 | 
					            path = []
 | 
				
			||||||
 | 
					            mins = []
 | 
				
			||||||
 | 
					            minh = heights[_ry * size + _rx]
 | 
				
			||||||
 | 
					            flowing = True
 | 
				
			||||||
 | 
					            while flowing:
 | 
				
			||||||
 | 
					                flowing = False
 | 
				
			||||||
 | 
					                path.append((_ry, _rx))
 | 
				
			||||||
 | 
					                mins.append(minh)
 | 
				
			||||||
 | 
					                rh = heights[_ry * size + _rx]
 | 
				
			||||||
 | 
					                if rh == 0.0:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                for by, bx in reversed(path):
 | 
				
			||||||
 | 
					                    ns = []
 | 
				
			||||||
 | 
					                    for oy, ox, w in offsets:
 | 
				
			||||||
 | 
					                        ny = (_ry + oy) % size
 | 
				
			||||||
 | 
					                        nx = (_rx + ox) % size
 | 
				
			||||||
 | 
					                        if (ny, nx) not in path:
 | 
				
			||||||
 | 
					                            nh = heights[ny * size + nx]
 | 
				
			||||||
 | 
					                            ns.append(((nh - rh) * w, min(minh, nh), ny, nx))
 | 
				
			||||||
 | 
					                    if ns:
 | 
				
			||||||
 | 
					                        _, minh, _ry, _rx = min(ns)
 | 
				
			||||||
 | 
					                        flowing = True
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					            return [(rx, ry, rh) for (rx, ry), rh in zip(path, mins)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def center(_cy, _cx):
 | 
				
			||||||
 | 
					            return (heights[_cy * size + _cx], _cy, _cx)
 | 
				
			||||||
 | 
					        centers = sorted(
 | 
				
			||||||
 | 
					            [center(round(cy) % size, round(cx) % size) for (cy, cx), _, _ in self.cones[1:]],
 | 
				
			||||||
 | 
					            reverse = True)
 | 
				
			||||||
 | 
					        sources = [(sy, sx) for _, sy, sx in centers[:32]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        paths = []
 | 
				
			||||||
 | 
					        for sy, sx in sources:
 | 
				
			||||||
 | 
					            paths.append(river(sy, sx))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rivers = [0.0 for _ in range(size ** 2)]
 | 
				
			||||||
 | 
					        path = max(paths, key = len)
 | 
				
			||||||
 | 
					        for ry, rx, minh in path:
 | 
				
			||||||
 | 
					            minh = max(0.0, minh - 1.0)
 | 
				
			||||||
 | 
					            addr = ry * size + rx
 | 
				
			||||||
 | 
					            heights[addr] = minh
 | 
				
			||||||
 | 
					            for oy, ox, _ in offsets:
 | 
				
			||||||
 | 
					                heights[(ry + oy) * size + (rx + ox)] = minh
 | 
				
			||||||
 | 
					            rivers[addr] = 1.0
 | 
				
			||||||
 | 
					        self.rivers = rivers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def smooth_heights(self):
 | 
				
			||||||
 | 
					        size = self.size
 | 
				
			||||||
 | 
					        heights = self.heights
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        samples = self.weighted_samples(2.0)
 | 
				
			||||||
 | 
					        def smooth(_y, _x):
 | 
				
			||||||
 | 
					            return sum(heights[((_y + dy) % size) * size + ((_x + dx) % size)] * w for dy, dx, w in samples)
 | 
				
			||||||
 | 
					        heights = list(starmap(smooth, self.map_coords))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.heights = list(map(mul, heights, repeat(255.0 / max(heights))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_normals(self):
 | 
				
			||||||
 | 
					        size = self.size
 | 
				
			||||||
 | 
					        heights = self.heights
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def normal(_y, _x):
 | 
				
			||||||
 | 
					            height = heights[_y * size + _x]
 | 
				
			||||||
 | 
					            def direction(_dy, _dx):
 | 
				
			||||||
 | 
					                dz = (heights[((_y - _dy) % size) * size + ((_x + _dx) % size)] - height) / 8.0
 | 
				
			||||||
 | 
					                di = 1.0 / sqrt(_dx ** 2.0 + _dy ** 2.0 + dz ** 2.0) #OPTIM: dx² + dy² = 1.0
 | 
				
			||||||
 | 
					                return (_dx * di, _dy * di, dz * di)
 | 
				
			||||||
 | 
					            hx, hy, hz = direction(0, 1)
 | 
				
			||||||
 | 
					            vx, vy, vz = direction(1, 0)
 | 
				
			||||||
 | 
					            return (hy * vz - hz * vy, hz * vx - hx * vz, hx * vy - hy * vx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.normals = list(starmap(normal, self.map_coords))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def smooth_normals(self):
 | 
				
			||||||
 | 
					        size = self.size
 | 
				
			||||||
 | 
					        normals = self.normals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        samples = self.weighted_samples(2.0)
 | 
				
			||||||
 | 
					        def smooth(_y, _x):
 | 
				
			||||||
 | 
					            tx = ty = tz = 0.0
 | 
				
			||||||
 | 
					            for dy, dx, w in samples:
 | 
				
			||||||
 | 
					                nx, ny, nz = normals[((_y + dy) % size) * size + ((_x + dx) % size)]
 | 
				
			||||||
 | 
					                tx += nx * w
 | 
				
			||||||
 | 
					                ty += ny * w
 | 
				
			||||||
 | 
					                tz += nz * w
 | 
				
			||||||
 | 
					            di = 1.0 / sqrt(tx ** 2.0 + ty ** 2.0 + tz ** 2.0)
 | 
				
			||||||
 | 
					            return (tx * di, ty * di, tz * di)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.normals = list(starmap(smooth, self.map_coords))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pack(self):
 | 
				
			||||||
 | 
					        self.packed_heights = array('f', self.heights)
 | 
				
			||||||
 | 
					        self.packed_normals = array('I', tuple(map(vec3_normal_rgb10a2, self.normals)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unpack(self, y, x):
 | 
				
			||||||
 | 
					        addr = y * self.size + x
 | 
				
			||||||
 | 
					        nx, ny, nz = self.normals[addr]
 | 
				
			||||||
 | 
					        return (nx, ny, nz, self.heights[addr])
 | 
				
			||||||
							
								
								
									
										71
									
								
								game/math.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from math import hypot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_add(a, b):
 | 
				
			||||||
 | 
					    return (a[0] + b[0], a[1] + b[1], a[2] + b[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_sub(a, b):
 | 
				
			||||||
 | 
					    return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_normalize(v):
 | 
				
			||||||
 | 
					    l = hypot(*v)
 | 
				
			||||||
 | 
					    return (v[0] / l, v[1] / l, v[2] / l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_direction(a, b):
 | 
				
			||||||
 | 
					    v = (b[0] - a[0], b[1] - a[1], b[2] - a[2])
 | 
				
			||||||
 | 
					    l = hypot(*v)
 | 
				
			||||||
 | 
					    return (v[0] / l, v[1] / l, v[2] / l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_scale(v, s):
 | 
				
			||||||
 | 
					    return (v[0] * s, v[1] * s, v[2] * s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_mul(a, b):
 | 
				
			||||||
 | 
					    return (a[0] * b[0], a[1] * b[1], a[2] * b[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_dot(a, b):
 | 
				
			||||||
 | 
					    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_cross(a, b):
 | 
				
			||||||
 | 
					    return (a[1] * b[2] - a[2] * b[1], -(a[0] * b[2] - a[2] * b[0]), a[0] * b[1] - a[1] * b[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Texture formats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def float_s8(f):
 | 
				
			||||||
 | 
					    return round((f ** (1.0 / 2.2)) * 255.0) #TODO: more accurate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_srgb8a8(v):
 | 
				
			||||||
 | 
					    p = 1.0 / 2.2 #TODO: more accurate
 | 
				
			||||||
 | 
					    return (round((v[0] ** p) * 255.0), round((v[1] ** p) * 255.0), round((v[2] ** p) * 255.0), 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_rgba8(v):
 | 
				
			||||||
 | 
					    return (round(v[0] * 255.0), round(v[1] * 255.0), round(v[2] * 255.0), 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_normal_rgba8(n):
 | 
				
			||||||
 | 
					    l = max(abs(n[0]), abs(n[1]), abs(n[2]))
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        round((0.5 + (n[0] / l) * 0.5) * 255.0),
 | 
				
			||||||
 | 
					        round((0.5 + (n[1] / l) * 0.5) * 255.0),
 | 
				
			||||||
 | 
					        round((n[2] / l) * 255.0), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vec3_normal_rgb10a2(n):
 | 
				
			||||||
 | 
					    l = max(abs(n[0]), abs(n[1]), abs(n[2]))
 | 
				
			||||||
 | 
					    return \
 | 
				
			||||||
 | 
					        round((0.5 + (n[0] / l) * 0.5) * 1023.0) | \
 | 
				
			||||||
 | 
					        round((0.5 + (n[1] / l) * 0.5) * 1023.0) << 10 | \
 | 
				
			||||||
 | 
					        round((n[2] / l) * 1023.0) << 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Vertex formats
 | 
				
			||||||
							
								
								
									
										271
									
								
								game/obj2rkar.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,271 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import struct
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					from itertools import starmap, chain, repeat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from engine import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game.math import float_s8, vec3_srgb8a8
 | 
				
			||||||
 | 
					from game.resources import load_png, TextureData, VerticesData, ModelData, Archive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_texture_flags = TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_NEAREST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ObjArchive(Archive):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def import_hacks(self, path):
 | 
				
			||||||
 | 
					        print("Importing hacks", path)
 | 
				
			||||||
 | 
					        hacks = {}
 | 
				
			||||||
 | 
					        for line in open(path):
 | 
				
			||||||
 | 
					            data = line.split()
 | 
				
			||||||
 | 
					            if not data:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            name = data.pop(0)
 | 
				
			||||||
 | 
					            if name == '#':
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            assert len(data) == 4 and data[0] == '=' and data[2] == 'mesh'
 | 
				
			||||||
 | 
					            alias = data[1]
 | 
				
			||||||
 | 
					            mesh = data[3]
 | 
				
			||||||
 | 
					            assert name not in hacks.keys()
 | 
				
			||||||
 | 
					            hacks[name] = (alias, mesh)
 | 
				
			||||||
 | 
					        return hacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def import_mtl(self, mtlpath):
 | 
				
			||||||
 | 
					        def load_value(x):
 | 
				
			||||||
 | 
					            x = round(float(x), 6)
 | 
				
			||||||
 | 
					            if x == -0.0:
 | 
				
			||||||
 | 
					                x = 0.0
 | 
				
			||||||
 | 
					            return x
 | 
				
			||||||
 | 
					        size = None
 | 
				
			||||||
 | 
					        def load_texture(pngpath, nchannels):
 | 
				
			||||||
 | 
					            width, height, pixels = load_png(pngpath)
 | 
				
			||||||
 | 
					            assert pixels.typecode == 'B'
 | 
				
			||||||
 | 
					            assert (size is None or size == (width, height))
 | 
				
			||||||
 | 
					            assert len(pixels) == width * height * nchannels
 | 
				
			||||||
 | 
					            return ((width, height), pixels)
 | 
				
			||||||
 | 
					        print("Importing mtl", mtlpath)
 | 
				
			||||||
 | 
					        texture = array('B')
 | 
				
			||||||
 | 
					        texlevels = {}
 | 
				
			||||||
 | 
					        name = ''
 | 
				
			||||||
 | 
					        texlevel = 0
 | 
				
			||||||
 | 
					        color = (0, 0, 0, 0)
 | 
				
			||||||
 | 
					        metallic = 0
 | 
				
			||||||
 | 
					        specular = 0
 | 
				
			||||||
 | 
					        roughness = 0
 | 
				
			||||||
 | 
					        bump = 0
 | 
				
			||||||
 | 
					        def finish(_texture, _color, _metallic, _specular, _roughness, _bump):
 | 
				
			||||||
 | 
					            width, height = size
 | 
				
			||||||
 | 
					            if not isinstance(_color, array):
 | 
				
			||||||
 | 
					                _color = array('B', _color * (width * height))
 | 
				
			||||||
 | 
					            _texture.extend(_color)
 | 
				
			||||||
 | 
					            if not isinstance(_metallic, array):
 | 
				
			||||||
 | 
					                _metallic = repeat(_metallic, width * height)
 | 
				
			||||||
 | 
					            if not isinstance(_specular, array):
 | 
				
			||||||
 | 
					                _specular = repeat(_specular, width * height)
 | 
				
			||||||
 | 
					            if not isinstance(_roughness, array):
 | 
				
			||||||
 | 
					                _roughness = repeat(_roughness, width * height)
 | 
				
			||||||
 | 
					            if not isinstance(_bump, array):
 | 
				
			||||||
 | 
					                _bump = repeat(_bump, width * height)
 | 
				
			||||||
 | 
					            _texture.extend(chain.from_iterable(zip(_metallic, _specular, _roughness, _bump)))
 | 
				
			||||||
 | 
					        for line in open(mtlpath):
 | 
				
			||||||
 | 
					            data = line.split()
 | 
				
			||||||
 | 
					            if not data:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            code = data.pop(0)
 | 
				
			||||||
 | 
					            if code == '#':
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            elif code == 'newmtl':
 | 
				
			||||||
 | 
					                if name:
 | 
				
			||||||
 | 
					                    if size is None:
 | 
				
			||||||
 | 
					                        size = (1, 1)
 | 
				
			||||||
 | 
					                    finish(texture, color, metallic, specular, roughness, bump)
 | 
				
			||||||
 | 
					                    texlevels[name] = texlevel
 | 
				
			||||||
 | 
					                    texlevel += 2
 | 
				
			||||||
 | 
					                name = data[0]
 | 
				
			||||||
 | 
					                print("Importing material", name)
 | 
				
			||||||
 | 
					                color = (0, 0, 0, 0)
 | 
				
			||||||
 | 
					                metallic = 0
 | 
				
			||||||
 | 
					                specular = 0
 | 
				
			||||||
 | 
					                roughness = 0
 | 
				
			||||||
 | 
					                bump = 0
 | 
				
			||||||
 | 
					            elif code == 'Kd': # color
 | 
				
			||||||
 | 
					                color = vec3_srgb8a8(tuple(map(load_value, data)))
 | 
				
			||||||
 | 
					                assert len(color) == 4
 | 
				
			||||||
 | 
					            elif code == 'Ni': # ior -> metallic
 | 
				
			||||||
 | 
					                metallic = float_s8(load_value(data[0]))
 | 
				
			||||||
 | 
					            elif code == 'Ks': # specular
 | 
				
			||||||
 | 
					                specular = float_s8(load_value(data[0]))
 | 
				
			||||||
 | 
					            elif code == 'Ns': # roughness
 | 
				
			||||||
 | 
					                roughness = float_s8(1.0 - load_value(data[0]) / 1000.0)
 | 
				
			||||||
 | 
					            elif code == 'map_Kd':
 | 
				
			||||||
 | 
					                pngpath = mtlpath.parent / data[0]
 | 
				
			||||||
 | 
					                print("Importing color texture", pngpath)
 | 
				
			||||||
 | 
					                size, color = load_texture(pngpath, 4)
 | 
				
			||||||
 | 
					                pngpath = pngpath.parent / (pngpath.stem + '_b.png')
 | 
				
			||||||
 | 
					                if pngpath.exists():
 | 
				
			||||||
 | 
					                    print("Importing bump channel", pngpath)
 | 
				
			||||||
 | 
					                    size, bump = load_texture(pngpath, 1)
 | 
				
			||||||
 | 
					            elif code == 'map_Ni':
 | 
				
			||||||
 | 
					                pngpath = mtlpath.parent / data[0]
 | 
				
			||||||
 | 
					                print("Importing metallic channel", pngpath)
 | 
				
			||||||
 | 
					                size, metallic = load_texture(pngpath, 1)
 | 
				
			||||||
 | 
					            elif code == 'map_Ks':
 | 
				
			||||||
 | 
					                pngpath = mtlpath.parent / data[0]
 | 
				
			||||||
 | 
					                print("Importing specular channel", pngpath)
 | 
				
			||||||
 | 
					                size, specular = load_texture(pngpath, 1)
 | 
				
			||||||
 | 
					            elif code == 'map_Ns':
 | 
				
			||||||
 | 
					                pngpath = mtlpath.parent / data[0]
 | 
				
			||||||
 | 
					                print("Importing roughness channel", pngpath)
 | 
				
			||||||
 | 
					                size, roughness = load_texture(pngpath, 1)
 | 
				
			||||||
 | 
					        if name:
 | 
				
			||||||
 | 
					            if size is None:
 | 
				
			||||||
 | 
					                size = (1, 1)
 | 
				
			||||||
 | 
					            finish(texture, color, metallic, specular, roughness, bump)
 | 
				
			||||||
 | 
					            texlevels[name] = texlevel
 | 
				
			||||||
 | 
					            texlevel += 2
 | 
				
			||||||
 | 
					        name = str(mtlpath.stem)
 | 
				
			||||||
 | 
					        assert texlevel < 255
 | 
				
			||||||
 | 
					        assert name not in self.textures_db.keys()
 | 
				
			||||||
 | 
					        print("Storing texture", name)
 | 
				
			||||||
 | 
					        width, height = size
 | 
				
			||||||
 | 
					        self.textures_db[name] = TextureData(
 | 
				
			||||||
 | 
					            name, TEXTURE_FORMAT_SRGB8_A8, width, height, texlevel, _texture_flags, texture)
 | 
				
			||||||
 | 
					        return texlevels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def import_obj(self, objpath):
 | 
				
			||||||
 | 
					        def load_coord(x):
 | 
				
			||||||
 | 
					            x = round(float(x), 6)
 | 
				
			||||||
 | 
					            if x == -0.0:
 | 
				
			||||||
 | 
					                x = 0.0
 | 
				
			||||||
 | 
					            return x
 | 
				
			||||||
 | 
					        def load_index(x):
 | 
				
			||||||
 | 
					            return int(x) - 1
 | 
				
			||||||
 | 
					        print("Importing obj", objpath)
 | 
				
			||||||
 | 
					        texlevels = {}
 | 
				
			||||||
 | 
					        name = ''
 | 
				
			||||||
 | 
					        texlevel = 0
 | 
				
			||||||
 | 
					        mesh = []
 | 
				
			||||||
 | 
					        positions = []
 | 
				
			||||||
 | 
					        normals = []
 | 
				
			||||||
 | 
					        texcoords = []
 | 
				
			||||||
 | 
					        objects = {}
 | 
				
			||||||
 | 
					        for line in open(objpath):
 | 
				
			||||||
 | 
					            data = line.split()
 | 
				
			||||||
 | 
					            if not data:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            code = data.pop(0)
 | 
				
			||||||
 | 
					            if code == '#':
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            elif code == 'mtllib':
 | 
				
			||||||
 | 
					                texlevels = self.import_mtl(objpath.parent / data[0])
 | 
				
			||||||
 | 
					            elif code == 'o':
 | 
				
			||||||
 | 
					                if name:
 | 
				
			||||||
 | 
					                    assert mesh
 | 
				
			||||||
 | 
					                    objects[name] = (texlevel, mesh)
 | 
				
			||||||
 | 
					                name = data[0]
 | 
				
			||||||
 | 
					                print("Importing object", name)
 | 
				
			||||||
 | 
					                mesh = []
 | 
				
			||||||
 | 
					            elif code == 'usemtl':
 | 
				
			||||||
 | 
					                texlevel = texlevels[data[0]]
 | 
				
			||||||
 | 
					            elif code == 'v':
 | 
				
			||||||
 | 
					                position = tuple(map(load_coord, data))
 | 
				
			||||||
 | 
					                assert len(position) == 3
 | 
				
			||||||
 | 
					                positions.append(position)
 | 
				
			||||||
 | 
					            elif code == 'vn':
 | 
				
			||||||
 | 
					                normal = tuple(map(load_coord, data))
 | 
				
			||||||
 | 
					                assert len(normal) == 3
 | 
				
			||||||
 | 
					                normals.append(normal)
 | 
				
			||||||
 | 
					            elif code == 'vt':
 | 
				
			||||||
 | 
					                texcoord = tuple(map(load_coord, data))
 | 
				
			||||||
 | 
					                assert len(texcoord) == 2
 | 
				
			||||||
 | 
					                texcoords.append((texcoord[0], 1.0 - texcoord[1]))
 | 
				
			||||||
 | 
					            elif code == 'f':
 | 
				
			||||||
 | 
					                indices = tuple(map(lambda x: tuple(map(load_index, x.split('/'))), data))
 | 
				
			||||||
 | 
					                assert len(indices) == 3
 | 
				
			||||||
 | 
					                assert len(indices[0]) == 3
 | 
				
			||||||
 | 
					                assert len(indices[1]) == 3
 | 
				
			||||||
 | 
					                assert len(indices[2]) == 3
 | 
				
			||||||
 | 
					                triangle = tuple(map(lambda x: positions[x[0]] + normals[x[2]] + texcoords[x[1]], indices))
 | 
				
			||||||
 | 
					                assert len(triangle) == 3 and len(set(triangle)) == 3
 | 
				
			||||||
 | 
					                mesh.append(triangle)
 | 
				
			||||||
 | 
					        if name:
 | 
				
			||||||
 | 
					            assert mesh
 | 
				
			||||||
 | 
					            objects[name] = (texlevel, mesh)
 | 
				
			||||||
 | 
					        vertices = set()
 | 
				
			||||||
 | 
					        for _, mesh in objects.values():
 | 
				
			||||||
 | 
					            vertices |= frozenset(chain.from_iterable(mesh))
 | 
				
			||||||
 | 
					        vertices = tuple(vertices)
 | 
				
			||||||
 | 
					        indices = []
 | 
				
			||||||
 | 
					        models = {}
 | 
				
			||||||
 | 
					        for name, (texlevel, mesh) in sorted(objects.items()):
 | 
				
			||||||
 | 
					            if name[0] == '_':
 | 
				
			||||||
 | 
					                print(name, ": texlevel =", texlevel)
 | 
				
			||||||
 | 
					                models[name] = (texlevel, -1, -1)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                offset = len(indices)
 | 
				
			||||||
 | 
					                assert offset < 65536
 | 
				
			||||||
 | 
					                indices.extend(map(vertices.index, chain.from_iterable(mesh)))
 | 
				
			||||||
 | 
					                count = len(indices) - offset
 | 
				
			||||||
 | 
					                assert count % 3 == 0
 | 
				
			||||||
 | 
					                count //= 3
 | 
				
			||||||
 | 
					                assert count < 65536
 | 
				
			||||||
 | 
					                print(name, ": texlevel =", texlevel, "offset =", offset, "count =", count)
 | 
				
			||||||
 | 
					                models[name] = (texlevel, offset, count)
 | 
				
			||||||
 | 
					        name = str(objpath.stem)
 | 
				
			||||||
 | 
					        assert name not in self.vertices_db.keys()
 | 
				
			||||||
 | 
					        #TODO: move to math
 | 
				
			||||||
 | 
					        def pack_10(_x):
 | 
				
			||||||
 | 
					            return round(_x * (512.0 if _x < 0.0 else 511.0)) & 1023
 | 
				
			||||||
 | 
					        def pack_vertex(_px, _py, _pz, _nx, _ny, _nz, _s, _t):
 | 
				
			||||||
 | 
					            n = (pack_10(_nx) << 20) | (pack_10(_ny) << 10) | (pack_10(_nz) <<  0)
 | 
				
			||||||
 | 
					            s = max(0, min(65535, round(_s * 65535.0)))
 | 
				
			||||||
 | 
					            t = max(0, min(65535, round(_t * 65535.0)))
 | 
				
			||||||
 | 
					            return struct.pack('fffIHH', _px, _py, _pz, n, s, t)
 | 
				
			||||||
 | 
					        self.vertices_db[name] = VerticesData(name,
 | 
				
			||||||
 | 
					            array('B', b''.join(starmap(pack_vertex, vertices))),
 | 
				
			||||||
 | 
					            array('H', indices))
 | 
				
			||||||
 | 
					        path = objpath.parent / (objpath.stem + '.hacks')
 | 
				
			||||||
 | 
					        if path.exists():
 | 
				
			||||||
 | 
					            hacks = self.import_hacks(path)
 | 
				
			||||||
 | 
					            for name, (alias, mesh) in hacks.items():
 | 
				
			||||||
 | 
					                print("Hacking", name, "from", alias, "with mesh", mesh)
 | 
				
			||||||
 | 
					                assert name not in models.keys() and alias in models.keys() and mesh in models.keys()
 | 
				
			||||||
 | 
					                texlevel, _, _ = models[alias]
 | 
				
			||||||
 | 
					                _, offset, count = models[mesh]
 | 
				
			||||||
 | 
					                models[name] = (texlevel, offset, count)
 | 
				
			||||||
 | 
					        for name, (texlevel, offset, count) in sorted(models.items()):
 | 
				
			||||||
 | 
					            if name[0] != '_':
 | 
				
			||||||
 | 
					                print("Storing", name)
 | 
				
			||||||
 | 
					                assert name not in self.models_db.keys()
 | 
				
			||||||
 | 
					                self.models_db[name] = ModelData(
 | 
				
			||||||
 | 
					                    name, INSTANCE_FLAG_VISIBLE, texlevel, offset | count << 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    if len(sys.argv) < 3:
 | 
				
			||||||
 | 
					        print("Usage: python3 -m tools.obj2rkar output.rkar input.obj ...")
 | 
				
			||||||
 | 
					        sys.exit(2)
 | 
				
			||||||
 | 
					    importer = ObjArchive()
 | 
				
			||||||
 | 
					    for argv in sys.argv[2:]:
 | 
				
			||||||
 | 
					        objpath = Path(argv)
 | 
				
			||||||
 | 
					        importer.import_obj(objpath)
 | 
				
			||||||
 | 
					    outpath = Path(sys.argv[1])
 | 
				
			||||||
 | 
					    print("Exporting", outpath)
 | 
				
			||||||
 | 
					    importer.save(outpath)
 | 
				
			||||||
 | 
					    print("Done.")
 | 
				
			||||||
							
								
								
									
										292
									
								
								game/resources.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,292 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import struct
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VERTEX_SIZE = 20
 | 
				
			||||||
 | 
					VERTEX_FORMAT = engine.vertex_format(
 | 
				
			||||||
 | 
					    engine.VERTEX_FORMAT_VEC3_FLOAT,
 | 
				
			||||||
 | 
					    engine.VERTEX_FORMAT_VEC3_INT10,
 | 
				
			||||||
 | 
					    engine.VERTEX_FORMAT_VEC2_USHORT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_png(path):
 | 
				
			||||||
 | 
					    width, height, data, _ = png.Reader(filename = path).read_flat()
 | 
				
			||||||
 | 
					    return (width, height, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _read_magic(file, magic):
 | 
				
			||||||
 | 
					    assert magic
 | 
				
			||||||
 | 
					    if file.read(len(magic)) != magic:
 | 
				
			||||||
 | 
					        raise RuntimeError("Archive magic mismatch!", magic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _write_magic(file, magic):
 | 
				
			||||||
 | 
					    assert magic
 | 
				
			||||||
 | 
					    size = file.write(magic)
 | 
				
			||||||
 | 
					    assert size == len(magic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _read_struct(file, format):
 | 
				
			||||||
 | 
					    assert format
 | 
				
			||||||
 | 
					    size = struct.calcsize(format)
 | 
				
			||||||
 | 
					    assert size
 | 
				
			||||||
 | 
					    data = file.read(size)
 | 
				
			||||||
 | 
					    assert len(data) == size
 | 
				
			||||||
 | 
					    _read_magic(file, b'RK')
 | 
				
			||||||
 | 
					    return struct.unpack(format, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _write_struct(file, format, elems):
 | 
				
			||||||
 | 
					    assert format
 | 
				
			||||||
 | 
					    data = struct.pack(format, *elems)
 | 
				
			||||||
 | 
					    size = file.write(data)
 | 
				
			||||||
 | 
					    assert size == len(data)
 | 
				
			||||||
 | 
					    _write_magic(file, b'RK')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _read_string(file):
 | 
				
			||||||
 | 
					    length, = _read_struct(file, 'B')
 | 
				
			||||||
 | 
					    assert length
 | 
				
			||||||
 | 
					    data = file.read(length)
 | 
				
			||||||
 | 
					    assert len(data) == length
 | 
				
			||||||
 | 
					    _read_magic(file, b'RK')
 | 
				
			||||||
 | 
					    return str(data, encoding='ascii')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _write_string(file, string):
 | 
				
			||||||
 | 
					    data = bytes(string, encoding='ascii')
 | 
				
			||||||
 | 
					    assert data and len(data) < 256
 | 
				
			||||||
 | 
					    _write_struct(file, 'B', (len(data),))
 | 
				
			||||||
 | 
					    size = file.write(data)
 | 
				
			||||||
 | 
					    assert size == len(data)
 | 
				
			||||||
 | 
					    _write_magic(file, b'RK')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _read_array(file, format, length):
 | 
				
			||||||
 | 
					    assert format
 | 
				
			||||||
 | 
					    data = array(format)
 | 
				
			||||||
 | 
					    data.fromfile(file, length)
 | 
				
			||||||
 | 
					    assert len(data) == length
 | 
				
			||||||
 | 
					    _read_magic(file, b'RK')
 | 
				
			||||||
 | 
					    return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _write_array(file, array):
 | 
				
			||||||
 | 
					    assert array
 | 
				
			||||||
 | 
					    array.tofile(file)
 | 
				
			||||||
 | 
					    _write_magic(file, b'RK')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _read_blob(file):
 | 
				
			||||||
 | 
					    typecode, length = _read_struct(file, 'II')
 | 
				
			||||||
 | 
					    typecode = chr(typecode)
 | 
				
			||||||
 | 
					    assert typecode, length
 | 
				
			||||||
 | 
					    data = array(typecode)
 | 
				
			||||||
 | 
					    data.fromfile(file, length)
 | 
				
			||||||
 | 
					    assert len(data) == length
 | 
				
			||||||
 | 
					    _read_magic(file, b'RK')
 | 
				
			||||||
 | 
					    return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _write_blob(file, array):
 | 
				
			||||||
 | 
					    assert array
 | 
				
			||||||
 | 
					    _write_struct(file, 'II', (ord(array.typecode), len(array)))
 | 
				
			||||||
 | 
					    array.tofile(file)
 | 
				
			||||||
 | 
					    _write_magic(file, b'RK')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TextureData:
 | 
				
			||||||
 | 
					    __slots__ = 'name', 'format', 'width', 'height', 'nlevels', 'flags', 'pixels'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name, format, width, height, nlevels, flags, pixels):
 | 
				
			||||||
 | 
					        assert pixels.typecode == engine.TEXTURE_FORMAT_TYPECODE[format]
 | 
				
			||||||
 | 
					        assert len(pixels) == width * height * max(1, nlevels) * engine.TEXTURE_FORMAT_NELEMS[format]
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.format = format
 | 
				
			||||||
 | 
					        self.width = width
 | 
				
			||||||
 | 
					        self.height = height
 | 
				
			||||||
 | 
					        self.nlevels = nlevels
 | 
				
			||||||
 | 
					        self.flags = flags
 | 
				
			||||||
 | 
					        self.pixels = pixels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_archive(cls, file):
 | 
				
			||||||
 | 
					        _read_magic(file, b'TX')
 | 
				
			||||||
 | 
					        name = _read_string(file)
 | 
				
			||||||
 | 
					        format, width, height, nlevels, flags = _read_struct(file, 'IIIII')
 | 
				
			||||||
 | 
					        pixels = _read_blob(file)
 | 
				
			||||||
 | 
					        assert pixels.typecode == engine.TEXTURE_FORMAT_TYPECODE[format]
 | 
				
			||||||
 | 
					        assert len(pixels) == width * height * max(1, nlevels) * engine.TEXTURE_FORMAT_NELEMS[format]
 | 
				
			||||||
 | 
					        return cls(name, format, width, height, nlevels, flags, pixels)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_archive(self, file):
 | 
				
			||||||
 | 
					        _write_magic(file, b'TX')
 | 
				
			||||||
 | 
					        _write_string(file, self.name)
 | 
				
			||||||
 | 
					        _write_struct(file, 'IIIII', (self.format, self.width, self.height, self.nlevels, self.flags))
 | 
				
			||||||
 | 
					        _write_blob(file, self.pixels)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_texture(slot, input, data):
 | 
				
			||||||
 | 
					    return engine.create_texture(
 | 
				
			||||||
 | 
					        slot, input, data.format, data.width, data.height, data.nlevels, data.flags, data.pixels)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VerticesData:
 | 
				
			||||||
 | 
					    __slots__ = 'name', 'vertices', 'indices'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name, vertices, indices):
 | 
				
			||||||
 | 
					        if len(vertices) % VERTEX_SIZE != 0:
 | 
				
			||||||
 | 
					            raise RuntimeError("Vertex format mismatch!")
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.vertices = vertices
 | 
				
			||||||
 | 
					        self.indices = indices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_archive(cls, file):
 | 
				
			||||||
 | 
					        _read_magic(file, b'VT')
 | 
				
			||||||
 | 
					        name = _read_string(file)
 | 
				
			||||||
 | 
					        nvertices, nindices = _read_struct(file, 'II')
 | 
				
			||||||
 | 
					        vertices = _read_array(file, 'B', nvertices * VERTEX_SIZE)
 | 
				
			||||||
 | 
					        indices = _read_array(file, 'H', nindices)
 | 
				
			||||||
 | 
					        return cls(name, vertices, indices)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_archive(self, file):
 | 
				
			||||||
 | 
					        _write_magic(file, b'VT')
 | 
				
			||||||
 | 
					        _write_string(file, self.name)
 | 
				
			||||||
 | 
					        _write_struct(file, 'II', (len(self.vertices) // VERTEX_SIZE, len(self.indices)))
 | 
				
			||||||
 | 
					        _write_array(file, self.vertices)
 | 
				
			||||||
 | 
					        _write_array(file, self.indices)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_vertices(data):
 | 
				
			||||||
 | 
					    return engine.create_vertices(VERTEX_FORMAT, len(data.vertices) // VERTEX_SIZE, data.vertices, data.indices)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ModelData:
 | 
				
			||||||
 | 
					    __slots__ = 'name', 'flags', 'texlevel', 'mesh'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name, flags, texlevel, mesh):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.flags = flags
 | 
				
			||||||
 | 
					        self.texlevel = texlevel
 | 
				
			||||||
 | 
					        self.mesh = mesh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_archive(cls, file):
 | 
				
			||||||
 | 
					        _read_magic(file, b'MD')
 | 
				
			||||||
 | 
					        name = _read_string(file)
 | 
				
			||||||
 | 
					        flags, texlevel, mesh = _read_struct(file, 'BHI')
 | 
				
			||||||
 | 
					        return ModelData(name, flags, texlevel, mesh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_archive(self, file):
 | 
				
			||||||
 | 
					        _write_magic(file, b'MD')
 | 
				
			||||||
 | 
					        _write_string(file, self.name)
 | 
				
			||||||
 | 
					        _write_struct(file, 'BHI', (self.flags, self.texlevel, self.mesh))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Model:
 | 
				
			||||||
 | 
					    __slots__ = 'flags', 'texlevel', 'mesh'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, flags, texlevel, mesh):
 | 
				
			||||||
 | 
					        self.flags = flags
 | 
				
			||||||
 | 
					        self.texlevel = texlevel
 | 
				
			||||||
 | 
					        self.mesh = mesh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def spawn(self, batch, translation = engine.vec3_zero, orientation = engine.vec3_forward):
 | 
				
			||||||
 | 
					        return batch.append(self.flags, self.texlevel, self.mesh, translation, orientation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_model(data):
 | 
				
			||||||
 | 
					    return Model(data.flags, data.texlevel, data.mesh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Archive:
 | 
				
			||||||
 | 
					    __slots__ = 'textures_db', 'vertices_db', 'models_db'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, textures_db = None, vertices_db = None, models_db = None):
 | 
				
			||||||
 | 
					        self.textures_db = textures_db or {}
 | 
				
			||||||
 | 
					        self.vertices_db = vertices_db or {}
 | 
				
			||||||
 | 
					        self.models_db = models_db or {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def destroy(self):
 | 
				
			||||||
 | 
					        for vertices in self.vertices_db.values():
 | 
				
			||||||
 | 
					            engine.destroy_vertices(vertices)
 | 
				
			||||||
 | 
					        for texture in self.textures_db.values():
 | 
				
			||||||
 | 
					            engine.destroy_texture(texture)
 | 
				
			||||||
 | 
					        self.textures_db.clear()
 | 
				
			||||||
 | 
					        self.vertices_db.clear()
 | 
				
			||||||
 | 
					        self.models_db.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_texture(self, name):
 | 
				
			||||||
 | 
					        return self.textures_db[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_vertices(self, name):
 | 
				
			||||||
 | 
					        return self.vertices_db[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_model(self, name):
 | 
				
			||||||
 | 
					        return self.models_db[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_texture(cls, data):
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_vertices(cls, data):
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_model(cls, data):
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_archive(cls, file):
 | 
				
			||||||
 | 
					        textures_db = {}
 | 
				
			||||||
 | 
					        vertices_db = {}
 | 
				
			||||||
 | 
					        models_db = {}
 | 
				
			||||||
 | 
					        _read_magic(file, b'RKAR')
 | 
				
			||||||
 | 
					        ntextures, nvertices, nmodels = _read_struct(file, 'III')
 | 
				
			||||||
 | 
					        for _ in range(ntextures):
 | 
				
			||||||
 | 
					            data = TextureData.from_archive(file)
 | 
				
			||||||
 | 
					            textures_db[data.name] = cls._new_texture(data)
 | 
				
			||||||
 | 
					        for _ in range(nvertices):
 | 
				
			||||||
 | 
					            data = VerticesData.from_archive(file)
 | 
				
			||||||
 | 
					            vertices_db[data.name] = cls._new_vertices(data)
 | 
				
			||||||
 | 
					        for _ in range(nmodels):
 | 
				
			||||||
 | 
					            data = ModelData.from_archive(file)
 | 
				
			||||||
 | 
					            models_db[data.name] = cls._new_model(data)
 | 
				
			||||||
 | 
					        return cls(textures_db, vertices_db, models_db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def load(cls, filename):
 | 
				
			||||||
 | 
					        file = open(Path(filename), 'rb')
 | 
				
			||||||
 | 
					        archive = cls.from_archive(file)
 | 
				
			||||||
 | 
					        file.close()
 | 
				
			||||||
 | 
					        return archive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_archive(self, file):
 | 
				
			||||||
 | 
					        _write_magic(file, b'RKAR')
 | 
				
			||||||
 | 
					        _write_struct(file, 'III', (len(self.textures_db), len(self.vertices_db), len(self.models_db)))
 | 
				
			||||||
 | 
					        for _, data in self.textures_db.items():
 | 
				
			||||||
 | 
					            data.to_archive(file)
 | 
				
			||||||
 | 
					        for _, data in self.vertices_db.items():
 | 
				
			||||||
 | 
					            data.to_archive(file)
 | 
				
			||||||
 | 
					        for _, data in self.models_db.items():
 | 
				
			||||||
 | 
					            data.to_archive(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, filename):
 | 
				
			||||||
 | 
					        file = open(Path(filename), 'wb')
 | 
				
			||||||
 | 
					        self.to_archive(file)
 | 
				
			||||||
 | 
					        file.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RuntimeArchive(Archive):
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_texture(cls, data):
 | 
				
			||||||
 | 
					        return create_texture(0, b'u_texture_sampler', data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_vertices(cls, data):
 | 
				
			||||||
 | 
					        return create_vertices(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def _new_model(cls, data):
 | 
				
			||||||
 | 
					        return create_model(data)
 | 
				
			||||||
							
								
								
									
										71
									
								
								game/sea.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from itertools import product
 | 
				
			||||||
 | 
					from math import tau, cos, sin, copysign
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from engine import (create_texture,
 | 
				
			||||||
 | 
					    TEXTURE_FORMAT_RGB10_A2, TEXTURE_FORMAT_TYPECODE, TEXTURE_FLAG_MIN_LINEAR, TEXTURE_FLAG_MAG_LINEAR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game.math import vec3_scale, vec3_direction, vec3_cross, vec3_normal_rgb10a2
 | 
				
			||||||
 | 
					from game.resources import load_png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_format = TEXTURE_FORMAT_RGB10_A2
 | 
				
			||||||
 | 
					_typecode = TEXTURE_FORMAT_TYPECODE[TEXTURE_FORMAT_RGB10_A2]
 | 
				
			||||||
 | 
					_conv = vec3_normal_rgb10a2
 | 
				
			||||||
 | 
					_flags = TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_polar_textures(paths, waves_height = 0.008):
 | 
				
			||||||
 | 
					    def load_texture(_path):
 | 
				
			||||||
 | 
					        width, height, data = load_png(_path)
 | 
				
			||||||
 | 
					        assert data.typecode == 'H'
 | 
				
			||||||
 | 
					        assert len(data) == width * height
 | 
				
			||||||
 | 
					        def polar(_y, _x, _h):
 | 
				
			||||||
 | 
					            d = 1.0 + (_y / height)
 | 
				
			||||||
 | 
					            a = (_x / width) * tau
 | 
				
			||||||
 | 
					            return (d * sin(a), d * cos(a), (_h / 65535.0) * waves_height)
 | 
				
			||||||
 | 
					        def normal(_pos, _h):
 | 
				
			||||||
 | 
					            y, x = _pos
 | 
				
			||||||
 | 
					            o = polar(y, x, _h)
 | 
				
			||||||
 | 
					            n = vec3_cross(
 | 
				
			||||||
 | 
					                vec3_direction(o, polar(y, x + 1, data[y * width + ((x + 1) % width)])),
 | 
				
			||||||
 | 
					                vec3_direction(o, polar(y + 1, x, data[((y + 1) % height) * width + x])))
 | 
				
			||||||
 | 
					            return vec3_scale(n, copysign(1.0, n[2]))
 | 
				
			||||||
 | 
					        return (width, height, list(map(normal, product(range(height), range(width)), data)))
 | 
				
			||||||
 | 
					    width, height, normals = load_texture(paths[0])
 | 
				
			||||||
 | 
					    data = array(_typecode, list(map(_conv, normals)))
 | 
				
			||||||
 | 
					    for path in paths[1:]:
 | 
				
			||||||
 | 
					        _width, _height, normals = load_texture(path)
 | 
				
			||||||
 | 
					        assert _width == width and _height == height
 | 
				
			||||||
 | 
					        data.extend(list(map(_conv, normals)))
 | 
				
			||||||
 | 
					    return create_texture(0, b'u_sea_polar_sampler', _format, width, height, len(paths), _flags, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_detail_texture(path, scale = 0.5, waves_height = 0.002):
 | 
				
			||||||
 | 
					    width, height, data = load_png(path)
 | 
				
			||||||
 | 
					    assert data.typecode == 'H'
 | 
				
			||||||
 | 
					    assert len(data) == width * height
 | 
				
			||||||
 | 
					    def coord(_y, _x, _h):
 | 
				
			||||||
 | 
					        return ((_x / width) * scale, (_y / height) * scale, (_h / 65535.0) * waves_height)
 | 
				
			||||||
 | 
					    def normal(_pos, _h):
 | 
				
			||||||
 | 
					        y, x = _pos
 | 
				
			||||||
 | 
					        o = coord(y, x, _h)
 | 
				
			||||||
 | 
					        n = vec3_cross(
 | 
				
			||||||
 | 
					            vec3_direction(o, coord(y, x + 1, data[y * width + ((x + 1) % width)])),
 | 
				
			||||||
 | 
					            vec3_direction(o, coord(y + 1, x, data[((y + 1) % height) * width + x])))
 | 
				
			||||||
 | 
					        return vec3_scale(n, copysign(1.0, n[2]))
 | 
				
			||||||
 | 
					    normals = list(map(normal, product(range(height), range(width)), data))
 | 
				
			||||||
 | 
					    data = array(_typecode, list(map(_conv, normals)))
 | 
				
			||||||
 | 
					    return create_texture(1, b'u_sea_detail_sampler', _format, width, height, 0, _flags, data)
 | 
				
			||||||
							
								
								
									
										90
									
								
								game/shaders/sky_opengles.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					// Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#version 320 es
 | 
				
			||||||
 | 
					precision highp float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					in vec3 v_position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform mat4 u_view_km; // world space -> view space, unit = km
 | 
				
			||||||
 | 
					uniform vec3 u_light_direction; // view space (-direction_x, -direction_y, -direction_z)
 | 
				
			||||||
 | 
					uniform vec3 u_light_color;
 | 
				
			||||||
 | 
					uniform vec3 u_horizon_color;
 | 
				
			||||||
 | 
					uniform vec3 u_sky_color;
 | 
				
			||||||
 | 
					uniform vec3 u_sun_color;
 | 
				
			||||||
 | 
					uniform float u_sea_phase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define u_right u_view_km[0].xyz
 | 
				
			||||||
 | 
					#define u_forward u_view_km[1].xyz
 | 
				
			||||||
 | 
					#define u_up u_view_km[2].xyz
 | 
				
			||||||
 | 
					#define u_origin u_view_km[3].xyz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform highp sampler2DArray u_sea_polar_sampler;
 | 
				
			||||||
 | 
					uniform highp sampler2D u_sea_detail_sampler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const float c_sea_radius = 637.1;
 | 
				
			||||||
 | 
					const float c_sea_radius_sq = c_sea_radius * c_sea_radius;
 | 
				
			||||||
 | 
					const float c_sky_radius = c_sea_radius + 10.0;
 | 
				
			||||||
 | 
					const vec3 c_normal_scale = vec3(2.0, 2.0, 1.0);
 | 
				
			||||||
 | 
					const vec3 c_normal_shift = vec3(-1.0, -1.0, 0.0);
 | 
				
			||||||
 | 
					const float c_detail_scale = 2.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec4 o_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 sky(in vec3 ray_direction) {
 | 
				
			||||||
 | 
					    float d = max(0.0, dot(ray_direction, u_light_direction));
 | 
				
			||||||
 | 
					    return mix(u_horizon_color, u_sky_color, max(0.0, dot(ray_direction, u_up))) + u_sun_color * pow(d, 1000.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main(void) {
 | 
				
			||||||
 | 
					    vec3 direction = normalize(v_position);
 | 
				
			||||||
 | 
					    vec3 earth_center = u_origin - u_up * c_sea_radius;
 | 
				
			||||||
 | 
					    float p_dist = dot(direction, earth_center);
 | 
				
			||||||
 | 
					    vec3 pc = earth_center - direction * p_dist;
 | 
				
			||||||
 | 
					    if (p_dist <= 0.0 || dot(pc, pc) >= c_sea_radius_sq) {
 | 
				
			||||||
 | 
					        // sky
 | 
				
			||||||
 | 
					        o_color = vec4(sky(direction), 1.0);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // sea
 | 
				
			||||||
 | 
					        vec3 sea_position = direction * (p_dist - sqrt(c_sea_radius_sq - dot(pc, pc))) - u_origin;
 | 
				
			||||||
 | 
					        vec3 sea_direction = normalize(sea_position);
 | 
				
			||||||
 | 
					        //TODO: vec2
 | 
				
			||||||
 | 
					        float s = dot(u_forward, sea_direction);
 | 
				
			||||||
 | 
					        if (dot(u_right, sea_direction) > 0.0) {
 | 
				
			||||||
 | 
					            // [1.0 -1.0] -> [0.0 0.5]
 | 
				
			||||||
 | 
					            s = (1.0 - s) * 0.25;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // [-1.0 1.0] -> [0.5 1.0] -> [0.0 0.5] + 0.5
 | 
				
			||||||
 | 
					            s = (1.0 + s) * 0.25 + 0.5;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        float t = sqrt(length(sea_position)); //TODO: more accurate
 | 
				
			||||||
 | 
					        vec3 sea_polar1 = normalize(
 | 
				
			||||||
 | 
					            c_normal_shift + texture(u_sea_polar_sampler, vec3(s, t + u_sea_phase, 0.0)).xyz * c_normal_scale);
 | 
				
			||||||
 | 
					        vec3 sea_polar2 = normalize(
 | 
				
			||||||
 | 
					            c_normal_shift + texture(u_sea_polar_sampler, vec3(s, t - u_sea_phase, 1.0)).xyz * c_normal_scale);
 | 
				
			||||||
 | 
					        //TODO: vec2
 | 
				
			||||||
 | 
					        s = (u_sea_phase + dot(sea_position, u_right)) * c_detail_scale;
 | 
				
			||||||
 | 
					        t = (u_sea_phase + dot(sea_position, u_forward)) * c_detail_scale;
 | 
				
			||||||
 | 
					        vec3 sea_detail = normalize(c_normal_shift + texture(u_sea_detail_sampler, vec2(s, t)).xyz * c_normal_scale);
 | 
				
			||||||
 | 
					        //TODO: better blending, with earth normal
 | 
				
			||||||
 | 
					        vec4 normal = u_view_km * vec4(normalize(sea_polar1 + sea_polar2 + sea_detail), 0.0);
 | 
				
			||||||
 | 
					        float d = max(0.0, dot(normal.xyz, u_light_direction));
 | 
				
			||||||
 | 
					        s = pow(max(0.0, dot(normal.xyz, normalize(u_light_direction - direction))), 500.0) * step(0.0, d);
 | 
				
			||||||
 | 
					        o_color = vec4(
 | 
				
			||||||
 | 
					            u_sky_color * d + //TODO: sea color
 | 
				
			||||||
 | 
					            u_light_color * s +
 | 
				
			||||||
 | 
					            sky(reflect(direction, normal.xyz)), 1.0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								game/shaders/sky_opengles.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					// Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#version 320 es
 | 
				
			||||||
 | 
					precision highp float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) in vec3 a_position; // view space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform mat4 u_projection; // view space -> screen space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out vec3 v_position; // view space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main(void) {
 | 
				
			||||||
 | 
					    v_position = a_position;
 | 
				
			||||||
 | 
					    gl_Position = u_projection * vec4(a_position, 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										56
									
								
								game/shaders/terrain_opengles.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					// Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#version 320 es
 | 
				
			||||||
 | 
					precision highp float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					in vec3 v_position; // view space
 | 
				
			||||||
 | 
					in vec3 v_normal; // view space
 | 
				
			||||||
 | 
					in vec4 v_terrain_normal; // view space (x, y, z, weight)
 | 
				
			||||||
 | 
					in vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define v_weight v_terrain_normal.w
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform vec3 u_light_direction; // view space (-direction_x, -direction_y, -direction_z)
 | 
				
			||||||
 | 
					uniform vec3 u_light_color; // (color.r * power, color.g * power, color.b * power)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform highp sampler2DArray u_texture_sampler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec4 o_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main(void) {
 | 
				
			||||||
 | 
					    vec4 pixel = texture(u_texture_sampler, v_texcoord.stp);
 | 
				
			||||||
 | 
					    vec4 material = texture(u_texture_sampler, v_texcoord.stq);
 | 
				
			||||||
 | 
					    #define m_metallic material.x
 | 
				
			||||||
 | 
					    #define m_specular material.y
 | 
				
			||||||
 | 
					    #define m_roughness material.z
 | 
				
			||||||
 | 
					    vec3 normal = normalize(v_normal);
 | 
				
			||||||
 | 
					    vec3 eye_dir = -normalize(v_position);
 | 
				
			||||||
 | 
					    float d = dot(normal, u_light_direction);
 | 
				
			||||||
 | 
					    float halfd = 0.5 + d * 0.5;
 | 
				
			||||||
 | 
					    float td = dot(normalize(v_terrain_normal.xyz), u_light_direction);
 | 
				
			||||||
 | 
					    float diffuse = halfd * mix(halfd, 0.5 + td * 0.5, v_weight) * (1.0 - m_metallic);
 | 
				
			||||||
 | 
					    float s = max(0.0, dot(normal, normalize(u_light_direction + eye_dir)));
 | 
				
			||||||
 | 
					    float shininess = 1.0 + pow(1.0 - m_roughness, 2.0) * 999.0;
 | 
				
			||||||
 | 
					    float stepd = step(0.0, d);
 | 
				
			||||||
 | 
					    float specular = pow(s, shininess) * mix(stepd, stepd * max(0.0, td), v_weight);
 | 
				
			||||||
 | 
					    vec3 color = pixel.rgb * u_light_color;
 | 
				
			||||||
 | 
					    o_color = vec4(
 | 
				
			||||||
 | 
					        vec3(
 | 
				
			||||||
 | 
					            color * diffuse +
 | 
				
			||||||
 | 
					            color * (specular * m_metallic) +
 | 
				
			||||||
 | 
					            u_light_color * (specular * m_specular)),
 | 
				
			||||||
 | 
					        pixel.a);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								game/shaders/terrain_opengles.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					// Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#version 320 es
 | 
				
			||||||
 | 
					precision highp float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) in vec3 a_position; // model space
 | 
				
			||||||
 | 
					layout(location = 1) in vec3 a_normal; // model space
 | 
				
			||||||
 | 
					layout(location = 2) in vec2 a_texcoord; // texture space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 3) in vec4 i_translation; // per mesh, model space -> world space (x, y, z, texlevel)
 | 
				
			||||||
 | 
					layout(location = 4) in vec3 i_orientation; // per mesh, model space -> world space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define i_texlevel i_translation.w
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform mat4 u_view; // world space -> view space
 | 
				
			||||||
 | 
					uniform mat4 u_projection; // view space -> screen space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform highp sampler2D u_height_sampler;
 | 
				
			||||||
 | 
					uniform highp sampler2D u_normal_sampler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const vec3 c_normal_scale = vec3(2.0, 2.0, 1.0);
 | 
				
			||||||
 | 
					const vec3 c_normal_shift = vec3(-1.0, -1.0, 0.0);
 | 
				
			||||||
 | 
					const vec2 c_terrain_scale = vec2(1.0 / 2048.0, -1.0 / 2048.0);
 | 
				
			||||||
 | 
					const vec2 c_terrain_shift = vec2(0.5, 0.5);
 | 
				
			||||||
 | 
					const float c_weight_scale = 1.0 / 64.f;
 | 
				
			||||||
 | 
					const vec3 c_world_forward = vec3(0.0, 1.0, 0.0);
 | 
				
			||||||
 | 
					const vec3 c_world_up = vec3(0.0, 0.0, 1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out vec3 v_position; // view space
 | 
				
			||||||
 | 
					out vec3 v_normal; // view space
 | 
				
			||||||
 | 
					out vec4 v_terrain_normal; // view space (x, y, z, weigth)
 | 
				
			||||||
 | 
					out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main(void) {
 | 
				
			||||||
 | 
					    vec3 orientation = normalize(i_orientation);
 | 
				
			||||||
 | 
					    mat3 rotation = mat3(cross(orientation, c_world_up), orientation, c_world_up);
 | 
				
			||||||
 | 
					    vec4 world_position = vec4(i_translation.xyz + rotation * a_position, 1.0);
 | 
				
			||||||
 | 
					    float weight = max(0.0, 1.0 - world_position.z * c_weight_scale);
 | 
				
			||||||
 | 
					    vec3 world_normal = rotation * normalize(a_normal);
 | 
				
			||||||
 | 
					    vec2 terrain_coords = c_terrain_shift + world_position.xy * c_terrain_scale;
 | 
				
			||||||
 | 
					    world_position.z += texture(u_height_sampler, terrain_coords).r;
 | 
				
			||||||
 | 
					    vec4 view_position = u_view * world_position;
 | 
				
			||||||
 | 
					    vec3 terrain_normal = normalize(c_normal_shift + texture(u_normal_sampler, terrain_coords).rgb * c_normal_scale);
 | 
				
			||||||
 | 
					    world_normal = mat3(cross(c_world_forward, terrain_normal), c_world_forward, terrain_normal) * world_normal;
 | 
				
			||||||
 | 
					    v_position = view_position.xyz;
 | 
				
			||||||
 | 
					    v_normal = (u_view * vec4(world_normal, 0.0)).xyz;
 | 
				
			||||||
 | 
					    v_terrain_normal = vec4((u_view * vec4(terrain_normal, 0.0)).xyz, weight);
 | 
				
			||||||
 | 
					    v_texcoord = vec4(a_texcoord, i_texlevel, i_texlevel + 1.0);
 | 
				
			||||||
 | 
					    gl_Position = u_projection * view_position;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								game/triangles.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from itertools import chain
 | 
				
			||||||
 | 
					from array import array
 | 
				
			||||||
 | 
					from math import cos, sin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: with FOV
 | 
				
			||||||
 | 
					def sky_triangles(vsubdivs, distance, projection_ratio):
 | 
				
			||||||
 | 
					    assert vsubdivs > 0
 | 
				
			||||||
 | 
					    vertices = []
 | 
				
			||||||
 | 
					    hsubdivs = round(vsubdivs * projection_ratio)
 | 
				
			||||||
 | 
					    z = -distance
 | 
				
			||||||
 | 
					    width = distance * projection_ratio
 | 
				
			||||||
 | 
					    height = distance
 | 
				
			||||||
 | 
					    startx = width * -0.5
 | 
				
			||||||
 | 
					    starty = height * -0.5
 | 
				
			||||||
 | 
					    stepx = width / hsubdivs
 | 
				
			||||||
 | 
					    stepy = height / vsubdivs
 | 
				
			||||||
 | 
					    y1 = starty
 | 
				
			||||||
 | 
					    y2 = y1 + stepy
 | 
				
			||||||
 | 
					    for sy in range(vsubdivs):
 | 
				
			||||||
 | 
					        x1 = startx
 | 
				
			||||||
 | 
					        x2 = x1 + stepx
 | 
				
			||||||
 | 
					        for sx in range(hsubdivs):
 | 
				
			||||||
 | 
					            a = (x1, y2, z)
 | 
				
			||||||
 | 
					            b = (x2, y1, z)
 | 
				
			||||||
 | 
					            vertices.append((x1, y1, z))
 | 
				
			||||||
 | 
					            vertices.append(b)
 | 
				
			||||||
 | 
					            vertices.append(a)
 | 
				
			||||||
 | 
					            vertices.append((x2, y2, z))
 | 
				
			||||||
 | 
					            vertices.append(a)
 | 
				
			||||||
 | 
					            vertices.append(b)
 | 
				
			||||||
 | 
					            x1 = x2
 | 
				
			||||||
 | 
					            x2 += stepx
 | 
				
			||||||
 | 
					        y1 = y2
 | 
				
			||||||
 | 
					        y2 += stepy
 | 
				
			||||||
 | 
					    return array('f', chain.from_iterable(vertices))
 | 
				
			||||||
							
								
								
									
										2
									
								
								rk_island-dev.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					exec python3 rk_island.py
 | 
				
			||||||
							
								
								
									
										3
									
								
								rk_island-profile.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					me=$(whoami)
 | 
				
			||||||
 | 
					exec sudo /bin/nice --adjustment=-20 su $me -c "exec python3 -O rk_island.py"
 | 
				
			||||||
							
								
								
									
										25
									
								
								rk_island.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2022 RozK
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libs = Path(sys.path[0]) / 'libs'
 | 
				
			||||||
 | 
					if libs.exists() and libs.is_dir():
 | 
				
			||||||
 | 
					    sys.path[1:1] = [str(libs)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from game import game
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					game.main()
 | 
				
			||||||
							
								
								
									
										2
									
								
								rk_island.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					exec python3 -O rk_island.py
 | 
				
			||||||