Compare commits
17 Commits
1015e0df34
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 75e95387bb | |||
| 0067459e9a | |||
| cf68067343 | |||
| 365c624d73 | |||
| 384a8a7ee8 | |||
| 4e2b59a1d6 | |||
| 6d07e70b11 | |||
| 42fdff4757 | |||
| d44fd9993a | |||
| 3fd1b395fb | |||
| 40bca62f96 | |||
| e5082835c4 | |||
| bc700a6374 | |||
| 1e500993d9 | |||
| d842744aeb | |||
| ada18b4648 | |||
| 5004efe046 |
87
leenkx.py
87
leenkx.py
@ -12,6 +12,7 @@ bl_info = {
|
||||
"tracker_url": "https://leenkx.com/support"
|
||||
}
|
||||
from enum import IntEnum
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import platform
|
||||
@ -32,6 +33,41 @@ from bpy.app.handlers import persistent
|
||||
from bpy.props import *
|
||||
from bpy.types import Operator, AddonPreferences
|
||||
|
||||
LEENKX_PREFS_ENV = 'LEENKX_ADDON_PREFS'
|
||||
|
||||
persist_props = [
|
||||
'apply_theme', 'show_advanced', 'sdk_path', 'tabs',
|
||||
'code_editor', 'ide_bin', 'ui_scale', 'viewport_controls',
|
||||
'khamake_threads', 'khamake_threads_use_auto', 'compilation_server',
|
||||
'renderdoc_path', 'ffmpeg_path', 'save_on_build', 'open_build_directory',
|
||||
'cmft_use_opencl', 'legacy_shaders', 'relative_paths',
|
||||
'debug_console_auto', 'debug_console_visible_sc',
|
||||
'debug_console_scale_in_sc', 'debug_console_scale_out_sc',
|
||||
'android_sdk_root_path', 'android_open_build_apk_directory',
|
||||
'android_apk_copy_path', 'android_apk_copy_open_directory',
|
||||
'html5_copy_path', 'html5_server_port',
|
||||
'html5_server_log', 'profile_exporter', 'khamake_debug',
|
||||
'haxe_times', 'use_leenkx_py_symlink', 'update_submodules',
|
||||
]
|
||||
|
||||
|
||||
def save_prefs():
|
||||
prefs = LeenkxAddonPreferences.get_prefs()
|
||||
data = {k: getattr(prefs, k) for k in persist_props}
|
||||
os.environ[LEENKX_PREFS_ENV] = json.dumps(data)
|
||||
|
||||
|
||||
def restore_prefs():
|
||||
raw = os.environ.get(LEENKX_PREFS_ENV)
|
||||
if not raw:
|
||||
return
|
||||
data = json.loads(raw)
|
||||
prefs = LeenkxAddonPreferences.get_prefs()
|
||||
prefs.skip_update = True
|
||||
for k, v in data.items():
|
||||
if hasattr(prefs, k):
|
||||
setattr(prefs, k, v)
|
||||
|
||||
|
||||
if bpy.app.version < (2, 90, 0):
|
||||
ListType = List
|
||||
@ -116,7 +152,9 @@ class LeenkxAddonPreferences(AddonPreferences):
|
||||
return
|
||||
self.skip_update = True
|
||||
self.sdk_path = bpy.path.reduce_dirs([bpy.path.abspath(self.sdk_path)])[0] + '/'
|
||||
save_prefs()
|
||||
restart_leenkx(context)
|
||||
update_theme(context)
|
||||
|
||||
def ide_bin_update(self, context):
|
||||
if self.skip_update:
|
||||
@ -311,6 +349,11 @@ class LeenkxAddonPreferences(AddonPreferences):
|
||||
" development. Warning: this will invalidate the installation if the SDK is removed"),
|
||||
update=lambda self, context: update_leenkx_py(get_sdk_path(context)),
|
||||
)
|
||||
apply_theme: BoolProperty(
|
||||
name="Apply Leenkx Theme", default=True,
|
||||
description="Automatically apply the Leenkx Blender theme on addon registration",
|
||||
update=lambda self, context: update_theme(context),
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
self.skip_update = False
|
||||
@ -450,6 +493,7 @@ class LeenkxAddonPreferences(AddonPreferences):
|
||||
|
||||
col = box.column(align=True)
|
||||
col.prop(self, "use_leenkx_py_symlink")
|
||||
col.prop(self, "apply_theme")
|
||||
|
||||
@staticmethod
|
||||
def get_prefs() -> 'LeenkxAddonPreferences':
|
||||
@ -458,9 +502,10 @@ class LeenkxAddonPreferences(AddonPreferences):
|
||||
|
||||
|
||||
def get_fp():
|
||||
if bpy.data.filepath == '':
|
||||
filepath = getattr(bpy.data, 'filepath', '')
|
||||
if filepath == '':
|
||||
return ''
|
||||
s = bpy.data.filepath.split(os.path.sep)
|
||||
s = filepath.split(os.path.sep)
|
||||
s.pop()
|
||||
return os.path.sep.join(s)
|
||||
|
||||
@ -934,13 +979,47 @@ def on_load_post(context):
|
||||
bpy.app.timers.register(lambda: restart_leenkx(bpy.context), first_interval=0.1)
|
||||
|
||||
|
||||
def remove_leenkx_theme():
|
||||
if "leenkx.theme" in sys.modules:
|
||||
sys.modules["leenkx.theme"].unregister()
|
||||
del sys.modules["leenkx.theme"]
|
||||
|
||||
|
||||
def apply_leenkx_theme(sdk_path: str):
|
||||
remove_leenkx_theme()
|
||||
import importlib.util
|
||||
theme_path = os.path.join(sdk_path, "leenkx", "blender", "theme", "theme.py")
|
||||
if os.path.exists(theme_path):
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"leenkx.theme", theme_path)
|
||||
theme = importlib.util.module_from_spec(spec)
|
||||
sys.modules["leenkx.theme"] = theme
|
||||
spec.loader.exec_module(theme)
|
||||
theme.register(sdk_path)
|
||||
else:
|
||||
print("Leenkx theme: theme.py not found at", theme_path)
|
||||
|
||||
|
||||
def update_theme(context):
|
||||
prefs = LeenkxAddonPreferences.get_prefs()
|
||||
if prefs.apply_theme:
|
||||
sdk_path = get_sdk_path(context)
|
||||
if sdk_path != "":
|
||||
apply_leenkx_theme(sdk_path)
|
||||
else:
|
||||
remove_leenkx_theme()
|
||||
|
||||
|
||||
def on_register_post():
|
||||
detect_sdk_path()
|
||||
save_prefs()
|
||||
restart_leenkx(bpy.context)
|
||||
update_theme(bpy.context)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(LeenkxAddonPreferences)
|
||||
restore_prefs()
|
||||
bpy.utils.register_class(LnxAddonPrintVersionInfoButton)
|
||||
bpy.utils.register_class(LnxAddonInstallButton)
|
||||
bpy.utils.register_class(LnxAddonUpdateButton)
|
||||
@ -953,7 +1032,11 @@ def register():
|
||||
|
||||
|
||||
def unregister():
|
||||
if bpy.app.timers.is_registered(on_register_post):
|
||||
bpy.app.timers.unregister(on_register_post)
|
||||
remove_leenkx_theme()
|
||||
stop_leenkx()
|
||||
save_prefs()
|
||||
bpy.utils.unregister_class(LeenkxAddonPreferences)
|
||||
bpy.utils.unregister_class(LnxAddonInstallButton)
|
||||
bpy.utils.unregister_class(LnxAddonPrintVersionInfoButton)
|
||||
|
||||
@ -420,7 +420,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV);
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
@ -581,15 +581,15 @@ void main() {
|
||||
vec3 sdirect;
|
||||
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
|
||||
vec3 sbitangent = normalize(cross(n, wTangent));
|
||||
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
|
||||
wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y;
|
||||
} else {
|
||||
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||
}
|
||||
#else
|
||||
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
vec3 sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||
#endif
|
||||
|
||||
|
||||
@ -227,7 +227,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV);
|
||||
|
||||
#ifdef _Rad // Indirect specular
|
||||
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5 * occspec.y;
|
||||
@ -342,15 +342,15 @@ void main() {
|
||||
vec3 sdirect;
|
||||
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
|
||||
vec3 sbitangent = normalize(cross(n, wTangent));
|
||||
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
|
||||
wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y;
|
||||
} else {
|
||||
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||
}
|
||||
#else
|
||||
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||
vec3 sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) +
|
||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||
#endif
|
||||
|
||||
|
||||
@ -88,6 +88,199 @@ vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
|
||||
return albedo * INV_PI * nl;
|
||||
}
|
||||
|
||||
#ifdef _BurleyDiffuse
|
||||
vec3 burleyDiffuseBRDF(const vec3 albedo, const float roughness,
|
||||
const float dotNL, const float dotNV, const float dotVH) {
|
||||
float nl = clamp(dotNL, 0.0, 1.0);
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float energyBias = mix(0.0, 0.5, roughness);
|
||||
float energyFactor = mix(1.0, 1.0 / 1.51, roughness);
|
||||
float fd90 = energyBias + 2.0 * roughness * dotVH * dotVH;
|
||||
float lightScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nl, 5.0);
|
||||
float viewScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nv, 5.0);
|
||||
return albedo * INV_PI * lightScatter * viewScatter * energyFactor * nl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EONDiffuse
|
||||
const float constant1_FON = 0.5 - 2.0 / (3.0 * PI);
|
||||
const float constant2_FON = 2.0 / 3.0 - 28.0 / (15.0 * PI);
|
||||
|
||||
float E_FON_approx(float mu, float r) {
|
||||
float mucomp = 1.0 - mu;
|
||||
const float g1 = 0.0571085289;
|
||||
const float g2 = 0.491881867;
|
||||
const float g3 = -0.332181442;
|
||||
const float g4 = 0.0714429953;
|
||||
float GoverPi = mucomp * (g1 + mucomp * (g2 + mucomp * (g3 + mucomp * g4)));
|
||||
return (1.0 + r * GoverPi) / (1.0 + constant1_FON * r);
|
||||
}
|
||||
|
||||
vec3 eonDiffuseBRDF(const vec3 albedo, const float roughness,
|
||||
const float dotNL, const float dotNV, const float dotVH) {
|
||||
float r = roughness;
|
||||
float mu_i = clamp(dotNL, 0.0, 1.0);
|
||||
float mu_o = clamp(dotNV, 0.0, 1.0);
|
||||
if (mu_i < 1.0e-7 || mu_o < 1.0e-7) return vec3(0.0);
|
||||
float dotLV = 2.0 * dotVH * dotVH - 1.0;
|
||||
float s = dotLV - mu_i * mu_o;
|
||||
float sovertF = s > 0.0 ? s / max(mu_i, mu_o) : s;
|
||||
float AF = 1.0 / (1.0 + constant1_FON * r);
|
||||
vec3 f_ss = (albedo * INV_PI) * AF * (1.0 + r * sovertF);
|
||||
float EFo = E_FON_approx(mu_o, r);
|
||||
float EFi = E_FON_approx(mu_i, r);
|
||||
float avgEF = AF * (1.0 + constant2_FON * r);
|
||||
vec3 rho_ms = (albedo * albedo) * avgEF
|
||||
/ max(vec3(1.0) - albedo * (1.0 - avgEF), vec3(1.0e-7));
|
||||
const float eps = 1.0e-7;
|
||||
vec3 f_ms = (rho_ms * INV_PI)
|
||||
* max(eps, 1.0 - EFo)
|
||||
* max(eps, 1.0 - EFi)
|
||||
/ max(eps, 1.0 - avgEF);
|
||||
return (f_ss + f_ms) * mu_i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _GotandaDiffuse
|
||||
vec3 gotandaDiffuseBRDF(const vec3 albedo, const float roughness, const vec3 f0,
|
||||
const float dotNL, const float dotNV, const float dotVH) {
|
||||
float nl = clamp(dotNL, 0.0, 1.0);
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float dotLV = 2.0 * dotVH * dotVH - 1.0;
|
||||
float Cosri = dotLV - nv * nl;
|
||||
float a2_13 = a2 + 1.36053;
|
||||
float Fr = (1.0 - (0.542026 * a2 + 0.303573 * a) / a2_13)
|
||||
* (1.0 - pow(1.0 - nv, 5.0 - 4.0 * a2) / a2_13)
|
||||
* ((-0.733996 * a2 * a + 1.50912 * a2 - 1.16402 * a)
|
||||
* pow(1.0 - nv, 1.0 + 1.0 / (39.0 * a2 * a2 + 1.0)) + 1.0);
|
||||
float Lm = (max(1.0 - 2.0 * a, 0.0) * (1.0 - pow(1.0 - nl, 5.0))
|
||||
+ min(2.0 * a, 1.0)) * (1.0 - 0.5 * a * (nl - 1.0)) * nl;
|
||||
float Vd = (a2 / ((a2 + 0.09) * (1.31072 + 0.995584 * nv)))
|
||||
* (1.0 - pow(1.0 - nl,
|
||||
(1.0 - 0.3726732 * nv * nv)
|
||||
/ (0.188566 + 0.38841 * nv)));
|
||||
float Bp = Cosri < 0.0 ? 1.4 * nv * nl * Cosri : Cosri;
|
||||
vec3 Lr = (21.0 / 20.0) * (1.0 - f0) * (Fr * Lm + Vd + Bp);
|
||||
return max(albedo * INV_PI * Lr, vec3(0.0));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ChanDiffuse
|
||||
vec3 chanDiffuseBRDF(const vec3 albedo, const float roughness,
|
||||
const float dotNL, const float dotNV, const float dotVH) {
|
||||
float nl = clamp(dotNL, 0.0, 1.0);
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float vh = clamp(dotVH, 0.0, 1.0);
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float g = clamp((1.0 / 18.0) * log2(2.0 / max(a2, 1e-7) - 1.0), 0.0, 1.0);
|
||||
float dotNH = clamp((nl + nv) / max(2.0 * vh, 1e-5), 0.0, 1.0);
|
||||
float F0 = vh + pow(1.0 - vh, 5.0);
|
||||
float FdV = 1.0 - 0.75 * pow(1.0 - nv, 5.0);
|
||||
float FdL = 1.0 - 0.75 * pow(1.0 - nl, 5.0);
|
||||
float Fd = mix(F0, FdV * FdL, clamp(2.2 * g - 0.5, 0.0, 1.0));
|
||||
float Fb = ((34.5 * g - 59.0) * g + 24.5) * vh
|
||||
* exp2(-max(73.2 * g - 21.2, 8.9) * sqrt(dotNH));
|
||||
float Lobe = clamp(Fd + Fb, 0.0, 1.0);
|
||||
return albedo * INV_PI * Lobe * nl;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 diffuseBRDF(const vec3 albedo, const float roughness, const vec3 f0,
|
||||
const float dotNL, const float dotNV, const float dotVH) {
|
||||
#ifdef _BurleyDiffuse
|
||||
return burleyDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH);
|
||||
#elif defined(_EONDiffuse)
|
||||
return eonDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH);
|
||||
#elif defined(_GotandaDiffuse)
|
||||
return gotandaDiffuseBRDF(albedo, roughness, f0, dotNL, dotNV, dotVH);
|
||||
#elif defined(_ChanDiffuse)
|
||||
return chanDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH);
|
||||
#else
|
||||
return lambertDiffuseBRDF(albedo, dotNL);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 lambertDiffuseIBL(const vec3 albedo) {
|
||||
return albedo;
|
||||
}
|
||||
|
||||
#ifdef _BurleyDiffuse
|
||||
vec3 burleyDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) {
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float energyBias = mix(0.0, 0.5, roughness);
|
||||
float energyFactor = mix(1.0, 1.0 / 1.51, roughness);
|
||||
float fd90 = energyBias + 2.0 * roughness * nv * nv;
|
||||
float viewScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nv, 5.0);
|
||||
return albedo * viewScatter * energyFactor;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EONDiffuse
|
||||
vec3 eonDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) {
|
||||
float r = roughness;
|
||||
float AF = 1.0 / (1.0 + constant1_FON * r);
|
||||
float EF = E_FON_approx(clamp(dotNV, 0.0, 1.0), r);
|
||||
float avgEF = AF * (1.0 + constant2_FON * r);
|
||||
vec3 rho_ms = (albedo * albedo) * avgEF
|
||||
/ max(vec3(1.0) - albedo * (1.0 - avgEF), vec3(1.0e-7));
|
||||
return max(albedo * EF + rho_ms * (1.0 - EF), vec3(0.0));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _GotandaDiffuse
|
||||
vec3 gotandaDiffuseIBL(const vec3 albedo, const float roughness, const vec3 f0, const float dotNV) {
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float a2_13 = a2 + 1.36053;
|
||||
float Fr = (1.0 - (0.542026 * a2 + 0.303573 * a) / a2_13)
|
||||
* (1.0 - pow(1.0 - nv, 5.0 - 4.0 * a2) / a2_13)
|
||||
* ((-0.733996 * a2 * a + 1.50912 * a2 - 1.16402 * a)
|
||||
* pow(1.0 - nv, 1.0 + 1.0 / (39.0 * a2 * a2 + 1.0)) + 1.0);
|
||||
float Lm = (max(1.0 - 2.0 * a, 0.0) * (1.0 - pow(1.0 - nv, 5.0))
|
||||
+ min(2.0 * a, 1.0)) * (1.0 - 0.5 * a * (nv - 1.0)) * nv;
|
||||
float Vd = (a2 / ((a2 + 0.09) * (1.31072 + 0.995584 * nv)))
|
||||
* (1.0 - pow(1.0 - nv,
|
||||
(1.0 - 0.3726732 * nv * nv)
|
||||
/ (0.188566 + 0.38841 * nv)));
|
||||
float Cosri = 1.0 - nv * nv;
|
||||
float Bp = Cosri;
|
||||
vec3 Lr = (21.0 / 20.0) * (1.0 - f0) * (Fr * Lm + Vd + Bp);
|
||||
return max(albedo * Lr, vec3(0.0));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ChanDiffuse
|
||||
vec3 chanDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) {
|
||||
float nv = clamp(dotNV, 0.0, 1.0);
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float g = clamp((1.0 / 18.0) * log2(2.0 / max(a2, 1e-7) - 1.0), 0.0, 1.0);
|
||||
float FdV = 1.0 - 0.75 * pow(1.0 - nv, 5.0);
|
||||
float Fd = mix(1.0, FdV * FdV, clamp(2.2 * g - 0.5, 0.0, 1.0));
|
||||
float Fb = ((34.5 * g - 59.0) * g + 24.5)
|
||||
* exp2(-max(73.2 * g - 21.2, 8.9) * sqrt(nv));
|
||||
return albedo * clamp(Fd + Fb, 0.0, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 diffuseIBL(const vec3 albedo, const float roughness, const vec3 f0, const float dotNV) {
|
||||
#ifdef _BurleyDiffuse
|
||||
return burleyDiffuseIBL(albedo, roughness, dotNV);
|
||||
#elif defined(_EONDiffuse)
|
||||
return eonDiffuseIBL(albedo, roughness, dotNV);
|
||||
#elif defined(_GotandaDiffuse)
|
||||
return gotandaDiffuseIBL(albedo, roughness, f0, dotNV);
|
||||
#elif defined(_ChanDiffuse)
|
||||
return chanDiffuseIBL(albedo, roughness, dotNV);
|
||||
#else
|
||||
return lambertDiffuseIBL(albedo);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
|
||||
return mix(baseColor, vec3(0.0), metalness);
|
||||
}
|
||||
|
||||
@ -131,15 +131,15 @@ vec3 sampleLightCore(const vec3 p, const vec3 n, const vec3 v, const float dotNV
|
||||
#ifdef _Anisotropy
|
||||
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
|
||||
vec3 bitangent = normalize(cross(n, tangent));
|
||||
standard = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
|
||||
tangent, bitangent, n, l, v, dotNL, dotNV) * spec;
|
||||
} else {
|
||||
standard = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
}
|
||||
#else
|
||||
standard = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
#endif
|
||||
|
||||
|
||||
@ -83,15 +83,15 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
||||
vec3 direct;
|
||||
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
|
||||
vec3 bitangent = normalize(cross(n, tangent));
|
||||
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
|
||||
tangent, bitangent, n, l, v, dotNL, dotNV) * spec;
|
||||
} else {
|
||||
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
}
|
||||
#else
|
||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
vec3 direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
#endif
|
||||
|
||||
|
||||
@ -75,9 +75,15 @@ vec3 PCFTileAware(sampler2DShadow shadowMap,
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
vec3 transResult = vec3(0.0);
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
vec4 smt = texture(shadowMapTransparent,
|
||||
clamp(uv + vec2(x, y) / smSize, tileMin, tileMax));
|
||||
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
|
||||
}
|
||||
}
|
||||
result *= transResult / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -142,9 +148,15 @@ vec3 PCF(sampler2DShadow shadowMap,
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
vec3 transResult = vec3(0.0);
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
vec4 smt = texture(shadowMapTransparent,
|
||||
uv + vec2(x, y) / smSize);
|
||||
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
|
||||
}
|
||||
}
|
||||
result *= transResult / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -187,9 +199,19 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube,
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
vec3 transResult = vec3(0.0);
|
||||
vec4 smt = texture(shadowMapCubeTransparent, ml);
|
||||
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
|
||||
for (int x = -1; x <= 1; x += 2) {
|
||||
for (int y = -1; y <= 1; y += 2) {
|
||||
for (int z = -1; z <= 1; z += 2) {
|
||||
smt = texture(shadowMapCubeTransparent,
|
||||
ml + vec3(x, y, z) * s);
|
||||
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
result *= transResult / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -385,9 +407,15 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
vec3 transResult = vec3(0.0);
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
vec4 smt = texture(shadowMapTransparent,
|
||||
clamp(uvtiled + vec2(x, y) / smSize, 0.0, 1.0));
|
||||
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
|
||||
}
|
||||
}
|
||||
result *= transResult / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -151,7 +151,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV);
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
|
||||
@ -137,7 +137,7 @@ void main() {
|
||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV);
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
@ -146,7 +146,7 @@ void main() {
|
||||
envl.rgb *= envmapStrength * voxelgiEnv * occspec.x;
|
||||
|
||||
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
|
||||
vec3 color = trace.rgb * albedo * (1.0 - F);
|
||||
vec3 color = trace.rgb * diffuseIBL(albedo, roughness, f0, dotNV) * (1.0 - F);
|
||||
color += envl * (1.0 - trace.a);
|
||||
|
||||
imageStore(voxels_diffuse, ivec2(pixel), vec4(color, 1.0));
|
||||
|
||||
@ -69,7 +69,7 @@ void main() {
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
|
||||
float occ = 1.0 - traceShadow(P, n, voxels, voxelsSDF, normalize(lPos - P), clipmaps, pixel);
|
||||
float occ = 1.0 - traceShadow(P, n, voxels, voxelsSDF, normalize(lPos - P), clipmaps, pixel, vec2(0.0));
|
||||
|
||||
imageStore(voxels_shadows, ivec2(pixel), vec4(occ));
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ class CurveObject extends Object {
|
||||
};
|
||||
|
||||
for (spline in data.splines) {
|
||||
var newSpline = {
|
||||
var newSpline: TSpline = {
|
||||
points: [],
|
||||
closed: spline.closed,
|
||||
resolution: spline.resolution,
|
||||
@ -441,7 +441,7 @@ class CurveObject extends Object {
|
||||
|
||||
for (splineIndex in 0...splinesLength) {
|
||||
var spline = data.splines[splineIndex];
|
||||
var matIdx = spline.material_index != null ? spline.material_index : 0;
|
||||
var matIdx = spline.material_index;
|
||||
if (!indicesByMaterial.exists(matIdx)) indicesByMaterial.set(matIdx, []);
|
||||
var indices = indicesByMaterial.get(matIdx);
|
||||
|
||||
@ -704,7 +704,7 @@ class CurveObject extends Object {
|
||||
|
||||
for (splineIndex in 0...splinesLength) {
|
||||
var spline = data.splines[splineIndex];
|
||||
var matIdx = spline.material_index != null ? spline.material_index : 0;
|
||||
var matIdx = spline.material_index;
|
||||
if (!indicesByMaterial.exists(matIdx)) indicesByMaterial.set(matIdx, []);
|
||||
var indices = indicesByMaterial.get(matIdx);
|
||||
|
||||
@ -1032,7 +1032,8 @@ class CurveObject extends Object {
|
||||
if (basePos == null) return null;
|
||||
|
||||
var baseVertCount = Std.int(basePos.length / 4);
|
||||
var baseScale = baseRaw.scale_pos;
|
||||
var baseScale: kha.FastFloat = 1.0;
|
||||
if (baseRaw.scale_pos != null) baseScale = baseRaw.scale_pos;
|
||||
|
||||
var minVal = 1e10;
|
||||
var maxVal = -1e10;
|
||||
|
||||
@ -333,7 +333,7 @@ class Inc {
|
||||
var shadowmap = getShadowMapAtlas(atlas, true);
|
||||
path.setTargetStream(shadowmap);
|
||||
|
||||
path.clearTarget(0xffffff, 0.0);
|
||||
path.currentG.clear(0xffffffff, 0.0);
|
||||
|
||||
for (tile in atlas.activeTiles) {
|
||||
if (tile.light == null || !tile.light.visible || tile.light.culledLight
|
||||
@ -549,7 +549,7 @@ class Inc {
|
||||
for (i in 0...faces) {
|
||||
if (faces > 1) path.currentFace = i;
|
||||
path.setTarget(shadowmap_transparent);
|
||||
path.clearTarget(0xffffff, 0.0);
|
||||
path.currentG.clear(0xffffffff, 0.0);
|
||||
if (l.data.raw.cast_shadow) {
|
||||
path.drawMeshes("shadowmap_transparent");
|
||||
}
|
||||
|
||||
@ -543,7 +543,7 @@ class RenderPathDeferred {
|
||||
t2.format = "RGBA64";
|
||||
path.createRenderTarget(t2);
|
||||
path.setTarget("empty_shadowmap_transparent");
|
||||
path.clearTarget(0xffffffff, null);
|
||||
path.currentG.clear(0xffffffff, null);
|
||||
#end
|
||||
}
|
||||
#end
|
||||
@ -936,6 +936,80 @@ class RenderPathDeferred {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssrefr != false)
|
||||
{
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("gbuffer0", "gbuffer1"); // Unbind depth so we can read it
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("tex"));
|
||||
#end
|
||||
|
||||
//save depth
|
||||
path.setTarget("gbufferD1");
|
||||
path.bindTarget("_main", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("gbuffer0", "tex"); // Re-bind depth
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("gbuffer0"));
|
||||
#end
|
||||
|
||||
//save background color
|
||||
path.setTarget("refr");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("gbuffer0", ["gbuffer1", "gbuffer_refraction"]);
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrs
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("buf");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("gbufferD1", "gbufferD1");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.bindTarget("gbuffer1", "gbuffer1");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer_refraction", "gbuffer_refraction");
|
||||
|
||||
path.drawShader("shader_datas/ssrefr_pass/ssrefr_pass");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("buf", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_translucency && !rp_ssrefr && rp_ssr)
|
||||
{
|
||||
path.setTarget("tex");
|
||||
path.drawMeshes("depth");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssr != false) {
|
||||
@ -1016,73 +1090,6 @@ class RenderPathDeferred {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssrefr != false)
|
||||
{
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("gbuffer0", "gbuffer1"); // Unbind depth so we can read it
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("tex"));
|
||||
#end
|
||||
|
||||
//save depth
|
||||
path.setTarget("gbufferD1");
|
||||
path.bindTarget("_main", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("gbuffer0", "tex"); // Re-bind depth
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("gbuffer0"));
|
||||
#end
|
||||
|
||||
//save background color
|
||||
path.setTarget("refr");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("gbuffer0", ["gbuffer1", "gbuffer_refraction"]);
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrs
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("buf");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("gbufferD1", "gbufferD1");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.bindTarget("gbuffer1", "gbuffer1");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer_refraction", "gbuffer_refraction");
|
||||
|
||||
path.drawShader("shader_datas/ssrefr_pass/ssrefr_pass");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("buf", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_chromatic_aberration
|
||||
{
|
||||
path.setTarget("buf");
|
||||
|
||||
@ -968,6 +968,7 @@ class DebugConsole extends Trait {
|
||||
ui.unindent();
|
||||
}
|
||||
|
||||
#if js
|
||||
if (ui.panel(Id.handle({selected: false}), "Console")) {
|
||||
ui.indent();
|
||||
var t = ui.textInput(Id.handle());
|
||||
@ -977,6 +978,7 @@ class DebugConsole extends Trait {
|
||||
}
|
||||
ui.unindent();
|
||||
}
|
||||
#end
|
||||
}
|
||||
if (ui.tab(htab, lastTraces[0] == "" ? "Console" : lastTraces[0].substr(0, 20))) {
|
||||
#if js
|
||||
|
||||
@ -71,7 +71,7 @@ def init_categories():
|
||||
lnx_nodes.add_category('Renderpath', icon='STICKY_UVS_LOC', section="graphics")
|
||||
|
||||
lnx_nodes.add_category('Sound', icon='OUTLINER_OB_SPEAKER', section="sound")
|
||||
lnx_nodes.add_category('3D_Audio', icon='SPEAKER', section="sound")
|
||||
lnx_nodes.add_category('Audio_3D', icon='SPEAKER', section="sound")
|
||||
|
||||
lnx_nodes.add_category('Miscellaneous', icon='RESTRICT_COLOR_ON', section="misc")
|
||||
lnx_nodes.add_category('Custom', icon='PLUGIN', section="misc")
|
||||
|
||||
@ -6,7 +6,7 @@ class AudioDSPFilterNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioDSPFilterNode'
|
||||
bl_label = 'DSP Filter'
|
||||
bl_description = 'DSP Audio Filter for lowpass/bandpass/highpass '
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
@ -27,5 +27,5 @@ class AudioDSPFilterNode(LnxLogicTreeNode):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioDSPFilterNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioDSPHaasEffectNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioDSPHaasEffectNode'
|
||||
bl_label = 'DSP Haas Effect'
|
||||
bl_description = 'DSP Audio Haas Effect'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
|
||||
@ -19,5 +19,5 @@ class AudioDSPHaasEffectNode(LnxLogicTreeNode):
|
||||
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioDSPHaasEffectNode.on_register()
|
||||
@ -6,14 +6,14 @@ class AudioHRTFPannerNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioHRTFPannerNode'
|
||||
bl_label = 'HRTF Panner'
|
||||
bl_description = 'Create 3D audio HRTF Panner'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
def update_input(self, context):
|
||||
while len(self.inputs) > 5:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Custom':
|
||||
self.add_input('LnxStringSocket', 'File Name', default_value=0)
|
||||
self.add_input('LnxStringSocket', 'File Name', default_value='')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
@ -35,5 +35,5 @@ class AudioHRTFPannerNode(LnxLogicTreeNode):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioHRTFPannerNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioLoadNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioLoadNode'
|
||||
bl_label = 'Load Audio'
|
||||
bl_description = 'Load audio'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
def update_input(self, context):
|
||||
@ -39,5 +39,5 @@ class AudioLoadNode(LnxLogicTreeNode):
|
||||
#col.prop_search(self, 'property0', bpy.data, 'sounds', icon='NONE', text='')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioLoadNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioPauseNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioPauseNode'
|
||||
bl_label = 'Pause Audio'
|
||||
bl_description = 'Trigger the pause function on audio'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
|
||||
@ -18,5 +18,5 @@ class AudioPauseNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxDynamicSocket', 'Audio')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioPauseNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioPlayNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioPlayNode'
|
||||
bl_label = 'Play Audio'
|
||||
bl_description = 'Trigger the play function on audio'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
|
||||
@ -19,5 +19,5 @@ class AudioPlayNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxDynamicSocket', 'Audio')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioPlayNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioStereoPannerNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioStereoPannerNode'
|
||||
bl_label = 'Stereo Panner'
|
||||
bl_description = 'Create 2D audio Stereo Panner'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
def update_input(self, context):
|
||||
@ -34,5 +34,5 @@ class AudioStereoPannerNode(LnxLogicTreeNode):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioStereoPannerNode.on_register()
|
||||
@ -6,7 +6,7 @@ class AudioStopNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAudioStopNode'
|
||||
bl_label = 'Stop Audio'
|
||||
bl_description = 'Trigger the stop function on audio'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
|
||||
@ -19,5 +19,5 @@ class AudioStopNode(LnxLogicTreeNode):
|
||||
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
AudioStopNode.on_register()
|
||||
@ -5,7 +5,7 @@ class GetAudioPositionNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNGetAudioPositionNode'
|
||||
bl_label = 'Get Audio Position'
|
||||
bl_description = 'Gets the current playback position of 3D audio in seconds.'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
@ -13,5 +13,5 @@ class GetAudioPositionNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxFloatSocket', 'Position (seconds)')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
GetAudioPositionNode.on_register()
|
||||
@ -5,7 +5,7 @@ class SetAudioPositionNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNSetAudioPositionNode'
|
||||
bl_label = 'Set Audio Position'
|
||||
bl_description = 'Sets the playback position of 3D audio'
|
||||
lnx_category = '3D_Audio'
|
||||
lnx_category = 'Audio_3D'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
@ -16,5 +16,5 @@ class SetAudioPositionNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def register():
|
||||
add_category('3D_Audio', icon='SOUND')
|
||||
add_category('Audio_3D', icon='SOUND')
|
||||
SetAudioPositionNode.on_register()
|
||||
@ -18,4 +18,9 @@ class GetTransformNode(LnxLogicTreeNode):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
return NodeReplacement(
|
||||
'LNGetTransformNode', self.lnx_version, 'LNGetTransformNode', 2,
|
||||
in_socket_mapping={0: 0},
|
||||
out_socket_mapping={0: 0},
|
||||
input_defaults={1: False},
|
||||
)
|
||||
|
||||
@ -173,6 +173,19 @@ def add_world_defs():
|
||||
wrd.world_defs += '_Brdf'
|
||||
assets.add_khafile_def("lnx_brdf")
|
||||
|
||||
if rpdat.lnx_diffuse_model == 'Burley':
|
||||
wrd.world_defs += '_BurleyDiffuse'
|
||||
assets.add_khafile_def('lnx_burley_diffuse')
|
||||
elif rpdat.lnx_diffuse_model == 'EON':
|
||||
wrd.world_defs += '_EONDiffuse'
|
||||
assets.add_khafile_def('lnx_eon_diffuse')
|
||||
elif rpdat.lnx_diffuse_model == 'Gotanda':
|
||||
wrd.world_defs += '_GotandaDiffuse'
|
||||
assets.add_khafile_def('lnx_gotanda_diffuse')
|
||||
elif rpdat.lnx_diffuse_model == 'Chan':
|
||||
wrd.world_defs += '_ChanDiffuse'
|
||||
assets.add_khafile_def('lnx_chan_diffuse')
|
||||
|
||||
def build():
|
||||
rpdat = lnx.utils.get_rp()
|
||||
project_path = lnx.utils.get_fp()
|
||||
|
||||
@ -247,6 +247,9 @@ def make(context_id, rpasses, shadowmap=False, shadowmap_transparent=False):
|
||||
if parse_opacity and not shadowmap_transparent:
|
||||
if mat_state.material.lnx_discard:
|
||||
opac = mat_state.material.lnx_discard_opacity_shadows
|
||||
frag.write('if (opacity < {0}) discard;'.format(opac))
|
||||
elif rpdat.rp_renderer == 'Deferred' and 'translucent' in rpasses and not shadowmap:
|
||||
pass
|
||||
else:
|
||||
opac = '1.0'
|
||||
frag.write('if (opacity < {0}) discard;'.format(opac))
|
||||
|
||||
@ -737,7 +737,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
if '_Rad' in wrd.world_defs:
|
||||
frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));')
|
||||
|
||||
frag.write('envl *= albedo;')
|
||||
frag.write('envl *= diffuseIBL(albedo, roughness, f0, dotNV);')
|
||||
|
||||
if '_Brdf' in wrd.world_defs:
|
||||
frag.write('envl.rgb *= 1.0 - F;')
|
||||
@ -771,7 +771,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
|
||||
if '_VoxelGI' in wrd.world_defs:
|
||||
frag.write('vec4 diffuse_indirect = traceDiffuse(wposition, n, voxels, clipmaps);')
|
||||
frag.write('indirect = (diffuse_indirect.rgb * albedo * (1.0 - F) + envl * (1.0 - diffuse_indirect.a)) * voxelgiDiff;')
|
||||
frag.write('indirect = (diffuse_indirect.rgb * diffuseIBL(albedo, roughness, f0, dotNV) * (1.0 - F) + envl * (1.0 - diffuse_indirect.a)) * voxelgiDiff;')
|
||||
frag.write('if (roughness < 1.0 && specular > 0.0) {')
|
||||
frag.write(' indirect += traceSpecular(wposition, n, voxels, voxelsSDF, vVec, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity).rgb * F * voxelgiRefl;')
|
||||
frag.write('}')
|
||||
@ -847,7 +847,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
if '_ExtBRDF' in wrd.world_defs:
|
||||
frag.write('float sunLayerWeight;')
|
||||
frag.write('vec3 sdirect = applyExtBRDFLayers(')
|
||||
frag.write(' lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular,')
|
||||
frag.write(' diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular,')
|
||||
frag.write(' albedo, f0, roughness, sdotNL, dotNV, sdotNH, sdotVH, n, sunDir, vVec, sh')
|
||||
if '_ClearCoat' in wrd.world_defs:
|
||||
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
|
||||
@ -858,7 +858,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
frag.write(', sunLayerWeight);')
|
||||
frag.write('direct += sdirect * sunCol * svisibility;')
|
||||
else:
|
||||
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
|
||||
frag.write('direct += (diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
|
||||
# sun
|
||||
|
||||
if '_SinglePoint' in wrd.world_defs:
|
||||
@ -880,6 +880,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
else:
|
||||
frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True)
|
||||
frag.add_uniform('samplerCubeShadow shadowMapPoint[1]', included=True)
|
||||
if is_transparent_shadows:
|
||||
frag.add_uniform('samplerCube shadowMapPointTransparent[1]', included=True)
|
||||
frag.write('direct += sampleLight(')
|
||||
frag.write(' wposition, n, vVec, dotNV, pointPos, pointCol, albedo, roughness, specular, f0')
|
||||
|
||||
@ -20,7 +20,7 @@ else:
|
||||
def make(context_id):
|
||||
con_refract = mat_state.data.add_context({
|
||||
'name': context_id,
|
||||
'depth_write': False,
|
||||
'depth_write': True,
|
||||
'compare_mode': 'less',
|
||||
'cull_mode': 'clockwise',
|
||||
'blend_source': 'blend_one',
|
||||
|
||||
@ -411,6 +411,7 @@ def make_gi(context_id):
|
||||
frag.add_uniform('vec4 pointLightDataArray[maxLightsCluster]', link='_pointLightsAtlasArray', included=True)
|
||||
else:
|
||||
frag.add_uniform('samplerCubeShadow shadowMapPoint[4]', included=True)
|
||||
if is_transparent_shadows:
|
||||
frag.add_uniform('samplerCube shadowMapPointTransparent[4]', included=True)
|
||||
|
||||
vert.add_out('vec4 wvppositionGeom')
|
||||
|
||||
@ -55,6 +55,8 @@ def get_rpasses(material):
|
||||
ar.append('voxel')
|
||||
if rpdat.rp_renderer == 'Forward' and rpdat.rp_depthprepass and not material.lnx_blending and not material.lnx_particle_flag:
|
||||
ar.append('depth')
|
||||
if rpdat.rp_renderer == 'Deferred' and rpdat.rp_ssr and 'translucent' in ar:
|
||||
ar.append('depth')
|
||||
|
||||
if material.lnx_cast_shadow and rpdat.rp_shadows and ('mesh' in ar):
|
||||
if 'translucent' in ar or 'refraction' in ar:
|
||||
|
||||
@ -256,7 +256,10 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(__REG_CLASSES):
|
||||
try:
|
||||
bpy.utils.unregister_class(cls)
|
||||
except RuntimeError:
|
||||
pass
|
||||
del bpy.types.Object.lnx_propertylist
|
||||
del bpy.types.Object.lnx_propertylist_index
|
||||
del bpy.types.Scene.lnx_propertylist
|
||||
|
||||
@ -486,6 +486,14 @@ class LnxRPListItem(bpy.types.PropertyGroup):
|
||||
('Solid', 'Solid', 'Solid'),
|
||||
],
|
||||
name="Materials", description="Material builder", default='Full', update=update_material_model)
|
||||
lnx_diffuse_model: EnumProperty(
|
||||
items=[('Lambert', 'Lambert', 'Lambert'),
|
||||
('Burley', 'Burley', 'Burley with Frostbite energy renormalization'),
|
||||
('EON', 'Oren-Nayar', 'Energy preserving Oren Nayar with multi scatter compensation'),
|
||||
('Gotanda', 'Gotanda GGX Diffuse', 'Microfacet GGX diffuse with Fresnel and visibility'),
|
||||
('Chan', 'Chan Retroreflective', 'GGX microfacet diffuse with retroreflective lobe'),
|
||||
],
|
||||
name="Diffuse BRDF", description="Diffuse BRDF model", default='Burley', update=update_material_model)
|
||||
lnx_rp_displacement: EnumProperty(
|
||||
items=[('Off', 'Off', 'Off'),
|
||||
('Vertex', 'Vertex', 'Vertex'),
|
||||
|
||||
@ -292,39 +292,38 @@ class LNX_PT_TilesheetPanel(bpy.types.Panel):
|
||||
bl_label = "Leenkx Tilesheet"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "render"
|
||||
bl_context = "object"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object is not None and context.object.type == 'MESH'
|
||||
|
||||
def draw_header(self, context):
|
||||
obj = context.object
|
||||
self.layout.prop(obj, "lnx_tilesheet_enabled", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
obj = context.object
|
||||
|
||||
layout.enabled = obj.lnx_tilesheet_enabled
|
||||
layout.prop(obj, "lnx_tilesheet_enabled", text="Enable Tilesheet")
|
||||
|
||||
body = layout.column()
|
||||
body.enabled = obj.lnx_tilesheet_enabled
|
||||
|
||||
# Start action dropdown
|
||||
layout.prop_search(obj, "lnx_tilesheet_default_action", obj, "lnx_tilesheet_actionlist", text="Start Action")
|
||||
body.prop_search(obj, "lnx_tilesheet_default_action", obj, "lnx_tilesheet_actionlist", text="Start Action")
|
||||
|
||||
row = layout.row()
|
||||
row = body.row()
|
||||
row.prop(obj, "lnx_tilesheet_flipx")
|
||||
row.prop(obj, "lnx_tilesheet_flipy")
|
||||
|
||||
# Actions list
|
||||
layout.separator()
|
||||
layout.label(text="Actions")
|
||||
body.separator()
|
||||
body.label(text="Actions")
|
||||
rows = 2
|
||||
if len(obj.lnx_tilesheet_actionlist) > 1:
|
||||
rows = 4
|
||||
row = layout.row()
|
||||
row = body.row()
|
||||
row.template_list("LNX_UL_TilesheetActionList", "The_List", obj, "lnx_tilesheet_actionlist", obj, "lnx_tilesheet_actionlist_index", rows=rows)
|
||||
col = row.column(align=True)
|
||||
col.operator("lnx_tilesheetactionlist.new_item", icon='ADD', text="")
|
||||
@ -340,7 +339,7 @@ class LNX_PT_TilesheetPanel(bpy.types.Panel):
|
||||
# Selected action details (per-action properties)
|
||||
if obj.lnx_tilesheet_actionlist_index >= 0 and len(obj.lnx_tilesheet_actionlist) > 0:
|
||||
adat = obj.lnx_tilesheet_actionlist[obj.lnx_tilesheet_actionlist_index]
|
||||
box = layout.box()
|
||||
box = body.box()
|
||||
# Grid dimensions
|
||||
row = box.row()
|
||||
row.use_property_split = False
|
||||
|
||||
@ -1696,6 +1696,7 @@ class LNX_PT_RenderPathRendererPanel(bpy.types.Panel):
|
||||
if rpdat.rp_renderer == 'Forward':
|
||||
layout.prop(rpdat, 'rp_depthprepass')
|
||||
layout.prop(rpdat, 'lnx_material_model')
|
||||
layout.prop(rpdat, 'lnx_diffuse_model')
|
||||
layout.prop(rpdat, 'rp_translucency_state')
|
||||
layout.prop(rpdat, 'rp_overlays_state')
|
||||
layout.prop(rpdat, 'rp_decals_state')
|
||||
|
||||
1271
leenkx/blender/theme/BlenderLeenkxTheme.xml
Normal file
1271
leenkx/blender/theme/BlenderLeenkxTheme.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
leenkx/blender/theme/LeenkxLogo.png
Normal file
BIN
leenkx/blender/theme/LeenkxLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
10
leenkx/blender/theme/blender_manifest.toml
Normal file
10
leenkx/blender/theme/blender_manifest.toml
Normal file
@ -0,0 +1,10 @@
|
||||
schema_version = "1.0.0"
|
||||
id = "Leenkx_Theme"
|
||||
name = "Leenkx Theme"
|
||||
version = "1.0.0"
|
||||
tagline = "Leenkx theme for Blender"
|
||||
maintainer = "Onek8 <info@leenkx.com>"
|
||||
type = "theme"
|
||||
tags = ["Dark","Leenkx", "Solarized"]
|
||||
blender_version_min = "5.0.0"
|
||||
license = ["SPDX:GPL-2.0-or-later"]
|
||||
BIN
leenkx/blender/theme/splash.png
Normal file
BIN
leenkx/blender/theme/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 304 KiB |
240
leenkx/blender/theme/theme.py
Normal file
240
leenkx/blender/theme/theme.py
Normal file
@ -0,0 +1,240 @@
|
||||
import os
|
||||
import traceback
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
|
||||
preview_collection = None
|
||||
logo_icon_id = 0
|
||||
splash_icon_id = 0
|
||||
original_splash_cls = None
|
||||
|
||||
|
||||
def load_icons():
|
||||
global preview_collection, logo_icon_id, splash_icon_id
|
||||
if preview_collection is not None:
|
||||
return
|
||||
preview_collection = bpy.utils.previews.new()
|
||||
theme_dir = os.path.dirname(__file__)
|
||||
logo_path = os.path.join(theme_dir, "LeenkxLogo.png")
|
||||
splash_path = os.path.join(theme_dir, "splash.png")
|
||||
if os.path.exists(logo_path):
|
||||
preview_collection.load("logo", logo_path, 'IMAGE', force_reload=True)
|
||||
logo_icon_id = preview_collection["logo"].icon_id
|
||||
else:
|
||||
print("Leenkx theme: logo not found at", logo_path)
|
||||
if os.path.exists(splash_path):
|
||||
preview_collection.load("splash", splash_path, 'IMAGE', force_reload=True)
|
||||
splash_icon_id = preview_collection["splash"].icon_id
|
||||
else:
|
||||
print("Leenkx theme: splash not found at", splash_path)
|
||||
|
||||
|
||||
def install_theme(sdk_path: str):
|
||||
theme_xml = os.path.join(sdk_path, "leenkx", "blender",
|
||||
"theme", "BlenderLeenkxTheme.xml")
|
||||
if not os.path.exists(theme_xml):
|
||||
print("Leenkx theme: theme XML not found at", theme_xml)
|
||||
return
|
||||
|
||||
bpy.ops.preferences.theme_install(
|
||||
filepath=theme_xml, overwrite=True)
|
||||
|
||||
|
||||
def setup_splash(sdk_path: str):
|
||||
splash_png = os.path.join(sdk_path, "leenkx", "blender",
|
||||
"theme", "splash.png")
|
||||
if os.path.exists(splash_png):
|
||||
os.environ["BLENDER_CUSTOM_SPLASH"] = splash_png
|
||||
else:
|
||||
print("Leenkx splash: splash.png not found at", splash_png)
|
||||
|
||||
|
||||
class LEENKX_MT_splash(Menu):
|
||||
bl_label = "Splash"
|
||||
bl_idname = "WM_MT_splash"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
layout.emboss = 'PULLDOWN_MENU'
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col1 = split.column()
|
||||
col1.label(text="New File")
|
||||
|
||||
bpy.types.TOPBAR_MT_file_new.draw_ex(col1, context, use_splash=True)
|
||||
|
||||
col2 = split.column()
|
||||
col2_title = col2.row()
|
||||
|
||||
found_recent = col2.template_recent_files(rows=5)
|
||||
|
||||
if found_recent:
|
||||
col2_title.label(text="Recent Files")
|
||||
|
||||
col_more = col2.column()
|
||||
col_more.operator_context = 'INVOKE_DEFAULT'
|
||||
more_props = col_more.operator("wm.search_single_menu", text="More...", icon='VIEWZOOM')
|
||||
more_props.menu_idname = "TOPBAR_MT_file_open_recent"
|
||||
else:
|
||||
col2_title.label(text="Getting Started")
|
||||
|
||||
col2.operator("wm.url_open", text="Leenkx Docs",
|
||||
icon='URL').url = "https://leenkx.com/docs"
|
||||
col2.operator("wm.url_open", text="Support",
|
||||
icon='URL').url = "https://leenkx.com/support"
|
||||
col2.operator("wm.url_open", text="Community",
|
||||
icon='URL').url = "https://leenkx.com/community"
|
||||
col2.operator("wm.url_open", text="GitHub",
|
||||
icon='URL').url = "https://github.com/leenkx/leenkx"
|
||||
|
||||
col_sep = layout.column()
|
||||
col_sep.separator()
|
||||
col_sep.separator(type='LINE')
|
||||
col_sep.separator()
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col1 = split.column()
|
||||
sub = col1.row()
|
||||
sub.operator_context = 'INVOKE_DEFAULT'
|
||||
sub.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
|
||||
col1.operator("wm.recover_last_session", icon='RECOVER_LAST')
|
||||
|
||||
col2 = split.column()
|
||||
|
||||
col2.operator("wm.url_open", text="Support Leenkx",
|
||||
icon='FUND').url = "https://leenkx.com/donate"
|
||||
col2.operator("wm.url_open", text="Leenkx Website",
|
||||
icon='URL').url = "https://leenkx.com"
|
||||
|
||||
layout.separator()
|
||||
|
||||
if (not bpy.app.online_access) and bpy.app.online_access_override:
|
||||
self.layout.label(text="Running in Offline Mode", icon='INTERNET_OFFLINE')
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
||||
def register_splash_menu():
|
||||
global original_splash_cls
|
||||
cls = getattr(bpy.types, "WM_MT_splash", None)
|
||||
if cls is not None and cls is not LEENKX_MT_splash:
|
||||
original_splash_cls = cls
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.utils.register_class(LEENKX_MT_splash)
|
||||
|
||||
|
||||
def unregister_splash_menu():
|
||||
global original_splash_cls
|
||||
bpy.utils.unregister_class(LEENKX_MT_splash)
|
||||
if original_splash_cls is not None:
|
||||
bpy.utils.register_class(original_splash_cls)
|
||||
original_splash_cls = None
|
||||
|
||||
|
||||
saved_draws = {}
|
||||
|
||||
|
||||
def override_draw(bl_idname, new_draw):
|
||||
cls = getattr(bpy.types, bl_idname, None)
|
||||
if cls is None:
|
||||
print("Leenkx menu: class not found", bl_idname)
|
||||
return
|
||||
if bl_idname not in saved_draws:
|
||||
saved_draws[bl_idname] = cls.draw
|
||||
elif cls.draw is new_draw:
|
||||
return
|
||||
cls.draw = new_draw
|
||||
|
||||
|
||||
def restore_draw(bl_idname):
|
||||
cls = getattr(bpy.types, bl_idname, None)
|
||||
if cls is not None and bl_idname in saved_draws:
|
||||
cls.draw = saved_draws[bl_idname]
|
||||
|
||||
def editor_menus_draw(self, context):
|
||||
layout = self.layout
|
||||
if logo_icon_id:
|
||||
layout.menu("TOPBAR_MT_blender", text="", icon_value=logo_icon_id)
|
||||
else:
|
||||
layout.menu("TOPBAR_MT_blender", text="Leenkx")
|
||||
layout.menu("TOPBAR_MT_file")
|
||||
layout.menu("TOPBAR_MT_edit")
|
||||
layout.menu("TOPBAR_MT_render")
|
||||
layout.menu("TOPBAR_MT_window")
|
||||
layout.menu("TOPBAR_MT_help")
|
||||
|
||||
|
||||
def blender_draw(self, _context):
|
||||
layout = self.layout
|
||||
layout.operator("wm.splash", text="Leenkx Splash")
|
||||
layout.separator()
|
||||
layout.operator("preferences.app_template_install",
|
||||
text="Install Application Template...")
|
||||
layout.separator()
|
||||
layout.menu("TOPBAR_MT_blender_system")
|
||||
|
||||
|
||||
def help_draw(self, context):
|
||||
layout = self.layout
|
||||
show_developer = context.preferences.view.show_developer_ui
|
||||
|
||||
layout.operator("wm.url_open", text="Leenkx Docs",
|
||||
icon='URL').url = "https://leenkx.com/api"
|
||||
layout.operator("wm.url_open", text="Leenkx Support",
|
||||
icon='URL').url = "https://leenkx.com/contact"
|
||||
layout.operator("wm.url_open", text="Tutorials",
|
||||
icon='URL').url = "https://leenkx.com/tutorials"
|
||||
layout.operator("wm.url_open", text="Community",
|
||||
icon='URL').url = "https://leenkx.com/community"
|
||||
layout.operator("wm.url_open", text="Support Leenkx (Donate)",
|
||||
icon='FUND').url = "https://leenkx.com/donate"
|
||||
|
||||
layout.separator()
|
||||
|
||||
if show_developer:
|
||||
layout.operator("wm.url_open", text="Developer Docs",
|
||||
icon='URL').url = "https://leenkx.com/wiki"
|
||||
layout.operator("wm.url_open_preset",
|
||||
text="Python API Reference").type = 'API'
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("wm.url_open", text="Report a Bug",
|
||||
icon='URL').url = "https://leenkx.com/contact"
|
||||
layout.operator("wm.sysinfo")
|
||||
|
||||
|
||||
def register(sdk_path: str):
|
||||
install_theme(sdk_path)
|
||||
setup_splash(sdk_path)
|
||||
load_icons()
|
||||
register_splash_menu()
|
||||
override_draw("TOPBAR_MT_editor_menus", editor_menus_draw)
|
||||
override_draw("TOPBAR_MT_blender", blender_draw)
|
||||
override_draw("TOPBAR_MT_help", help_draw)
|
||||
|
||||
|
||||
def unregister():
|
||||
restore_draw("TOPBAR_MT_editor_menus")
|
||||
restore_draw("TOPBAR_MT_blender")
|
||||
restore_draw("TOPBAR_MT_help")
|
||||
saved_draws.clear()
|
||||
unregister_splash_menu()
|
||||
|
||||
global preview_collection
|
||||
if preview_collection is not None:
|
||||
bpy.utils.previews.remove(preview_collection)
|
||||
preview_collection = None
|
||||
os.environ.pop("BLENDER_CUSTOM_SPLASH", None)
|
||||
|
||||
window = bpy.context.window_manager.windows[0]
|
||||
if bpy.app.version >= (3, 0, 0):
|
||||
with bpy.context.temp_override(window=window):
|
||||
bpy.ops.preferences.reset_default_theme()
|
||||
else:
|
||||
override = bpy.context.copy()
|
||||
override['window'] = window
|
||||
bpy.ops.preferences.reset_default_theme(override_context=override)
|
||||
Reference in New Issue
Block a user