forked from LeenkxTeam/LNXSDK
Update
This commit is contained in:
@ -154,14 +154,14 @@ def _deferred_set_rendered_mode():
|
||||
_rendered_mode_pending = False
|
||||
_rendered_mode_retries = 0
|
||||
return None
|
||||
|
||||
|
||||
space.shading.type = 'RENDERED'
|
||||
area.tag_redraw()
|
||||
|
||||
_rendered_mode_pending = False
|
||||
_rendered_mode_retries = 0
|
||||
return None
|
||||
|
||||
|
||||
_rendered_mode_retries += 1
|
||||
if _rendered_mode_retries < 10:
|
||||
print(f"Viewport VIEW_3D not found, retrying... ({_rendered_mode_retries})")
|
||||
@ -232,14 +232,14 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
return
|
||||
|
||||
current_mode = space.shading.type
|
||||
|
||||
|
||||
if self._last_shading_mode == 'SOLID' and current_mode == 'RENDERED':
|
||||
self._initialized = False
|
||||
self._rendered_mode_set = False
|
||||
self._krom_launch_attempted = False
|
||||
self._cleanup_shared_memory()
|
||||
self._pending_camera_sync = True
|
||||
|
||||
|
||||
if self._last_shading_mode == 'RENDERED' and current_mode != 'RENDERED':
|
||||
self._rendered_mode_set = False
|
||||
# keep krom running in solid mode for switching back ti rendered
|
||||
@ -260,9 +260,9 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
|
||||
view_matrix = rv3d.view_matrix
|
||||
proj_matrix = rv3d.window_matrix
|
||||
|
||||
|
||||
view_data = struct.pack('<16f', *[view_matrix[i][j] for j in range(4) for i in range(4)])
|
||||
|
||||
|
||||
proj_data = struct.pack('<16f', *[proj_matrix[i][j] for j in range(4) for i in range(4)])
|
||||
|
||||
if sys.platform == 'win32':
|
||||
@ -275,7 +275,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._shm.write(view_data)
|
||||
self._shm.seek(OFFSET_PROJ_MATRIX)
|
||||
self._shm.write(proj_data)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed camera sync: {e}")
|
||||
|
||||
@ -295,11 +295,11 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
if not self._viewport_id:
|
||||
import time
|
||||
self._viewport_id = hex(int(time.time() * 1000) % 0xFFFFFF)[-6:]
|
||||
|
||||
|
||||
region = context.region
|
||||
width = region.width // 2 if region else 960
|
||||
height = region.height if region else 540
|
||||
|
||||
|
||||
viewport_id = self._viewport_id
|
||||
engine_id = self._engine_id
|
||||
shmem_name = _get_viewport_shmem_name(viewport_id)
|
||||
@ -331,7 +331,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._ensure_initialized()
|
||||
if self._initialized:
|
||||
return True
|
||||
|
||||
|
||||
if self._viewport_id is None and context is not None:
|
||||
try:
|
||||
space = context.space_data
|
||||
@ -339,11 +339,11 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._viewport_id = hex(space.as_pointer())[-6:]
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
if self._viewport_id is None:
|
||||
import time
|
||||
self._viewport_id = hex(int(time.time() * 1000) % 0xFFFFFF)[-6:]
|
||||
|
||||
|
||||
shmem_name = _get_viewport_shmem_name(self._viewport_id)
|
||||
self._shmem_name = shmem_name
|
||||
|
||||
@ -356,7 +356,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
|
||||
FILE_MAP_ALL_ACCESS = 0x000F001F
|
||||
|
||||
|
||||
kernel32.OpenFileMappingW.argtypes = [ctypes.wintypes.DWORD, ctypes.wintypes.BOOL, ctypes.wintypes.LPCWSTR]
|
||||
kernel32.OpenFileMappingW.restype = ctypes.wintypes.HANDLE
|
||||
|
||||
@ -371,7 +371,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
|
||||
kernel32.VirtualQuery.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
|
||||
kernel32.VirtualQuery.restype = ctypes.c_size_t
|
||||
|
||||
|
||||
handle = kernel32.OpenFileMappingW(
|
||||
FILE_MAP_ALL_ACCESS,
|
||||
False,
|
||||
@ -395,7 +395,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
kernel32.CloseHandle(handle)
|
||||
print(f"Failed to map shared memory: {error}")
|
||||
return False
|
||||
|
||||
|
||||
self._shm_handle = handle
|
||||
self._shm_ptr = ptr
|
||||
|
||||
@ -420,11 +420,10 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
actual_size = mbi.RegionSize
|
||||
|
||||
self._shm_size = actual_size
|
||||
|
||||
|
||||
self._shm_buffer = (ctypes.c_ubyte * actual_size).from_address(ptr)
|
||||
|
||||
self._initialized = True
|
||||
# print(f"Connected: {shmem_name}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed to open shared memory: {e}")
|
||||
@ -451,7 +450,6 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._shm_file = open(shm_path, 'r+b')
|
||||
self._shm = mmap.mmap(self._shm_file.fileno(), max_size, mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE)
|
||||
self._initialized = True
|
||||
# print(f"Connected: {shm_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed to open /dev/shm: {e}")
|
||||
@ -548,7 +546,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
header = self._read_header()
|
||||
if not header:
|
||||
return None
|
||||
|
||||
|
||||
if header['frame_id'] == self._last_frame_id:
|
||||
return None
|
||||
|
||||
@ -570,7 +568,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
pixel_buffer = (ctypes.c_ubyte * pixel_size)()
|
||||
ctypes.memmove(pixel_buffer, self._shm_ptr + VIEWPORT_HEADER_SIZE, pixel_size)
|
||||
pixels = bytes(pixel_buffer)
|
||||
|
||||
|
||||
ready_bytes = struct.pack('<I', 0)
|
||||
ctypes.memmove(self._shm_ptr + OFFSET_READY_FLAG, ready_bytes, 4)
|
||||
else:
|
||||
@ -602,9 +600,9 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
|
||||
view_matrix = rv3d.view_matrix
|
||||
proj_matrix = rv3d.window_matrix
|
||||
|
||||
|
||||
view_data = struct.pack('<16f', *[view_matrix[i][j] for j in range(4) for i in range(4)])
|
||||
|
||||
|
||||
proj_data = struct.pack('<16f', *[proj_matrix[i][j] for j in range(4) for i in range(4)])
|
||||
|
||||
if sys.platform == 'win32':
|
||||
@ -640,7 +638,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
dirty = struct.unpack('<I', dirty_data)[0]
|
||||
if dirty == 0:
|
||||
return
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
pos_data = ctypes.string_at(self._shm_ptr + OFFSET_KROM_CAMERA_POS, 12)
|
||||
rot_data = ctypes.string_at(self._shm_ptr + OFFSET_KROM_CAMERA_ROT, 16)
|
||||
@ -652,16 +650,16 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
|
||||
pos = struct.unpack('<3f', pos_data)
|
||||
rot = struct.unpack('<4f', rot_data) # quaternion (x, y, z, w)
|
||||
|
||||
|
||||
clear_data = struct.pack('<I', 0)
|
||||
if sys.platform == 'win32':
|
||||
ctypes.memmove(self._shm_ptr + OFFSET_KROM_CAMERA_DIRTY, clear_data, 4)
|
||||
else:
|
||||
self._shm.seek(OFFSET_KROM_CAMERA_DIRTY)
|
||||
self._shm.write(clear_data)
|
||||
|
||||
|
||||
from mathutils import Quaternion, Matrix, Vector
|
||||
|
||||
|
||||
rv3d = context.space_data.region_3d if context.space_data else None
|
||||
if not rv3d:
|
||||
return
|
||||
@ -670,12 +668,12 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
quat = Quaternion((rot[3], rot[0], rot[1], rot[2]))
|
||||
|
||||
forward = quat @ Vector((0, 0, -1))
|
||||
|
||||
|
||||
camera_pos = Vector(pos)
|
||||
view_dist = rv3d.view_distance if rv3d.view_distance > 0 else 10.0
|
||||
|
||||
|
||||
target = camera_pos + forward * view_dist
|
||||
|
||||
|
||||
rv3d.view_location = target
|
||||
rv3d.view_rotation = quat
|
||||
|
||||
@ -687,7 +685,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._ensure_initialized()
|
||||
if not self._initialized:
|
||||
return
|
||||
|
||||
|
||||
if hasattr(self, '_last_requested_width') and hasattr(self, '_last_requested_height'):
|
||||
if self._last_requested_width == width and self._last_requested_height == height:
|
||||
return
|
||||
@ -764,23 +762,23 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
|
||||
# calculate event offset in ring buffer
|
||||
event_offset = OFFSET_INPUT_EVENTS + (write_idx % MAX_INPUT_EVENTS) * INPUT_EVENT_SIZE
|
||||
|
||||
|
||||
event_data = struct.pack('<BBhhhI', event_type, button, x, y, delta, modifiers)
|
||||
ctypes.memmove(self._shm_ptr + event_offset, event_data, len(event_data))
|
||||
|
||||
|
||||
new_write_idx = struct.pack('<I', (write_idx + 1) % MAX_INPUT_EVENTS)
|
||||
ctypes.memmove(self._shm_ptr + OFFSET_INPUT_WRITE_IDX, new_write_idx, 4)
|
||||
return True
|
||||
else:
|
||||
self._shm.seek(OFFSET_INPUT_WRITE_IDX)
|
||||
write_idx = struct.unpack('<I', self._shm.read(4))[0]
|
||||
|
||||
|
||||
event_offset = OFFSET_INPUT_EVENTS + (write_idx % MAX_INPUT_EVENTS) * INPUT_EVENT_SIZE
|
||||
|
||||
|
||||
self._shm.seek(event_offset)
|
||||
event_data = struct.pack('<BBhhhI', event_type, button, x, y, delta, modifiers)
|
||||
self._shm.write(event_data)
|
||||
|
||||
|
||||
self._shm.seek(OFFSET_INPUT_WRITE_IDX)
|
||||
self._shm.write(struct.pack('<I', (write_idx + 1) % MAX_INPUT_EVENTS))
|
||||
return True
|
||||
@ -799,7 +797,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
self._ensure_initialized()
|
||||
try:
|
||||
num_pixels = width * height * 4
|
||||
|
||||
|
||||
if len(pixels) < num_pixels:
|
||||
return
|
||||
|
||||
@ -823,7 +821,7 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
else:
|
||||
float_pixels.append(_srgb_to_linear_lut_list[p])
|
||||
buffer = gpu.types.Buffer('FLOAT', len(float_pixels), float_pixels)
|
||||
|
||||
|
||||
self._texture = gpu.types.GPUTexture((width, height), format='RGBA32F', data=buffer)
|
||||
self._tex_width = width
|
||||
self._tex_height = height
|
||||
@ -856,11 +854,11 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
was_initialized = self._initialized
|
||||
if not self._init_shared_memory(context):
|
||||
if not self._krom_launch_attempted:
|
||||
# print(f"Shared memory not found, launching Krom for viewport {self._viewport_id}")
|
||||
print(f"Shared memory not found, launching Krom for viewport {self._viewport_id}")
|
||||
self._launch_krom_process(context)
|
||||
self._draw_placeholder(context)
|
||||
return
|
||||
|
||||
|
||||
if not was_initialized and self._initialized:
|
||||
region = context.region
|
||||
if region and region.width > 0 and region.height > 0:
|
||||
@ -879,13 +877,13 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
# TODO: input forwarding when viewport is active
|
||||
global _active_krom_engine, _active_krom_engines, _active_viewport_id, _input_operator_running
|
||||
_active_krom_engine = self # legacy single-engine reference
|
||||
|
||||
|
||||
if self._viewport_id:
|
||||
_active_krom_engines[self._viewport_id] = self
|
||||
_active_viewport_id = self._viewport_id
|
||||
|
||||
self._set_input_enabled(True)
|
||||
|
||||
|
||||
if not _input_operator_running:
|
||||
bpy.app.timers.register(_start_input_capture, first_interval=0.1)
|
||||
else:
|
||||
@ -895,13 +893,13 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
if self._input_check_counter > 60:
|
||||
self._input_check_counter = 0
|
||||
bpy.app.timers.register(_start_input_capture, first_interval=0.5)
|
||||
|
||||
|
||||
region = context.region
|
||||
if region and region.width > 0 and region.height > 0:
|
||||
self._request_resize(region.width, region.height)
|
||||
|
||||
|
||||
self._read_krom_camera(context)
|
||||
|
||||
|
||||
pixels = self._read_framebuffer()
|
||||
|
||||
if pixels:
|
||||
@ -910,16 +908,16 @@ class KromViewportEngine(bpy.types.RenderEngine):
|
||||
if not self._texture:
|
||||
self._draw_placeholder(context)
|
||||
return
|
||||
|
||||
|
||||
self._create_shader()
|
||||
|
||||
|
||||
if HAS_GPU_STATE:
|
||||
gpu.state.blend_set('NONE')
|
||||
else:
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
|
||||
region = context.region
|
||||
|
||||
|
||||
vertices = (
|
||||
(0, 0),
|
||||
(region.width, 0),
|
||||
@ -1000,13 +998,13 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
pass
|
||||
_input_operator_running = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
if event.type in {'SCREEN_SET', 'SCREEN_CHANGED'}:
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
|
||||
if not context.space_data or not context.area:
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
if context.engine != 'KROM_VIEWPORT':
|
||||
try:
|
||||
@ -1016,18 +1014,18 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
pass
|
||||
_input_operator_running = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
current_engine = self._get_engine_for_area(context, event)
|
||||
if current_engine:
|
||||
self._engine = current_engine
|
||||
|
||||
|
||||
try:
|
||||
if not self._engine or not self._engine._initialized:
|
||||
return {'PASS_THROUGH'}
|
||||
except ReferenceError:
|
||||
_input_operator_running = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
region = context.region
|
||||
if not region:
|
||||
return {'PASS_THROUGH'}
|
||||
@ -1041,7 +1039,7 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
|
||||
if not mouse_in_region:
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
|
||||
area = context.area
|
||||
if area:
|
||||
mouse_x_abs = event.mouse_x
|
||||
@ -1059,14 +1057,14 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
mouse_x = event.mouse_region_x
|
||||
# flip Y for Krom
|
||||
mouse_y = region.height - event.mouse_region_y
|
||||
|
||||
|
||||
try:
|
||||
if event.type == 'MOUSEMOVE':
|
||||
self._engine._send_input_event(INPUT_EVENT_MOUSE_MOVE, x=mouse_x, y=mouse_y)
|
||||
self._last_mouse_x = mouse_x
|
||||
self._last_mouse_y = mouse_y
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
if event.type == 'LEFTMOUSE':
|
||||
if event.value == 'PRESS':
|
||||
self._engine._send_input_event(INPUT_EVENT_MOUSE_DOWN, button=MOUSE_BUTTON_LEFT, x=mouse_x, y=mouse_y)
|
||||
@ -1087,14 +1085,14 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
elif event.value == 'RELEASE':
|
||||
self._engine._send_input_event(INPUT_EVENT_MOUSE_UP, button=MOUSE_BUTTON_MIDDLE, x=mouse_x, y=mouse_y)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
if event.type == 'WHEELUPMOUSE':
|
||||
self._engine._send_input_event(INPUT_EVENT_MOUSE_WHEEL, delta=1)
|
||||
return {'RUNNING_MODAL'}
|
||||
if event.type == 'WHEELDOWNMOUSE':
|
||||
self._engine._send_input_event(INPUT_EVENT_MOUSE_WHEEL, delta=-1)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
if event.value in {'PRESS', 'RELEASE'}:
|
||||
key_code = self._blender_to_krom_key(event.type)
|
||||
if key_code is not None:
|
||||
@ -1106,7 +1104,7 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
except ReferenceError:
|
||||
_input_operator_running = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def _blender_to_krom_key(self, blender_key):
|
||||
@ -1136,15 +1134,15 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
if event:
|
||||
mouse_x = event.mouse_x
|
||||
mouse_y = event.mouse_y
|
||||
|
||||
|
||||
for window in bpy.context.window_manager.windows:
|
||||
for area in window.screen.areas:
|
||||
if area.type != 'VIEW_3D':
|
||||
continue
|
||||
|
||||
|
||||
if (area.x <= mouse_x < area.x + area.width and
|
||||
area.y <= mouse_y < area.y + area.height):
|
||||
|
||||
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
try:
|
||||
@ -1154,7 +1152,7 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
except:
|
||||
pass
|
||||
break
|
||||
|
||||
|
||||
if context.space_data:
|
||||
try:
|
||||
viewport_id = hex(context.space_data.as_pointer())[-6:]
|
||||
@ -1162,10 +1160,10 @@ class KROM_OT_viewport_input(bpy.types.Operator):
|
||||
return _active_krom_engines[viewport_id]
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
if _active_viewport_id and _active_viewport_id in _active_krom_engines:
|
||||
return _active_krom_engines[_active_viewport_id]
|
||||
|
||||
|
||||
return _active_krom_engine
|
||||
|
||||
def invoke(self, context, event):
|
||||
@ -1209,7 +1207,7 @@ def get_panels():
|
||||
'VIEWLAYER_PT_filter',
|
||||
'VIEWLAYER_PT_layer_passes',
|
||||
}
|
||||
|
||||
|
||||
compatible_engines = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
|
||||
|
||||
panels = []
|
||||
@ -1256,7 +1254,7 @@ class KROM_OT_stop_viewport(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
import lnx.make as make
|
||||
|
||||
|
||||
viewport_id = self.viewport_id
|
||||
if not viewport_id and context.space_data:
|
||||
viewport_id = hex(context.space_data.as_pointer())[-6:]
|
||||
@ -1279,12 +1277,12 @@ def draw_viewport_stop_button(self, context):
|
||||
space = context.space_data
|
||||
if not space or not hasattr(space, 'shading'):
|
||||
return
|
||||
|
||||
|
||||
if space.shading.type != 'RENDERED':
|
||||
return
|
||||
|
||||
|
||||
viewport_id = hex(space.as_pointer())[-6:]
|
||||
|
||||
|
||||
global _active_krom_engines
|
||||
if viewport_id not in _active_krom_engines:
|
||||
layout = self.layout
|
||||
@ -1301,12 +1299,12 @@ def register():
|
||||
bpy.utils.register_class(KromViewportEngine)
|
||||
bpy.utils.register_class(KROM_OT_viewport_input)
|
||||
bpy.utils.register_class(KROM_OT_stop_viewport)
|
||||
|
||||
|
||||
bpy.types.VIEW3D_HT_header.append(draw_viewport_stop_button)
|
||||
|
||||
|
||||
for panel in get_panels():
|
||||
panel.COMPAT_ENGINES.add('KROM_VIEWPORT')
|
||||
|
||||
|
||||
if _on_depsgraph_update not in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.append(_on_depsgraph_update)
|
||||
atexit.register(_cleanup_krom_on_exit)
|
||||
@ -1319,21 +1317,21 @@ def unregister():
|
||||
_active_krom_engines.clear()
|
||||
_active_viewport_id = None
|
||||
_input_operator_running = False
|
||||
|
||||
|
||||
if _on_depsgraph_update in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(_on_depsgraph_update)
|
||||
|
||||
|
||||
_cleanup_krom_on_exit()
|
||||
|
||||
|
||||
try:
|
||||
atexit.unregister(_cleanup_krom_on_exit)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
for panel in get_panels():
|
||||
if 'KROM_VIEWPORT' in panel.COMPAT_ENGINES:
|
||||
panel.COMPAT_ENGINES.remove('KROM_VIEWPORT')
|
||||
|
||||
|
||||
bpy.types.VIEW3D_HT_header.remove(draw_viewport_stop_button)
|
||||
|
||||
bpy.utils.unregister_class(KROM_OT_stop_viewport)
|
||||
|
||||
Reference in New Issue
Block a user