Fix thinWall and copy_pass in Forward rendering #141
@ -34,9 +34,9 @@ class RenderPath {
|
|||||||
public static var vrCalibrationPosition:Vec4 = null;
|
public static var vrCalibrationPosition:Vec4 = null;
|
||||||
public static var vrCalibrationRotation:iron.math.Quat = null;
|
public static var vrCalibrationRotation:iron.math.Quat = null;
|
||||||
public static var vrCalibrationSaved:Bool = false;
|
public static var vrCalibrationSaved:Bool = false;
|
||||||
|
|
||||||
public static var vrCenterCameraWorld:Mat4 = null;
|
public static var vrCenterCameraWorld:Mat4 = null;
|
||||||
|
|
||||||
static var vrOriginalSuperSample:Float = -1.0;
|
static var vrOriginalSuperSample:Float = -1.0;
|
||||||
public static inline function isVRPresenting(): Bool {
|
public static inline function isVRPresenting(): Bool {
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
@ -45,7 +45,7 @@ class RenderPath {
|
|||||||
return false;
|
return false;
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public static inline function isVRSimulateMode(): Bool {
|
public static inline function isVRSimulateMode(): Bool {
|
||||||
return vrSimulateMode;
|
return vrSimulateMode;
|
||||||
}
|
}
|
||||||
@ -162,24 +162,24 @@ class RenderPath {
|
|||||||
|
|
||||||
var appW = iron.App.w();
|
var appW = iron.App.w();
|
||||||
var appH = iron.App.h();
|
var appH = iron.App.h();
|
||||||
|
|
||||||
// use native XR framebuffer dimensions
|
// use native XR framebuffer dimensions
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
if (kha.vr.VrInterface.instance != null) {
|
if (kha.vr.VrInterface.instance != null) {
|
||||||
var vr = kha.vr.VrInterface.instance;
|
var vr = kha.vr.VrInterface.instance;
|
||||||
var isPresenting = vr != null && vr.IsPresenting();
|
var isPresenting = vr != null && vr.IsPresenting();
|
||||||
|
|
||||||
// save/restore camera position between modes
|
// save/restore camera position between modes
|
||||||
if (!wasVRPresenting && isPresenting) {
|
if (!wasVRPresenting && isPresenting) {
|
||||||
if (Scene.active != null && Scene.active.camera != null) {
|
if (Scene.active != null && Scene.active.camera != null) {
|
||||||
if (vrCalibrationPosition == null) vrCalibrationPosition = new Vec4();
|
if (vrCalibrationPosition == null) vrCalibrationPosition = new Vec4();
|
||||||
if (vrCalibrationRotation == null) vrCalibrationRotation = new Quat();
|
if (vrCalibrationRotation == null) vrCalibrationRotation = new Quat();
|
||||||
|
|
||||||
vrCalibrationPosition.setFrom(Scene.active.camera.transform.loc);
|
vrCalibrationPosition.setFrom(Scene.active.camera.transform.loc);
|
||||||
vrCalibrationRotation.setFrom(Scene.active.camera.transform.rot);
|
vrCalibrationRotation.setFrom(Scene.active.camera.transform.rot);
|
||||||
vrCalibrationSaved = true;
|
vrCalibrationSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save original super sampling for later
|
// save original super sampling for later
|
||||||
vrOriginalSuperSample = leenkx.renderpath.Inc.superSample;
|
vrOriginalSuperSample = leenkx.renderpath.Inc.superSample;
|
||||||
|
|
||||||
@ -196,18 +196,18 @@ class RenderPath {
|
|||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
iron.system.Time.vrFrameTime = -1.0;
|
iron.system.Time.vrFrameTime = -1.0;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
if (vrCalibrationSaved && Scene.active != null && Scene.active.camera != null) {
|
if (vrCalibrationSaved && Scene.active != null && Scene.active.camera != null) {
|
||||||
Scene.active.camera.transform.loc.setFrom(vrCalibrationPosition);
|
Scene.active.camera.transform.loc.setFrom(vrCalibrationPosition);
|
||||||
Scene.active.camera.transform.rot.setFrom(vrCalibrationRotation);
|
Scene.active.camera.transform.rot.setFrom(vrCalibrationRotation);
|
||||||
Scene.active.camera.buildMatrix();
|
Scene.active.camera.buildMatrix();
|
||||||
Scene.active.camera.buildProjection();
|
Scene.active.camera.buildProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore original super sampling from simulate mode
|
// restore original super sampling from simulate mode
|
||||||
if (vrOriginalSuperSample >= 0.0) {
|
if (vrOriginalSuperSample >= 0.0) {
|
||||||
leenkx.renderpath.Inc.superSample = vrOriginalSuperSample;
|
leenkx.renderpath.Inc.superSample = vrOriginalSuperSample;
|
||||||
|
|
||||||
for (rt in renderTargets) {
|
for (rt in renderTargets) {
|
||||||
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
||||||
rt.raw.scale = vrOriginalSuperSample;
|
rt.raw.scale = vrOriginalSuperSample;
|
||||||
@ -216,13 +216,13 @@ class RenderPath {
|
|||||||
resize();
|
resize();
|
||||||
vrOriginalSuperSample = -1.0;
|
vrOriginalSuperSample = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset offset for next session
|
// reset offset for next session
|
||||||
vrCameraOffsetSet = false;
|
vrCameraOffsetSet = false;
|
||||||
vrCameraOffset = null;
|
vrCameraOffset = null;
|
||||||
}
|
}
|
||||||
wasVRPresenting = isPresenting;
|
wasVRPresenting = isPresenting;
|
||||||
|
|
||||||
if (isPresenting) {
|
if (isPresenting) {
|
||||||
// TODO: re-investigate using super sampling to avoid pixelation in simulate mode while giving max quality in headset
|
// TODO: re-investigate using super sampling to avoid pixelation in simulate mode while giving max quality in headset
|
||||||
if (vrOriginalSuperSample >= 0.0 && leenkx.renderpath.Inc.superSample != 4.0) {
|
if (vrOriginalSuperSample >= 0.0 && leenkx.renderpath.Inc.superSample != 4.0) {
|
||||||
@ -234,7 +234,7 @@ class RenderPath {
|
|||||||
}
|
}
|
||||||
resize();
|
resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||||
if (xrVr.xrGLLayer != null) {
|
if (xrVr.xrGLLayer != null) {
|
||||||
appW = xrVr.xrGLLayer.framebufferWidth;
|
appW = xrVr.xrGLLayer.framebufferWidth;
|
||||||
@ -384,7 +384,7 @@ class RenderPath {
|
|||||||
if (currentG != null) end();
|
if (currentG != null) end();
|
||||||
currentG = g;
|
currentG = g;
|
||||||
additionalTargets = additionalRenderTargets;
|
additionalTargets = additionalRenderTargets;
|
||||||
|
|
||||||
// we still bind but skip begin() when explicitly rendering to XR framebuffer (renderToXRFramebuffer flag)
|
// we still bind but skip begin() when explicitly rendering to XR framebuffer (renderToXRFramebuffer flag)
|
||||||
#if lnx_vr
|
#if lnx_vr
|
||||||
if (!renderToXRFramebuffer) {
|
if (!renderToXRFramebuffer) {
|
||||||
@ -405,7 +405,7 @@ class RenderPath {
|
|||||||
currentG.disableScissor();
|
currentG.disableScissor();
|
||||||
scissorSet = false;
|
scissorSet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if lnx_vr
|
#if lnx_vr
|
||||||
if (beginCalled) {
|
if (beginCalled) {
|
||||||
currentG.end();
|
currentG.end();
|
||||||
@ -692,7 +692,7 @@ class RenderPath {
|
|||||||
if (vr == null || vr._glContext == null || vr.xrGLLayer == null) {
|
if (vr == null || vr._glContext == null || vr.xrGLLayer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gl: js.html.webgl.WebGL2RenderingContext = cast vr._glContext;
|
var gl: js.html.webgl.WebGL2RenderingContext = cast vr._glContext;
|
||||||
var source = renderTargets.get(sourceTarget);
|
var source = renderTargets.get(sourceTarget);
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@ -703,21 +703,21 @@ class RenderPath {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// trace('Framebuffer OK');
|
// trace('Framebuffer OK');
|
||||||
|
|
||||||
renderToXRFramebuffer = true;
|
renderToXRFramebuffer = true;
|
||||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER, vr.xrGLLayer.framebuffer);
|
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER, vr.xrGLLayer.framebuffer);
|
||||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER, sourceFB);
|
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER, sourceFB);
|
||||||
|
|
||||||
var readStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER);
|
var readStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER);
|
||||||
var drawStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER);
|
var drawStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER);
|
||||||
if (readStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE ||
|
if (readStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE ||
|
||||||
drawStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE) {
|
drawStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var halfWidth = Std.int(source.image.width / 2);
|
var halfWidth = Std.int(source.image.width / 2);
|
||||||
var fullHeight = source.image.height;
|
var fullHeight = source.image.height;
|
||||||
|
|
||||||
if (vr._leftViewport != null) {
|
if (vr._leftViewport != null) {
|
||||||
var vp = vr._leftViewport;
|
var vp = vr._leftViewport;
|
||||||
gl.blitFramebuffer(
|
gl.blitFramebuffer(
|
||||||
@ -736,7 +736,7 @@ class RenderPath {
|
|||||||
js.html.webgl.WebGL2RenderingContext.LINEAR
|
js.html.webgl.WebGL2RenderingContext.LINEAR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER, null);
|
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER, null);
|
||||||
renderToXRFramebuffer = false;
|
renderToXRFramebuffer = false;
|
||||||
#end
|
#end
|
||||||
@ -749,24 +749,24 @@ class RenderPath {
|
|||||||
if (currentG == null && frameG != null) {
|
if (currentG == null && frameG != null) {
|
||||||
currentG = frameG;
|
currentG = frameG;
|
||||||
}
|
}
|
||||||
|
|
||||||
var appw = iron.App.w();
|
var appw = iron.App.w();
|
||||||
var apph = iron.App.h();
|
var apph = iron.App.h();
|
||||||
var g = currentG;
|
var g = currentG;
|
||||||
|
|
||||||
// get render target dimensions not App.w/h gbuffer is scaled in simulate mode with supersampling
|
// get render target dimensions not App.w/h gbuffer is scaled in simulate mode with supersampling
|
||||||
|
|
||||||
var gbuffer0 = renderTargets.get("gbuffer0");
|
var gbuffer0 = renderTargets.get("gbuffer0");
|
||||||
var actualWidth = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.width : appw;
|
var actualWidth = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.width : appw;
|
||||||
var actualHeight = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.height : apph;
|
var actualHeight = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.height : apph;
|
||||||
var actualHalfWidth = Std.int(actualWidth / 2);
|
var actualHalfWidth = Std.int(actualWidth / 2);
|
||||||
|
|
||||||
var vrFBWidth = actualWidth;
|
var vrFBWidth = actualWidth;
|
||||||
var vrFBHeight = actualHeight;
|
var vrFBHeight = actualHeight;
|
||||||
var vrHalfWidth = actualHalfWidth;
|
var vrHalfWidth = actualHalfWidth;
|
||||||
var isVRPresenting = false;
|
var isVRPresenting = false;
|
||||||
vrSimulateMode = false;
|
vrSimulateMode = false;
|
||||||
|
|
||||||
var vr:Dynamic = null;
|
var vr:Dynamic = null;
|
||||||
var vrExists = false;
|
var vrExists = false;
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
@ -779,7 +779,7 @@ class RenderPath {
|
|||||||
if (vrExists && vr != null && vr.IsPresenting()) {
|
if (vrExists && vr != null && vr.IsPresenting()) {
|
||||||
vrSimulateMode = false;
|
vrSimulateMode = false;
|
||||||
isVRPresenting = true;
|
isVRPresenting = true;
|
||||||
|
|
||||||
// get framebuffer dimensions from XR layer
|
// get framebuffer dimensions from XR layer
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||||
@ -789,16 +789,16 @@ class RenderPath {
|
|||||||
vrHalfWidth = Std.int(vrFBWidth / 2);
|
vrHalfWidth = Std.int(vrFBWidth / 2);
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
if (Scene.active == null || Scene.active.camera == null) {
|
if (Scene.active == null || Scene.active.camera == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
// LEFT EYE
|
// LEFT EYE
|
||||||
// HMD center for room scale position tracking
|
// HMD center for room scale position tracking
|
||||||
#if (kha_webgl && lnx_vr)
|
#if (kha_webgl && lnx_vr)
|
||||||
@ -808,10 +808,10 @@ class RenderPath {
|
|||||||
if (viewerTransform != null && viewerTransform.position != null) {
|
if (viewerTransform != null && viewerTransform.position != null) {
|
||||||
// VR present calibration is used to position objects in world space not the camera
|
// VR present calibration is used to position objects in world space not the camera
|
||||||
var pos = viewerTransform.position;
|
var pos = viewerTransform.position;
|
||||||
|
|
||||||
// camera follows headset directly in local floor space
|
// camera follows headset directly in local floor space
|
||||||
Scene.active.camera.transform.loc.set(pos.x, pos.y, pos.z);
|
Scene.active.camera.transform.loc.set(pos.x, pos.y, pos.z);
|
||||||
|
|
||||||
if (viewerTransform.orientation != null) {
|
if (viewerTransform.orientation != null) {
|
||||||
Scene.active.camera.transform.rot.set(
|
Scene.active.camera.transform.rot.set(
|
||||||
viewerTransform.orientation.x,
|
viewerTransform.orientation.x,
|
||||||
@ -825,7 +825,7 @@ class RenderPath {
|
|||||||
}
|
}
|
||||||
iron.system.VRController.updatePoses();
|
iron.system.VRController.updatePoses();
|
||||||
#end
|
#end
|
||||||
|
|
||||||
Scene.active.camera.V.self = vr.GetViewMatrix(0);
|
Scene.active.camera.V.self = vr.GetViewMatrix(0);
|
||||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
||||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||||
@ -835,7 +835,7 @@ class RenderPath {
|
|||||||
var renderWidth = actualWidth;
|
var renderWidth = actualWidth;
|
||||||
var renderHeight = actualHeight;
|
var renderHeight = actualHeight;
|
||||||
var renderHalfWidth = actualHalfWidth;
|
var renderHalfWidth = actualHalfWidth;
|
||||||
|
|
||||||
// left half of render target
|
// left half of render target
|
||||||
g.viewport(0, 0, renderHalfWidth, renderHeight);
|
g.viewport(0, 0, renderHalfWidth, renderHeight);
|
||||||
g.scissor(0, 0, renderHalfWidth, renderHeight);
|
g.scissor(0, 0, renderHalfWidth, renderHeight);
|
||||||
@ -847,12 +847,12 @@ class RenderPath {
|
|||||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||||
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
||||||
Scene.active.camera.buildMatrix();
|
Scene.active.camera.buildMatrix();
|
||||||
|
|
||||||
// right half of render target
|
// right half of render target
|
||||||
g.viewport(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
g.viewport(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||||
g.scissor(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
g.scissor(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||||
drawMeshes();
|
drawMeshes();
|
||||||
|
|
||||||
// restore for post-processing
|
// restore for post-processing
|
||||||
g.disableScissor();
|
g.disableScissor();
|
||||||
g.viewport(0, 0, renderWidth, renderHeight);
|
g.viewport(0, 0, renderWidth, renderHeight);
|
||||||
@ -865,7 +865,7 @@ class RenderPath {
|
|||||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
Scene.active.camera.buildProjection(actualHalfWidth / actualHeight);
|
Scene.active.camera.buildProjection(actualHalfWidth / actualHeight);
|
||||||
|
|
||||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
||||||
@ -908,7 +908,9 @@ class RenderPath {
|
|||||||
#end
|
#end
|
||||||
|
|
||||||
Data.getShader(shaderPath[0], shaderPath[1], function(res: ShaderData) {
|
Data.getShader(shaderPath[0], shaderPath[1], function(res: ShaderData) {
|
||||||
cc.context = res.getContext(shaderPath[2]);
|
if (res != null) {
|
||||||
|
cc.context = res.getContext(shaderPath[2]);
|
||||||
|
}
|
||||||
loading--;
|
loading--;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,7 @@ class ShaderData {
|
|||||||
if (raw == null) {
|
if (raw == null) {
|
||||||
trace('Shader data "$name" not found!');
|
trace('Shader data "$name" not found!');
|
||||||
done(null);
|
done(null);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
new ShaderData(raw, done, overrideContext);
|
new ShaderData(raw, done, overrideContext);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -301,18 +301,18 @@ def export_data_impl(fp, sdk_path):
|
|||||||
for scene_name, asset_path in scene_targets:
|
for scene_name, asset_path in scene_targets:
|
||||||
# Reset shader comparison arrays to prevent cross-scene shader merging
|
# Reset shader comparison arrays to prevent cross-scene shader merging
|
||||||
assets.reset_shader_cons()
|
assets.reset_shader_cons()
|
||||||
|
|
||||||
scene = bpy.data.scenes[scene_name]
|
scene = bpy.data.scenes[scene_name]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if bpy.context.window.scene != scene:
|
if bpy.context.window.scene != scene:
|
||||||
bpy.context.window.scene = scene
|
bpy.context.window.scene = scene
|
||||||
bpy.context.view_layer.update()
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
scene_depsgraph = bpy.context.evaluated_depsgraph_get()
|
scene_depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
|
|
||||||
LeenkxExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=scene_depsgraph, build_cache=build_cache)
|
LeenkxExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=scene_depsgraph, build_cache=build_cache)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if bpy.context.window.scene != initial_window_scene:
|
if bpy.context.window.scene != initial_window_scene:
|
||||||
bpy.context.window.scene = initial_window_scene
|
bpy.context.window.scene = initial_window_scene
|
||||||
@ -384,7 +384,8 @@ def export_data_impl(fp, sdk_path):
|
|||||||
os.utime(g, None)
|
os.utime(g, None)
|
||||||
|
|
||||||
# Write referenced shader passes
|
# Write referenced shader passes
|
||||||
if not os.path.isfile(build_dir + '/compiled/Shaders/shader_datas.lnx') or state.last_world_defs != wrd.world_defs:
|
current_passes = tuple(sorted(assets.shader_passes))
|
||||||
|
if not os.path.isfile(build_dir + '/compiled/Shaders/shader_datas.lnx') or state.last_world_defs != wrd.world_defs or getattr(state, 'last_shader_passes', None) != current_passes:
|
||||||
res = {'shader_datas': []}
|
res = {'shader_datas': []}
|
||||||
|
|
||||||
for ref in assets.shader_passes:
|
for ref in assets.shader_passes:
|
||||||
@ -431,6 +432,7 @@ def export_data_impl(fp, sdk_path):
|
|||||||
if not os.path.exists(target):
|
if not os.path.exists(target):
|
||||||
shutil.copy(file, target)
|
shutil.copy(file, target)
|
||||||
state.last_world_defs = wrd.world_defs
|
state.last_world_defs = wrd.world_defs
|
||||||
|
state.last_shader_passes = current_passes
|
||||||
|
|
||||||
# Reset path
|
# Reset path
|
||||||
os.chdir(fp)
|
os.chdir(fp)
|
||||||
@ -682,7 +684,7 @@ def _get_viewport_shmem_name(viewport_id):
|
|||||||
def _kill_viewport_process(viewport_id):
|
def _kill_viewport_process(viewport_id):
|
||||||
"""Kill a specific viewport's Krom process."""
|
"""Kill a specific viewport's Krom process."""
|
||||||
global _viewport_processes
|
global _viewport_processes
|
||||||
|
|
||||||
if viewport_id in _viewport_processes:
|
if viewport_id in _viewport_processes:
|
||||||
proc = _viewport_processes[viewport_id]
|
proc = _viewport_processes[viewport_id]
|
||||||
try:
|
try:
|
||||||
@ -698,7 +700,7 @@ def _kill_viewport_process(viewport_id):
|
|||||||
def _kill_all_viewport_processes():
|
def _kill_all_viewport_processes():
|
||||||
"""Kill all viewport Krom processes."""
|
"""Kill all viewport Krom processes."""
|
||||||
global _viewport_processes
|
global _viewport_processes
|
||||||
|
|
||||||
for viewport_id in list(_viewport_processes.keys()):
|
for viewport_id in list(_viewport_processes.keys()):
|
||||||
_kill_viewport_process(viewport_id)
|
_kill_viewport_process(viewport_id)
|
||||||
|
|
||||||
@ -709,7 +711,7 @@ def _kill_all_viewport_processes():
|
|||||||
capture_output=True, text=True, timeout=5
|
capture_output=True, text=True, timeout=5
|
||||||
)
|
)
|
||||||
if 'Krom.exe' in result.stdout:
|
if 'Krom.exe' in result.stdout:
|
||||||
subprocess.run(['taskkill', '/F', '/IM', 'Krom.exe'],
|
subprocess.run(['taskkill', '/F', '/IM', 'Krom.exe'],
|
||||||
capture_output=True, timeout=5)
|
capture_output=True, timeout=5)
|
||||||
import time
|
import time
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
@ -727,7 +729,7 @@ def run_viewport_runtime(viewport_id, width=1920, height=1080):
|
|||||||
_kill_viewport_process(viewport_id)
|
_kill_viewport_process(viewport_id)
|
||||||
|
|
||||||
shmem_name = _get_viewport_shmem_name(viewport_id)
|
shmem_name = _get_viewport_shmem_name(viewport_id)
|
||||||
|
|
||||||
wrd = bpy.data.worlds['Lnx']
|
wrd = bpy.data.worlds['Lnx']
|
||||||
krom_location, krom_path = lnx.utils.krom_paths()
|
krom_location, krom_path = lnx.utils.krom_paths()
|
||||||
path = lnx.utils.get_fp_build() + '/debug/krom'
|
path = lnx.utils.get_fp_build() + '/debug/krom'
|
||||||
@ -742,7 +744,7 @@ def run_viewport_runtime(viewport_id, width=1920, height=1080):
|
|||||||
open(path + '/krom.patch', 'w', encoding='utf-8').close()
|
open(path + '/krom.patch', 'w', encoding='utf-8').close()
|
||||||
|
|
||||||
os.chdir(krom_location)
|
os.chdir(krom_location)
|
||||||
|
|
||||||
cmd = [krom_path, path, path_resources]
|
cmd = [krom_path, path, path_resources]
|
||||||
if lnx.utils.get_os() == 'win':
|
if lnx.utils.get_os() == 'win':
|
||||||
cmd.append('--consolepid')
|
cmd.append('--consolepid')
|
||||||
@ -757,7 +759,7 @@ def run_viewport_runtime(viewport_id, width=1920, height=1080):
|
|||||||
cmd.append(str(width))
|
cmd.append(str(width))
|
||||||
cmd.append('--viewport-height')
|
cmd.append('--viewport-height')
|
||||||
cmd.append(str(height))
|
cmd.append(str(height))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(cmd)
|
proc = subprocess.Popen(cmd)
|
||||||
_viewport_processes[viewport_id] = proc
|
_viewport_processes[viewport_id] = proc
|
||||||
@ -778,7 +780,7 @@ _viewport_proc_build = None # Separate process tracker for viewport builds
|
|||||||
def compile_viewport(assets_only=False):
|
def compile_viewport(assets_only=False):
|
||||||
"""Compile for viewport mode using separate process tracking."""
|
"""Compile for viewport mode using separate process tracking."""
|
||||||
global _viewport_proc_build
|
global _viewport_proc_build
|
||||||
|
|
||||||
wrd = bpy.data.worlds['Lnx']
|
wrd = bpy.data.worlds['Lnx']
|
||||||
fp = lnx.utils.get_fp()
|
fp = lnx.utils.get_fp()
|
||||||
os.chdir(fp)
|
os.chdir(fp)
|
||||||
@ -786,50 +788,50 @@ def compile_viewport(assets_only=False):
|
|||||||
node_path = lnx.utils.get_node_path()
|
node_path = lnx.utils.get_node_path()
|
||||||
khamake_path = lnx.utils.get_khamake_path()
|
khamake_path = lnx.utils.get_khamake_path()
|
||||||
cmd = [node_path, khamake_path, 'krom']
|
cmd = [node_path, khamake_path, 'krom']
|
||||||
|
|
||||||
ffmpeg_path = lnx.utils.get_ffmpeg_path()
|
ffmpeg_path = lnx.utils.get_ffmpeg_path()
|
||||||
if ffmpeg_path not in (None, ''):
|
if ffmpeg_path not in (None, ''):
|
||||||
cmd.append('--ffmpeg')
|
cmd.append('--ffmpeg')
|
||||||
cmd.append(ffmpeg_path)
|
cmd.append(ffmpeg_path)
|
||||||
|
|
||||||
cmd.append('-g')
|
cmd.append('-g')
|
||||||
cmd.append(lnx.utils.get_gapi())
|
cmd.append(lnx.utils.get_gapi())
|
||||||
cmd.append('--shaderversion')
|
cmd.append('--shaderversion')
|
||||||
cmd.append('330')
|
cmd.append('330')
|
||||||
|
|
||||||
if lnx.utils.get_khamake_threads() != 1:
|
if lnx.utils.get_khamake_threads() != 1:
|
||||||
cmd.append('--parallelAssetConversion')
|
cmd.append('--parallelAssetConversion')
|
||||||
cmd.append(str(lnx.utils.get_khamake_threads()))
|
cmd.append(str(lnx.utils.get_khamake_threads()))
|
||||||
|
|
||||||
cmd.append('--to')
|
cmd.append('--to')
|
||||||
cmd.append(lnx.utils.build_dir() + '/debug')
|
cmd.append(lnx.utils.build_dir() + '/debug')
|
||||||
|
|
||||||
if not wrd.lnx_verbose_output:
|
if not wrd.lnx_verbose_output:
|
||||||
cmd.append("--quiet")
|
cmd.append("--quiet")
|
||||||
|
|
||||||
krom_js_path = lnx.utils.build_dir() + '/debug/krom/krom.js'
|
krom_js_path = lnx.utils.build_dir() + '/debug/krom/krom.js'
|
||||||
if assets_only and os.path.exists(krom_js_path):
|
if assets_only and os.path.exists(krom_js_path):
|
||||||
cmd.append('--nohaxe')
|
cmd.append('--nohaxe')
|
||||||
cmd.append('--noproject')
|
cmd.append('--noproject')
|
||||||
|
|
||||||
log.info(f'Running: {" ".join(cmd)}')
|
log.info(f'Running: {" ".join(cmd)}')
|
||||||
_viewport_proc_build = run_proc(cmd, viewport_build_done)
|
_viewport_proc_build = run_proc(cmd, viewport_build_done)
|
||||||
|
|
||||||
def viewport_build_done():
|
def viewport_build_done():
|
||||||
"""Called when viewport build completes - launches all pending Krom processes."""
|
"""Called when viewport build completes - launches all pending Krom processes."""
|
||||||
global _viewport_build_in_progress, _viewport_pending_launches, _viewport_proc_build
|
global _viewport_build_in_progress, _viewport_pending_launches, _viewport_proc_build
|
||||||
|
|
||||||
log.info('Viewport compilation finished')
|
log.info('Viewport compilation finished')
|
||||||
|
|
||||||
if _viewport_proc_build is None:
|
if _viewport_proc_build is None:
|
||||||
_viewport_build_in_progress = False
|
_viewport_build_in_progress = False
|
||||||
return
|
return
|
||||||
|
|
||||||
result = _viewport_proc_build.poll()
|
result = _viewport_proc_build.poll()
|
||||||
_viewport_proc_build = None
|
_viewport_proc_build = None
|
||||||
_viewport_build_in_progress = False
|
_viewport_build_in_progress = False
|
||||||
state.redraw_ui = True
|
state.redraw_ui = True
|
||||||
|
|
||||||
if result == 0:
|
if result == 0:
|
||||||
bpy.data.worlds['Lnx'].lnx_recompile = False
|
bpy.data.worlds['Lnx'].lnx_recompile = False
|
||||||
|
|
||||||
@ -1101,7 +1103,7 @@ def build_success():
|
|||||||
cmd.append(str(state.viewport_width))
|
cmd.append(str(state.viewport_width))
|
||||||
cmd.append('--viewport-height')
|
cmd.append('--viewport-height')
|
||||||
cmd.append(str(state.viewport_height))
|
cmd.append(str(state.viewport_height))
|
||||||
|
|
||||||
elif state.target.startswith(('windows-hl', 'linux-hl', 'macos-hl')):
|
elif state.target.startswith(('windows-hl', 'linux-hl', 'macos-hl')):
|
||||||
log.info(f"Runtime Hashlink/C target: {state.target}")
|
log.info(f"Runtime Hashlink/C target: {state.target}")
|
||||||
|
|
||||||
@ -1109,7 +1111,7 @@ def build_success():
|
|||||||
|
|
||||||
if not hl_build_dir:
|
if not hl_build_dir:
|
||||||
log.error(f"Could not find build directory for target {state.target}. Playback aborted.")
|
log.error(f"Could not find build directory for target {state.target}. Playback aborted.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if state.target == 'windows-hl':
|
if state.target == 'windows-hl':
|
||||||
vs_version_major = wrd.lnx_project_win_list_vs
|
vs_version_major = wrd.lnx_project_win_list_vs
|
||||||
@ -1144,14 +1146,14 @@ def build_success():
|
|||||||
log.error(f'.vcxproj file not found in {hl_build_dir}. Cannot compile.')
|
log.error(f'.vcxproj file not found in {hl_build_dir}. Cannot compile.')
|
||||||
return
|
return
|
||||||
vcxproj_path = found_vcxproj
|
vcxproj_path = found_vcxproj
|
||||||
proj_name = os.path.splitext(os.path.basename(vcxproj_path))[0]
|
proj_name = os.path.splitext(os.path.basename(vcxproj_path))[0]
|
||||||
|
|
||||||
msbuild_cmd = [
|
msbuild_cmd = [
|
||||||
msbuild_path,
|
msbuild_path,
|
||||||
vcxproj_path,
|
vcxproj_path,
|
||||||
f'/p:Configuration={build_mode}',
|
f'/p:Configuration={build_mode}',
|
||||||
f'/p:Platform={platform}',
|
f'/p:Platform={platform}',
|
||||||
'/m'
|
'/m'
|
||||||
]
|
]
|
||||||
|
|
||||||
log.info(f"Compiling {state.target} project with MSBuild...")
|
log.info(f"Compiling {state.target} project with MSBuild...")
|
||||||
@ -1181,7 +1183,7 @@ def build_success():
|
|||||||
return
|
return
|
||||||
|
|
||||||
log.info(f"Found compiled executable: {exe_path}")
|
log.info(f"Found compiled executable: {exe_path}")
|
||||||
|
|
||||||
dest_exe_name = proj_name + '.exe'
|
dest_exe_name = proj_name + '.exe'
|
||||||
base_build_dir = lnx.utils.get_fp_build()
|
base_build_dir = lnx.utils.get_fp_build()
|
||||||
dest_dir = os.path.join(base_build_dir, state.target)
|
dest_dir = os.path.join(base_build_dir, state.target)
|
||||||
@ -1200,7 +1202,7 @@ def build_success():
|
|||||||
# TO DO switch from default Release
|
# TO DO switch from default Release
|
||||||
build_mode = 'Release'
|
build_mode = 'Release'
|
||||||
proj_name = lnx.utils.blend_name()
|
proj_name = lnx.utils.blend_name()
|
||||||
exe_path = str(hl_build_dir + "/" + build_mode)
|
exe_path = str(hl_build_dir + "/" + build_mode)
|
||||||
if not exe_path:
|
if not exe_path:
|
||||||
log.error(f"Build finished, but could not find the executable for {state.target}.")
|
log.error(f"Build finished, but could not find the executable for {state.target}.")
|
||||||
return
|
return
|
||||||
@ -1219,7 +1221,7 @@ def build_success():
|
|||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log.error(f"'make' compilation failed with return code {e.returncode}.")
|
log.error(f"'make' compilation failed with return code {e.returncode}.")
|
||||||
log.error(f"Make Error Output:\n{e.stderr}")
|
log.error(f"Make Error Output:\n{e.stderr}")
|
||||||
return
|
return
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
log.error("'make' command not found. Ensure 'make' is installed and in your system's PATH.")
|
log.error("'make' command not found. Ensure 'make' is installed and in your system's PATH.")
|
||||||
return
|
return
|
||||||
@ -1231,15 +1233,15 @@ def build_success():
|
|||||||
|
|
||||||
dest_exe_name = lnx.utils.safesrc(wrd.lnx_project_name + '-' + wrd.lnx_project_version)
|
dest_exe_name = lnx.utils.safesrc(wrd.lnx_project_name + '-' + wrd.lnx_project_version)
|
||||||
base_build_dir = lnx.utils.get_fp_build()
|
base_build_dir = lnx.utils.get_fp_build()
|
||||||
dest_dir = os.path.join(base_build_dir, state.target)
|
dest_dir = os.path.join(base_build_dir, state.target)
|
||||||
og_path = os.path.join(exe_path, dest_exe_name)
|
og_path = os.path.join(exe_path, dest_exe_name)
|
||||||
dest_path = os.path.join(dest_dir, dest_exe_name)
|
dest_path = os.path.join(dest_dir, dest_exe_name)
|
||||||
os.makedirs(dest_dir, exist_ok=True)
|
os.makedirs(dest_dir, exist_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log.info(f"Moving '{og_path}' to '{dest_dir}'...")
|
log.info(f"Moving '{og_path}' to '{dest_dir}'...")
|
||||||
shutil.move(og_path, dest_dir)
|
shutil.move(og_path, dest_dir)
|
||||||
cmd = [dest_path]
|
cmd = [dest_path]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Failed to move executable: {e}. Attempting to run from original location.")
|
log.error(f"Failed to move executable: {e}. Attempting to run from original location.")
|
||||||
cmd = [exe_path]
|
cmd = [exe_path]
|
||||||
|
|||||||
@ -40,7 +40,7 @@ def add_world_defs():
|
|||||||
# Store contexts
|
# Store contexts
|
||||||
if rpdat.rp_hdr == False:
|
if rpdat.rp_hdr == False:
|
||||||
wrd.world_defs += '_LDR'
|
wrd.world_defs += '_LDR'
|
||||||
|
|
||||||
if lnx.utils.get_active_scene().world is not None:
|
if lnx.utils.get_active_scene().world is not None:
|
||||||
if lnx.utils.get_active_scene().world.lnx_light_ies_texture:
|
if lnx.utils.get_active_scene().world.lnx_light_ies_texture:
|
||||||
wrd.world_defs += '_LightIES'
|
wrd.world_defs += '_LightIES'
|
||||||
@ -236,6 +236,8 @@ def build():
|
|||||||
|
|
||||||
if rpdat.rp_renderer == 'Deferred':
|
if rpdat.rp_renderer == 'Deferred':
|
||||||
assets.add_shader_pass('copy_pass')
|
assets.add_shader_pass('copy_pass')
|
||||||
|
elif rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes:
|
||||||
|
assets.add_shader_pass('copy_pass')
|
||||||
|
|
||||||
assets.add_shader_pass('blend_pass')
|
assets.add_shader_pass('blend_pass')
|
||||||
assets.add_shader_pass('add_pass')
|
assets.add_shader_pass('add_pass')
|
||||||
@ -243,9 +245,6 @@ def build():
|
|||||||
if rpdat.rp_render_to_texture:
|
if rpdat.rp_render_to_texture:
|
||||||
assets.add_khafile_def('rp_render_to_texture')
|
assets.add_khafile_def('rp_render_to_texture')
|
||||||
|
|
||||||
if rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes:
|
|
||||||
assets.add_shader_pass('copy_pass')
|
|
||||||
|
|
||||||
if rpdat.rp_compositornodes:
|
if rpdat.rp_compositornodes:
|
||||||
assets.add_khafile_def('rp_compositornodes')
|
assets.add_khafile_def('rp_compositornodes')
|
||||||
compo_depth = False
|
compo_depth = False
|
||||||
@ -343,7 +342,8 @@ def build():
|
|||||||
wrd.world_defs += '_FSR1_{0}'.format(rpdat.rp_fsr1)
|
wrd.world_defs += '_FSR1_{0}'.format(rpdat.rp_fsr1)
|
||||||
assets.add_shader_pass('fsr1_easu_pass')
|
assets.add_shader_pass('fsr1_easu_pass')
|
||||||
assets.add_shader_pass('fsr1_rcas_pass')
|
assets.add_shader_pass('fsr1_rcas_pass')
|
||||||
assets.add_shader_pass('copy_pass')
|
if rpdat.rp_renderer == 'Forward':
|
||||||
|
assets.add_shader_pass('copy_pass')
|
||||||
|
|
||||||
if rpdat.rp_ssao:
|
if rpdat.rp_ssao:
|
||||||
assets.add_khafile_def('rp_ssao')
|
assets.add_khafile_def('rp_ssao')
|
||||||
|
|||||||
@ -67,19 +67,19 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in
|
|||||||
"""
|
"""
|
||||||
if max_size <= 0:
|
if max_size <= 0:
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
if image.size[0] <= max_size and image.size[1] <= max_size:
|
if image.size[0] <= max_size and image.size[1] <= max_size:
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
wrd = bpy.data.worlds['Lnx']
|
wrd = bpy.data.worlds['Lnx']
|
||||||
texture_quality = wrd.lnx_texture_quality
|
texture_quality = wrd.lnx_texture_quality
|
||||||
|
|
||||||
cache_key = (filepath, max_size, texture_quality, os.path.getmtime(filepath) if os.path.exists(filepath) else 0)
|
cache_key = (filepath, max_size, texture_quality, os.path.getmtime(filepath) if os.path.exists(filepath) else 0)
|
||||||
if cache_key in texture_resize_cache:
|
if cache_key in texture_resize_cache:
|
||||||
cached_path = texture_resize_cache[cache_key]
|
cached_path = texture_resize_cache[cache_key]
|
||||||
if os.path.exists(cached_path):
|
if os.path.exists(cached_path):
|
||||||
return cached_path
|
return cached_path
|
||||||
|
|
||||||
width, height = image.size[0], image.size[1]
|
width, height = image.size[0], image.size[1]
|
||||||
if width > height:
|
if width > height:
|
||||||
new_width = max_size
|
new_width = max_size
|
||||||
@ -87,55 +87,55 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in
|
|||||||
else:
|
else:
|
||||||
new_height = max_size
|
new_height = max_size
|
||||||
new_width = int((width / height) * max_size)
|
new_width = int((width / height) * max_size)
|
||||||
|
|
||||||
build_dir = lnx.utils.get_fp_build()
|
build_dir = lnx.utils.get_fp_build()
|
||||||
resized_dir = os.path.join(build_dir, 'compiled', 'Assets', 'unpacked')
|
resized_dir = os.path.join(build_dir, 'compiled', 'Assets', 'unpacked')
|
||||||
os.makedirs(resized_dir, exist_ok=True)
|
os.makedirs(resized_dir, exist_ok=True)
|
||||||
|
|
||||||
basename = os.path.basename(filepath)
|
basename = os.path.basename(filepath)
|
||||||
name, ext = os.path.splitext(basename)
|
name, ext = os.path.splitext(basename)
|
||||||
quality_suffix = f"q{int(texture_quality * 100)}"
|
quality_suffix = f"q{int(texture_quality * 100)}"
|
||||||
resized_path = os.path.join(resized_dir, f"{name}_{max_size}px_{quality_suffix}{ext}")
|
resized_path = os.path.join(resized_dir, f"{name}_{max_size}px_{quality_suffix}{ext}")
|
||||||
|
|
||||||
if os.path.exists(resized_path):
|
if os.path.exists(resized_path):
|
||||||
src_mtime = os.path.getmtime(filepath)
|
src_mtime = os.path.getmtime(filepath)
|
||||||
dst_mtime = os.path.getmtime(resized_path)
|
dst_mtime = os.path.getmtime(resized_path)
|
||||||
if dst_mtime >= src_mtime:
|
if dst_mtime >= src_mtime:
|
||||||
texture_resize_cache[cache_key] = resized_path
|
texture_resize_cache[cache_key] = resized_path
|
||||||
return resized_path
|
return resized_path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ffmpeg_path = lnx.utils.get_ffmpeg_path()
|
ffmpeg_path = lnx.utils.get_ffmpeg_path()
|
||||||
|
|
||||||
if ffmpeg_path is None or ffmpeg_path == '':
|
if ffmpeg_path is None or ffmpeg_path == '':
|
||||||
print(f"[Texture Optimizer] WARNING: FFmpeg not found. Please set FFmpeg path in addon preferences.")
|
print(f"[Texture Optimizer] WARNING: FFmpeg not found. Please set FFmpeg path in addon preferences.")
|
||||||
print(f"[Texture Optimizer] Skipping resize for: {basename}")
|
print(f"[Texture Optimizer] Skipping resize for: {basename}")
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
file_ext = os.path.splitext(filepath)[1].lower().lstrip('.')
|
file_ext = os.path.splitext(filepath)[1].lower().lstrip('.')
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
ffmpeg_path,
|
ffmpeg_path,
|
||||||
'-y',
|
'-y',
|
||||||
'-i', filepath,
|
'-i', filepath,
|
||||||
'-vf', f'scale={new_width}:{new_height}:flags=lanczos',
|
'-vf', f'scale={new_width}:{new_height}:flags=lanczos',
|
||||||
]
|
]
|
||||||
|
|
||||||
if file_ext in ('png', 'tga', 'bmp'):
|
if file_ext in ('png', 'tga', 'bmp'):
|
||||||
compression_level = round((1.0 - texture_quality) * 9)
|
compression_level = round((1.0 - texture_quality) * 9)
|
||||||
cmd.extend(['-compression_level', str(compression_level)])
|
cmd.extend(['-compression_level', str(compression_level)])
|
||||||
else:
|
else:
|
||||||
qscale = round(2 + (1.0 - texture_quality) * 29)
|
qscale = round(2 + (1.0 - texture_quality) * 29)
|
||||||
cmd.extend(['-q:v', str(qscale)])
|
cmd.extend(['-q:v', str(qscale)])
|
||||||
|
|
||||||
cmd.append(resized_path)
|
cmd.append(resized_path)
|
||||||
|
|
||||||
startupinfo = None
|
startupinfo = None
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||||
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
cmd,
|
cmd,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
@ -143,7 +143,7 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in
|
|||||||
startupinfo=startupinfo,
|
startupinfo=startupinfo,
|
||||||
timeout=60
|
timeout=60
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.returncode == 0 and os.path.exists(resized_path):
|
if result.returncode == 0 and os.path.exists(resized_path):
|
||||||
print(f"[Texture Optimizer] Resized: {basename} {width}x{height} -> {new_width}x{new_height}")
|
print(f"[Texture Optimizer] Resized: {basename} {width}x{height} -> {new_width}x{new_height}")
|
||||||
texture_resize_cache[cache_key] = resized_path
|
texture_resize_cache[cache_key] = resized_path
|
||||||
@ -152,7 +152,7 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in
|
|||||||
error_msg = result.stderr.decode('utf-8', errors='ignore') if result.stderr else 'Unknown error'
|
error_msg = result.stderr.decode('utf-8', errors='ignore') if result.stderr else 'Unknown error'
|
||||||
print(f"[Texture Optimizer] WARNING: FFmpeg failed to resize {basename}: {error_msg}")
|
print(f"[Texture Optimizer] WARNING: FFmpeg failed to resize {basename}: {error_msg}")
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
print(f"[Texture Optimizer] WARNING: FFmpeg timeout while resizing {basename}")
|
print(f"[Texture Optimizer] WARNING: FFmpeg timeout while resizing {basename}")
|
||||||
return filepath
|
return filepath
|
||||||
@ -641,7 +641,7 @@ def parse_normal_map_color_input(inp, strength_input=None, space='TANGENT'):
|
|||||||
|
|
||||||
state.normal_parsed = True
|
state.normal_parsed = True
|
||||||
frag.write_normal += 1
|
frag.write_normal += 1
|
||||||
|
|
||||||
color_val = parse_vector_input(inp)
|
color_val = parse_vector_input(inp)
|
||||||
strength = parse_value_input(strength_input) if strength_input is not None else '1.0'
|
strength = parse_value_input(strength_input) if strength_input is not None else '1.0'
|
||||||
|
|
||||||
@ -660,7 +660,7 @@ def parse_normal_map_color_input(inp, strength_input=None, space='TANGENT'):
|
|||||||
frag.write(f'texn.xy *= {strength};')
|
frag.write(f'texn.xy *= {strength};')
|
||||||
frag.write('n = normalize(TBN * texn);')
|
frag.write('n = normalize(TBN * texn);')
|
||||||
state.con.add_elem('tang', 'short4norm')
|
state.con.add_elem('tang', 'short4norm')
|
||||||
|
|
||||||
elif space in ['OBJECT', 'BLENDER_OBJECT']:
|
elif space in ['OBJECT', 'BLENDER_OBJECT']:
|
||||||
frag.add_uniform('mat3 N', '_normalMatrix')
|
frag.add_uniform('mat3 N', '_normalMatrix')
|
||||||
frag.write(f'vec3 objn = ({color_val}) * 2.0 - 1.0;')
|
frag.write(f'vec3 objn = ({color_val}) * 2.0 - 1.0;')
|
||||||
@ -693,6 +693,8 @@ def parse_value_input(inp: bpy.types.NodeSocket) -> floatstr:
|
|||||||
return rgb_to_bw(res_var)
|
return rgb_to_bw(res_var)
|
||||||
elif socket_type in ('VALUE', 'INT'):
|
elif socket_type in ('VALUE', 'INT'):
|
||||||
return res_var
|
return res_var
|
||||||
|
elif socket_type == 'BOOLEAN':
|
||||||
|
return f'({res_var} ? 1.0 : 0.0)'
|
||||||
else:
|
else:
|
||||||
log.warn(f'Node tree "{tree_name()}": socket "{link.from_socket.name}" of node "{link.from_node.name}" cannot be connected to a scalar value socket')
|
log.warn(f'Node tree "{tree_name()}": socket "{link.from_socket.name}" of node "{link.from_node.name}" cannot be connected to a scalar value socket')
|
||||||
return '0.0'
|
return '0.0'
|
||||||
@ -990,6 +992,12 @@ def dfdy_fine(val: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def to_vec1(v):
|
def to_vec1(v):
|
||||||
|
if isinstance(v, bool):
|
||||||
|
return '1.0' if v else '0.0'
|
||||||
|
if v == 'False':
|
||||||
|
return '0.0'
|
||||||
|
if v == 'True':
|
||||||
|
return '1.0'
|
||||||
return str(v)
|
return str(v)
|
||||||
|
|
||||||
|
|
||||||
@ -1177,7 +1185,7 @@ def make_texture(
|
|||||||
if filepath != original_filepath:
|
if filepath != original_filepath:
|
||||||
resized_filename = lnx.utils.extract_filename(filepath)
|
resized_filename = lnx.utils.extract_filename(filepath)
|
||||||
tex['file'] = lnx.utils.safestr(resized_filename)
|
tex['file'] = lnx.utils.safestr(resized_filename)
|
||||||
|
|
||||||
# Link image path to assets
|
# Link image path to assets
|
||||||
# TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows
|
# TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows
|
||||||
if lnx.utils.get_os() == 'win':
|
if lnx.utils.get_os() == 'win':
|
||||||
|
|||||||
@ -149,6 +149,10 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
|||||||
if val_str is None:
|
if val_str is None:
|
||||||
return None
|
return None
|
||||||
val_str = str(val_str).strip()
|
val_str = str(val_str).strip()
|
||||||
|
if val_str in ('True', 'true'):
|
||||||
|
return 1.0
|
||||||
|
if val_str in ('False', 'false'):
|
||||||
|
return 0.0
|
||||||
try:
|
try:
|
||||||
return float(val_str)
|
return float(val_str)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
@ -296,7 +300,7 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
|||||||
|
|
||||||
elif rp == 'translucent' or rp == 'refraction':
|
elif rp == 'translucent' or rp == 'refraction':
|
||||||
c['bind_constants'].append({'name': 'receiveShadow', 'boolValue': material.lnx_receive_shadow})
|
c['bind_constants'].append({'name': 'receiveShadow', 'boolValue': material.lnx_receive_shadow})
|
||||||
|
|
||||||
elif rp == 'shadowmap':
|
elif rp == 'shadowmap':
|
||||||
if wrd.lnx_batch_materials:
|
if wrd.lnx_batch_materials:
|
||||||
if len(c['bind_textures']) > 0:
|
if len(c['bind_textures']) > 0:
|
||||||
|
|||||||
@ -99,12 +99,12 @@ class ShaderContext:
|
|||||||
def sort_vs(self):
|
def sort_vs(self):
|
||||||
vs = []
|
vs = []
|
||||||
ar = ['pos', 'nor', 'tex', 'tex1', 'morph', 'col', 'tang', 'bone', 'weight', 'ipos', 'irot', 'iscl']
|
ar = ['pos', 'nor', 'tex', 'tex1', 'morph', 'col', 'tang', 'bone', 'weight', 'ipos', 'irot', 'iscl']
|
||||||
|
|
||||||
if 'vertex_elements' in self.data:
|
if 'vertex_elements' in self.data:
|
||||||
for elem in self.data['vertex_elements']:
|
for elem in self.data['vertex_elements']:
|
||||||
if elem['name'] not in ar:
|
if elem['name'] not in ar:
|
||||||
ar.append(elem['name'])
|
ar.append(elem['name'])
|
||||||
|
|
||||||
for ename in ar:
|
for ename in ar:
|
||||||
elem = self.get_elem(ename)
|
elem = self.get_elem(ename)
|
||||||
if elem != None:
|
if elem != None:
|
||||||
@ -137,6 +137,15 @@ class ShaderContext:
|
|||||||
if default_value is not None:
|
if default_value is not None:
|
||||||
if ctype == 'float':
|
if ctype == 'float':
|
||||||
c['floatValue'] = default_value
|
c['floatValue'] = default_value
|
||||||
|
if isinstance(default_value, bool):
|
||||||
|
c['floatValue'] = 1.0 if default_value else 0.0
|
||||||
|
elif isinstance(default_value, (int, float)):
|
||||||
|
c['floatValue'] = float(default_value)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
c['floatValue'] = float(default_value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
c['floatValue'] = default_value
|
||||||
if ctype == 'vec3':
|
if ctype == 'vec3':
|
||||||
c['vec3Value'] = default_value
|
c['vec3Value'] = default_value
|
||||||
if is_lnx_mat_param is not None:
|
if is_lnx_mat_param is not None:
|
||||||
@ -418,11 +427,11 @@ class Shader:
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
import re
|
import re
|
||||||
issues = []
|
issues = []
|
||||||
|
|
||||||
# Check for duplicate variable declarations in main_attribs
|
# Check for duplicate variable declarations in main_attribs
|
||||||
var_pattern = re.compile(r'\b(vec[234]|float|int|mat[234])\s+(\w+)\s*[;=]')
|
var_pattern = re.compile(r'\b(vec[234]|float|int|mat[234])\s+(\w+)\s*[;=]')
|
||||||
declared_vars = {}
|
declared_vars = {}
|
||||||
|
|
||||||
for line in self.main_attribs.split('\n'):
|
for line in self.main_attribs.split('\n'):
|
||||||
match = var_pattern.search(line)
|
match = var_pattern.search(line)
|
||||||
if match:
|
if match:
|
||||||
@ -431,7 +440,7 @@ class Shader:
|
|||||||
issues.append(f"Duplicate variable declaration: '{var_name}' (type: {var_type})")
|
issues.append(f"Duplicate variable declaration: '{var_name}' (type: {var_type})")
|
||||||
else:
|
else:
|
||||||
declared_vars[var_name] = var_type
|
declared_vars[var_name] = var_type
|
||||||
|
|
||||||
return issues
|
return issues
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user