Skip to content

Commit

Permalink
[BLENDER] #572 Control editor LED bulb support (WIP) (#581)
Browse files Browse the repository at this point in the history
* Control editor add bulb editing UI

* Control agent support led bulb
  • Loading branch information
Chalkman071 authored Mar 18, 2024
1 parent c679e9d commit 1cfa335
Show file tree
Hide file tree
Showing 17 changed files with 199 additions and 20 deletions.
20 changes: 16 additions & 4 deletions editor-blender/api/control_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
EDIT_CONTROL_FRAME_TIME,
REQUEST_EDIT_CONTROL_BY_ID,
MutCancelEditControlResponse,
MutDancerLEDStatusPayload,
MutDancerStatusPayload,
MutDeleteControlFrameInput,
MutEditControlFrameInput,
MutEditControlFrameTimeInput,
Expand Down Expand Up @@ -81,13 +83,19 @@ async def add_frame(
self,
start: int,
fade: bool,
controlData: List[List[Tuple[Union[ColorID, LEDEffectID], int]]],
controlData: List[MutDancerStatusPayload],
ledControlData: List[MutDancerLEDStatusPayload],
) -> Optional[str]:
try:
response = await client.execute(
str,
ADD_CONTROL_FRAME,
{"start": start, "controlData": controlData, "fade": fade},
{
"start": start,
"controlData": controlData,
"fade": fade,
"ledControlData": ledControlData,
},
)
return response["addControlFrame"]

Expand All @@ -103,7 +111,8 @@ async def add_frame(
async def save_frame(
self,
id: MapID,
controlData: List[List[Tuple[Union[ColorID, LEDEffectID], int]]],
controlData: List[MutDancerStatusPayload],
ledBulbData: List[MutDancerLEDStatusPayload],
fade: Optional[bool] = None,
start: Optional[int] = None,
):
Expand All @@ -116,7 +125,10 @@ async def save_frame(
EDIT_CONTROL_FRAME,
{
"input": MutEditControlFrameInput(
frameId=id, controlData=controlData, fade=fade
frameId=id,
controlData=controlData,
ledBulbData=ledBulbData,
fade=fade,
)
},
)
Expand Down
4 changes: 4 additions & 0 deletions editor-blender/core/actions/property/lights.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def update_current_effect(self: bpy.types.Object, context: bpy.types.Context):

control_index -= 1

if effect_id == 0:
return

if effect_id != -1:
effect = state.led_effect_id_table[effect_id]

Expand Down Expand Up @@ -89,6 +92,7 @@ def update_current_alpha(self: bpy.types.Object, context: bpy.types.Context):
led_bulb_obj.color[0] = bulb_ld_color_float[0] * (ld_alpha / 255)
led_bulb_obj.color[1] = bulb_ld_color_float[1] * (ld_alpha / 255)
led_bulb_obj.color[2] = bulb_ld_color_float[2] * (ld_alpha / 255)
setattr(led_bulb_obj, "ld_alpha", ld_alpha)
else:
self.color[0] = ld_color_float[0] * (ld_alpha / 255)
self.color[1] = ld_color_float[1] * (ld_alpha / 255)
Expand Down
37 changes: 32 additions & 5 deletions editor-blender/core/actions/state/control_editor.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from typing import List, Optional
from typing import List, Optional, Tuple

import bpy

from ....api.control_agent import control_agent
from ....graphqls.mutations import MutDancerStatusPayload
from ....graphqls.mutations import MutDancerLEDStatusPayload, MutDancerStatusPayload
from ....properties.types import LightType
from ...models import EditingData, EditMode, PartType, SelectMode
from ...states import state
from ...utils.convert import control_status_state_to_mut, rgb_to_float
from ...utils.convert import (
control_status_state_to_mut,
led_status_state_to_mut,
rgb_to_float,
)
from ...utils.notification import notify
from ...utils.object import clear_selection
from ...utils.ui import redraw_area
Expand Down Expand Up @@ -69,10 +73,11 @@ def sync_editing_control_frame_properties():
async def add_control_frame():
start = bpy.context.scene.frame_current
controlData = control_status_state_to_mut(state.current_status)
ledControlData = led_status_state_to_mut(state.current_led_status)

try:
set_requesting(True)
await control_agent.add_frame(start, False, controlData)
await control_agent.add_frame(start, False, controlData, ledControlData)
set_requesting(False)
notify("INFO", f"Added control frame")
except:
Expand All @@ -85,10 +90,12 @@ async def save_control_frame(start: Optional[int] = None):
fade: bool = getattr(bpy.context.window_manager, "ld_fade")

controlData: List[MutDancerStatusPayload] = []
ledBulbData: List[MutDancerLEDStatusPayload] = []
default_color = list(state.color_map.keys())[0]

for dancer in state.dancers_array:
partControlData: MutDancerStatusPayload = []
partLedBulbData: MutDancerLEDStatusPayload = []
obj: Optional[bpy.types.Object] = bpy.data.objects.get(dancer.name)

if obj is not None:
Expand All @@ -101,8 +108,10 @@ async def save_control_frame(start: Optional[int] = None):
if part.name not in part_obj_names:
if part.type == PartType.FIBER:
partControlData.append((default_color, 0))
partLedBulbData.append(([(0, 0)]))
elif part.type == PartType.LED:
partControlData.append((-1, 0))
partLedBulbData.append(([(0, 0)]))
continue

part_index = part_obj_names.index(part.name)
Expand All @@ -112,23 +121,41 @@ async def save_control_frame(start: Optional[int] = None):
color_id = part_obj["ld_color"]
ld_alpha: int = getattr(part_obj, "ld_alpha")
partControlData.append((color_id, ld_alpha))
partLedBulbData.append([(0, 0)])
elif part.type == PartType.LED:
effect_id = part_obj["ld_effect"]
ld_alpha: int = getattr(part_obj, "ld_alpha")
partControlData.append((effect_id, ld_alpha))
if effect_id == 0:
bulb_objs: List[bpy.types.Object] = list(
getattr(part_obj, "children")
)
bulb_objs.sort(key=lambda _obj: getattr(_obj, "ld_led_pos"))
bulb_color_list: List[Tuple[int, int]] = [
(obj["ld_color"], getattr(obj, "ld_alpha"))
for obj in bulb_objs
]
partLedBulbData.append(bulb_color_list)
else:
partLedBulbData.append([(0, 0)])

else:
for part in dancer.parts:
if part.type == PartType.FIBER:
partControlData.append((default_color, 0))
partLedBulbData.append(None)
elif part.type == PartType.LED:
partControlData.append((-1, 0))
partLedBulbData.append(None)

controlData.append(partControlData)
ledBulbData.append(partLedBulbData)

try:
set_requesting(True)
await control_agent.save_frame(id, controlData, fade=fade, start=start)
await control_agent.save_frame(
id, controlData, ledBulbData, fade=fade, start=start
)
notify("INFO", f"Saved control frame")

# Cancel editing
Expand Down
2 changes: 2 additions & 0 deletions editor-blender/core/actions/state/current_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def update_current_status_by_index():
setattr(bpy.context.window_manager, "ld_start", current_control_map.start)

current_status = current_control_map.status
current_led_status = current_control_map.led_status
state.current_status = current_status
state.current_led_status = current_led_status

for dancer in state.dancers_array:
dancer_status = current_status.get(dancer.name)
Expand Down
6 changes: 6 additions & 0 deletions editor-blender/core/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class FiberData:

PartData = Union[LEDData, FiberData]
DancerStatus = Dict[PartName, PartData]
DancerLEDBulbStatus = Dict[PartName, List[LEDBulbData]]


@dataclass
Expand All @@ -76,13 +77,16 @@ class Revision:

ControlMapStatus = Dict[DancerName, DancerStatus]

ControlMapLEDBulbStatus = Dict[DancerName, DancerLEDBulbStatus]


@dataclass
class ControlMapElement:
start: int
fade: bool
rev: Revision
status: ControlMapStatus
led_status: ControlMapLEDBulbStatus


ControlMap = Dict[MapID, ControlMapElement]
Expand Down Expand Up @@ -185,6 +189,7 @@ class SelectedPartType(Enum):
FIBER = 1
LED = 2
MIXED_LIGHT = 3
LED_BULB = 4


@dataclass
Expand Down Expand Up @@ -358,6 +363,7 @@ class State:
# NOTE: Maybe we don't need these
current_fade: bool
current_status: ControlMapStatus
current_led_status: ControlMapLEDBulbStatus
current_pos: PosMapStatus

current_editing_frame: int
Expand Down
1 change: 1 addition & 0 deletions editor-blender/core/states/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
current_led_index=0,
current_fade=False,
current_status={},
current_led_status={},
current_pos={},
current_editing_frame=0,
current_editing_detached=False,
Expand Down
74 changes: 71 additions & 3 deletions editor-blender/core/utils/convert.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
from typing import List, Tuple, Union

from ...graphqls.mutations import MutDancerStatusPayload
from ...graphqls.mutations import MutDancerLEDStatusPayload, MutDancerStatusPayload
from ...graphqls.queries import (
QueryColorMapPayload,
QueryColorMapPayloadItem,
QueryControlFrame,
QueryControlMapPayload,
QueryCoordinatesPayload,
QueryDancerLEDBulbStatusPayload,
QueryDancersPayload,
QueryDancerStatusPayload,
QueryDancerStatusPayloadItem,
QueryEffectListControlFrame,
QueryEffectListItem,
QueryEffectListPositionFrame,
QueryLEDBulbDataPayload,
QueryLEDMapPayload,
QueryModelPayload,
QueryPosFrame,
Expand All @@ -31,7 +33,9 @@
ColorMap,
ControlMap,
ControlMapElement,
ControlMapLEDBulbStatus,
ControlMapStatus,
DancerLEDBulbStatus,
DancersArray,
DancersArrayItem,
DancersArrayPartsItem,
Expand Down Expand Up @@ -136,6 +140,10 @@ def part_data_query_to_state(
return FiberData(color_id=payload[0], alpha=payload[1])


def part_led_data_query_to_state(payload: QueryLEDBulbDataPayload) -> List[LEDBulbData]:
return [LEDBulbData(color_id=bulb[0], alpha=bulb[1]) for bulb in payload]


def part_data_state_to_mut(
part_data: PartData,
) -> Tuple[Union[LEDEffectID, ColorID], int]:
Expand All @@ -145,6 +153,12 @@ def part_data_state_to_mut(
return (part_data.color_id, part_data.alpha)


def part_led_data_state_to_mut(
led_data: List[LEDBulbData],
) -> List[Tuple[ColorID, int]]:
return [(bulb.color_id, bulb.alpha) for bulb in led_data]


def control_status_query_to_state(
payload: List[QueryDancerStatusPayload],
) -> ControlMapStatus:
Expand All @@ -167,14 +181,37 @@ def control_status_query_to_state(
return control_map_status


def led_status_query_to_state(
payload: List[QueryDancerLEDBulbStatusPayload],
) -> ControlMapLEDBulbStatus:
control_map_led_status: ControlMapLEDBulbStatus = {}

for dancerIndex, dancerStatus in enumerate(payload):
dancers_array_item = state.dancers_array[dancerIndex]
dancer_name = dancers_array_item.name
dancer_parts = dancers_array_item.parts
dancer_status: DancerLEDBulbStatus = {}

for partIndex, partStatus in enumerate(dancerStatus):
part_name = dancer_parts[partIndex].name
part_type = state.part_type_map[part_name]

dancer_status[part_name] = part_led_data_query_to_state(partStatus)

control_map_led_status[dancer_name] = dancer_status

return control_map_led_status


def control_frame_query_to_state(payload: QueryControlFrame) -> ControlMapElement:
rev = Revision(meta=payload.rev.meta, data=payload.rev.data)

control_map_element = ControlMapElement(
start=payload.start, fade=payload.fade, status={}, rev=rev
start=payload.start, fade=payload.fade, status={}, led_status={}, rev=rev
)

control_map_element.status = control_status_query_to_state(payload.status)
control_map_element.led_status = led_status_query_to_state(payload.led_status)

return control_map_element

Expand All @@ -191,13 +228,23 @@ def control_map_query_to_state(frames: QueryControlMapPayload) -> ControlMap:
def control_frame_sub_to_query(data: SubControlFrame) -> QueryControlFrame:
rev = QueryRevision(meta=data.rev.meta, data=data.rev.data)

response = QueryControlFrame(start=data.start, fade=data.fade, status=[], rev=rev)
response = QueryControlFrame(
start=data.start, fade=data.fade, status=[], led_status=[], rev=rev
)

response.status = [
[(partControl[0], partControl[1]) for partControl in partControls]
for partControls in data.status
]

response.led_status = [
[
[(control[0], control[1]) for control in partControl]
for partControl in partLEDBulbControls
]
for partLEDBulbControls in data.led_status
]

return response


Expand All @@ -219,6 +266,27 @@ def control_status_state_to_mut(
return mut_dancer_status_payload


def led_status_state_to_mut(
led_status: ControlMapLEDBulbStatus,
) -> List[MutDancerLEDStatusPayload]:
mut_dancer_status_payload: List[MutDancerLEDStatusPayload] = []

for dancer in state.dancers_array:
dancer_name = dancer.name
dancer_status = led_status.get(dancer_name)
if dancer_status is None:
raise Exception("Dancer LED status not found")

mut_dancer_status_payload.append(
[
part_led_data_state_to_mut(dancer_status[part.name])
for part in dancer.parts
]
)

return mut_dancer_status_payload


def rgb_to_hex(rgb: Tuple[int, int, int]) -> str:
r, g, b = rgb
return f"#{r:02x}{g:02x}{b:02x}"
Expand Down
Loading

0 comments on commit 1cfa335

Please sign in to comment.