package gay.pizza.CavesOfJolk import com.badlogic.gdx.ApplicationAdapter import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.g2d.BitmapFont import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g3d.* import com.badlogic.gdx.graphics.g3d.attributes.* import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight import com.badlogic.gdx.graphics.g3d.environment.PointLight import com.badlogic.gdx.graphics.g3d.model.data.* import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder import com.badlogic.gdx.graphics.g3d.utils.TextureDescriptor import com.badlogic.gdx.graphics.g3d.utils.TextureProvider.AssetTextureProvider import com.badlogic.gdx.math.* import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.ScreenUtils import gay.pizza.CavesOfJolk.Resources.Companion.assetManager import ktx.math.times class Game: ApplicationAdapter() { private lateinit var texJolk: Texture private lateinit var fntComic: BitmapFont private lateinit var cube: Model private lateinit var floor: Model private lateinit var spriteBatch: SpriteBatch private lateinit var modelBatch: ModelBatch private lateinit var env: Environment private lateinit var colin: Colin private var jolkRot = 0.0f private var lightTheta = 0.0f private lateinit var cubeInstance: ModelInstance private lateinit var floorInstance: ModelInstance private lateinit var suzanneInstance: ModelInstance private lateinit var rockBatch: ModelCache private fun makeCube(texture: Texture): Model { val modelBuilder = ModelBuilder() val size = 2.0f val material = Material( ColorAttribute.createDiffuse(XnaColor.White), TextureAttribute(TextureAttribute.Diffuse, TextureDescriptor(texture, Texture.TextureFilter.Linear, Texture.TextureFilter.Linear, Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge)), ColorAttribute.createSpecular(XnaColor.Gray), FloatAttribute.createShininess(20.0f)) val attribs = VertexAttributes.Usage.Position or VertexAttributes.Usage.TextureCoordinates or VertexAttributes.Usage.Normal return modelBuilder.createBox(size, size, size, material, attribs.toLong()) } private fun makeFloor(): Model { val size = 16.0f val texs = 4.0f val vertex = { pos: Vector3, tex: Vector2 -> val normal = Util.up val tangent = Util.right val bitangent = Util.forward floatArrayOf( pos.x, pos.y, pos.z, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, bitangent.x, bitangent.y, bitangent.z, tex.x, tex.y) } val modelTexture = { modelTextureUsage: Int, textureFilename: String -> ModelTexture().apply { usage = modelTextureUsage fileName = textureFilename }} return Model(ModelData().apply { addMesh(ModelMesh().apply { id = "floormodel" attributes = arrayOf(VertexAttribute.Position(), VertexAttribute.Normal(), VertexAttribute.Tangent(), VertexAttribute.Binormal(), VertexAttribute.TexCoords(0)) vertices = vertex(Vector3(0.0f, 0.0f, 0.0f), Vector2(0.0f, texs)) + vertex(Vector3(size, 0.0f, 0.0f), Vector2(texs, texs)) + vertex(Vector3(0.0f, 0.0f, -size), Vector2(0.0f, 0.0f)) + vertex(Vector3(size, 0.0f, -size), Vector2(texs, 0.0f)) parts = arrayOf(ModelMeshPart().apply { id = "floormesh" primitiveType = GL20.GL_TRIANGLES indices = shortArrayOf( 0, 1, 2, 3, 2, 1) }) }) materials.add(ModelMaterial().apply { id = "floormat" diffuse = XnaColor.White specular = XnaColor.BlanchedAlmond.mix(XnaColor.Black, 0.12f) shininess = 65.0f textures = Array() textures.add( modelTexture(ModelTexture.USAGE_DIFFUSE, "cobblestone.png"), modelTexture(ModelTexture.USAGE_NORMAL, "cobblestone_normal.png"), modelTexture(ModelTexture.USAGE_SPECULAR, "cobblestone_specular.png")) }) nodes.add(ModelNode().apply { id = "floornode" scale = Util.one parts = arrayOf(ModelNodePart().apply { meshPartId = "floormesh" materialId = "floormat" }) }) }, AssetTextureProvider(assetManager)) } override fun create() { Resources.instance.loadAssets() assetManager.finishLoading() texJolk = assetManager.get("jolkmeup.jpg") fntComic = assetManager.get("Comic Sans MS.ttf") cube = makeCube(texJolk) floor = makeFloor() spriteBatch = SpriteBatch() env = Environment() env.set( IntAttribute.createCullFace(GL20.GL_BACK), ColorAttribute.createAmbientLight(XnaColor.DarkSlateGray.lighten(-0.666)), ColorAttribute.createFog(XnaColor.CornflowerBlue)) env.set( CustomIntAttribute.createFogMode(CustomIntAttribute.FogModes.Depth), CustomIntAttribute.createFogType(CustomIntAttribute.FogTypes.Smooth), CustomFloatAttribute.createFogNear(1.25f), CustomFloatAttribute.createFogFar(24.5f)) /* env.set( CustomIntAttribute.createFogMode(CustomIntAttribute.FogModes.Distance), CustomIntAttribute.createFogType(CustomIntAttribute.FogTypes.Exp2), CustomFloatAttribute.createFogDensity(0.1f)) */ env.add(DirectionalLight().set( XnaColor.BlanchedAlmond.lighten(-0.02).mix(XnaColor.LightSlateGray, 0.5f).mix(XnaColor.White, 0.125f), Vector3(1.0f, -1.0f, -1.0f).nor())) env.add(PointLight().set( XnaColor.Green.mix(XnaColor.Gray, 0.5f), Vector3(3.0f, 0.33f, -5.0f), 2.0f)) env.add(PointLight().set( XnaColor.Red.mix(XnaColor.Gray, 0.5f), Vector3(5.5f, 0.33f, -6.0f), 2.0f)) env.add(PointLight().set( XnaColor.Blue.mix(XnaColor.Gray, 0.5f), Vector3(4.0f, 0.33f, -7.0f), 2.0f)) val shaderConfig = DefaultShader.Config() shaderConfig.numDirectionalLights = 1 shaderConfig.numPointLights = 3 shaderConfig.numBones = 0 modelBatch = ModelBatch(CustomDefaultShaderProvider(shaderConfig)) colin = Colin() cubeInstance = ModelInstance(cube) floorInstance = ModelInstance(floor) suzanneInstance = ModelInstance(assetManager.get("suzanne.g3db", Model::class.java)) val rock = assetManager.get("rock.g3db", Model::class.java) val rand = RandomXS128(69 + 420 + 1919 + 916 + 42 + 911) val randQuaternion = { rand: RandomXS128 -> var x: Float var y: Float var z: Float do { x = rand.nextFloat(-1.0f, 1.0f); y = rand.nextFloat(-1.0f, 1.0f); z = x * x + y * y } while (z > 1.0f) var u: Float var v: Float var w: Float do { u = rand.nextFloat(-1.0f, 1.0f); v = rand.nextFloat(-1.0f, 1.0f); w = u * u + v * v } while (w > 1.0f) val s = kotlin.math.sqrt((1.0f - z) / w) Quaternion(x, y, s * u, s * v) } val rocks = Array(50) { i-> ModelInstance(rock, Matrix4( Vector3( rand.nextFloat(16.0f), rand.nextFloat(-0.75f, 0.125f), -rand.nextFloat(16.0f)), randQuaternion(rand), Util.one * rand.nextFloat(0.6f, 1.2f))) } rockBatch = ModelCache().apply { begin() add(rocks.asIterable()) end() } suzanneInstance.transform = Matrix4().translate(3.0f, 1.0f, -3.5f) } override fun resize(width: Int, height: Int) { colin.resize(width, height) spriteBatch.projectionMatrix.setToOrtho2D(0.0f, 0.0f, Gdx.graphics.getWidth().toFloat(), Gdx.graphics.getHeight().toFloat()); } private fun update(deltaTime: Float) { colin.update(deltaTime) lightTheta += deltaTime jolkRot += 15.0f * deltaTime } override fun render() { val deltaTime = Gdx.graphics.deltaTime update(deltaTime) ScreenUtils.clear(XnaColor.CornflowerBlue, true) env.get(PointLightsAttribute.Type)?.let { it as PointLightsAttribute var thetaa = lightTheta * 6.0f * 0.12f var thetab = lightTheta * 6.0f * 0.011f var thetac = lightTheta * 6.0f * 0.056f for (light in it.lights) { val x = 4.0f + 6.0f * MathUtils.cos(thetaa) val z = -6.0f + 3.0f * MathUtils.sin(thetaa * 2.0f) val y = 0.33f + 0.33f * MathUtils.sin(thetab) val i = 3.1f + 1.53f * MathUtils.cos(thetac) val spacing = 0.5f * MathUtils.PI * (2.0f / 3.0f) thetaa += spacing thetab += spacing * 0.98f thetac += spacing * 0.5566f light.setPosition(x, y, z) light.setIntensity(i) } } val jolkPos = Vector3(0.0f, 1.0f + MathUtils.sin(jolkRot * 0.25f) * 0.25f, -4.0f) val world = Matrix4() .setTranslation(jolkPos) .rotateRad(1.0f, 0.0f, 0.0f, jolkRot * 0.25f) .rotate(0.0f, 1.0f, 0.0f, jolkRot) .scale(0.25f, 0.25f, 0.25f) cubeInstance.transform = world modelBatch.begin(colin.camera) modelBatch.render(floorInstance, env) modelBatch.render(rockBatch, env) modelBatch.render(cubeInstance, env) modelBatch.render(suzanneInstance, env) modelBatch.end() spriteBatch.begin() colin.draw(spriteBatch) val textPos = colin.camera.project(jolkPos) if (textPos.z < 1.0) fntComic.draw(spriteBatch, "I am filled with jolk", textPos.x, textPos.y) fntComic.draw(spriteBatch, "${colin.position.x}\n${colin.position.y}", 10.0f, Gdx.graphics.height - 10.0f) spriteBatch.end() } override fun dispose() { rockBatch.dispose() floor.dispose() cube.dispose() modelBatch.dispose() spriteBatch.dispose() assetManager.dispose() } }