Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package ru.poopycoders.cavedefense.loader
- import com.badlogic.gdx.assets.loaders.FileHandleResolver
- import com.badlogic.gdx.assets.loaders.ModelLoader
- import com.badlogic.gdx.files.FileHandle
- import com.badlogic.gdx.graphics.Color
- import com.badlogic.gdx.graphics.GL20
- import com.badlogic.gdx.graphics.VertexAttributes
- import com.badlogic.gdx.graphics.g3d.model.MeshPart
- import com.badlogic.gdx.graphics.g3d.model.data.*
- import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder
- import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder
- import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.BoxShapeBuilder
- import com.badlogic.gdx.math.Matrix4
- import com.badlogic.gdx.math.Quaternion
- import com.badlogic.gdx.math.Vector2
- import com.badlogic.gdx.math.Vector3
- import com.badlogic.gdx.utils.ArrayMap
- import com.badlogic.gdx.utils.BaseJsonReader
- import com.badlogic.gdx.utils.JsonValue
- class JsonModelLoader(val reader: BaseJsonReader, resolver: FileHandleResolver?) : ModelLoader<ModelLoader.ModelParameters>(resolver) {
- companion object {
- private const val rawAttributes = VertexAttributes.Usage.Position.toLong() or VertexAttributes.Usage.Normal.toLong() or VertexAttributes.Usage.TextureCoordinates.toLong()
- private const val primitiveType = GL20.GL_TRIANGLES
- }
- val attributes = MeshBuilder.createAttributes(rawAttributes)
- override fun loadModelData(fileHandle: FileHandle, parameters: ModelParameters?): ModelData {
- return parseModel(fileHandle)
- }
- private fun parseModel(handle: FileHandle): ModelData {
- val json = reader.parse(handle)
- val model = ModelData()
- model.id = "model"
- for (i in 0 until json.size) {
- val tag = json[i]
- if (tag.name != "format_version") {
- parseGeometry(tag, model)
- break
- }
- }
- return model
- }
- private fun parseGeometry(geometry: JsonValue, model: ModelData) {
- val textureWidth = geometry.getInt("texturewidth")
- val textureHeight = geometry.getInt("textureheight")
- val visibleBoundsWidth = geometry.getInt("visible_bounds_width")
- val visibleBoundsHeight = geometry.getInt("visible_bounds_height")
- val visibleBoundsOffset = Vector3(geometry.require("visible_bounds_offset").asFloatArray())
- val bonesJson = geometry.get("bones")
- // Parse bones
- val bonesMap = HashMap<String, Bone>()
- val bones = Array(bonesJson.size) {
- parseBone(bonesJson[it]).apply {
- if (this.parent != null) {
- bonesMap[this.parent]!!.children.add(this)
- }
- bonesMap[this.name] = this
- }
- }
- // Build nodes, root meshes and mesh parts
- val nodesMap = HashMap<String, ModelNode>()
- for (bone in bones) {
- if (bone.parent == null) {
- val node = bone.buildNode(nodesMap)
- model.nodes.add(node)
- model.addMesh(bone.buildRootMesh(node))
- }
- }
- // Default material for all parts
- model.materials.add(ModelMaterial().apply {
- id = "default"
- ambient = Color(1f, 1f, 1f, 1f)
- diffuse = Color(0.8f, 0.8f, 0.8f, 0.8f)
- emissive = Color(0.8f, 0.8f, 0.8f, 0.8f)
- opacity = 1f
- shininess = 0f
- textures = com.badlogic.gdx.utils.Array()
- })
- // Test animation
- model.animations.add(ModelAnimation().apply {
- id = "test"
- nodeAnimations.add(ModelNodeAnimation().apply {
- nodeId = "head"
- rotation = com.badlogic.gdx.utils.Array<ModelNodeKeyframe<Quaternion>>(30)
- for (i in 0 until 30) {
- rotation.insert(i, ModelNodeKeyframe<Quaternion>().apply {
- keytime = 1f / 30 * i
- value = Quaternion(Vector3.Y, 90 + 360f / 30 * i)
- })
- }
- })
- })
- }
- private fun parseBone(bone: JsonValue): Bone {
- val name = bone.getString("name")
- val parent = bone.getString("parent", null)
- val pivot = Vector3(bone.require("pivot").asFloatArray())
- val rotation = if (bone.has("rotation")) Vector3(bone.require("rotation").asFloatArray()) else Vector3.Zero
- val cubesJson = if (bone.has("cubes")) bone.require("cubes") else null
- val cubes = Array(cubesJson?.size ?: 0) {
- val cube = cubesJson!![it]
- val origin = Vector3(cube.require("origin").asFloatArray())
- val size = Vector3(cube.require("size").asFloatArray())
- val uv = cube.require("uv").asFloatArray()
- val inflate = if (cube.has("inflate")) cube.getFloat("inflate") else 0f
- Cube(origin, size, Vector2(uv[0], uv[1]), inflate)
- }
- return Bone(name, parent, pivot, rotation, cubes, ArrayList())
- }
- inner class Bone(val name: String, val parent: String?, val pivot: Vector3, val rotation: Vector3, val cubes: Array<Cube>, var children: ArrayList<Bone>) {
- fun buildNode(nodesMap: HashMap<String, ModelNode>): ModelNode {
- println("Build node: $name")
- val node = ModelNode()
- nodesMap[name] = node
- node.id = name
- node.translation = Vector3.Zero
- node.scale = Vector3(1.0f, 1.0f, 1.0f)
- // node.rotation = Quaternion(rotation.x, rotation.y, rotation.z, 0.0f)
- node.meshId = if (parent == null) name else nodesMap[parent]!!.meshId
- node.children = Array(children.size) {
- children[it].buildNode(nodesMap)
- }
- return node
- }
- fun buildRootMesh(rootNode: ModelNode): ModelMesh {
- val mesh = ModelMesh()
- mesh.id = name
- mesh.attributes = Array(attributes.size()) { attributes[it] }
- val builder = DirectMeshBuilder()
- val rawParts = ArrayList<MeshPart>()
- builder.begin(rawAttributes)
- buildMesh(rootNode, builder, rawParts, null) // build mesh of this part
- val (vertices, indices) = builder.endAndGetItems()
- mesh.vertices = vertices
- mesh.parts = Array(rawParts.size) { // build meshes of child parts
- ModelMeshPart().apply {
- val rawPart = rawParts[it]
- this.id = rawPart.id
- this.primitiveType = rawPart.primitiveType
- this.indices = indices.copyOfRange(rawPart.offset, rawPart.offset + rawPart.size)
- }
- }
- return mesh
- }
- fun buildMesh(node: ModelNode, builder: MeshBuilder, parts: ArrayList<MeshPart>, parent: ModelNode?) {
- if (cubes.isNotEmpty()) {
- val part = builder.part(name, primitiveType)
- for (cube in cubes) {
- val origin = cube.origin.mulAdd(cube.size, 0.5f)
- val size = cube.size
- BoxShapeBuilder.build(builder, origin.x, origin.y, origin.z, size.x, size.y, size.z)
- }
- node.parts = arrayOf(ModelNodePart().apply {
- materialId = "default"
- meshPartId = part.id
- bones = ArrayMap(1)
- if(parent != null){
- bones.put(parent.id, Matrix4())
- }
- // uvMapping = Array(2) {
- // IntArray(2) // later
- // }
- })
- parts.add(part)
- } else {
- node.parts = arrayOf()
- }
- for ((i, child) in children.withIndex()) {
- child.buildMesh(node.children[i], builder, parts, node)
- }
- }
- }
- data class Cube(val origin: Vector3, val size: Vector3, val uv: Vector2, val inflate: Float)
- class DirectMeshBuilder : MeshBuilder() {
- private val vertTmp1 = MeshPartBuilder.VertexInfo()
- private val vertTmp2 = MeshPartBuilder.VertexInfo()
- private val vertTmp3 = MeshPartBuilder.VertexInfo()
- private val vertTmp4 = MeshPartBuilder.VertexInfo()
- fun endAndGetItems(): Pair<FloatArray, ShortArray> {
- part("mesh_end", GL20.GL_TRIANGLES)
- return Pair(vertices!!, indices!!)
- }
- override fun rect(corner00: Vector3?, corner10: Vector3?, corner11: Vector3?, corner01: Vector3?, normal: Vector3?) {
- rect(vertTmp1.set(corner00, normal, null, null).setUV(0f, 1f), vertTmp2.set(corner10, normal, null, null).setUV(1f, 1f),
- vertTmp3.set(corner11, normal, null, null).setUV(1f, 0f), vertTmp4.set(corner01, normal, null, null).setUV(0f, 0f))
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement