<commit_before>root = exports ? this

root.planetBufferSize = 100

class root.Planetfield
	constructor: ({starfield, maxPlanetsPerSystem, minOrbitScale, maxOrbitScale, planetSize, nearRange, farRange}) ->
		@_starfield = starfield
		@_planetBufferSize = root.planetBufferSize

		@nearRange = nearRange
		@farRange = farRange
		@planetSize = planetSize

		@maxPlanetsPerSystem = maxPlanetsPerSystem
		@minOrbitScale = minOrbitScale
		@maxOrbitScale = maxOrbitScale

		randomStream = new RandomStream(universeSeed)

		# load planet shader
		@shader = xgl.loadProgram("planetfield")
		@shader.uniforms = xgl.getProgramUniforms(@shader, ["modelViewMat", "projMat", "spriteSizeAndViewRangeAndBlur"])
		@shader.attribs = xgl.getProgramAttribs(@shader, ["aPos", "aUV"])

		# we just re-use the index buffer from the starfield because the sprites are indexed the same
		@iBuff = @_starfield.iBuff
		if @_planetBufferSize*6 > @iBuff.numItems
			console.log("Warning: planetBufferSize should not be larger than starBufferSize. Setting planetBufferSize = starBufferSize.")
			@_planetBufferSize = @iBuff.numItems

		# prepare vertex buffer
		@buff = new Float32Array(@_planetBufferSize * 4 * 6)
		j = 0
		for i in [0 .. @_planetBufferSize-1]
			randAngle = randomStream.range(0, Math.PI*2)

			for vi in [0..3]
				angle = ((vi - 0.5) / 2.0) * Math.PI + randAngle
				u = Math.sin(angle) * Math.sqrt(2) * 0.5
				v = Math.cos(angle) * Math.sqrt(2) * 0.5
				marker = if vi <= 1 then 1 else -1

				@buff[j+3] = u
				@buff[j+4] = v
				@buff[j+5] = marker
				j += 6

		@vBuff = gl.createBuffer()
		@vBuff.itemSize = 6
		@vBuff.numItems = @_planetBufferSize * 4

		# prepare to render geometric planet representations as well
		#@farMesh = new PlanetFarMesh(8)
		@farMesh = new PlanetFarMesh(16)

		#@farMapGen = new FarMapGenerator(128) # low resolution maps for far planet meshes
		@farMapGen = new FarMapGenerator(512) # low resolution maps for far planet meshes

		generateCallback = do (gen = @farMapGen) -> (seed) -> gen.generate(seed)
		@farMapCache = new ContentCache(16, generateCallback) 


	setPlanetSprite: (index, position) ->
		j = index * 6*4
		for vi in [0..3]
			@buff[j] = position[0]
			@buff[j+1] = position[1]
			@buff[j+2] = position[2]
			j += 6


	render: (camera, originOffset, blur) ->
		# get list of nearby stars, sorted from nearest to farthest
		@starList = @_starfield.queryStars(camera.position, originOffset, @farRange)
		@starList.sort( ([ax,ay,az,aw], [cx,cy,cz,cw]) -> (ax*ax + ay*ay + az*az) - (cx*cx + cy*cy + cz*cz) )

		# populate vertex buffer with planet positions, and track positions of mesh-range planets
		@generatePlanetPositions()

		camera.far = @farRange * 1.1
		camera.near = @nearRange * 0.9
		camera.update()
		@renderSprites(camera, originOffset, blur)

		camera.far = @nearRange * 5.0
		camera.near = @nearRange * 0.001
		camera.update()
		@renderFarMeshes(camera, originOffset)

		@farMapGen.start()
		@farMapCache.update(1)
		@farMapGen.finish()


	generatePlanetPositions: ->
		randomStream = new RandomStream()
		@numPlanets = 0

		@meshPlanets = []
		numMeshPlanets = 0

		for [dx, dy, dz, w] in @starList
			randomStream.seed = Math.floor(w * 1000000)

			systemPlanets = randomStream.intRange(0, @maxPlanetsPerSystem)
			if @numPlanets + systemPlanets > @_planetBufferSize then break

			for i in [1 .. systemPlanets]
				radius = @_starfield.starSize * randomStream.range(@minOrbitScale, @maxOrbitScale)
				angle = randomStream.radianAngle()
				[x, y, z] = [dx + radius * Math.sin(angle), dy + radius * Math.cos(angle), dz + w * Math.sin(angle)]

				# store in @meshPlanets if this is close enough that it will be rendered as a mesh
				dist = Math.sqrt(x*x + y*y + z*z)
				alpha = 2.0 - (dist / @nearRange) * 0.5
				pw = randomStream.unit()
				if alpha > 0.001
					@meshPlanets[numMeshPlanets] = [x, y, z, pw, alpha]
					numMeshPlanets++

				# add this to the vertex buffer to render as a sprite
				@setPlanetSprite(@numPlanets, [x, y, z])
				@numPlanets++


	renderFarMeshes: (camera, originOffset) ->
		if not @meshPlanets or @meshPlanets.length == 0 or @starList.length == 0 then return

		@farMesh.startRender()

		# calculate weighted sum of up to three near stars within +-50% distance
		lightCenter = vec3.fromValues(@starList[0][0], @starList[0][1], @starList[0][2])
		for i in [1 .. Math.min(2, @starList.length)]
			star = @starList[i]
			lightPos = vec3.fromValues(star[0], star[1], star[2])
			if Math.abs(1.0 - (vec3.distance(lightPos, lightCenter) / vec3.length(lightCenter))) < 0.5
				vec3.scale(lightCenter, lightCenter, 0.75)
				vec3.scale(lightPos, lightPos, 0.25)
				vec3.add(lightCenter, lightCenter, lightPos)

		# build a list of planets to render in reverse order, since we need to render farthest to nearest
		# because the depth buffer is not enabled yet (we're still rendering on massive scales, potentially)
		[localPos, globalPos, lightVec] = [vec3.create(), vec3.create(), vec3.create()]
		for i in [@meshPlanets.length-1 .. 0]
			[x, y, z, w, alpha] = @meshPlanets[i]
			localPos = vec3.fromValues(x, y, z)
			vec3.add(globalPos, localPos, camera.position)

			#lightVec = vec3.fromValues(lx - x, ly - y, lz - z)
			vec3.subtract(lightVec, lightCenter, localPos)
			vec3.normalize(lightVec, lightVec)

			seed = Math.floor(w * 1000000)
			textureMap = @farMapCache.getContent(seed)
			@farMesh.renderInstance(camera, globalPos, lightVec, alpha, textureMap)

		@farMesh.finishRender()
<commit_msg>Fixed far planet mesh render order<commit_after>root = exports ? this

root.planetBufferSize = 100

class root.Planetfield
	constructor: ({starfield, maxPlanetsPerSystem, minOrbitScale, maxOrbitScale, planetSize, nearRange, farRange}) ->
		@_starfield = starfield
		@_planetBufferSize = root.planetBufferSize

		@nearRange = nearRange
		@farRange = farRange
		@planetSize = planetSize

		@maxPlanetsPerSystem = maxPlanetsPerSystem
		@minOrbitScale = minOrbitScale
		@maxOrbitScale = maxOrbitScale

		randomStream = new RandomStream(universeSeed)

		# load planet shader
		@shader = xgl.loadProgram("planetfield")
		@shader.uniforms = xgl.getProgramUniforms(@shader, ["modelViewMat", "projMat", "spriteSizeAndViewRangeAndBlur"])
		@shader.attribs = xgl.getProgramAttribs(@shader, ["aPos", "aUV"])

		# we just re-use the index buffer from the starfield because the sprites are indexed the same
		@iBuff = @_starfield.iBuff
		if @_planetBufferSize*6 > @iBuff.numItems
			console.log("Warning: planetBufferSize should not be larger than starBufferSize. Setting planetBufferSize = starBufferSize.")
			@_planetBufferSize = @iBuff.numItems

		# prepare vertex buffer
		@buff = new Float32Array(@_planetBufferSize * 4 * 6)
		j = 0
		for i in [0 .. @_planetBufferSize-1]
			randAngle = randomStream.range(0, Math.PI*2)

			for vi in [0..3]
				angle = ((vi - 0.5) / 2.0) * Math.PI + randAngle
				u = Math.sin(angle) * Math.sqrt(2) * 0.5
				v = Math.cos(angle) * Math.sqrt(2) * 0.5
				marker = if vi <= 1 then 1 else -1

				@buff[j+3] = u
				@buff[j+4] = v
				@buff[j+5] = marker
				j += 6

		@vBuff = gl.createBuffer()
		@vBuff.itemSize = 6
		@vBuff.numItems = @_planetBufferSize * 4

		# prepare to render geometric planet representations as well
		#@farMesh = new PlanetFarMesh(8)
		@farMesh = new PlanetFarMesh(16)

		#@farMapGen = new FarMapGenerator(128) # low resolution maps for far planet meshes
		@farMapGen = new FarMapGenerator(512) # low resolution maps for far planet meshes

		generateCallback = do (gen = @farMapGen) -> (seed) -> gen.generate(seed)
		@farMapCache = new ContentCache(16, generateCallback) 


	setPlanetSprite: (index, position) ->
		j = index * 6*4
		for vi in [0..3]
			@buff[j] = position[0]
			@buff[j+1] = position[1]
			@buff[j+2] = position[2]
			j += 6


	render: (camera, originOffset, blur) ->
		# get list of nearby stars, sorted from nearest to farthest
		@starList = @_starfield.queryStars(camera.position, originOffset, @farRange)
		@starList.sort( ([ax,ay,az,aw], [cx,cy,cz,cw]) -> (ax*ax + ay*ay + az*az) - (cx*cx + cy*cy + cz*cz) )

		# populate vertex buffer with planet positions, and track positions of mesh-range planets
		@generatePlanetPositions()

		camera.far = @farRange * 1.1
		camera.near = @nearRange * 0.9
		camera.update()
		@renderSprites(camera, originOffset, blur)

		camera.far = @nearRange * 5.0
		camera.near = @nearRange * 0.001
		camera.update()
		@renderFarMeshes(camera, originOffset)

		@farMapGen.start()
		@farMapCache.update(1)
		@farMapGen.finish()


	generatePlanetPositions: ->
		randomStream = new RandomStream()
		@numPlanets = 0

		@meshPlanets = []
		numMeshPlanets = 0

		for [dx, dy, dz, w] in @starList
			randomStream.seed = Math.floor(w * 1000000)

			systemPlanets = randomStream.intRange(0, @maxPlanetsPerSystem)
			if @numPlanets + systemPlanets > @_planetBufferSize then break

			for i in [1 .. systemPlanets]
				radius = @_starfield.starSize * randomStream.range(@minOrbitScale, @maxOrbitScale)
				angle = randomStream.radianAngle()
				[x, y, z] = [dx + radius * Math.sin(angle), dy + radius * Math.cos(angle), dz + w * Math.sin(angle)]

				# store in @meshPlanets if this is close enough that it will be rendered as a mesh
				dist = Math.sqrt(x*x + y*y + z*z)
				alpha = 2.0 - (dist / @nearRange) * 0.5
				pw = randomStream.unit()
				if alpha > 0.001
					@meshPlanets[numMeshPlanets] = [x, y, z, pw, alpha]
					numMeshPlanets++

				# add this to the vertex buffer to render as a sprite
				@setPlanetSprite(@numPlanets, [x, y, z])
				@numPlanets++


	renderFarMeshes: (camera, originOffset) ->
		if not @meshPlanets or @meshPlanets.length == 0 or @starList.length == 0 then return

		@farMesh.startRender()

		# calculate weighted sum of up to three near stars within +-50% distance
		lightCenter = vec3.fromValues(@starList[0][0], @starList[0][1], @starList[0][2])
		for i in [1 .. Math.min(2, @starList.length)]
			star = @starList[i]
			lightPos = vec3.fromValues(star[0], star[1], star[2])
			if Math.abs(1.0 - (vec3.distance(lightPos, lightCenter) / vec3.length(lightCenter))) < 0.5
				vec3.scale(lightCenter, lightCenter, 0.75)
				vec3.scale(lightPos, lightPos, 0.25)
				vec3.add(lightCenter, lightCenter, lightPos)

		# sort the list of planets to render in reverse order, since we need to render farthest to nearest
		# because the depth buffer is not enabled yet (we're still rendering on massive scales, potentially)
		@meshPlanets.sort( ([ax,ay,az,aw,ak], [cx,cy,cz,cw,ck]) -> (cx*cx + cy*cy + cz*cz) - (ax*ax + ay*ay + az*az) )
		[localPos, globalPos, lightVec] = [vec3.create(), vec3.create(), vec3.create()]
		for i in [0 .. @meshPlanets.length-1]
			[x, y, z, w, alpha] = @meshPlanets[i]
			localPos = vec3.fromValues(x, y, z)
			vec3.add(globalPos, localPos, camera.position)

			#lightVec = vec3.fromValues(lx - x, ly - y, lz - z)
			vec3.subtract(lightVec, lightCenter, localPos)
			vec3.normalize(lightVec, lightVec)

			seed = Math.floor(w * 1000000)
			textureMap = @farMapCache.getContent(seed)
			@farMesh.renderInstance(camera, globalPos, lightVec, alpha, textureMap)

		@farMesh.finishRender()

{'fraction_non_alphanumeric': 0.13020411833468212, 'fraction_numerical': 0.02409855228846327, 'mean_word_length': 3.91037527593819, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6115702', 'n_tokens_mistral': 4484, 'n_tokens_neox': 3885, 'n_words': 1028}