Added dev mode and added more manual tweaks for the render geometry.

This commit is contained in:
Daan Vanden Bosch 2021-04-13 17:42:37 +02:00
parent 29192e5684
commit b856a22851
8 changed files with 211 additions and 8 deletions

View File

@ -50,7 +50,8 @@ private fun <Model : NinjaModel, Obj : NinjaObject<Model, Obj>, Context> parseNi
}
}
// TODO: cache model and object offsets so we don't reparse the same data.
// We don't need to cache references to other objects or models because in practice the graph is
// a tree, i.e. no two objects point to the same object or model.
private fun <Model : NinjaModel, Obj : NinjaObject<Model, Obj>, Context> parseSiblingObjects(
cursor: Cursor,
parseModel: (cursor: Cursor, context: Context) -> Model,

View File

@ -74,7 +74,7 @@ private val AREAS by lazy {
@Suppress("UNUSED_CHANGED_VALUE")
val ep4 = listOf(
createArea(0, "Pioneer II (Ep. IV)", order++, 1),
createArea(0, "Pioneer II", order++, 1),
createArea(1, "Crater Route 1", order++, 1),
createArea(2, "Crater Route 2", order++, 1),
createArea(3, "Crater Route 3", order++, 1),

View File

@ -241,8 +241,8 @@ class UiStore(private val applicationUrl: ApplicationUrl) : Store() {
val bindingParts = mutableListOf<String>()
if (e.ctrlKey) bindingParts.add("Ctrl")
if (e.shiftKey) bindingParts.add("Shift")
if (e.altKey) bindingParts.add("Alt")
if (e.shiftKey) bindingParts.add("Shift")
bindingParts.add(e.key.toUpperCase())
val binding = bindingParts.joinToString("-")

View File

@ -614,6 +614,7 @@ external class MeshBasicMaterial(
external interface MeshLambertMaterialParameters : MaterialParameters {
var color: Color
var map: Texture?
var skinning: Boolean
}

View File

@ -209,7 +209,6 @@ class AreaAssetLoader(private val assetLoader: AssetLoader) : DisposableContaine
): Pair<Object3D, List<SectionModel>> {
val fix = MANUAL_FIXES[Pair(episode, areaVariant.area.id)]
val sections = mutableMapOf<Int, SectionModel>()
console.log(renderGeometry)
val group =
renderGeometryToGroup(renderGeometry, textures) { renderSection, areaObj, mesh ->
@ -370,7 +369,33 @@ class AreaAssetLoader(private val assetLoader: AssetLoader) : DisposableContaine
// Pioneer 2
Pair(Episode.I, 0) to Fix(
renderOnTopTextures = jsSetOf(
70, 71, 72, 126, 127, 155, 156, 198, 230, 231, 232, 233, 234,
20,
40,
41,
67,
70,
71,
72,
93,
94,
96,
105,
120,
121,
122,
155,
156,
170,
198,
218,
220,
221,
230,
231,
232,
233,
234,
243,
),
hiddenObjects = jsSetOf(
"s_m_0_6a_d_iu5sg6",
@ -404,14 +429,39 @@ class AreaAssetLoader(private val assetLoader: AssetLoader) : DisposableContaine
"s_m_0_4_1_is53va",
"s_m_0_3l_6_igzvga",
"s_n_0_en_3_iiawrz",
"a_k_0_1k_3_ihdi9s",
),
),
// Forest 1
Pair(Episode.I, 1) to Fix(
renderOnTopTextures = jsSetOf(12, 41),
renderOnTopTextures = jsSetOf(12, 24, 41),
// Hiding trees and their shadows, doesn't seem to improve things.
// hiddenObjects = jsSetOf(
// // Trees
// "s_n_0_2i_2_im1teq",
// "s_n_0_2i_2_im1tep",
// // Baked-in shadows.
// "s_n_0_2n_1_irv6ha",
// "s_n_0_2g_1_iqvdru",
// "s_n_0_2p_1_irv6h6",
// "s_n_0_47_1_iqve55",
// "s_n_0_3p_1_ip2uvk",
// "s_n_0_1r_1_iqve64",
// "s_n_0_1f_1_irv6h0",
// "s_n_0_1o_1_iqvdnv",
// "s_n_0_28_1_iqvdw5",
// "s_n_0_2b_1_iqvdrj",
// "s_n_0_22_1_ip2w4r",
// "s_n_0_3i_1_iqvdxp",
// "s_n_0_33_1_iqve4e",
// "s_n_0_2i_1_ip2v47",
// "s_n_0_3a_1_ip2ugm",
// "s_n_0_39_1_irv672",
// ),
),
// Cave 1
Pair(Episode.I, 3) to Fix(
renderOnTopTextures = jsSetOf(89),
hiddenObjects = jsSetOf(
"s_n_0_8_1_iqrqjj",
"s_i_0_b5_1_is7ajh",
@ -437,6 +487,14 @@ class AreaAssetLoader(private val assetLoader: AssetLoader) : DisposableContaine
"s_n_0_3i_1_iurb4o",
"s_n_0_22_1_ii9035",
"s_n_0_2i_3_iiqupy",
"s_n_0_s_3_im3sg2",
"s_n_0_o_2_im3v5x",
"s_n_0_52_2_ilqxdf",
"s_n_0_1g_3_im5sui",
"s_n_0_15_2_im5sum",
"s_n_0_6l_1_im1ktx",
"s_n_0_3v_1_ikzchf",
"s_n_0_2i_3_ilfw56",
),
),
// Cave 2
@ -530,10 +588,69 @@ class AreaAssetLoader(private val assetLoader: AssetLoader) : DisposableContaine
// Jungle Area East
Pair(Episode.II, 6) to Fix(
renderOnTopTextures = jsSetOf(0, 1, 2, 18, 21, 24),
hiddenObjects = jsSetOf(
"a_m_0_1i_1_isf1hw",
"a_m_0_1i_1_isfvf0",
"a_m_0_1i_1_ise7ew",
"a_m_0_1i_1_ishhj6",
"a_m_0_1i_1_isiw4p",
"a_m_0_1i_1_ishyp4",
"a_m_0_1i_1_isewhg",
"a_m_0_1i_1_isemhl",
"a_m_0_1i_1_isiuce",
"a_m_0_1i_1_isfvey",
"a_m_0_1i_1_isgolp",
"a_m_0_1i_1_iseg19",
"a_m_0_1i_1_isdzut",
"a_m_0_1i_1_isf0vs",
"a_m_0_1i_1_ishrwm",
"a_m_0_1i_1_isivaf",
"a_m_0_1i_1_isf0vs",
"a_m_0_1i_1_isfqe9",
),
),
// Subterranean Desert 1
Pair(Episode.IV, 6) to Fix(
renderOnTopTextures = jsSetOf(48, 50, 58, 66, 80, 81, 92, 93, 94, 99, 100, 103),
hiddenObjects = jsSetOf(
"s_v_f_16u_b_j2s5tx",
"s_v_d_84_f_j046sf",
"s_v_1v_205_2n_jb17vl",
"s_n_0_1s_1_iwnfqt",
"s_n_0_g1_6_iovjxw",
"s_v_d_z6_k_j1viu6",
"s_n_0_do_4_ipdh8p",
"s_v_c_7y_c_iu7yzc",
"s_v_8_4a_8_ixe9km",
"s_v_4_15_4_in60hf",
"s_n_0_6_1_ihtf3l",
"s_n_0_6_1_ikxbmr",
"s_v_9_3e_9_itbo7o",
"s_v_t_19k_r_iv3zbt",
"s_v_a_2s_a_ix4iob",
"s_v_b_37_b_iu5dp9",
"s_v_6_5t_7_iqx2nn",
"s_v_8_145_l_j0crhw",
"s_n_0_6_1_ikk5cn",
"s_v_5_15r_d_j2n06s",
"s_v_p_8n_p_j1enrp",
"s_v_b_p3_d_iu4vwf",
"s_v_c_3z_c_ithfqt",
"s_v_2_3g_2_itis48",
"s_v_17_h3_13_j7o59x",
"s_n_0_2t_1_iw2868",
"s_v_5_k1_8_ir35lp",
"s_v_h_7k_y_j5h3h2",
"s_v_8_4d_8_irrw8y",
"s_v_o_1qg_h_iyilpg", // Removes roof and walls but also some rocks in the middle.
"s_v_10_14y_11_j0vhyd",
),
),
).also {
// VR Spaceship Beta = VR Spaceship Alpha
it[Pair(Episode.II, 4)] = it[Pair(Episode.II, 3)]!!
// Ep. IV Pioneer II = Ep. I Pioneer II
it[Pair(Episode.IV, 0)] = it[Pair(Episode.I, 0)]!!
}
private val raycaster = Raycaster()

View File

@ -1,6 +1,7 @@
package world.phantasmal.web.questEditor.rendering.input.state
import world.phantasmal.web.core.minus
import world.phantasmal.web.externals.three.Mesh
import world.phantasmal.web.externals.three.Vector2
import world.phantasmal.web.externals.three.Vector3
import world.phantasmal.web.questEditor.models.QuestEntityModel
@ -85,6 +86,7 @@ class IdleState(
pickEntity(event.pointerDevicePosition) == null
) {
ctx.setSelectedEntity(null)
pickAndHighlightMesh()
}
}
@ -175,6 +177,19 @@ class IdleState(
return Pick(entity, grabOffset, dragAdjust)
}
private fun pickAndHighlightMesh() {
if (ctx.devMode.value) {
val intersection = ctx.intersectObject(
pointerDevicePosition,
ctx.renderContext.renderGeometry,
) { it.`object`.visible }
ctx.setHighlightedMesh(intersection?.`object` as Mesh?)
} else {
ctx.setHighlightedMesh(null)
}
}
private class Pick(
val entity: QuestEntityModel<*, *>,

View File

@ -1,10 +1,15 @@
package world.phantasmal.web.questEditor.rendering.input.state
import mu.KotlinLogging
import world.phantasmal.core.asJsArray
import world.phantasmal.lib.fileFormats.ninja.XjObject
import world.phantasmal.observable.value.Val
import world.phantasmal.web.core.dot
import world.phantasmal.web.core.minusAssign
import world.phantasmal.web.core.plusAssign
import world.phantasmal.web.core.rendering.OrbitalCameraInputManager
import world.phantasmal.web.core.rendering.conversion.AreaObjectUserData
import world.phantasmal.web.core.rendering.conversion.fingerPrint
import world.phantasmal.web.externals.three.*
import world.phantasmal.web.questEditor.actions.CreateEntityAction
import world.phantasmal.web.questEditor.actions.DeleteEntityAction
@ -17,11 +22,19 @@ import world.phantasmal.web.questEditor.stores.QuestEditorStore
import kotlin.math.PI
import kotlin.math.atan2
private val logger = KotlinLogging.logger {}
class StateContext(
private val questEditorStore: QuestEditorStore,
val renderContext: QuestRenderContext,
val cameraInputManager: OrbitalCameraInputManager,
) {
/**
* Highlighted mesh with its original colors.
*/
private var highlightedMesh: Pair<Mesh, List<Color>>? = null
val devMode: Val<Boolean> = questEditorStore.devMode
val quest: Val<QuestModel?> = questEditorStore.currentQuest
val area: Val<AreaModel?> = questEditorStore.currentArea
val wave: Val<WaveModel?> = questEditorStore.selectedEvent.flatMapNull { it?.wave }
@ -153,8 +166,8 @@ class StateContext(
// Calculate the angle between the two vectors and rotate the entity around its y-axis
// by that angle.
val cos = axisToGrab.dot(axisToPointer)
val sin = planeNormal.dot(axisToGrab.cross(axisToPointer))
val cos = axisToGrab dot axisToPointer
val sin = planeNormal dot axisToGrab.cross(axisToPointer)
val angle = atan2(sin, cos)
entity.setWorldRotation(
@ -240,6 +253,51 @@ class StateContext(
return raycasterIntersections.find(predicate)
}
fun setHighlightedMesh(mesh: Mesh?) {
highlightedMesh?.let { (prevMesh, prevColors) ->
prevMesh.material.unsafeCast<Array<MeshBasicMaterial>>().forEachIndexed { i, mat ->
mat.color.set(prevColors[i])
}
}
highlightedMesh = null
if (mesh != null) {
logger.info {
val userData = mesh.userData.unsafeCast<AreaObjectUserData>()
val areaObj = userData.areaObject
val textureIds = mutableSetOf<Int>()
fun getAllTextureIds(xjObject: XjObject) {
xjObject.model?.meshes?.forEach { it.material.textureId?.let(textureIds::add) }
xjObject.children.forEach(::getAllTextureIds)
}
getAllTextureIds(areaObj.xjObject)
buildString {
append("Section ")
append(userData.sectionId)
append(" (finger print: ")
append(areaObj.fingerPrint())
append(", texture IDs: ")
textureIds.joinTo(this)
append(')')
}
}
val origColors = mutableListOf<Color>()
mesh.material.unsafeCast<Array<MeshBasicMaterial>>().forEach {
origColors.add(it.color.clone())
it.color.set(0xB0FF00)
}
highlightedMesh = Pair(mesh, origColors)
}
}
private fun intersectPlane(
origin: Vector2,
plane: Plane,

View File

@ -22,6 +22,7 @@ class QuestEditorStore(
private val areaStore: AreaStore,
private val undoManager: UndoManager,
) : Store() {
private val _devMode = mutableVal(false)
private val _currentQuest = mutableVal<QuestModel?>(null)
private val _currentArea = mutableVal<AreaModel?>(null)
private val _selectedEvent = mutableVal<QuestEventModel?>(null)
@ -30,6 +31,8 @@ class QuestEditorStore(
private val mainUndo = UndoStack(undoManager)
private val _showCollisionGeometry = mutableVal(true)
val devMode: Val<Boolean> = _devMode
val runner = QuestRunner()
val currentQuest: Val<QuestModel?> = _currentQuest
val currentArea: Val<AreaModel?> = _currentArea
@ -55,6 +58,14 @@ class QuestEditorStore(
val showCollisionGeometry: Val<Boolean> = _showCollisionGeometry
init {
addDisposables(
uiStore.onGlobalKeyDown(PwToolType.QuestEditor, "Ctrl-Alt-Shift-D") {
_devMode.value = !_devMode.value
logger.info { "Dev mode ${if (devMode.value) "on" else "off"}." }
},
)
observe(uiStore.currentTool) { tool ->
if (tool == PwToolType.QuestEditor) {
makeMainUndoCurrent()