Skip to content

Commit

Permalink
removed EditorState object
Browse files Browse the repository at this point in the history
  • Loading branch information
fabmax committed Mar 21, 2024
1 parent 701c425 commit cada136
Show file tree
Hide file tree
Showing 32 changed files with 295 additions and 326 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,39 @@ interface AppAssetsLoader {
}

object AppAssets : AppAssetsLoader {
var impl: AppAssetsLoader = DefaultLoader()
var impl: AppAssetsLoader = DefaultLoader("assets")

override suspend fun loadHdriEnvironment(path: String): EnvironmentMaps? = impl.loadHdriEnvironment(path)
override suspend fun loadModel(modelPath: String): GltfFile? = impl.loadModel(modelPath)
override suspend fun loadTexture2d(path: String): Texture2d? = impl.loadTexture2d(path)

class DefaultLoader : AppAssetsLoader {
class DefaultLoader(val pathPrefix: String) : AppAssetsLoader {
override suspend fun loadHdriEnvironment(path: String): EnvironmentMaps? {
val prefixed = "${pathPrefix}/${path}"
return try {
EnvironmentHelper.hdriEnvironment(Assets.loadTexture2d(path))
EnvironmentHelper.hdriEnvironment(Assets.loadTexture2d(prefixed))
} catch (e: Exception) {
logE { "Failed loading HDRI: $path" }
logE { "Failed loading HDRI: $prefixed" }
null
}
}

override suspend fun loadModel(modelPath: String): GltfFile? {
val prefixed = "${pathPrefix}/${modelPath}"
return try {
Assets.loadGltfFile(modelPath)
Assets.loadGltfFile(prefixed)
} catch (e: Exception) {
logE { "Failed loading model: $modelPath" }
logE { "Failed loading model: $prefixed" }
null
}
}

override suspend fun loadTexture2d(path: String): Texture2d? {
val prefixed = "${pathPrefix}/${path}"
return try {
Assets.loadTexture2d(path)
Assets.loadTexture2d(prefixed)
} catch (e: Exception) {
logE { "Failed loading texture: $path" }
logE { "Failed loading texture: $prefixed" }
null
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package de.fabmax.kool.editor.model

import de.fabmax.kool.Assets
import de.fabmax.kool.editor.data.MaterialData
import de.fabmax.kool.editor.data.PbrShaderData
import de.fabmax.kool.editor.data.ProjectData
import de.fabmax.kool.editor.data.SceneNodeData
import de.fabmax.kool.editor.data.*
import de.fabmax.kool.math.MutableMat4d
import de.fabmax.kool.math.Vec3d
import de.fabmax.kool.math.deg
import de.fabmax.kool.modules.ui2.mutableStateListOf
import de.fabmax.kool.util.MdColor
import de.fabmax.kool.util.logE
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json

class EditorProject(val projectData: ProjectData) {
Expand Down Expand Up @@ -129,5 +129,43 @@ class EditorProject(val projectData: ProjectData) {
null
}
}

fun emptyProject(): EditorProject = EditorProject(
ProjectData().apply {
val sceneId = nextId++
val camId = nextId++
val boxId = nextId++
val lightId = nextId++
sceneNodeIds += sceneId
sceneNodes += SceneNodeData("New Scene", sceneId).apply {
childNodeIds += listOf(camId, boxId, lightId)
components += ScenePropertiesComponentData(cameraNodeId = camId)
components += SceneBackgroundComponentData(
SceneBackgroundData.SingleColor(ColorData(MdColor.GREY toneLin 900))
)
}
sceneNodes += SceneNodeData("Camera", camId).apply {
components += CameraComponentData(CameraTypeData.Perspective())
components += TransformComponentData(
TransformData.fromMatrix(
MutableMat4d()
.translate(0.0, 2.5, 5.0)
.rotate(-30.0.deg, Vec3d.X_AXIS)
))
}
sceneNodes += SceneNodeData("Default Cube", boxId).apply {
components += MeshComponentData(MeshShapeData.Box(Vec3Data(1.0, 1.0, 1.0)))
}
sceneNodes += SceneNodeData("Directional Light", lightId).apply {
components += DiscreteLightComponentData(LightTypeData.Directional())
components += TransformComponentData(
TransformData.fromMatrix(
MutableMat4d()
.translate(5.0, 5.0, 5.0)
.rotate(0.0.deg, 30.0.deg, (-120.0).deg)
))
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class ZipFileSytem(zip: JsZip) : FileSystem {
.filter { it.isNotEmpty() }
.fold(root as Directory) { parent, name ->
parent.items.getOrPut(name) {
val newDir = Directory("${parent.path}/${name}")
val newDir = Directory(FileSystem.sanitizePath("${parent.path}/${name}"))
fsItems[newDir.path] = newDir
newDir
} as Directory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import de.fabmax.kool.util.logI
class AppModeController(val editor: KoolEditor) {

fun startApp() {
val app = EditorState.loadedApp.value?.app ?: return
val sceneModel = EditorState.projectModel.getCreatedScenes().getOrNull(0) ?: return
val app = editor.loadedApp.value?.app ?: return
val sceneModel = editor.projectModel.getCreatedScenes().getOrNull(0) ?: return

logI { "Start app" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
val textureAssets = mutableStateListOf<AssetItem>()
val hdriAssets = mutableStateListOf<AssetItem>()

private val assetPathPrefix = projectFiles.assets.path
private val assetsByPath = mutableMapOf<String, AssetItem>()

private val fsWatcher = object : FileSystemWatcher {
Expand All @@ -27,7 +28,7 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
if (parent == null) {
refreshAllAssets()
} else {
val assetItem = AssetItem(fileItem)
val assetItem = AssetItem(fileItem, fileItem.assetPath)
assetsByPath[fileItem.path] = assetItem
parent.children += assetItem
parent.sortChildrenByName()
Expand Down Expand Up @@ -67,21 +68,25 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
}

fun createAssetDir(createPath: String) {
val parentPath = FileSystem.parentPath(createPath)
val prefixedPath = FileSystem.sanitizePath("${assetPathPrefix}/${createPath}")
val parentPath = FileSystem.parentPath(prefixedPath)
val parentItem = assetsByPath[parentPath]?.fileItem as? WritableFileSystemDirectory?
if (parentItem == null) {
logE { "Unable to create directory: ${createPath}. Parent directory not found or not writable" }
return
}
parentItem.createDirectory(createPath.removePrefix(parentPath))
parentItem.createDirectory(prefixedPath.removePrefix(parentPath))
}

suspend fun renameAsset(sourcePath: String, destPath: String) {
projectFiles.fileSystem.move(sourcePath, destPath)
val prefixedSrc = FileSystem.sanitizePath("${assetPathPrefix}/${sourcePath}")
val prefixedDst = FileSystem.sanitizePath("${assetPathPrefix}/${destPath}")
projectFiles.fileSystem.move(prefixedSrc, prefixedDst)
}

fun deleteAsset(deletePath: String) {
val deleteItem = assetsByPath[deletePath]?.fileItem as? WritableFileSystemItem?
val prefixedPath = FileSystem.sanitizePath("${assetPathPrefix}/${deletePath}")
val deleteItem = assetsByPath[prefixedPath]?.fileItem as? WritableFileSystemItem?
if (deleteItem == null) {
logE { "Unable to delete asset: ${deletePath}. Path not found or not writable" }
return
Expand All @@ -90,7 +95,8 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
}

suspend fun importAssets(targetPath: String, assetFiles: List<LoadableFile>) {
val targetDir = assetsByPath[FileSystem.sanitizePath(targetPath)]?.fileItem as? WritableFileSystemDirectory?
val prefixedPath = FileSystem.sanitizePath("${assetPathPrefix}/${targetPath}")
val targetDir = assetsByPath[prefixedPath]?.fileItem as? WritableFileSystemDirectory?
if (targetDir == null) {
logE { "Unable to import assets into target directory: ${targetPath}. Path not found or not writable" }
return
Expand All @@ -113,7 +119,7 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
val parent = assetsByPath[parentPath]

val assetItem = assetsByPath.getOrPut(file.path) {
AssetItem(file)
AssetItem(file, file.assetPath)
}

if (parent != null) {
Expand All @@ -135,13 +141,18 @@ class AvailableAssets(private val projectFiles: ProjectFiles) {
addAll(newRootAssets)
}
}

private val FileSystemItem.assetPath: String
get() = path.removePrefix(assetPathPrefix)
}

class AssetItem(val fileItem: FileSystemItem, val type: AppAssetType = AppAssetType.fromFileItem(fileItem)) {
class AssetItem(
val fileItem: FileSystemItem,
val path: String,
val type: AppAssetType = AppAssetType.fromFileItem(fileItem)
) {
val name: String
get() = fileItem.name
val path: String
get() = fileItem.path

val children = mutableStateListOf<AssetItem>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class EditorCamTransform(val editor: KoolEditor) : OrbitInputTransform("Editor c
}
}

fun focusSelectedObject() = focusObjects(EditorState.getSelectedSceneNodes())
fun focusSelectedObject() = focusObjects(editor.selectionOverlay.getSelectedSceneNodes())

fun focusObject(objectModel: SceneNodeModel) = focusObjects(listOf(objectModel))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ import de.fabmax.kool.editor.model.SceneNodeModel
import de.fabmax.kool.util.launchOnMainThread
import de.fabmax.kool.util.logD
import de.fabmax.kool.util.logW
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString

object EditorCopyAndPaste {
object EditorClipboard {

private val editor: KoolEditor
get() = KoolEditor.instance

fun copySelection() {
val selection = EditorState.getSelectedSceneNodes()
val selection = editor.selectionOverlay.getSelectedSceneNodes()
if (selection.isNotEmpty()) {
logD { "Copy ${selection.size} selected objects" }
if (selection.any { it.nodeData.childNodeIds.isNotEmpty() }) {
logW { "Copied nodes contain child nodes, hierarchy won't be preserved during copy and paste. All copied nodes will be flattened" }
}
val json = EditorState.jsonCodec.encodeToString(selection.map { it.nodeData })
val json = KoolEditor.jsonCodec.encodeToString(selection.map { it.nodeData })
Clipboard.copyToClipboard(json)
} else {
logD { "Nothing to copy: Selection is empty" }
Expand All @@ -28,19 +30,19 @@ object EditorCopyAndPaste {

fun paste() {
Clipboard.getStringFromClipboard { json ->
val scene = EditorState.activeScene.value
val scene = editor.activeScene.value
if (json != null && scene != null) {
try {
val copyData = EditorState.jsonCodec.decodeFromString<List<SceneNodeData>>(json)
val copyData = KoolEditor.jsonCodec.decodeFromString<List<SceneNodeData>>(json)
if (copyData.isNotEmpty()) {
logD { "Pasting ${copyData.size} objects from clipboard" }
sanitizeCopiedNodeIds(copyData)

val selection = EditorState.getSelectedNodes()
val selection = editor.selectionOverlay.getSelectedNodes()
val parent = if (selection.size == 1) selection[0] else scene
val sceneNodes = copyData.map { SceneNodeModel(it, parent, scene) }
AddNodeAction(sceneNodes).apply()
EditorState.setSelection(sceneNodes)
editor.selectionOverlay.setSelection(sceneNodes)
}
} catch (e: Exception) {
logW { "Unable to paste clipboard content: Invalid content" }
Expand All @@ -50,11 +52,11 @@ object EditorCopyAndPaste {
}

fun duplicateSelection() {
val selection = EditorState.getSelectedSceneNodes()
val selection = editor.selectionOverlay.getSelectedSceneNodes()
logD { "Duplicate ${selection.size} selected objects" }
val duplicatedNodes = selection.map { nodeModel ->
val json = EditorState.jsonCodec.encodeToString(nodeModel.nodeData)
val copyData = EditorState.jsonCodec.decodeFromString<SceneNodeData>(json)
val json = KoolEditor.jsonCodec.encodeToString(nodeModel.nodeData)
val copyData = KoolEditor.jsonCodec.decodeFromString<SceneNodeData>(json)
sanitizeCopiedNodeIds(listOf(copyData))

val parent = nodeModel.parent
Expand All @@ -64,14 +66,14 @@ object EditorCopyAndPaste {
// update selection via launchOnMainThread so that it is called after node is inserted and components
// are created
launchOnMainThread {
EditorState.setSelection(duplicatedNodes)
editor.selectionOverlay.setSelection(duplicatedNodes)
}
}

private fun sanitizeCopiedNodeIds(copyData: List<SceneNodeData>) {
// todo: support pasting node hierarchies, for now hierarchies are flattened
copyData.forEach {
it.nodeId = EditorState.projectModel.nextId()
it.nodeId = editor.projectModel.nextId()
it.childNodeIds.clear()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import de.fabmax.kool.math.Vec3d
object EditorDefaults {

val DEFAULT_LIGHT_POSITION = Vec3d(5.0, 5.0, 5.0)
val DEFAULT_LIGHT_ROTATION = QuatD(-0.09500162, -0.36375725, 0.6792372, -0.46138754)
val DEFAULT_LIGHT_ROTATION = QuatD(0.224144, 0.129410, -0.836516, 0.482963).normed()

}
Loading

0 comments on commit cada136

Please sign in to comment.