* Collect gizmo data from FGUI node tree * 从 FGUI 节点树收集 Gizmo 数据 * * Uses the same coordinate conversion as FGUIRenderDataProvider: * - FGUI: top-left origin, Y-down * - Engine: center origin, Y-up * - Conversion: engineX = fguiX - halfWidth, engineY = halfHeight - fguiY * * 使用与 FGUIRenderDa
(
obj: GObject,
halfWidth: number,
halfHeight: number,
gizmos: IGizmoRenderData[],
entityId: number,
selectedVirtualNodeId: string | null,
parentPath: string
)
| 73 | * @param parentPath Path prefix for virtual node ID generation | 虚拟节点 ID 生成的路径前缀 |
| 74 | */ |
| 75 | function collectFGUIGizmos( |
| 76 | obj: GObject, |
| 77 | halfWidth: number, |
| 78 | halfHeight: number, |
| 79 | gizmos: IGizmoRenderData[], |
| 80 | entityId: number, |
| 81 | selectedVirtualNodeId: string | null, |
| 82 | parentPath: string |
| 83 | ): void { |
| 84 | // Skip invisible objects |
| 85 | if (!obj.visible) return; |
| 86 | |
| 87 | // Generate virtual node ID (same logic as collectFGUIVirtualNodes) |
| 88 | const nodePath = parentPath ? `${parentPath}/${obj.name || obj.id}` : (obj.name || obj.id); |
| 89 | |
| 90 | // Use localToGlobal to get the global position in FGUI coordinate system |
| 91 | // This handles all parent transforms correctly |
| 92 | // 使用 localToGlobal 获取 FGUI 坐标系中的全局位置 |
| 93 | // 这正确处理了所有父级变换 |
| 94 | const globalPos = obj.localToGlobal(0, 0); |
| 95 | const fguiX = globalPos.x; |
| 96 | const fguiY = globalPos.y; |
| 97 | |
| 98 | // Convert from FGUI coordinates to engine coordinates |
| 99 | // Same formula as FGUIRenderDataProvider |
| 100 | // 从 FGUI 坐标转换为引擎坐标,与 FGUIRenderDataProvider 使用相同公式 |
| 101 | // Engine position is the top-left corner converted to engine coords |
| 102 | const engineX = fguiX - halfWidth; |
| 103 | const engineY = halfHeight - fguiY; |
| 104 | |
| 105 | // For gizmo rect, we need the center position |
| 106 | // Engine Y increases upward, so center is at (engineX + width/2, engineY - height/2) |
| 107 | // 对于 gizmo 矩形,我们需要中心位置 |
| 108 | // 引擎 Y 向上递增,所以中心在 (engineX + width/2, engineY - height/2) |
| 109 | const centerX = engineX + obj.width / 2; |
| 110 | const centerY = engineY - obj.height / 2; |
| 111 | |
| 112 | // Determine color based on selection state |
| 113 | // 根据选中状态确定颜色 |
| 114 | const isSelected = nodePath === selectedVirtualNodeId; |
| 115 | const color = isSelected ? FGUIGizmoColors.childSelected : FGUIGizmoColors.childUnselected; |
| 116 | |
| 117 | // Add rect gizmo for this object |
| 118 | const rectGizmo: IRectGizmoData = { |
| 119 | type: 'rect', |
| 120 | x: centerX, |
| 121 | y: centerY, |
| 122 | width: obj.width, |
| 123 | height: obj.height, |
| 124 | rotation: 0, |
| 125 | originX: 0.5, |
| 126 | originY: 0.5, |
| 127 | color, |
| 128 | showHandles: isSelected, |
| 129 | virtualNodeId: nodePath |
| 130 | }; |
| 131 | gizmos.push(rectGizmo); |
| 132 |
no test coverage detected