Cleanup bindings and viewport

This commit is contained in:
2026-06-16 01:15:06 -07:00
parent 6a81522c29
commit 3c2242cc08
6 changed files with 98 additions and 61 deletions

View File

@ -2361,7 +2361,17 @@ static void XMLHttpRequestGetResponseHeader(const FunctionCallbackInfo<Value>& a
}
}
void createXMLHttpRequestClass(Isolate* isolate, Local<ObjectTemplate>& global) {
void bind_httprequest_class(Isolate* isolate, const Global<Context>& context) {
HttpRequestWrapper::initialize();
Locker locker{isolate};
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> current_context = Local<Context>::New(isolate, context);
Context::Scope context_scope(current_context);
Local<Object> global = current_context->Global();
Local<FunctionTemplate> xhrTpl = FunctionTemplate::New(isolate, XMLHttpRequestConstructor);
xhrTpl->SetClassName(String::NewFromUtf8(isolate, "XMLHttpRequest").ToLocalChecked());
xhrTpl->InstanceTemplate()->SetInternalFieldCount(1);
@ -2374,14 +2384,14 @@ void createXMLHttpRequestClass(Isolate* isolate, Local<ObjectTemplate>& global)
proto->Set(isolate, "getAllResponseHeaders", FunctionTemplate::New(isolate, XMLHttpRequestGetAllResponseHeaders));
proto->Set(isolate, "getResponseHeader", FunctionTemplate::New(isolate, XMLHttpRequestGetResponseHeader));
Local<Function> xhrFunc = xhrTpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked();
xhrFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "UNSENT").ToLocalChecked(), Integer::New(isolate, 0));
xhrFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "OPENED").ToLocalChecked(), Integer::New(isolate, 1));
xhrFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "HEADERS_RECEIVED").ToLocalChecked(), Integer::New(isolate, 2));
xhrFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "LOADING").ToLocalChecked(), Integer::New(isolate, 3));
xhrFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "DONE").ToLocalChecked(), Integer::New(isolate, 4));
Local<Function> xhrFunc = xhrTpl->GetFunction(current_context).ToLocalChecked();
xhrFunc->Set(current_context, String::NewFromUtf8(isolate, "UNSENT").ToLocalChecked(), Integer::New(isolate, 0));
xhrFunc->Set(current_context, String::NewFromUtf8(isolate, "OPENED").ToLocalChecked(), Integer::New(isolate, 1));
xhrFunc->Set(current_context, String::NewFromUtf8(isolate, "HEADERS_RECEIVED").ToLocalChecked(), Integer::New(isolate, 2));
xhrFunc->Set(current_context, String::NewFromUtf8(isolate, "LOADING").ToLocalChecked(), Integer::New(isolate, 3));
xhrFunc->Set(current_context, String::NewFromUtf8(isolate, "DONE").ToLocalChecked(), Integer::New(isolate, 4));
global->Set(isolate, "XMLHttpRequest", xhrTpl);
global->Set(current_context, String::NewFromUtf8(isolate, "XMLHttpRequest").ToLocalChecked(), xhrFunc);
}
#endif

View File

@ -230,6 +230,6 @@ void runt_httprequest_set_onprogress(const v8::FunctionCallbackInfo<v8::Value>&
void runt_httprequest_set_onloadstart(const v8::FunctionCallbackInfo<v8::Value>& args);
void runt_httprequest_set_onloadend(const v8::FunctionCallbackInfo<v8::Value>& args);
void createXMLHttpRequestClass(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& global);
void bind_httprequest_class(v8::Isolate* isolate, const v8::Global<v8::Context>& context);
#endif

View File

@ -3054,13 +3054,6 @@ namespace {
}
}
#ifdef WITH_NETWORKING
WebSocketWrapper::initialize();
//kinc_log(KINC_LOG_LEVEL_INFO, "WebSocket client support initialized successfully");
HttpRequestWrapper::initialize();
//kinc_log(KINC_LOG_LEVEL_INFO, "Initializing native HTTP request support");
#endif
}
void start_runt(char *scriptfile) {
@ -4037,11 +4030,9 @@ int kickstart(int argc, char **argv) {
#ifdef WITH_WORKER
bind_worker_class(isolate, global_context);
#endif
#ifdef WITH_NETWORKING
//#ifndef WITH_UWS
//bind_socket_bridge(isolate, global_context);
//#endif
bind_websocket_class(isolate, global_context);
bind_httprequest_class(isolate, global_context);
WEBSOCKET_BIND_V8(isolate, global_context);
#endif

View File

@ -1,6 +1,6 @@
/**
* Viewport Server Implementation - Shared Memory Framebuffer Export
*
*
*/
#include "viewport_server.h"
@ -12,7 +12,11 @@
#include <stdlib.h>
#include <math.h>
#ifdef KINC_WINDOWS
#ifdef KINC_OPENGL
#include <GL/glew.h>
#endif
#ifdef KINC_DIRECT3D11
#include <d3d11.h>
#include <dxgi.h>
@ -254,6 +258,8 @@ bool viewport_server_init(const char* shmem_name, int width, int height) {
uint8_t* pixel_dest = (uint8_t*)g_viewport_state.shmem_ptr + VIEWPORT_HEADER_SIZE;
memset(pixel_dest, 0, max_pixel_size);
#if !defined(KINC_DIRECT3D11) && !defined(KINC_OPENGL)
// Only create render target for platforms that need it (not Direct3D11 or OpenGL)
kinc_g4_render_target_t* rt = (kinc_g4_render_target_t*)malloc(sizeof(kinc_g4_render_target_t));
if (!rt) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to allocate render target");
@ -264,6 +270,7 @@ bool viewport_server_init(const char* shmem_name, int width, int height) {
kinc_g4_render_target_init(rt, width, height, KINC_G4_RENDER_TARGET_FORMAT_32BIT, 24, 0);
g_viewport_state.render_target = rt;
#endif
g_viewport_state.enabled = true;
g_viewport_state.initialized = true;
@ -275,7 +282,7 @@ bool viewport_server_init(const char* shmem_name, int width, int height) {
return true;
}
#ifdef KINC_WINDOWS
#ifdef KINC_DIRECT3D11
static ID3D11Texture2D* g_stagingTexture = NULL;
static int g_stagingWidth = 0, g_stagingHeight = 0;
#endif
@ -285,7 +292,7 @@ void viewport_server_shutdown(void) {
return;
}
#ifdef KINC_WINDOWS
#ifdef KINC_DIRECT3D11
if (g_stagingTexture) {
g_stagingTexture->Release();
g_stagingTexture = NULL;
@ -294,11 +301,13 @@ void viewport_server_shutdown(void) {
}
#endif
#if !defined(KINC_DIRECT3D11) && !defined(KINC_OPENGL)
if (g_viewport_state.render_target) {
kinc_g4_render_target_destroy((kinc_g4_render_target_t*)g_viewport_state.render_target);
free(g_viewport_state.render_target);
g_viewport_state.render_target = NULL;
}
#endif
if (g_viewport_state.pixel_buffer) {
free(g_viewport_state.pixel_buffer);
@ -346,7 +355,7 @@ void viewport_server_end_frame(void) {
uint8_t* pixels = g_viewport_state.pixel_buffer;
uint8_t* pixel_dest = (uint8_t*)g_viewport_state.shmem_ptr + VIEWPORT_HEADER_SIZE;
#ifdef KINC_WINDOWS
#ifdef KINC_DIRECT3D11
// Direct3D11 - read from backbuffer BEFORE swap_buffers
ID3D11DeviceContext* context = dx_ctx.context;
ID3D11Device* device = dx_ctx.device;
@ -417,20 +426,33 @@ void viewport_server_end_frame(void) {
memcpy(pixel_dest, pixels, pixel_size);
}
}
#elif defined(KINC_OPENGL)
// OpenGL - read from default framebuffer using glReadPixels
glReadPixels(0, 0, g_viewport_state.width, g_viewport_state.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// OpenGL returns pixels bottom-to-top, need to flip
size_t row_size = g_viewport_state.width * 4;
for (int y = 0; y < g_viewport_state.height / 2; ++y) {
uint8_t* row_top = pixels + y * row_size;
uint8_t* row_bottom = pixels + (g_viewport_state.height - 1 - y) * row_size;
for (size_t x = 0; x < row_size; ++x) {
uint8_t temp = row_top[x];
row_top[x] = row_bottom[x];
row_bottom[x] = temp;
}
}
memcpy(pixel_dest, pixels, pixel_size);
#else
// other platforms use render target
if (g_viewport_state.render_target) {
kinc_g4_render_target_t* rt = (kinc_g4_render_target_t*)g_viewport_state.render_target;
kinc_g4_render_target_get_pixels(rt, pixels);
memcpy(pixel_dest, pixels, pixel_size);
}
kinc_g4_render_target_t* rt = (kinc_g4_render_target_t*)g_viewport_state.render_target;
kinc_g4_render_target_get_pixels(rt, pixels);
memcpy(pixel_dest, pixels, pixel_size);
#endif
g_viewport_state.frame_count++;
header->frame_id = g_viewport_state.frame_count;
// NOTE: Camera sync from RunT to Blender is handled via viewport_server_set_camera()
// which is called explicitly when RunT's internal camera changes.
// NOTE: Camera sync from Krom to Blender is handled via viewport_server_set_camera()
// which is called explicitly when Krom's internal camera changes.
// We do NOT extract camera from view_matrix here as that would create a feedback loop
// (Blender sends view_matrix -> we extract camera -> Blender applies it -> repeat)
@ -478,19 +500,23 @@ bool viewport_server_resize(int new_width, int new_height) {
// resize the actual Kinc window so the D3D11 backbuffer is the correct size critical because viewport_server_end_frame captures from the backbuffer
kinc_window_resize(0, new_width, new_height);
#if !defined(KINC_DIRECT3D11) && !defined(KINC_OPENGL)
if (g_viewport_state.render_target) {
kinc_g4_render_target_destroy((kinc_g4_render_target_t*)g_viewport_state.render_target);
// dont free here we reuse the allocation
}
#endif
// update dimensions pre-allocated and reinitialize render target with new size using same memory
g_viewport_state.width = new_width;
g_viewport_state.height = new_height;
#if !defined(KINC_DIRECT3D11) && !defined(KINC_OPENGL)
kinc_g4_render_target_t* rt = (kinc_g4_render_target_t*)g_viewport_state.render_target;
if (rt) {
kinc_g4_render_target_init(rt, new_width, new_height, KINC_G4_RENDER_TARGET_FORMAT_32BIT, 24, 0);
}
#endif
SharedFramebufferHeader* header = (SharedFramebufferHeader*)g_viewport_state.shmem_ptr;
if (header) {
@ -537,16 +563,16 @@ void viewport_server_set_camera(float pos_x, float pos_y, float pos_z,
SharedFramebufferHeader* header = (SharedFramebufferHeader*)g_viewport_state.shmem_ptr;
if (!header) return;
header->runt_camera_pos[0] = pos_x;
header->runt_camera_pos[1] = pos_y;
header->runt_camera_pos[2] = pos_z;
header->krom_camera_pos[0] = pos_x;
header->krom_camera_pos[1] = pos_y;
header->krom_camera_pos[2] = pos_z;
header->runt_camera_rot[0] = rot_x;
header->runt_camera_rot[1] = rot_y;
header->runt_camera_rot[2] = rot_z;
header->runt_camera_rot[3] = rot_w;
header->krom_camera_rot[0] = rot_x;
header->krom_camera_rot[1] = rot_y;
header->krom_camera_rot[2] = rot_z;
header->krom_camera_rot[3] = rot_w;
header->runt_camera_dirty = 1;
header->krom_camera_dirty = 1;
}
bool viewport_server_read_input(InputEvent* event) {
@ -572,9 +598,9 @@ bool viewport_server_read_input(InputEvent* event) {
bool viewport_server_input_enabled(void) {
if (!viewport_server_is_enabled()) return false;
SharedFramebufferHeader* header = (SharedFramebufferHeader*)g_viewport_state.shmem_ptr;
if (!header) return false;
return header->input_enabled != 0;
}

View File

@ -2766,24 +2766,6 @@ static void WebSocketClose(const FunctionCallbackInfo<Value>& args) {
}
}
void createWebSocketClass(Isolate* isolate, Local<ObjectTemplate>& global) {
Local<FunctionTemplate> wsTpl = FunctionTemplate::New(isolate, WebSocketConstructor);
wsTpl->SetClassName(String::NewFromUtf8(isolate, "WebSocket").ToLocalChecked());
wsTpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<ObjectTemplate> proto = wsTpl->PrototypeTemplate();
proto->Set(isolate, "send", FunctionTemplate::New(isolate, WebSocketSend));
proto->Set(isolate, "close", FunctionTemplate::New(isolate, WebSocketClose));
Local<Function> wsFunc = wsTpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked();
wsFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "CONNECTING").ToLocalChecked(), Integer::New(isolate, 0));
wsFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "OPEN").ToLocalChecked(), Integer::New(isolate, 1));
wsFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "CLOSING").ToLocalChecked(), Integer::New(isolate, 2));
wsFunc->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "CLOSED").ToLocalChecked(), Integer::New(isolate, 3));
global->Set(isolate, "WebSocket", wsTpl);
}
static void EventConstructor(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
@ -2887,4 +2869,32 @@ void createWebSocketEventClasses(Isolate* isolate, Local<ObjectTemplate>& global
global->Set(isolate, "CloseEvent", closeEventTpl);
}
void bind_websocket_class(Isolate* isolate, const Global<Context>& context) {
WebSocketWrapper::initialize();
Locker locker{isolate};
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> current_context = Local<Context>::New(isolate, context);
Context::Scope context_scope(current_context);
Local<Object> global = current_context->Global();
Local<FunctionTemplate> wsTpl = FunctionTemplate::New(isolate, WebSocketConstructor);
wsTpl->SetClassName(String::NewFromUtf8(isolate, "WebSocket").ToLocalChecked());
wsTpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<ObjectTemplate> proto = wsTpl->PrototypeTemplate();
proto->Set(isolate, "send", FunctionTemplate::New(isolate, WebSocketSend));
proto->Set(isolate, "close", FunctionTemplate::New(isolate, WebSocketClose));
Local<Function> wsFunc = wsTpl->GetFunction(current_context).ToLocalChecked();
wsFunc->Set(current_context, String::NewFromUtf8(isolate, "CONNECTING").ToLocalChecked(), Integer::New(isolate, 0));
wsFunc->Set(current_context, String::NewFromUtf8(isolate, "OPEN").ToLocalChecked(), Integer::New(isolate, 1));
wsFunc->Set(current_context, String::NewFromUtf8(isolate, "CLOSING").ToLocalChecked(), Integer::New(isolate, 2));
wsFunc->Set(current_context, String::NewFromUtf8(isolate, "CLOSED").ToLocalChecked(), Integer::New(isolate, 3));
global->Set(current_context, String::NewFromUtf8(isolate, "WebSocket").ToLocalChecked(), wsFunc);
}
#endif

View File

@ -201,6 +201,6 @@ void runt_websocket_set_onmessage(const v8::FunctionCallbackInfo<v8::Value>& arg
void runt_websocket_set_onerror(const v8::FunctionCallbackInfo<v8::Value>& args);
void runt_websocket_set_onclose(const v8::FunctionCallbackInfo<v8::Value>& args);
void createWebSocketClass(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& global);
void bind_websocket_class(v8::Isolate* isolate, const v8::Global<v8::Context>& context);
void createWebSocketEventClasses(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& global);
#endif