Namespace
Namespace
Namespace
DreamShader » DreamShaderLang » Namespace
A top-level block that prefixes the names of the Function and GraphFunction declarations it
contains with <Name>::.
| Declared in | .dsm, .dsf, .dsh |
| Kind | top-level block |
| Generates | nothing directly — its members generate exactly what they would generate at top level |
| Multiplicity | any number per file; the same name may be opened more than once |
Synopsis
Namespace(Name = "<identifier>" [ , Generate = "<template>" ] [ , Library = "<category>" ] [ , Description = "<text>" ])
{
{ <function-declaration> | <graph-function-declaration> } …
}The keyword Namespace is matched case-sensitively. namespace and NAMESPACE are not the
keyword.
Header attributes
| Attribute | Required | Value | Effect |
|---|---|---|---|
Name | yes | string | The qualifier prepended to every member's name |
Generate | no | string, {Name} the member's name | (after 2.1.2) in a package's header, every member generates a material function of that name — see Packages ▸ Asset headers. A member's own Generate wins; Generate = "" on it opts it out |
Library | no | string | (after 2.1.2) the function-library category of every generated function |
Description | no | string | (after 2.1.2) the description of every generated function |
Any other key is parsed and silently ignored. Attribute
keys are matched case-insensitively, so Namespace(name="Common") works. The value may be quoted or
bare; a bare value runs to the next , or ) outside parentheses. A key written twice is a warning
(DSH2244) and the later value wins. A trailing comma
before ) is accepted, as in 1.x (2.0.0 – 2.1.0 refused it with
DSH2243).
Name must be an identifier — a letter or _, then letters, digits and _. A missing, empty or
whitespace-only name, and a name containing ::, ., -, a space or any other character, is
DSH6309. There is therefore no multi-segment declaration
form: Namespace(Name="A::B") is an error.
Body contents
| Construct | Accepted |
|---|---|
Function | yes, any number |
GraphFunction | yes, any number |
Nested Namespace | no |
Shader, ShaderFunction, ShaderLayer, ShaderLayerBlend, VirtualFunction | no |
Sections (Properties, Settings, Inputs, Outputs, Graph, Layout, …) | no |
import | no (since 2.0.0) — an import stands at file scope only |
Members may appear in any order and any number of times; a stray ; between them is skipped. Both
keywords are matched case-sensitively inside the body, exactly as at top level. Anything else is
DSH6310, and the parser resumes at the next member keyword or
the closing }.
No nesting
Namespace is only reachable from the top-level keyword loop; the body recognizes just the two
function keywords. A nested Namespace therefore hits DSH6310. There is no way to declare
A::B::C, and re-opening does not compose:
Namespace(Name="A") { Namespace(Name="B") { Function f(out float r) { r = 0; } } }
// DSH6310 at the inner NamespaceName flattening
A Namespace is not an entity. No object is stored for it, and it creates no scope. Its only effect
is on the member's name, which (since 2.0.0) is the flattened identifier:
Namespace(Name = "Common") { Function ApplyTint(…) } → Common::ApplyTint → function Common_ApplyTintThe flattening is the identifier sanitizer: every non-[A-Za-z0-9_] character becomes _, and runs
of consecutive underscores collapse to one (Common__ApplyTint → Common_ApplyTint). Members land
among the top-level functions under that name; name lookup, binder diagnostics and the generated HLSL
symbol DreamShaderFn_Common_ApplyTint all see Common_ApplyTint. The qualified spelling survives in
one place: the title (Description) of the member's Custom node is Common::ApplyTint, as in 1.x.
[!WARNING] Because
::and_flatten to the same thing,Namespace(Name="Common") { Function ApplyTint … }and a top-levelFunction Common_ApplyTint …declare the same name:DSH4210.
Calling a namespaced function
From a Graph block, use Ns::Fn(…). The :: chain is read as one name and
flattened the same way, so the call reaches Ns_Fn.
Graph = {
vec3 Tinted;
Common::ApplyTint(BaseColor, Tint, Tinted); // statement call
float K = Common::Remap01(Raw); // value call
}| Rule | Behaviour |
|---|---|
| Resolution | The qualified name, or its flattened spelling Common_ApplyTint. There is no using directive and no unqualified fallback: a bare ApplyTint(…) is DSH4208. |
| Case | (since 2.0.0) names are case-sensitive. common::applytint(…) still resolves when it matches one function, with DSH5275. |
| Mangled spelling | DreamShaderFn_Common_ApplyTint(…) no longer names the function (since 2.0.0): DSH4208. |
| Missing name | Common:: with nothing after it is DSH5260. |
| Call forms | Identical to unqualified calls. See Calling functions. |
From a .dss that includes the header, Ns::Fn(…) is read the same way (after 2.1.2): the call
reaches Ns_Fn, dsc fmt and the language service keep the qualified spelling, and an unknown member is
DSH4208 naming Ns::Fn as written. A library such as
dreamshader-blender is called the way its own Graphs call it:
#include "@typedreammoon/dreamshader-blender/Library/Noise.dsh"
export void M_Noise(inout material m)
{
float2 uv = UE.TexCoord(Index = 0);
float Fac;
float3 Color;
BL::TexNoise3D(float3(uv, 0.0), 5.0, 2.0, 0.5, 2.0, 0.0, 1.0, Fac, Color);
m.EmissiveColor = Color;
}The out arguments are ordinary .dss locals, declared before the call; the 1.x Graph's implicit
declaration of a receiver (DSH5283) is a legacy rule. Up to 2.1.2 a
.dss reached the member only as Ns_Fn(…), and Ns::Fn was DSH2154 at the second :.
Inside another Function or GraphFunction body a Ns::Fn(…) call works (since 2.0.0). Body
normalisation rewrites Common::ApplyTint to Common_ApplyTint, which is now the function's own name,
so the call is embedded like any other Function call. In 1.x it reached the shader compiler as an
undefined Common_ApplyTint and failed there. The qualifier has to be written without spaces around
::.
Notes
- Re-opening is allowed and unchecked. Two
Namespace(Name="Common")blocks — in the same file or across imported headers — both prefixCommon::. There is no duplicate-namespace diagnostic; two members with the same qualified name areDSH4210. - A namespace does not create a lookup scope. A member calls a sibling by its qualified (or flattened) name. Inside a body, a bare sibling name is not recognised as a call to the sibling and is left for the shader compiler.
Namespace(Name="X") { }with an empty body is accepted and declares nothing (since 2.0.0; 1.x then failed the file for having no block).- Headers are parsed on their own. Namespaces of an imported header are declared into the importing file, and their members collide across files exactly as within one. See import.
- Parser diagnostics about a member's declaration name the member as written (
ApplyTint); the ones about a liftedUE.*call name itCommon::ApplyTint; everything after the parser names the flattenedCommon_ApplyTint.
Diagnostics
Each code carries the line and column of the construct; the code's page has the message.
Parse time
| Code | Raised when |
|---|---|
DSH2241 | no ( after Namespace |
DSH2243 | a malformed attribute list |
DSH2244 | an attribute written twice (warning) |
DSH6309 | no Name, an empty one, or one that is not an identifier |
DSH2257 | no { after the header |
DSH6310 | anything but Function / GraphFunction in the body — a nested Namespace included |
DSH2150 | the body is never closed |
DSH2103 | the Name value's " is never closed |
Member declarations report their own errors — see Function § Diagnostics.
Binding and call time
| Code | Raised when |
|---|---|
DSH4210 | two members flatten to one name, or a member and a top-level function do |
DSH5260 | no name follows :: |
DSH4208 | the called name declares nothing — for example an unqualified call to a member |
DSH5275 | the called name matches a member only in case (warning) |
The complete cross-stage list lives in the diagnostics index.
Example
// DShader/Lib/Common.dsh
Namespace(Name="Common")
{
Function ApplyTint(in vec3 color, in vec3 tint, out vec3 result)
{
result = color * tint;
}
Function float Remap01(in float value)
{
return saturate(value * 0.5 + 0.5);
}
GraphFunction Pulse(in float speed, out float value)
{
value = sin(UE.Time() * speed);
}
}import "Lib/Common.dsh"
Shader(Name="Materials/M_Common")
{
Properties = {
vec3 Tint = vec3(1.0, 0.6, 0.2);
float Speed = 2.0;
}
Outputs = { vec3 Color; Base.EmissiveColor = Color; }
Graph = {
vec3 Gray = vec3(0.5, 0.5, 0.5);
vec3 Tinted;
Common::ApplyTint(Gray, Tint, Tinted);
float Key = Common::Remap01(Tinted.r);
float P;
Common::Pulse(Speed, P);
Color = Tinted * Key * P;
}
}Resulting names:
declaration function name Custom node title helper symbol when embedded
Namespace "Common" > ApplyTint Common_ApplyTint Common::ApplyTint DreamShaderFn_Common_ApplyTint
Namespace "Common" > Remap01 Common_Remap01 Common::Remap01 DreamShaderFn_Common_Remap01
Namespace "Common" > Pulse Common_Pulse Common::Pulse (none — it lifts a UE.* call, so it is never embedded)See also
- Function — the member declaration grammar and the
DreamShaderFn_*helper symbol - GraphFunction — the other legal member kind
- Calling functions — value vs statement calls
- Name resolution — the lookup order a
Graphblock uses - import — how a header's declarations reach the importing file
- Source files — which of
.dsm/.dsh/.dsfmay hold aNamespace - Lexical elements — identifiers,
::, and the case-sensitivity matrix - Keywords — the complete keyword index
- Diagnostics index — every code, by stage