Recent Posts

Pages: [1] 2 3 ... 10
1
Runtime activation of Common Controls v6 (Manifest-free alternative)

For years, the standard way to enable modern Windows visual styles (ComCtl32 v6) has been through a manifest, either embedded or via:

Code: [Select]
// Include the v6 common controls in the manifest
#pragma comment(linker,""/manifestdependency:type='win32'
name='Microsoft.Windows.Common-Controls' version='6.0.0.0'
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")

While this works, it introduces a dependency on the linker and can sometimes lead to inconsistent behavior depending on build settings, resources, or memory conditions.


Alternative: Runtime activation (no manifest required)

It is possible to activate visual styles dynamically at runtime using an activation context (ACTCTX).
This method loads the ComCtl32 v6 resources directly from shell32.dll.

Code: [Select]
static HANDLE    g_hActCtx = INVALID_HANDLE_VALUE;
static ULONG_PTR g_ulActCookie = 0;
static BOOL      g_bActCtxActive = FALSE;

static BOOL EnableVisualStylesRuntime(VOID) {
    WCHAR dir[MAX_PATH];
    DWORD cch = GetSystemDirectory(dir, MAX_PATH);
    if (!cch || cch >= MAX_PATH) return FALSE;

    ACTCTX actCtx; ClearMemory(&actCtx, sizeof(actCtx));
    actCtx.cbSize = sizeof(actCtx);
    actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
    actCtx.lpSource = TEXT("shell32.dll");
    actCtx.lpAssemblyDirectory = dir;
    actCtx.lpResourceName = MAKEINTRESOURCE(124);

    g_hActCtx = CreateActCtx(&actCtx);
    if (g_hActCtx == INVALID_HANDLE_VALUE) return FALSE;

    if (!ActivateActCtx(g_hActCtx, &g_ulActCookie)) {
        ReleaseActCtx(g_hActCtx);
        g_hActCtx = INVALID_HANDLE_VALUE;
        return FALSE;
    }

    g_bActCtxActive = TRUE;
    return TRUE;
}

static VOID DisableVisualStylesRuntime(VOID) {
    if (g_bActCtxActive) {
        DeactivateActCtx(0, g_ulActCookie);
        g_bActCtxActive = FALSE;
        g_ulActCookie = 0;
    }

    if (g_hActCtx != INVALID_HANDLE_VALUE) {
        ReleaseActCtx(g_hActCtx);
        g_hActCtx = INVALID_HANDLE_VALUE;
    }
}


Important notes

* Must be called very early (ideally at the start of wWinMain or inside your core init like skInitEngine).
* Affects all subsequently created controls (ComboBox, ListView, TreeView, etc.).
* Ensures consistent theming without relying on external manifests.
* Particularly useful in:
   - CRT-free builds
   - DLL-based UI engines (e.g. WinLIFT)
   - Custom control frameworks
* Avoid calling it after controls are already created.


Why this matters

In practice, inconsistent behavior of controls (especially owner-drawn or themed ones) often comes from:

* Missing or partial v6 activation
* Timing issues (controls created before activation)
* Resource/memory edge cases

By forcing activation at runtime, behavior becomes deterministic and uniform.


Conclusion

This approach is a reliable replacement for manifest-based activation and gives full control over when and how visual styles are enabled.

In my case, integrating this directly into the initialization phase removed all inconsistencies without requiring any manifest handling.


Tip

If you already use a framework like WinLIFT, placing this call inside the engine initialization guarantees that all controls benefit from v6 styling automatically.
2
64-bit SDK programming / zBff.dll (C/C++ source code)
« Last post by Patrice Terrier on March 31, 2026, 10:08:19 am »
C/C++ Visual Studio 2022 source code for zBff.dll

Custom file dialog replacement built on GDImage and WinLIFT, providing full control over UI, rendering, and interaction.

Core features

  • Custom message loop
       
    • Fine-grained control over message flow
    • Idle-time processing (folder watch, process tracking)
    • Automatic Z-order restore after launched process termination

  • Full UI ownership (no common dialog)
       
    • Edit path + filter combo + view selector
    • TreeView (folder navigation)
    • ListView (details mode with sorting)
    • GDImage-based thumbnail view (custom rendered)

  • Dual view system
       
    • List mode (Explorer-like, sortable columns)
    • Thumbnail mode (GDImage objects, atlas + real previews)

  • Advanced thumbnail pipeline
       
    • Image formats via GDImage (including ORB/PNG-based content)
    • Embedded album art extraction (APIC / WMA tags)
    • Dynamic atlas fallback for non-previewable files

  • Custom drag & drop (no OLE)
       
    • WM_DROPFILES-based implementation
    • Multi-selection support via MULTI_SZ
    • Layered drag image with alpha blending
    • Real-time drop target detection (child window aware)
    • Dynamic cursor feedback over valid targets

  • Process integration
       
    • Launch files via ShellExecuteEx or custom ProcessCreate
    • Track external process lifetime (HANDLE-based)
    • Automatic dialog refocus when process exits

  • Context menu system
       
    • Open / Open with
    • Custom ObjReader integration (.orb)
    • Copy path / Delete / Properties
    • Registry-driven command resolution

  • Persistent state
       
    • Last folder, filter, view mode
    • Sort column + direction
    • Tree expansion state
    • Stored in lightweight binary config

  • Folder monitoring
       
    • Timestamp-based change detection
    • Auto-refresh with scroll/selection preservation

  • Save/Open behavior control
       
    • Unified engine with ZB_OPEN / ZB_SAVE
    • Automatic extension handling
    • Filter-aware filename correction

  • Skinning / theming
       
    • Full WinLIFT integration
    • V6 controls handled internally
    • GDImage rendering for custom visuals
Design goals

  • No dependency on standard Windows dialogs
  • No OLE drag & drop (lightweight alternative)
  • Minimal external dependencies
  • Full control over behavior, rendering, and interaction

Note: GoodMsg is the central point to add multiple language support.
3
64-bit SDK programming / zBrowser demo
« Last post by Patrice Terrier on March 27, 2026, 05:53:51 pm »
This is a small demo to expose the use of zBrowser with a skinned application.

The use of WinLIFT/GDImage is a mandatory to render the thumbnails (images, .orb thumbnail, audio tag cover art).
It is also important to use Common Controls (ComCtl32 v6), to use skinned combo drop down.

You can select one file, or several if you hold down the CTRL key while clicking on thumbnails.
Use right mouse click, to popup the contextual menu, to fire a specific actions.

Drag and drop, is available from a mouse wheel click, to drop a thumbnail onto MBox64 or ObjReader64 (audio, image, .orb, .obj, folder).
A complete folder audio, could be used with Mbox64.
That would work with any application using the classic DragAcceptFiles.
4
Get ObjReader & Documentation / Re: ObjReader 4.00+ - the .ORB challenge
« Last post by Patrice Terrier on March 27, 2026, 10:13:01 am »
The previous post attachment has been updated, because the new code added to support .glb .gltf, broke the legacy .obj to .orb process.
5
64-bit SDK programming / zBrowser
« Last post by Patrice Terrier on March 20, 2026, 06:32:51 pm »
zBrowser – Lightweight Win32 File Dialog Replacement

I’ve just integrated a new feature into my custom file dialog zBrowser, used across my apps (MBox64, ObjReader, etc.).



What it is:
A fully custom, skinned, Win32 file explorer built on top of GDImage + WinLIFT, designed to replace the standard Open/Save dialog with something faster, cleaner, and fully controllable.

Key features:

* ✔ Dual view: List / Thumbnails (with real previews)
* ✔ Native shell icons + overlays
* ✔ Fast folder navigation (TreeView + ListView sync)
* ✔ Multi-selection support
* ✔ Built-in media detection (audio, image, ORB, etc.)
* ✔ Custom popup menu ("Open with", Properties, etc.)
* ✔ Persistent state (folder, sorting, view mode)

New addition: Drag & Drop (2 KB only)

* ✔ Custom drag visual (layered window, alpha = 200)
* ✔ Multi-file drag (true MULTI_SZ → CF_HDROP)
* ✔ Works between my apps (MBox64 ⇄ ObjReader)
* ✔ No OLE / COM / ATL / MFC
* ✔ Pure Win32 (WM_DROPFILES)

Design philosophy:

* No bloat
* No hidden frameworks
* Full control
* Maximum reuse of existing engine code

Everything is built using existing GDImage objects (selection, thumbnails, labels), so there is zero duplication and perfect consistency across applications.

Limitations (by design):

* Does not target Explorer / modern apps (DirectUIHWND)
* OLE drag & drop intentionally avoided to keep things lightweight

Result:
A fast, clean, and fully controllable file dialog with integrated drag & drop, all in a minimal footprint.

---

This is now the default file interface for my toolchain.
6
64-bit SDK programming / Capture
« Last post by Patrice Terrier on March 12, 2026, 07:59:15 am »
Tiny screen capture utility.

I needed it, thus I wrote it.

• No install
• Single executable (only 6 Kb)
• Saves capture beside the executable
• Ideal for quick bug reports or forum screenshots

The full C/C++ project is attached to this post

7
Get ObjReader & Documentation / Re: ObjReader 4.00+ - the .ORB challenge
« Last post by Patrice Terrier on February 18, 2026, 06:31:15 pm »
ObjReader / orbtool — New GLB Import Feature

I am pleased to introduce a new capability recently added to orbtool:

Direct .GLB → .ORB conversion

This allows modern asset pipelines (Blender, Maya, etc.) to feed ObjReader without relying on the legacy OBJ stage.

------------------------------------------------------------

Why GLB?

GLB is the binary form of glTF and provides several practical advantages:

• compact binary structure 
• faster parsing 
• embedded geometry, materials, and textures 
• fewer ambiguities than text-based formats 

That said, GLB is NOT intended to become a runtime format inside ObjReader.

ORB remains the native, optimized container designed for fast loading and deterministic behavior.

The workflow is intentionally simple:

Code: [Select]
DCC Tool → GLB → orbtool → ORB → ObjReader

GLB acts as an asset source, while ORB stays the final runtime format.

------------------------------------------------------------

Architecture Notes

• GLB parsing is strictly isolated inside orbtool 
• No glTF code is introduced into the runtime engine 
• ORDLL remains lightweight and rendering-focused 
• CRT-free discipline is preserved 

This separation ensures the viewer stays fast and avoids dependency creep.

------------------------------------------------------------

Early Results

Initial integration shows:

• controlled binary growth 
• stable conversion 
• preserved materials 
• clean mesh extraction 

Further optimizations will follow as the pipeline matures.

------------------------------------------------------------

What This Means

This addition quietly moves ObjReader toward a more modern asset workflow while keeping the engine philosophy intact:

✔ preprocess offline 
✔ load fast 
✔ render immediately 

Exactly what a runtime should do.

------------------------------------------------------------

The latest orbtool version is attached to this post, with its full VS2022 C/C++ source code.
The release folder is provided with a ferrari.glb 3D model for test purpose.

Syntax to convert a .glb into a .orb
orbtool -c ferrari.glb -o ferrari.orb

8
64-bit SDK programming / BBP_DiscoBall plugin
« Last post by Patrice Terrier on January 08, 2026, 01:54:21 pm »
BBP_DiscoBall

Converted from https://www.shadertoy.com/view/ssycDR
Original created by Shane on 2022-06-08
Audio + accumulator + BBP_plugin integration by Patrice Terrier



This plugin is based on a GLSL shader by Shane and required a true temporal accumulator to reproduce the original visual quality.

The effect relies on stochastic sampling and progressive convergence over time, which means a classic single-pass shader is not sufficient.
A floating-point ping-pong accumulator is used to achieve stable lighting, clean reflections, and low noise in dark areas.

This version goes further by adding audio-driven behavior:
  • Monotonic, audio-sensitive sphere rotation.
  • Automatic accumulation freeze during strong motion to avoid blur.
  • High sample count for stable dark regions.
  • Fully functional in landscape and portrait modes (BassBox64)
The result is a physically coherent, music-reactive disco sphere without geometry tricks or artificial brightness.

The full VS2022 source code is attached to this post.
You must also copy the OrganicUD.jpg texture, inside the bbplugin\texture folder.
9
64-bit SDK programming / BBP_Glow plugin
« Last post by Patrice Terrier on January 05, 2026, 10:19:41 am »
BBP_Glow

Converted from https://www.shadertoy.com/view/W3tSR4
Original created by Xor on 2025-08-23
Audio + color LUT + BBP_plugin integration by Patrice Terrier



Paste this in the BBProc section
Code: [Select]
    case BBP_CREATE:
        // Host asks: "who are you and what do you render to?"
        strcpy(BBP.title,"Volumetric Glow");
        strcpy(BBP.author, "Xor (Shadertoy)");
        BBP.version  = MAKEWORD(1,0);

        // Critical: This plugin renders using OpenGL into the host-provided GL context.
        BBP.renderto = BBP_OPENGL;

        // Default background ARGB used by host (informational/fallback).
        BBP.backargb = bbpARGB(255,0,0,0);
        break;

Paste this in the GLSL.h section
Code: [Select]
static GLuint CompileShaderFromString() {
    const char* CharBuffer =
    "#version 330 core\n"
    "\n"
    "uniform vec3  iResolution;\n"
    "uniform float iTime;\n"
    "uniform float iAudio;\n" // smoothed audio level (0..~1)
    "\n"
    "out vec4 FragColor;\n"
    "\n"
    "#define STEPS 50.0\n"
    "#define FOV   1.0\n"
    "#define BASE_DENSITY 1.5\n"
    "\n"
    "float Audio01() {\n"
    "    float a = max(iAudio, 0.0);\n"
    "    a = 1.0 - exp(-1.8 * a);\n"
    "    return clamp(a, 0.0, 1.0);\n"
    "}\n"
    "\n"
    "float volumeField(vec3 p, float density, float wfreq) {\n"
    "    float l = length(p);\n"
    "    vec3 v = cos(abs(p) * wfreq / max(4.0, l) + iTime);\n"
    "    return length(vec4(max(v, v.yzx) - 0.9, l - 4.0)) / density;\n"
    "}\n"
    "\n"
    "vec3 rotate90(vec3 p, vec3 a) {\n"
    "    return a * dot(p, a) + cross(p, a);\n"
    "}\n"
    "\n"
    "// MOIRE FIX: tiny stable per-pixel hash (no noise texture needed)\n"
    "float hash12(vec2 p) {\n"
    "    vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n"
    "    p3 += dot(p3, p3.yzx + 33.33);\n"
    "    return fract((p3.x + p3.y) * p3.z);\n"
    "}\n"
    "\n"
    "void main() {\n"
    "    vec2 fragCoord = gl_FragCoord.xy;\n"
    "    vec2 center = 2.0 * fragCoord - iResolution.xy;\n"
    "\n"
    "    float a = Audio01();\n"
    "\n"
    "    float breathe = 1.0 - 0.08 * a;\n"
    "\n"
    "    float density = BASE_DENSITY * (1.0 + 1.2 * a);\n"
    "    float wfreq   = 8.0 * mix(1.0, 0.65, a);\n"
    "    float brightness = 0.002 * (1.0 + 0.6 * a);\n"
    "\n"
    "    vec3 axis = normalize(cos(vec3(0.5 * iTime) + vec3(0.0, 2.0, 4.0)));\n"
    "\n"
    "    vec3 dir = rotate90(normalize(vec3(center, FOV * iResolution.y)), axis);\n"
    "\n"
    "    float camZ = -8.0 * mix(1.0, 0.92, a);\n"
    "    vec3 cam = rotate90(vec3(0.0, 0.0, camZ), axis);\n"
    "\n"
    "    // Start point\n"
    "    vec3 pos = cam;\n"
    "\n"
    "    // MOIRE FIX: jitter the start along the ray by a tiny amount (breaks band alignment)\n"
    "    float j = hash12(floor(fragCoord));\n"
    "    pos += dir * (j - 0.5) * 0.10;\n"
    "\n"
    "    vec3 col = vec3(0.0);\n"
    "\n"
    "    for (float i = 0.0; i < STEPS; i += 1.0) {\n"
    "        float vol = volumeField(pos * breathe, density, wfreq);\n"
    "        pos += dir * vol;\n"
    "        float inv = 1.0 / max(vol, 0.02);\n"
    "        col += (cos(pos.z / (1.0 + vol) + iTime + vec3(6.0, 1.0, 2.0)) + 1.2) * inv;\n"
    "    }\n"
    "\n"
    "    col = tanh(brightness * col);\n"
    "    FragColor = vec4(col, 1.0);\n"
    "}\n";

    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, CharBuffer);
    return fs;
}
10
64-bit SDK programming / BBP_Cubism.cpp
« Last post by Patrice Terrier on January 04, 2026, 10:46:22 am »
BBP_Cubism

Converted from https://www.shadertoy.com/view/ftGfDK
Original created by mrange on 2022-10-08
Audio + color LUT + BBP_plugin integration by Patrice Terrier



Paste this in the BBProc section
Code: [Select]
    case BBP_CREATE:
        // Host asks: "who are you and what do you render to?"
        strcpy(BBP.title,"Cubism experiment");
        strcpy(BBP.author, "Mrange (Shadertoy)");
        BBP.version  = MAKEWORD(1,0);

        // Critical: This plugin renders using OpenGL into the host-provided GL context.
        BBP.renderto = BBP_OPENGL;

        // Default background ARGB used by host (informational/fallback).
        BBP.backargb = bbpARGB(255,0,0,0);
        break;

Paste this in the GLSL.h section
Code: [Select]
static GLuint CompileShaderFromString() {
    const char* CharBuffer =
    "#version 330 core\n"
    "\n"
    "uniform vec3  iResolution;\n"
    "uniform float iTime;\n"
    "uniform float iAudio;\n"
    "uniform vec3  iLutColor;   // RGB directly from host (lutR,lutG,lutB)\n"
    "\n"
    "out vec4 FragColor;\n"
    "\n"
    "#define TIME        iTime\n"
    "#define RESOLUTION  iResolution\n"
    "#define PI          3.141592654\n"
    "#define TAU         (2.0*PI)\n"
    "#define ROT(a)      mat2(cos(a), sin(a), -sin(a), cos(a))\n"
    "\n"
    "#define TOLERANCE       0.0005\n"
    "#define MAX_RAY_LENGTH  20.0\n"
    "#define MAX_RAY_MARCHES 80\n"
    "#define MAX_SHD_MARCHES 20\n"
    "#define NORM_OFF        0.005\n"
    "\n"
    "const mat2 rot0 = ROT(0.0);\n"
    "mat2 g_rot0 = rot0;\n"
    "\n"
    "const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"
    "#define HSV2RGB(c)  (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))\n"
    "\n"
    "const float hoff = 0.0;\n"
    "\n"
    "// Keep sky exactly as original\n"
    "const vec3 skyCol     = HSV2RGB(vec3(hoff+0.57, 0.90, 0.25));\n"
    "const vec3 skylineCol = HSV2RGB(vec3(hoff+0.02, 0.95, 0.5));\n"
    "const vec3 sunCol     = HSV2RGB(vec3(hoff+0.07, 0.95, 0.5));\n"
    "\n"
    "const vec3 sunDir1    = normalize(vec3(0., 0.05, -1.0));\n"
    "\n"
    "const vec3 lightPos1  = vec3(10.0, 10.0, 10.0);\n"
    "const vec3 lightPos2  = vec3(-10.0, 10.0, -10.0);\n"
    "\n"
    "vec3 sRGB(vec3 t) {\n"
    "  return mix(1.055*pow(t, vec3(1./2.4)) - 0.055, 12.92*t, step(t, vec3(0.0031308)));\n"
    "}\n"
    "\n"
    "vec3 aces_approx(vec3 v) {\n"
    "  v = max(v, 0.0);\n"
    "  v *= 0.6;\n"
    "  float a = 2.51;\n"
    "  float b = 0.03;\n"
    "  float c = 2.43;\n"
    "  float d = 0.59;\n"
    "  float e = 0.14;\n"
    "  return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0, 1.0);\n"
    "}\n"
    "\n"
    "float tanh_approx(float x) {\n"
    "  float x2 = x*x;\n"
    "  return clamp(x*(27.0 + x2)/(27.0+9.0*x2), -1.0, 1.0);\n"
    "}\n"
    "\n"
    "float rayPlane(vec3 ro, vec3 rd, vec4 p) {\n"
    "  return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);\n"
    "}\n"
    "\n"
    "float box(vec2 p, vec2 b) {\n"
    "  vec2 d = abs(p)-b;\n"
    "  return length(max(d,0.0)) + min(max(d.x,d.y),0.0);\n"
    "}\n"
    "\n"
    "float box(vec3 p, vec3 b) {\n"
    "  vec3 q = abs(p) - b;\n"
    "  return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);\n"
    "}\n"
    "\n"
    "float ref(inout vec3 p, vec3 r) {\n"
    "  float d = dot(p, r);\n"
    "  p -= r*min(0.0, d)*2.0;\n"
    "  return d < 0.0 ? 0.0 : 1.0;\n"
    "}\n"
    "\n"
    "vec3 render0(vec3 ro, vec3 rd) {\n"
    "  vec3 col = vec3(0.0);\n"
    "  float sf = 1.0001-max(dot(sunDir1, rd), 0.0);\n"
    "  col += skyCol*pow((1.0-abs(rd.y)), 8.0);\n"
    "  col += clamp(vec3(mix(0.0025, 0.125, tanh_approx(.005/sf))/abs(rd.y))*skylineCol, 0.0, 10.0);\n"
    "  sf *= sf;\n"
    "  col += sunCol*0.00005/sf;\n"
    "\n"
    "  float tp1  = rayPlane(ro, rd, vec4(vec3(0.0, -1.0, 0.0), 6.0));\n"
    "\n"
    "  if (tp1 > 0.0) {\n"
    "    vec3 pos  = ro + tp1*rd;\n"
    "    vec2 pp = pos.xz;\n"
    "    float db = box(pp, vec2(5.0, 9.0))-3.0;\n"
    "    col += vec3(4.0)*skyCol*rd.y*rd.y*smoothstep(0.25, 0.0, db);\n"
    "    col += vec3(0.8)*skyCol*exp(-0.5*max(db, 0.0));\n"
    "  }\n"
    "\n"
    "  return clamp(col, 0.0, 10.0);\n"
    "}\n"
    "\n"
    "float df(vec3 p) {\n"
    "  p.xz *= g_rot0;\n"
    "  vec3 p0 = p;\n"
    "  vec3 p1 = p;\n"
    "  vec3 p2 = p;\n"
    "\n"
    "  // --- AUDIO BREATHING (SHRINK ON LOUD TO AVOID COLLISIONS) ---\n"
    "  float a = max(iAudio, 0.0);\n"
    "  a = 1.0 - exp(-1.5 * a);\n"
    "  float breathe = 1.0 - 0.10 * a;\n"
    "  breathe = clamp(breathe, 0.75, 1.0);\n"
    "\n"
    "  const float ss = 1.;\n"
    "  p0.y -= -0.2;\n"
    "  p0.z = abs(p0.z);\n"
    "  p0.x = -abs(p0.x);\n"
    "  p0.x -= -0.4*ss;\n"
    "  ref(p0, normalize(vec3(1.0, -0.05, -1.0)));\n"
    "  p0.x -= 1.3*ss;\n"
    "  ref(p0, normalize(vec3(1.0, 0.30, 1.0)));\n"
    "  p0.x -= 1.4*ss;\n"
    "  p0.z -= 0.3*ss;\n"
    "  ref(p0, normalize(vec3(1.0, -1.0, 0.5)));\n"
    "  p0.x -= 1.25*ss;\n"
    "  p0.z -= -0.5*ss;\n"
    "  p0.y -= -0.3*ss;\n"
    "  float d0 = box(p0, vec3(0.5) * breathe)-0.0125;\n"
    "\n"
    "  p1.x -= 0.4;\n"
    "  p1.y -= 0.75;\n"
    "  float d1 = box(p1, vec3(1.25) * breathe)-0.0125;\n"
    "\n"
    "  p2.y += 2.0;\n"
    "  float d2 = p2.y;\n"
    "\n"
    "  float d = d1;\n"
    "  d = min(d, d0);\n"
    "  d = min(d, d2);\n"
    "  return d;\n"
    "}\n"
    "\n"
    "vec3 normal(vec3 pos) {\n"
    "  vec2  eps = vec2(NORM_OFF,0.0);\n"
    "  vec3 nor;\n"
    "  nor.x = df(pos+eps.xyy) - df(pos-eps.xyy);\n"
    "  nor.y = df(pos+eps.yxy) - df(pos-eps.yxy);\n"
    "  nor.z = df(pos+eps.yyx) - df(pos-eps.yyx);\n"
    "  return normalize(nor);\n"
    "}\n"
    "\n"
    "float rayMarch(vec3 ro, vec3 rd, float initt) {\n"
    "  float t = initt;\n"
    "  for (int i = 0; i < MAX_RAY_MARCHES; ++i) {\n"
    "    if (t > MAX_RAY_LENGTH) { t = MAX_RAY_LENGTH; break; }\n"
    "    float d = df(ro + rd*t);\n"
    "    if (d < TOLERANCE) break;\n"
    "    t += d;\n"
    "  }\n"
    "  return t;\n"
    "}\n"
    "\n"
    "float shadow(vec3 lp, vec3 ld, float mint, float maxt) {\n"
    "  const float ds = 1.0-0.4;\n"
    "  float t = mint;\n"
    "  float nd = 1E6;\n"
    "  const float soff = 0.05;\n"
    "  const float smul = 1.5;\n"
    "  for (int i=0; i < MAX_SHD_MARCHES; ++i) {\n"
    "    vec3 p = lp + ld*t;\n"
    "    float d = df(p);\n"
    "    if (d < TOLERANCE || t >= maxt) {\n"
    "      float sd = 1.0-exp(-smul*max(t/maxt-soff, 0.0));\n"
    "      return t >= maxt ? mix(sd, 1.0, smoothstep(0.0, 0.025, nd)) : sd;\n"
    "    }\n"
    "    nd = min(nd, d);\n"
    "    t += ds*d;\n"
    "  }\n"
    "  float sd = 1.0-exp(-smul*max(t/maxt-soff, 0.0));\n"
    "  return sd;\n"
    "}\n"
    "\n"
    "vec3 boxCol(vec3 col, vec3 nsp, vec3 rd, vec3 nnor, vec3 nrcol, float nshd1, float nshd2) {\n"
    "  // --- LUT-driven cube palette (from host RGB) ---\n"
    "  vec3 lut  = clamp(iLutColor, 0.0, 1.0);\n"
    "  vec3 diff1 = lut;\n"
    "  vec3 diff2 = mix(lut, vec3(1.0), 0.25);\n"
    "  vec3 rim   = mix(lut, vec3(1.0), 0.50);\n"
    "\n"
    "  float nfre  = 1.0+dot(rd, nnor);\n"
    "  nfre        *= nfre;\n"
    "\n"
    "  vec3 nld1   = normalize(lightPos1-nsp);\n"
    "  vec3 nld2   = normalize(lightPos2-nsp);\n"
    "\n"
    "  float ndif1 = max(dot(nld1, nnor), 0.0);\n"
    "  ndif1       *= ndif1;\n"
    "\n"
    "  float ndif2 = max(dot(nld2, nnor), 0.0);\n"
    "  ndif2       *= ndif2;\n"
    "\n"
    "  vec3 scol = vec3(0.0);\n"
    "  float rf = smoothstep(1.0, 0.9, nfre);\n"
    "  scol += diff1*ndif1*nshd1;\n"
    "  scol += diff2*ndif2*nshd2;\n"
    "  scol += 0.1*(skyCol+skylineCol);\n"
    "  scol += nrcol*0.75*mix(vec3(0.25), rim, nfre);\n"
    "\n"
    "  col = mix(col, scol, rf*smoothstep(90.0, 20.0, dot(nsp, nsp)));\n"
    "  return col;\n"
    "}\n"
    "\n"
    "vec3 render1(vec3 ro, vec3 rd) {\n"
    "  vec3 skyCol0 = render0(ro, rd);\n"
    "  vec3 col = skyCol0;\n"
    "\n"
    "  float nt = rayMarch(ro, rd, 0.0);\n"
    "  if (nt < MAX_RAY_LENGTH) {\n"
    "    vec3 nsp  = ro + rd*nt;\n"
    "    vec3 nnor = normal(nsp);\n"
    "\n"
    "    vec3 nref  = reflect(rd, nnor);\n"
    "    float nrt  = rayMarch(nsp, nref, 0.2);\n"
    "    vec3 nrcol = render0(nsp, nref);\n"
    "\n"
    "    if (nrt < MAX_RAY_LENGTH) {\n"
    "      vec3 nrsp  = nsp + nref*nrt;\n"
    "      vec3 nrnor = normal(nrsp);\n"
    "      vec3 nrref = reflect(nref, nrnor);\n"
    "      nrcol = boxCol(nrcol, nrsp, nref, nrnor, render0(nrsp, nrref), 1.0, 1.0);\n"
    "    }\n"
    "\n"
    "    float nshd1 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos1 - nsp), 0.1, distance(lightPos1, nsp)));\n"
    "    float nshd2 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos2 - nsp), 0.1, distance(lightPos2, nsp)));\n"
    "\n"
    "    col = boxCol(col, nsp, rd, nnor, nrcol, nshd1, nshd2);\n"
    "  }\n"
    "\n"
    "  return col;\n"
    "}\n"
    "\n"
    "vec3 effect(vec2 p) {\n"
    "  g_rot0 = ROT(-0.2*TIME);\n"
    "\n"
    "  const float fov = tan(TAU/6.0);\n"
    "  const vec3 ro = vec3(0.0, 2.5, 5.0);\n"
    "  const vec3 la = vec3(0.0, 0.0, 0.0);\n"
    "  const vec3 up = vec3(0.1, 1.0, 0.0);\n"
    "\n"
    "  vec3 ww = normalize(la - ro);\n"
    "  vec3 uu = normalize(cross(up, ww));\n"
    "  vec3 vv = cross(ww,uu);\n"
    "  vec3 rd = normalize(-p.x*uu + p.y*vv + fov*ww);\n"
    "\n"
    "  return render1(ro, rd);\n"
    "}\n"
    "\n"
    "void main() {\n"
    "  vec2 fragCoord = gl_FragCoord.xy;\n"
    "  vec2 q = fragCoord/RESOLUTION.xy;\n"
    "  vec2 p = -1. + 2. * q;\n"
    "  p.x *= RESOLUTION.x/RESOLUTION.y;\n"
    "\n"
    "  vec3 col = effect(p);\n"
    "  col = aces_approx(col);\n"
    "  col = sRGB(col);\n"
    "  FragColor = vec4(col, 1.0);\n"
    "}\n";

    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, CharBuffer);
    return fs;
}
Pages: [1] 2 3 ... 10