Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: File-Based Shaders and Projects #191

Open
AntonPieper opened this issue Jul 28, 2024 · 0 comments
Open

Feature Request: File-Based Shaders and Projects #191

AntonPieper opened this issue Jul 28, 2024 · 0 comments

Comments

@AntonPieper
Copy link
Contributor

AntonPieper commented Jul 28, 2024

Motivation

Transitioning to a file-based system for shaders and projects would greatly enhance the app's functionality. This approach would enable the use of #include directives, allow per-project image assets, and facilitate editing additional file types in the future.

Concept

Project Structure

Instead of a list of shaders, the app will feature a file explorer within the drawer, accompanied by Open Project and Open Recent Project menu items. The Open Recent Project menu will include a submenu listing the last N (default: 10) opened projects.

Project Properties

  • Comprises multiple files within a directory.
  • Has a main shader entry point (default: ./main.frag).
  • Supports #include directives.
  • Contains an optional shader-project.json configuration file:
    • "main": overrides the entry point file.
    • "assetPaths": specifies paths to search for asset descriptors (default: ["${prefix}/.assets", "./assets/"]).
    • "includePath": specifies the include path list (default: ["${prefix}/.include"]).

Image Handling

Images can be stored within the project and referenced using comments within GLSL code:

/// @src {./res/something.jpg}
uniform sampler2D myImage;
/// Example using ./res/pic.json from asset path
uniform sampler2D alsoWorks; ///< @src {pic}
/// Example using the resource by uniform name
/// This uses first noise.json found in "assetPaths"
uniform sampler2D noise;

Asset Descriptor JSON

The JSON descriptor for assets, generated from the add texture fragment, follows this structure:

{
  "type": "sampler2D",
  "src": "./texture.png",
  "filtering": {
    "min": "LINEAR_MIPMAP_LINEAR",
    "mag": "LINEAR"
  },
  "wrapping": "REPEAT",
  "format": "RGBA",
  "mipmap": true,
  "options": {
    "flipY": true
  }
}
JSON Schema
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Asset Configuration",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": ["sampler2D", "samplerCube", "sampler3D"],
      "description": "Type of the texture sampler",
      "default": "sampler2D"
    },
    "src": {
      "type": "string",
      "description": "Source texture file"
    },
    "filtering": {
      "type": "object",
      "properties": {
        "min": {
          "type": "string",
          "enum": ["LINEAR_MIPMAP_LINEAR", "LINEAR", "NEAREST_MIPMAP_LINEAR", "NEAREST", "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_NEAREST"],
          "default": "LINEAR_MIPMAP_LINEAR"
        },
        "mag": {
          "type": "string",
          "enum": ["LINEAR", "NEAREST"],
          "default": "LINEAR"
        }
      },
      "additionalProperties": false,
      "default": {}
    },
    "wrapping": {
      "oneOf": [
        {
          "type": "string",
          "enum": ["REPEAT", "CLAMP_TO_EDGE", "MIRRORED_REPEAT"],
          "default": "REPEAT"
        },
        {
          "type": "object",
          "properties": {
            "s": {
              "type": "string",
              "enum": ["REPEAT", "CLAMP_TO_EDGE", "MIRRORED_REPEAT"],
              "default": "REPEAT"
            },
            "t": {
              "type": "string",
              "enum": ["REPEAT", "CLAMP_TO_EDGE", "MIRRORED_REPEAT"],
              "default": "REPEAT"
            },
            "r": {
              "type": "string",
              "enum": ["REPEAT", "CLAMP_TO_EDGE", "MIRRORED_REPEAT"],
              "default": "REPEAT"
            }
          },
          "additionalProperties": false,
          "default": {}
        }
      ]
    },
    "format": {
      "type": "object",
      "properties": {
        "source": {
          "type": "string",
          "enum": ["RGBA", "RGB", "LUMINANCE", "ALPHA", "LUMINANCE_ALPHA"],
          "default": "RGBA"
        },
        "internal": {
          "type": "string",
          "enum": ["RGBA", "RGB", "LUMINANCE", "ALPHA", "LUMINANCE_ALPHA"],
          "default": "RGBA"
        },
        "dataType": {
          "type": "string",
          "enum": ["UNSIGNED_BYTE", "UNSIGNED_SHORT_5_6_5", "UNSIGNED_SHORT_4_4_4_4", "UNSIGNED_SHORT_5_5_5_1"],
          "default": "UNSIGNED_BYTE"
        }
      },
      "required": ["source", "internal"],
      "additionalProperties": false,
      "default": {
        "source": "RGBA",
        "internal": "RGBA",
        "dataType": "UNSIGNED_BYTE"
      }
    },
    "mipmap": {
      "oneOf": [
        {
          "type": "boolean",
          "description": "Enable or disable mipmap generation",
          "default": true
        },
        {
          "type": "object",
          "properties": {
            "generate": {
              "type": "boolean",
              "default": true
            },
            "baseLevel": {
              "type": "integer",
              "default": 0
            },
            "maxLevel": {
              "type": "integer",
              "default": 10
            }
          },
          "required": ["generate"],
          "additionalProperties": false
        }
      ]
    },
    "options": {
      "type": "object",
      "properties": {
        "flipY": {
          "type": "boolean",
          "default": true
        },
        "premultiplyAlpha": {
          "type": "boolean",
          "default": false
        },
        "borderColor": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 4,
          "maxItems": 4,
          "default": [0.0, 0.0, 0.0, 0.0]
        }
      },
      "additionalProperties": false,
      "default": {}
    }
  },
  "required": ["type", "src"],
  "additionalProperties": false
}

Migration Plan

To ensure a seamless transition with no data loss or need for source code refactoring, the following actions are necessary:

  1. Backup the entire shader database upon first opening after the update.
  2. Add a Add shaders from database file option in settings and automatically execute this action when first opening the app afzer the update.

Migration Procedure

  1. Create a directory for each shader using its name.
  2. Place the shader's content in main.frag.
  3. Store existing textures in the default (${prefix}/.assets) path and generate corresponding asset descriptor .json files.

Requirements

File Explorer UI

  • Design: Similar to Google Files with breadcrumbs at the top.
    • Clicking on a segment navigates inside the directory with a ripple effect.
    • Active directory name in primary color.
    • Horizontal scrolling.
    • On change: scroll to show active directory.
    • Horizontal line below breadcrumbs.
  • Create Button: + button for creating files or directories.
    • Bottom sheet options: Create Directory, Shader, or Image Asset.
  • Icons:
    • Material Symbol Icons for directories, config files, and shaders.
    • Main shader has a preview as its icon, stored in app cache.
  • Navigation: Clicking on a directory navigates inside it; clicking on a file opens it in the editor.
  • Item Menu: button at the end of each item opens a menu:
    1. Rename
    2. Delete
    3. Copy
  • View Menu: button at the top end of the view opens a menu:
    1. Sort by: Alphabetical, Last Modified
    2. Paste
    3. Add new item

#include Directive

  • Error messages:
    • Display file names.
    • Visible in the relevant file and on each line that includes the file.
  • #include "...": Searches relative to the current file first.
  • #include <...>: Searches "includePath" first.

shader-project.json

Minimal Version

  1. Migration shall work.
  2. Open Project shall work.
  3. File Explorer:
    • Can navigate via breadcrumbs
    • Can navigate by clicking on directories
    • Clicking on GLSL files (*.glsl, *.frag) shall open the file
  4. Shader Editor shall show the current project's main entry point (regardless of opened file)
  5. For any valid GLSL variable name <some-name>, uniform sampler2D <some-name> shall load the first <some-name>.json found in the project's "assetPaths".
  6. #include shall work.
  7. All fields of shader-project.json shall work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant