Skip to content

Commit

Permalink
Merge pull request #192 from JamesTKhan/add-primitive-meshes
Browse files Browse the repository at this point in the history
Ability to add primitive meshes (Planes, Cubes)
  • Loading branch information
JamesTKhan authored Jun 28, 2023
2 parents d6a6e27 + 245b547 commit 0e176dc
Show file tree
Hide file tree
Showing 4 changed files with 386 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.PixmapIO
import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.utils.Array
import com.badlogic.gdx.utils.ObjectSet
import com.kotcrab.vis.ui.util.dialog.Dialogs
Expand Down Expand Up @@ -49,6 +50,7 @@ import com.mbrlabs.mundus.editor.events.LogEvent
import com.mbrlabs.mundus.editor.events.LogType
import com.mbrlabs.mundus.editor.ui.UI
import com.mbrlabs.mundus.editor.utils.Log
import net.mgsx.gltf.exporters.GLTFExporter
import org.apache.commons.io.FileUtils
import org.apache.commons.io.FilenameUtils
import java.io.BufferedOutputStream
Expand Down Expand Up @@ -272,6 +274,36 @@ class EditorAssetManager(assetsRoot: FileHandle) : AssetManager(assetsRoot) {
return asset
}

/**
* Creates a new model asset. This variant of the method
* is used when the model does not have a file, e.g.
* a model that was generated by code (planes, cubes, etc)..
* It uses GLTF exporter to create a new gltf model file.
*
* @param fileName name of the model file
* @param model the loaded model
*/
@Throws(IOException::class, AssetAlreadyExistsException::class)
fun createModelAsset(fileName: String, model: Model): ModelAsset {
val modelFilename = fileName
val metaFilename = modelFilename + ".meta"

// create meta file
val metaPath = FilenameUtils.concat(rootFolder.path(), metaFilename)
val meta = createNewMetaFile(FileHandle(metaPath), AssetType.MODEL)

val assetFile = FileHandle(FilenameUtils.concat(rootFolder.path(), modelFilename))
val exporter = GLTFExporter()
exporter.export(model, assetFile)

// load & return asset
val asset = ModelAsset(meta, assetFile)
asset.load()

addAsset(asset)
return asset
}

/**
* Creates a new terrainAsset asset.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti
* required for resolving image/texture files.
*/
fun populateMaterialAsset(
importedModel: FileHandleWithDependencies,
importedModel: FileHandleWithDependencies?,
assetManager: EditorAssetManager,
materialToUse: Material,
materialAssetToPopulate: MaterialAsset,
Expand Down Expand Up @@ -126,7 +126,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti
// Texture Attributes
if (materialToUse.has(PBRTextureAttribute.BaseColorTexture)) {
materialAssetToPopulate.diffuseTexture = getTextureAssetForMaterial(
importedModel,
importedModel!!,
assetManager,
materialToUse.id,
PBRTextureAttribute.BaseColorTexture)
Expand All @@ -135,7 +135,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti

if (materialToUse.has(PBRTextureAttribute.NormalTexture)) {
materialAssetToPopulate.normalMap = getTextureAssetForMaterial(
importedModel,
importedModel!!,
assetManager,
materialToUse.id,
PBRTextureAttribute.NormalTexture
Expand All @@ -145,7 +145,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti

if (materialToUse.has(PBRTextureAttribute.EmissiveTexture)) {
materialAssetToPopulate.emissiveTexture = getTextureAssetForMaterial(
importedModel,
importedModel!!,
assetManager,
materialToUse.id,
PBRTextureAttribute.EmissiveTexture
Expand All @@ -155,7 +155,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti

if (materialToUse.has(PBRTextureAttribute.MetallicRoughnessTexture)) {
materialAssetToPopulate.metallicRoughnessTexture = getTextureAssetForMaterial(
importedModel,
importedModel!!,
assetManager,
materialToUse.id,
PBRTextureAttribute.MetallicRoughnessTexture
Expand All @@ -165,7 +165,7 @@ class ModelImporter(private val registry: Registry) : SettingsChangedEvent.Setti

if (materialToUse.has(PBRTextureAttribute.OcclusionTexture)) {
materialAssetToPopulate.occlusionTexture = getTextureAssetForMaterial(
importedModel,
importedModel!!,
assetManager,
materialToUse.id,
PBRTextureAttribute.OcclusionTexture
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
package com.mbrlabs.mundus.editor.ui.modules.outline

import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.g3d.Material
import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.graphics.g3d.attributes.IntAttribute
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Array
import com.kotcrab.vis.ui.util.dialog.Dialogs
import com.kotcrab.vis.ui.util.dialog.InputDialogAdapter
import com.kotcrab.vis.ui.widget.MenuItem
import com.kotcrab.vis.ui.widget.PopupMenu
import com.mbrlabs.mundus.commons.assets.ModelAsset
import com.mbrlabs.mundus.commons.assets.meta.MetaModel
import com.mbrlabs.mundus.commons.scene3d.GameObject
import com.mbrlabs.mundus.commons.scene3d.SceneGraph
import com.mbrlabs.mundus.commons.scene3d.components.Component
import com.mbrlabs.mundus.commons.scene3d.components.TerrainComponent
import com.mbrlabs.mundus.editor.Mundus
import com.mbrlabs.mundus.editor.assets.MetaSaver
import com.mbrlabs.mundus.editor.assets.ModelImporter
import com.mbrlabs.mundus.editor.core.project.ProjectManager
import com.mbrlabs.mundus.editor.events.AssetImportEvent
import com.mbrlabs.mundus.editor.events.SceneGraphChangedEvent
import com.mbrlabs.mundus.editor.events.TerrainRemovedEvent
import com.mbrlabs.mundus.editor.scene3d.components.PickableModelComponent
import com.mbrlabs.mundus.editor.tools.ToolManager
import com.mbrlabs.mundus.editor.ui.UI
import com.mbrlabs.mundus.editor.utils.Log
import com.mbrlabs.mundus.editor.utils.UsefulMeshs
import net.mgsx.gltf.scene3d.attributes.PBRColorAttribute
import net.mgsx.gltf.scene3d.attributes.PBRFloatAttribute

/**
* Holds code for Outlines right click menu. Separated from Outline class
Expand All @@ -33,6 +48,8 @@ class OutlineRightClickMenu(outline: Outline) : PopupMenu() {
private val outline: Outline
private val projectManager: ProjectManager = Mundus.inject()
private val toolManager: ToolManager = Mundus.inject()
private val modelImporter: ModelImporter = Mundus.inject()


init {
this.outline = outline
Expand Down Expand Up @@ -261,34 +278,85 @@ class OutlineRightClickMenu(outline: Outline) : PopupMenu() {
private val addEmpty: MenuItem = MenuItem("Add Empty")
private val addTerrain: MenuItem = MenuItem("Add Terrain")
private val addWater: MenuItem = MenuItem("Add Water")
private val addPlane: MenuItem = MenuItem("Add Plane")
private val addCube: MenuItem = MenuItem("Add Cube")
init {
addItem(addEmpty)
addItem(addTerrain)
addItem(addWater)
addItem(addPlane)
addItem(addCube)

// add empty
addEmpty.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
val sceneGraph = projectManager.current().currScene.sceneGraph
val id = projectManager.current().obtainID()
// the new game object
val go = GameObject(sceneGraph, GameObject.DEFAULT_NAME, id)
val go = createGameObject(sceneGraph)

// update outline
if (selectedGO == null) {
// update sceneGraph
Log.trace(TAG, "Add empty game object [{}] in root node.", go)
sceneGraph.addGameObject(go)
// update outline
outline.addGoToTree(null, go)
} else {
Log.trace(TAG, "Add empty game object [{}] child in node [{}].", go, selectedGO)
// update sceneGraph
selectedGO!!.addChild(go)
// update outline
val n = outline.tree.findNode(selectedGO!!)
outline.addGoToTree(n, go)
updateOutline(sceneGraph, go)
}
})

addPlane.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
val fileName = "standard_plane.gltf"
val assetManager = projectManager.current().assetManager
var modelAsset = assetManager.findAssetByFileName(fileName) as ModelAsset?

val sceneGraph = projectManager.current().currScene.sceneGraph
val go = createGameObject(sceneGraph)

if (modelAsset == null) {
// Create new material
val material = Material("plane_material")
setDefaultValues(material)
modelAsset = createModelAsset(fileName, UsefulMeshs.createPlane(material, 5f))
}
Mundus.postEvent(SceneGraphChangedEvent())

// Create model component
val modelComponent = PickableModelComponent(go)

// Set model and add to game object
modelComponent.setModel(modelAsset, true)
go.addComponent(modelComponent)
modelComponent.encodeRaypickColorId()

Mundus.postEvent(AssetImportEvent(modelAsset))

// update outline
updateOutline(sceneGraph, go)
}
})

addCube.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
val fileName = "standard_cube.gltf"
val assetManager = projectManager.current().assetManager
var modelAsset = assetManager.findAssetByFileName(fileName) as ModelAsset?

val sceneGraph = projectManager.current().currScene.sceneGraph
val go = createGameObject(sceneGraph)

if (modelAsset == null) {
// Create new material
val material = Material("cube_material")
setDefaultValues(material)
modelAsset = createModelAsset(fileName, UsefulMeshs.createCube(material, 5f))
}

// Create model component
val modelComponent = PickableModelComponent(go)

// Set model and add to game object
modelComponent.setModel(modelAsset, true)
go.addComponent(modelComponent)
modelComponent.encodeRaypickColorId()

Mundus.postEvent(AssetImportEvent(modelAsset!!))

// update outline
updateOutline(sceneGraph, go)
}
})

Expand All @@ -307,6 +375,61 @@ class OutlineRightClickMenu(outline: Outline) : PopupMenu() {
})
}

private fun createModelAsset(fileName: String, model: Model): ModelAsset {
val assetManager = projectManager.current().assetManager
val modelAsset = assetManager.createModelAsset(fileName, model)
modelAsset.meta.model = MetaModel()

for (mat in modelAsset.model.materials) {
val materialAsset = assetManager.createMaterialAsset(modelAsset.id.substring(0, 4) + "_" + mat.id)

modelImporter.populateMaterialAsset(null, projectManager.current().assetManager, mat, materialAsset)
projectManager.current().assetManager.saveMaterialAsset(materialAsset)

modelAsset.meta.model.defaultMaterials.put(mat.id, materialAsset.id)
modelAsset.defaultMaterials.put(mat.id, materialAsset)
}

// save meta file
val saver = MetaSaver()
saver.save(modelAsset.meta)

modelAsset.applyDependencies()
return modelAsset
}

private fun setDefaultValues(material: Material) {
material.set(PBRColorAttribute.createBaseColorFactor(Color.GRAY))
material.set(PBRFloatAttribute.createMetallic(0f))
material.set(PBRFloatAttribute.createRoughness(1.0f))
material.set(IntAttribute.createCullFace(GL20.GL_BACK))
}

private fun updateOutline(sceneGraph: SceneGraph, go: GameObject) {
// update outline
if (selectedGO == null) {
// update sceneGraph
Log.trace(TAG, "Add empty game object [{}] in root node.", go)
sceneGraph.addGameObject(go)
// update outline
outline.addGoToTree(null, go)
} else {
Log.trace(TAG, "Add empty game object [{}] child in node [{}].", go, selectedGO)
// update sceneGraph
selectedGO!!.addChild(go)
// update outline
val n = outline.tree.findNode(selectedGO!!)
outline.addGoToTree(n, go)
}
Mundus.postEvent(SceneGraphChangedEvent())
}

fun createGameObject(sceneGraph : SceneGraph): GameObject {
val id = projectManager.current().obtainID()
// the new game object
return GameObject(sceneGraph, GameObject.DEFAULT_NAME, id)
}

}
//endregion Add Sub Menu

Expand Down
Loading

0 comments on commit 0e176dc

Please sign in to comment.