Shaders - Relative paths

Shaders are no longer found under /shaders in the project; they can be
anywhere. In addition, paths for both (program) instructions in the
script and include directives in shader source code are relative to the
file which contains them.
This commit is contained in:
Emmanuel BENOîT 2017-12-29 11:33:15 +01:00
parent 3344f96af0
commit 68d01ca42e
41 changed files with 198 additions and 132 deletions

2
TODO
View file

@ -23,8 +23,6 @@ Compiler / emulator:
* Check for overrides on the same inputs when setting things up * Check for overrides on the same inputs when setting things up
* Aliases * Aliases
* Display errors in UI * Display errors in UI
* Shader paths relative to scripts (will require different way of handling
libraries)
Optimizer: Optimizer:

View file

@ -828,21 +828,22 @@ class T_PipelineInstrNode : public A_ResourceDefInstrNode
class T_ProgramInstrNode : public A_ResourceDefInstrNode class T_ProgramInstrNode : public A_ResourceDefInstrNode
{ {
private: private:
T_String path_; T_FSPath path_;
ebcl::T_SRDLocation pathLocation_; ebcl::T_SRDLocation pathLocation_;
public: public:
T_ProgramInstrNode( T_ProgramInstrNode(
T_InstrListNode& parent , T_InstrListNode& parent ,
ebcl::T_SRDToken const& idToken , ebcl::T_SRDToken const& idToken ,
ebcl::T_SRDToken const& pathToken ) noexcept ebcl::T_FSPath path ,
ebcl::T_SRDLocation const& pathLoc ) noexcept
: A_ResourceDefInstrNode( OP_PROGRAM , parent , : A_ResourceDefInstrNode( OP_PROGRAM , parent ,
idToken , E_DataType::PROGRAM ) , idToken , E_DataType::PROGRAM ) ,
path_( pathToken.stringValue( ) ) , path_( std::move( path ) ) ,
pathLocation_( pathToken.location( ) ) pathLocation_( pathLoc )
{ } { }
T_String const& path( ) const noexcept T_FSPath const& path( ) const noexcept
{ return path_; } { return path_; }
ebcl::T_SRDLocation const& pathLocation( ) const noexcept ebcl::T_SRDLocation const& pathLocation( ) const noexcept
{ return pathLocation_; } { return pathLocation_; }

View file

@ -1,6 +1,10 @@
#include "externals.hh" #include "externals.hh"
#include "common.hh"
#include "c-project.hh"
#include "c-ops.hh" #include "c-ops.hh"
#include "c-opcomp.hh" #include "c-opcomp.hh"
#include <ebcl/Algorithms.hh> #include <ebcl/Algorithms.hh>
using namespace ebcl; using namespace ebcl;
@ -505,12 +509,13 @@ bool T_CompilerImpl_::compileNode(
case A_Node::OP_PROGRAM: case A_Node::OP_PROGRAM:
if ( exit ) { if ( exit ) {
auto& pn( (T_ProgramInstrNode&) node ); auto& pn( (T_ProgramInstrNode&) node );
if ( !output->progNames.contains( pn.path( ) ) ) { const auto p{ pn.path( ).makeRelative( Common::Project( ).basePath( ) ) };
output->progNames.add( pn.path( ) ); if ( !output->progNames.contains( p ) ) {
output->progNames.add( p );
} }
assert( locations.contains( pn.id( ) ) ); assert( locations.contains( pn.id( ) ) );
addInstruction( OP_INIT_PROGRAM , output->progNames.indexOf( pn.path( ) ) , addInstruction( OP_INIT_PROGRAM , output->progNames.indexOf( p ) ,
pn.location( ) ); pn.location( ) );
addInstruction( OP_STORE , *locations.get( pn.id( ) ) , pn.idLocation( ) ); addInstruction( OP_STORE , *locations.get( pn.id( ) ) , pn.idLocation( ) );
} }

View file

@ -1,5 +1,7 @@
#include "externals.hh" #include "externals.hh"
#include "common.hh"
#include "c-project.hh"
#include "c-opast.hh" #include "c-opast.hh"
#include "c-ops.hh" #include "c-ops.hh"
#include "c-opcomp.hh" #include "c-opcomp.hh"
@ -1704,8 +1706,21 @@ M_INSTR_( Program )
return; return;
} }
T_FSPath path{ input[ 2 ].stringValue( ) };
if ( path.isAbsolute( ) ) {
path = path.makeRelative( path.root( ) );
path = ( Common::Project( ).basePath( ) + path ).canonical( );
} else {
path = ( curFile.parent( ) + path ).canonical( );
}
if ( !path.isUnder( Common::Project( ).basePath( ) ) ) {
errors.addNew( "shader is not in project directory" ,
input[ 2 ].location( ) );
}
T_ProgramInstrNode& program{ instructions.add< T_ProgramInstrNode >( T_ProgramInstrNode& program{ instructions.add< T_ProgramInstrNode >(
input[ 1 ] , input[ 2 ] ) }; input[ 1 ] , std::move( path ) ,
input[ 2 ].location( ) ) };
program.location( ) = input[ 0 ].location( ); program.location( ) = input[ 0 ].location( );
} }

View file

@ -142,7 +142,7 @@ struct T_OpProgram
nPipelines{ 0 } , // Amount of pipelines nPipelines{ 0 } , // Amount of pipelines
nSamplers{ 0 } , // Amount of samplers nSamplers{ 0 } , // Amount of samplers
nTextures{ 0 }; // Amount of textures nTextures{ 0 }; // Amount of textures
T_Array< T_String > progNames; // GLSL program files T_Array< T_FSPath > progNames; // GLSL program files
T_Array< T_String > uiStrings; // UI strings for profiling, etc. T_Array< T_String > uiStrings; // UI strings for profiling, etc.
T_Array< P_SyncOverrideSection > overrides; T_Array< P_SyncOverrideSection > overrides;

View file

@ -34,6 +34,12 @@ void T_Project::setBasePath(
T_FSPath T_Project::pathOf( T_FSPath T_Project::pathOf(
T_FSPath const& file ) const noexcept T_FSPath const& file ) const noexcept
{ {
if ( file.isAbsolute( ) ) {
if ( file.canonical( ).isUnder( basePath_ ) ) {
return file;
}
return basePath_;
}
return ( basePath_ + file ).canonical( ); return ( basePath_ + file ).canonical( );
} }

View file

@ -1,4 +1,6 @@
#include "externals.hh" #include "externals.hh"
#include "common.hh"
#include "c-project.hh"
#include "c-shaders.hh" #include "c-shaders.hh"
@ -30,6 +32,7 @@ struct T_InputReader_
{ {
using T_Tokens_ = std::vector< std::string >; using T_Tokens_ = std::vector< std::string >;
const T_FSPath path;
FILE* const file; FILE* const file;
T_ShaderInput& input; T_ShaderInput& input;
uint32_t line{ 0 }; uint32_t line{ 0 };
@ -40,9 +43,10 @@ struct T_InputReader_
std::string accumulator{ }; std::string accumulator{ };
uint32_t accumLines{ 0 }; uint32_t accumLines{ 0 };
T_InputReader_( FILE* const file , T_InputReader_( T_FSPath const& path ,
FILE* const file ,
T_ShaderInput& input ) T_ShaderInput& input )
: file( file ) , input( input ) : path( path ) , file( file ) , input( input )
{ } { }
~T_InputReader_( ); ~T_InputReader_( );
@ -100,9 +104,28 @@ void T_InputReader_::handleDirective(
error( "invalid arguments" ); error( "invalid arguments" );
return; return;
} }
T_FSPath inclPath{ tokens[ 1 ].c_str( ) };
if ( !inclPath.isValid( ) ) {
nl( );
error( "invalid path" );
return;
}
if ( inclPath.isAbsolute( ) ) {
inclPath = inclPath.makeRelative( inclPath.root( ) );
inclPath = ( Common::Project( ).basePath( ) + inclPath ).canonical( );
} else {
inclPath = ( path.parent( ) + inclPath ).canonical( );
}
if ( !inclPath.isUnder( Common::Project( ).basePath( ) ) ) {
nl( );
error( "path is outside of project" );
return;
}
addAccumulated( ); addAccumulated( );
auto& ck( input.chunks ); auto& ck( input.chunks );
ck.addNew( E_ShaderInputChunk::INCLUDE , tokens[ 1 ].c_str( ) , 1 ); ck.addNew( inclPath , 1 );
} else if ( directive == "type" ) { } else if ( directive == "type" ) {
nl( ); nl( );
@ -141,8 +164,7 @@ void T_InputReader_::addAccumulated( )
{ {
if ( accumLines ) { if ( accumLines ) {
auto& ck( input.chunks ); auto& ck( input.chunks );
ck.addNew( E_ShaderInputChunk::CODE , ck.addNew( accumulator.c_str( ) , accumLines );
accumulator.c_str( ) , accumLines );
accumulator = {}; accumulator = {};
accumLines = 0; accumLines = 0;
} }
@ -154,18 +176,19 @@ void T_InputReader_::addAccumulated( )
/*= T_ShaderInput ============================================================*/ /*= T_ShaderInput ============================================================*/
bool T_ShaderInput::load( bool T_ShaderInput::load(
T_String const& path ) T_FSPath const& path )
{ {
type = E_ShaderInput::CHUNK; type = E_ShaderInput::CHUNK;
chunks.clear( ); chunks.clear( );
errors.clear( ); errors.clear( );
FILE* const file{ fopen( (char const*) path.toOSString( ).data( ) , "r" ) }; const auto osPath{ path.toString( ).toOSString( ) };
FILE* const file{ fopen( (char const*) osPath.data( ) , "r" ) };
if ( !file ) { if ( !file ) {
return false; return false;
} }
T_InputReader_ reader( file , *this ); T_InputReader_ reader{ path , file , *this };
reader.read( ); reader.read( );
return true; return true;

View file

@ -17,20 +17,20 @@ enum class E_ShaderType {
// the input loader, the shader loader or the driver. // the input loader, the shader loader or the driver.
struct T_ShaderError struct T_ShaderError
{ {
T_String source; T_FSPath source;
uint32_t line; uint32_t line;
T_String error; T_String error;
T_ShaderError( ) = default; T_ShaderError( ) = default;
T_ShaderError( T_String source , T_ShaderError( T_FSPath source ,
const uint32_t line , const uint32_t line ,
T_String error ) T_String error )
: source( std::move( source ) ) , line( line ) , : source( std::move( source ) ) , line( line ) ,
error( std::move( error ) ) error( std::move( error ) )
{ } { }
T_ShaderError( T_String source , T_ShaderError( T_FSPath source ,
const uint32_t line , const uint32_t line ,
T_StringBuilder& error ) T_StringBuilder& error )
: source( std::move( source ) ) , line( line ) , : source( std::move( source ) ) , line( line ) ,
@ -51,15 +51,25 @@ enum class E_ShaderInputChunk {
struct T_ShaderInputChunk struct T_ShaderInputChunk
{ {
E_ShaderInputChunk type; E_ShaderInputChunk type;
T_String text; T_Union< T_String , T_FSPath > data;
uint32_t lines; uint32_t lines;
T_ShaderInputChunk( ) = default; T_ShaderInputChunk( ) = default;
T_ShaderInputChunk( T_ShaderInputChunk(
const E_ShaderInputChunk type ,
T_String text , T_String text ,
const uint32_t lines ) const uint32_t lines )
: type( type ) , text( std::move( text ) ) , lines( lines ) : type( E_ShaderInputChunk::CODE ) ,
data( std::move( text ) ) ,
lines( lines )
{ }
T_ShaderInputChunk(
T_FSPath path ,
const uint32_t lines )
: type( E_ShaderInputChunk::INCLUDE ) ,
data( std::move( path ) ) ,
lines( lines )
{ } { }
}; };
@ -93,6 +103,6 @@ struct T_ShaderInput
T_Array< T_ShaderInputChunk > chunks; T_Array< T_ShaderInputChunk > chunks;
T_Array< T_ShaderInputError > errors; T_Array< T_ShaderInputError > errors;
bool load( T_String const& path ); bool load( T_FSPath const& path );
}; };
using P_ShaderInput = T_OwnPtr< T_ShaderInput >; using P_ShaderInput = T_OwnPtr< T_ShaderInput >;

View file

@ -1,7 +1,7 @@
(include "fx-bloom.srd") (include "fx-bloom/fx-bloom.srd")
(include "fx-dof.srd") (include "fx-dof/fx-dof.srd")
(include "fx-combine.srd") (include "fx-combine/fx-combine.srd")
(include "fx-fxaa.srd") (include "fx-fxaa/fx-fxaa.srd")
(init (init
# Compute viewport size # Compute viewport size
@ -20,7 +20,7 @@
(set vp-x (div (sub $width $vp-width) 2)) (set vp-x (div (sub $width $vp-width) 2))
(set vp-y (div (sub $height $vp-height) 2)) (set vp-y (div (sub $height $vp-height) 2))
(program prg-fullscreen "fullscreen.v.glsl") (program prg-fullscreen "/fullscreen.v.glsl")
(set use-compute 1) (set use-compute 1)

View file

@ -6,7 +6,7 @@ layout(
) in; ) in;
//! type compute //! type compute
//! include lib/utils.glsl //! include /lib/utils.glsl
layout( location = 0 ) uniform sampler2D u_MainInput; layout( location = 0 ) uniform sampler2D u_MainInput;
layout( location = 1 ) uniform sampler2D u_BlurInput; layout( location = 1 ) uniform sampler2D u_BlurInput;

View file

@ -1,7 +1,7 @@
#version 450 core #version 450 core
//! type fragment //! type fragment
//! include lib/utils.glsl //! include /lib/utils.glsl
layout( location = 0 ) uniform sampler2D u_MainInput; layout( location = 0 ) uniform sampler2D u_MainInput;
layout( location = 1 ) uniform sampler2D u_BlurInput; layout( location = 1 ) uniform sampler2D u_BlurInput;

View file

@ -17,7 +17,7 @@ layout( location = 4 ) uniform vec3 u_ResolutionTime;
layout( binding = 0 , rgba16f ) writeonly uniform image2D u_Output; layout( binding = 0 , rgba16f ) writeonly uniform image2D u_Output;
//!include lib/utils.glsl //!include /lib/utils.glsl
float DOF_CoC( float DOF_CoC(
in float z ) in float z )

View file

@ -1,5 +1,5 @@
//!type library //!type library
//!include lib/utils.glsl //!include /lib/utils.glsl
float DOF_CoC( float DOF_CoC(
in float z ) in float z )

View file

@ -7,7 +7,7 @@ layout(
local_size_y = 64 local_size_y = 64
) in; ) in;
//! include chunks/dof-cs.glsl //! include dof-cs.glsl
void main() void main()
{ {

View file

@ -1,7 +1,7 @@
#version 450 core #version 450 core
//! type fragment //! type fragment
//! include chunks/dof.glsl //! include dof.glsl
void main() void main()
{ {

View file

@ -7,7 +7,7 @@ layout(
local_size_y = 20 local_size_y = 20
) in; ) in;
//! include chunks/dof-cs.glsl //! include dof-cs.glsl
void main() void main()
{ {

View file

@ -1,7 +1,7 @@
#version 450 core #version 450 core
//! type fragment //! type fragment
//! include chunks/dof.glsl //! include dof.glsl
void main() void main()
{ {

View file

@ -20,4 +20,4 @@ layout( location = 4 ) uniform vec3 u_ResolutionTime;
layout( location = 0 ) out vec3 o_Color; layout( location = 0 ) out vec3 o_Color;
//!include lib/dof.glsl //!include dof-lib.glsl

View file

@ -8,7 +8,7 @@
#define FXAA_GATHER4_ALPHA 1 #define FXAA_GATHER4_ALPHA 1
#define FXAA_QUALITY__PRESET 39 #define FXAA_QUALITY__PRESET 39
//! include chunks/fxaa-3.11.glsl //! include fxaa-3.11.glsl
layout( location = 0 ) uniform sampler2D u_Input; layout( location = 0 ) uniform sampler2D u_Input;
layout( location = 1 ) uniform vec4 u_Viewport; layout( location = 1 ) uniform vec4 u_Viewport;

View file

@ -126,7 +126,7 @@
//! type library //! type library
//! include lib/utils.glsl //! include utils.glsl

View file

@ -19,4 +19,4 @@ layout( location = 8 ) uniform int u_Correction;
//layout( location = 1 ) out float o_Z; //layout( location = 1 ) out float o_Z;
layout( binding = 0 , rgba16f ) writeonly uniform image2D u_Output; layout( binding = 0 , rgba16f ) writeonly uniform image2D u_Output;
//! include lib/raymarching.glsl //! include raymarching.glsl

View file

@ -13,4 +13,4 @@ layout( location = 8 ) uniform int u_Correction;
layout( location = 0 ) out vec3 o_Color; layout( location = 0 ) out vec3 o_Color;
layout( location = 1 ) out float o_Z; layout( location = 1 ) out float o_Z;
//! include lib/raymarching.glsl //! include raymarching.glsl

View file

@ -1,5 +1,5 @@
//! type library //! type library
//! include lib/utils.glsl //! include utils.glsl
vec2 RM_Map( in vec3 pos ); vec2 RM_Map( in vec3 pos );

View file

@ -1,5 +1,5 @@
//! type library //! type library
//! include lib/utils.glsl //! include utils.glsl
struct T_PBRMaterial struct T_PBRMaterial

View file

@ -1,12 +1,12 @@
#version 450 core #version 450 core
//! type compute //! type compute
//! include chunks/raymarcher-cs.glsl //! include /lib/raymarcher-cs.glsl
//! include lib/hg_sdf.glsl //! include /lib/hg_sdf.glsl
//! include lib/shading-pbr.glsl //! include /lib/shading-pbr.glsl
//! include lib/shading-blinnphong.glsl //! include /lib/shading-blinnphong.glsl
//! include lib/fog.glsl //! include /lib/fog.glsl
T_BPMaterial BPMaterials[1] = { T_BPMaterial BPMaterials[1] = {

View file

@ -1,12 +1,12 @@
#version 450 core #version 450 core
//! type fragment //! type fragment
//! include chunks/raymarcher.glsl //! include /lib/raymarcher.glsl
//! include lib/hg_sdf.glsl //! include /lib/hg_sdf.glsl
//! include lib/shading-pbr.glsl //! include /lib/shading-pbr.glsl
//! include lib/shading-blinnphong.glsl //! include /lib/shading-blinnphong.glsl
//! include lib/fog.glsl //! include /lib/fog.glsl
T_BPMaterial BPMaterials[1] = { T_BPMaterial BPMaterials[1] = {

View file

@ -436,7 +436,7 @@ void T_OpContext::run(
if ( !prIndex ) { if ( !prIndex ) {
throw X_OpFailure{ instr , "pipeline uses uninitialised program" }; throw X_OpFailure{ instr , "pipeline uses uninitialised program" };
} }
progNames[ i ] = programs[ prIndex - 1 ]->name( ); progNames[ i ] = programs[ prIndex - 1 ]->name( ).toString( );
} }
pipelines[ plIndex ] = NewOwned< T_ShaderPipeline >( pipelines[ plIndex ] = NewOwned< T_ShaderPipeline >(

View file

@ -133,7 +133,7 @@ T_Optional< E_ShaderType > T_ShaderProgram::type( ) const
} }
} }
T_String T_ShaderProgram::name( ) const T_FSPath T_ShaderProgram::name( ) const
{ {
if ( id_ ) { if ( id_ ) {
return UI::Shaders( ).programs_[ id_ - 1 ].name; return UI::Shaders( ).programs_[ id_ - 1 ].name;
@ -260,32 +260,32 @@ GLuint T_ShaderPipeline::program(
namespace { namespace {
using F_GetInput_ = std::function< T_ShaderInput const*( T_String const& ) >; using F_GetInput_ = std::function< T_ShaderInput const*( T_FSPath const& ) >;
using T_Code_ = T_ShaderManager::T_ShaderCode; using T_Code_ = T_ShaderManager::T_ShaderCode;
// Code builder, state and functions // Code builder, state and functions
struct T_CodeBuilder_ struct T_CodeBuilder_
{ {
struct T_StackEntry_ { struct T_StackEntry_ {
T_String name; T_FSPath name;
T_ShaderInput const* input; T_ShaderInput const* input;
uint32_t pos; uint32_t pos;
}; };
F_GetInput_ loader; F_GetInput_ loader;
const T_String name; const T_FSPath name;
T_Code_& code; T_Code_& code;
T_ShaderInput const* main; T_ShaderInput const* main;
T_KeyValueTable< T_String , uint32_t > pos; T_KeyValueTable< T_FSPath , uint32_t > pos;
std::vector< T_StackEntry_ > stack; std::vector< T_StackEntry_ > stack;
T_Array< T_String > libraries; T_Array< T_FSPath > libraries;
T_ShaderInput const* current; T_ShaderInput const* current;
uint32_t cpos{ 0 }; uint32_t cpos{ 0 };
T_String cname; T_FSPath cname;
T_CodeBuilder_( F_GetInput_ loader , T_CodeBuilder_( F_GetInput_ loader ,
T_String const& name , T_FSPath const& name ,
T_Code_& code ) T_Code_& code )
: loader( loader ) , name( name ) , code( code ) , : loader( loader ) , name( name ) , code( code ) ,
main( loader( name ) ) main( loader( name ) )
@ -293,13 +293,13 @@ struct T_CodeBuilder_
bool buildCode( ); bool buildCode( );
void appendChunk( T_ShaderInputChunk const& chunk ); void appendChunk( T_ShaderInputChunk const& chunk );
void include( T_String const& name , void include( T_FSPath const& name ,
const uint32_t lines ); const uint32_t lines );
void next( ); void next( );
void addInputLoaderErrors( void addInputLoaderErrors(
T_ShaderInput const* input , T_ShaderInput const* input ,
T_String const& name ); T_FSPath const& name );
}; };
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
@ -326,7 +326,7 @@ bool T_CodeBuilder_::buildCode( )
if ( chunk.type == E_ShaderInputChunk::CODE ) { if ( chunk.type == E_ShaderInputChunk::CODE ) {
appendChunk( chunk ); appendChunk( chunk );
} else { } else {
include( chunk.text , chunk.lines ); include( chunk.data.value< T_FSPath >( ) , chunk.lines );
} }
next( ); next( );
@ -347,12 +347,12 @@ void T_CodeBuilder_::appendChunk(
code.sources.addNew( cname ); code.sources.addNew( cname );
code.counts.add( chunk.lines ); code.counts.add( chunk.lines );
code.starts.add( *p ); code.starts.add( *p );
code.code << chunk.text; code.code << chunk.data.value< T_String >( );
*p += chunk.lines; *p += chunk.lines;
} }
void T_CodeBuilder_::include( void T_CodeBuilder_::include(
T_String const& nname , T_FSPath const& nname ,
const uint32_t lines ) const uint32_t lines )
{ {
auto* const p( pos.get( cname ) ); auto* const p( pos.get( cname ) );
@ -376,7 +376,7 @@ void T_CodeBuilder_::include(
return; return;
} }
T_ShaderInput const* const isi( loader( nname ) ); T_ShaderInput const* const isi{ loader( nname ) };
code.files.add( nname , isi != nullptr ); code.files.add( nname , isi != nullptr );
// Check for problems // Check for problems
@ -420,7 +420,7 @@ void T_CodeBuilder_::next( )
void T_CodeBuilder_::addInputLoaderErrors( void T_CodeBuilder_::addInputLoaderErrors(
T_ShaderInput const* input , T_ShaderInput const* input ,
T_String const& name ) T_FSPath const& name )
{ {
for ( auto const& errs : input->errors ) { for ( auto const& errs : input->errors ) {
code.errors.addNew( name , errs.line , (char*) errs.error.toOSString( ).data( ) ); code.errors.addNew( name , errs.line , (char*) errs.error.toOSString( ).data( ) );
@ -441,7 +441,7 @@ T_ShaderManager::T_ShaderManager( ) noexcept
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
T_ShaderProgram T_ShaderManager::program( T_ShaderProgram T_ShaderManager::program(
T_String const& name ) T_FSPath const& name )
{ {
loadProgram( name ); loadProgram( name );
assert( programIndex_.contains( name ) ); assert( programIndex_.contains( name ) );
@ -530,16 +530,16 @@ T_ShaderPipeline T_ShaderManager::pipeline(
void T_ShaderManager::update( ) void T_ShaderManager::update( )
{ {
using namespace ebcl; using namespace ebcl;
T_Set< T_String > temp{ UseTag< ArrayBacked< 64 > >( ) }; T_Set< T_FSPath > temp{ UseTag< ArrayBacked< 64 > >( ) };
T_StringBuilder sb; T_StringBuilder sb;
inputs_.clear( ); inputs_.clear( );
// Check for missing files // Check for missing files
for ( auto it = missing_.keys( ).cbegin( ) ; it.valid( ) ; ++it ) { for ( auto it = missing_.keys( ).cbegin( ) ; it.valid( ) ; ++it ) {
const bool exists( ([] ( T_String const& name ) -> bool { const bool exists( ([] ( T_FSPath const& name ) -> bool {
T_FSPath p{ T_FSPath{ "shaders" } + T_FSPath{ name } };
struct stat buffer; struct stat buffer;
return ( stat( Common::Project( ).strPathOf( p ).data( ) , &buffer ) == 0 ); const auto p{ Common::Project( ).strPathOf( name ).toOSString( ) };
return ( stat( (char const*) p.data( ) , &buffer ) == 0 );
})( *it ) ); })( *it ) );
if ( !exists ) { if ( !exists ) {
continue; continue;
@ -613,7 +613,7 @@ void T_ShaderManager::update( )
void T_ShaderManager::loadProgram( void T_ShaderManager::loadProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ) T_FSPath const& name )
{ {
if ( !useExistingProgram( pipeline , name ) ) { if ( !useExistingProgram( pipeline , name ) ) {
initProgramRecord( name ).plReferences.add( pipeline ); initProgramRecord( name ).plReferences.add( pipeline );
@ -622,7 +622,7 @@ void T_ShaderManager::loadProgram(
bool T_ShaderManager::useExistingProgram( bool T_ShaderManager::useExistingProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ) T_FSPath const& name )
{ {
auto const* pos( programIndex_.get( name ) ); auto const* pos( programIndex_.get( name ) );
if ( !pos ) { if ( !pos ) {
@ -635,7 +635,7 @@ bool T_ShaderManager::useExistingProgram(
} }
void T_ShaderManager::loadProgram( void T_ShaderManager::loadProgram(
T_String const& name ) T_FSPath const& name )
{ {
if ( !useExistingProgram( name ) ) { if ( !useExistingProgram( name ) ) {
initProgramRecord( name ); initProgramRecord( name );
@ -653,7 +653,7 @@ void T_ShaderManager::loadBuiltinProgram(
} }
bool T_ShaderManager::useExistingProgram( bool T_ShaderManager::useExistingProgram(
T_String const& name ) T_FSPath const& name )
{ {
auto const* pos( programIndex_.get( name ) ); auto const* pos( programIndex_.get( name ) );
if ( !pos ) { if ( !pos ) {
@ -680,7 +680,7 @@ uint32_t T_ShaderManager::newProgramRecord( )
} }
T_ShaderManager::T_Program_& T_ShaderManager::initProgramRecord( T_ShaderManager::T_Program_& T_ShaderManager::initProgramRecord(
T_String const& name , T_FSPath const& name ,
const E_ShaderType type , const E_ShaderType type ,
char const* const source ) char const* const source )
{ {
@ -713,24 +713,32 @@ T_ShaderManager::T_Program_& T_ShaderManager::initProgramRecord(
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
T_ShaderInput const* T_ShaderManager::getInput( T_ShaderInput const* T_ShaderManager::getInput(
T_String const& name ) T_FSPath const& name )
{ {
auto const* const existing( inputs_.get( name ) ); T_FSPath extra;
T_FSPath const* absPath;
T_FSPath const* relPath;
if ( name.isAbsolute( ) ) {
extra = name.makeRelative( Common::Project( ).basePath( ) );
absPath = &name;
relPath = &extra;
} else {
extra = Common::Project( ).pathOf( name );
absPath = &extra;
relPath = &name;
}
auto const* const existing( inputs_.get( *relPath ) );
if ( existing ) { if ( existing ) {
return existing->get( ); return existing->get( );
} }
T_ShaderInput ni; T_ShaderInput ni;
const T_String path{ [&]() -> T_String { if ( !ni.load( *absPath ) ) {
T_StringBuilder sb;
sb << "shaders/" << name;
return std::move( sb );
}() };
if ( !ni.load( Common::Project( ).strPathOf( path ) ) ) {
return nullptr; return nullptr;
} }
inputs_.add( name , NewOwned< T_ShaderInput >( std::move( ni ) ) ); inputs_.add( *relPath , NewOwned< T_ShaderInput >( std::move( ni ) ) );
return inputs_.get( name )->get( ); return inputs_.get( *relPath )->get( );
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
@ -844,15 +852,13 @@ void T_ShaderManager::initProgram(
// Build the code // Build the code
auto name( program.name ); auto name( program.name );
printf( "init program %s\n" , program.name.toOSString( ).data( ) ); printf( "init program %s\n" , program.name.toString( ).toOSString( ).data( ) );
auto& code( program.code ); auto& code( program.code );
T_CodeBuilder_ cb( [this]( T_String const& n ) { return getInput( n ); } , T_CodeBuilder_ cb{
name , code ); [this]( T_FSPath const& n ) { return getInput( n ); } ,
const bool built( name , code
T_CodeBuilder_{ };
[this]( T_String const& n ) { return getInput( n ); } , const bool built{ cb.buildCode( ) };
program.name , code
}.buildCode( ) );
// Initialise file watcher + missing files // Initialise file watcher + missing files
program.watch = T_WatchedFiles{ Common::Watcher( ) , program.watch = T_WatchedFiles{ Common::Watcher( ) ,
@ -862,10 +868,9 @@ void T_ShaderManager::initProgram(
const auto nf( code.files.size( ) ); const auto nf( code.files.size( ) );
auto& w( *( program.watch.target( ) ) ); auto& w( *( program.watch.target( ) ) );
for ( auto i = 0u ; i < nf ; i ++ ) { for ( auto i = 0u ; i < nf ; i ++ ) {
T_String const& fn( code.files.keys( )[ i ] ); T_FSPath const& fn( code.files.keys( )[ i ] );
if ( code.files.values( )[ i ] ) { if ( code.files.values( )[ i ] ) {
T_FSPath p{ T_FSPath{ "shaders" } + T_FSPath{ fn } }; w.watch( Common::Project( ).pathOf( fn ) );
w.watch( Common::Project( ).strPathOf( p ) );
} else { } else {
auto& mset( missing_.getOrCreate( fn ) ); auto& mset( missing_.getOrCreate( fn ) );
if ( !mset.contains( name ) ) { if ( !mset.contains( name ) ) {
@ -875,6 +880,7 @@ void T_ShaderManager::initProgram(
} }
if ( !( built && code.errors.empty( ) ) ) { if ( !( built && code.errors.empty( ) ) ) {
printf( "... failed\n" );
return; return;
} }
buildProgram( program ); buildProgram( program );
@ -887,7 +893,7 @@ void T_ShaderManager::initBuiltinProgram(
{ {
auto name( program.name ); auto name( program.name );
printf( "init built-in program %s\n" , printf( "init built-in program %s\n" ,
program.name.substr( 1 ).toOSString( ).data( ) ); program.name.toString( ).substr( 1 ).toOSString( ).data( ) );
program.code.code << source << '\0'; program.code.code << source << '\0';
program.code.type = type; program.code.type = type;
@ -968,7 +974,7 @@ void T_ShaderManager::parseGLSLError(
} }
code.errors.addNew( code.errors.addNew(
pos == 0 ? "*unknown*" : ((char*)code.sources[ pos - 1 ].toOSString( ).data( ) ) , pos == 0 ? T_FSPath{ "*unknown*" } : code.sources[ pos - 1 ] ,
pos == 0 ? 0 : ( rawLine + code.counts[ pos - 1 ] - check + code.starts[ pos - 1 ] ) , pos == 0 ? 0 : ( rawLine + code.counts[ pos - 1 ] - check + code.starts[ pos - 1 ] ) ,
errorLine ); errorLine );
} }
@ -976,7 +982,7 @@ void T_ShaderManager::parseGLSLError(
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
void T_ShaderManager::programUpdated( void T_ShaderManager::programUpdated(
T_String const& name ) T_FSPath const& name )
{ {
if ( !updates_.contains( name ) ) { if ( !updates_.contains( name ) ) {
updates_.add( name ); updates_.add( name );
@ -998,7 +1004,7 @@ void T_ShaderManager::resetProgram(
auto const& files( program.code.files ); auto const& files( program.code.files );
const auto nf( files.size( ) ); const auto nf( files.size( ) );
for ( auto i = 0u ; i < nf ; i ++ ) { for ( auto i = 0u ; i < nf ; i ++ ) {
T_String const& k{ files.keys( )[ i ] }; T_FSPath const& k{ files.keys( )[ i ] };
bool v{ files[ i ] }; bool v{ files[ i ] };
auto* const ptr( missing_.get( k ) ); auto* const ptr( missing_.get( k ) );
if ( v || !ptr ) { if ( v || !ptr ) {
@ -1032,7 +1038,7 @@ void T_ShaderManager::makeUI( )
const auto n( std::count_if( programs_.begin( ) , programs_.end( ) , const auto n( std::count_if( programs_.begin( ) , programs_.end( ) ,
[]( auto const& p ) { []( auto const& p ) {
return ( !p.plReferences.empty( ) || p.saReferences != 0 ) return ( !p.plReferences.empty( ) || p.saReferences != 0 )
&& !p.name.startsWith( "*" ); && p.name.isValid( );
} ) ); } ) );
std::vector< size_t > indices; std::vector< size_t > indices;
@ -1040,7 +1046,7 @@ void T_ShaderManager::makeUI( )
for ( auto i = 0u ; i < rn ; i ++ ) { for ( auto i = 0u ; i < rn ; i ++ ) {
auto const& p( programs_[ i ] ); auto const& p( programs_[ i ] );
if ( ( !p.plReferences.empty( ) || p.saReferences ) if ( ( !p.plReferences.empty( ) || p.saReferences )
&& !p.name.startsWith( "*" ) ) { && p.name.isValid( ) ) {
indices.push_back( i ); indices.push_back( i );
} }
} }
@ -1064,11 +1070,11 @@ void T_ShaderManager::makeUI( )
const bool open( nErrors const bool open( nErrors
? TreeNodeEx( &program , ImGuiTreeNodeFlags_OpenOnArrow ? TreeNodeEx( &program , ImGuiTreeNodeFlags_OpenOnArrow
| ImGuiTreeNodeFlags_OpenOnDoubleClick , "%s" , | ImGuiTreeNodeFlags_OpenOnDoubleClick , "%s" ,
program.name.toOSString( ).data( ) ) program.name.toString( ).toOSString( ).data( ) )
: false ); : false );
if ( !nErrors ) { if ( !nErrors ) {
Text( "%s" , program.name.toOSString( ).data( ) ); Text( "%s" , program.name.toString( ).toOSString( ).data( ) );
} }
SameLine( 400 ); SameLine( 400 );
@ -1087,10 +1093,12 @@ void T_ShaderManager::makeUI( )
for ( auto const& err : program.code.errors ) { for ( auto const& err : program.code.errors ) {
NewLine( ); NewLine( );
SameLine( 50 ); SameLine( 50 );
Text( "%s" , err.source.toOSString( ).data( ) ); Text( "%s" , err.source.makeRelative(
SameLine( 250 ); Common::Project( ).basePath( )
).toString( ).toOSString( ).data( ) );
SameLine( 350 );
Text( "line %d" , err.line ); Text( "line %d" , err.line );
SameLine( 370 ); SameLine( 470 );
Text( "%s" , err.error.toOSString( ).data( ) ); Text( "%s" , err.error.toOSString( ).data( ) );
} }
TreePop( ); TreePop( );

View file

@ -18,7 +18,7 @@ struct T_ShaderProgram
void enable( ) const; void enable( ) const;
GLuint id( ) const; GLuint id( ) const;
T_Optional< E_ShaderType > type( ) const; T_Optional< E_ShaderType > type( ) const;
T_String name( ) const; T_FSPath name( ) const;
private: private:
explicit T_ShaderProgram( uint32_t id ) noexcept; explicit T_ShaderProgram( uint32_t id ) noexcept;
@ -56,16 +56,16 @@ struct T_ShaderManager
E_ShaderType type; E_ShaderType type;
T_AutoArray< uint32_t , 8 > starts; // Position of chunk in source file T_AutoArray< uint32_t , 8 > starts; // Position of chunk in source file
T_AutoArray< uint32_t , 8 > counts; // Chunk lengths T_AutoArray< uint32_t , 8 > counts; // Chunk lengths
T_AutoArray< T_String , 8 > sources; // Chunk source files T_AutoArray< T_FSPath , 8 > sources; // Chunk source files
T_StringBuilder code; T_StringBuilder code;
T_Array< T_ShaderError > errors; T_Array< T_ShaderError > errors;
T_KeyValueTable< T_String , bool > files; T_KeyValueTable< T_FSPath , bool > files;
}; };
T_ShaderManager( ) noexcept; T_ShaderManager( ) noexcept;
// Build / get a program based on its name // Build / get a program based on its name
T_ShaderProgram program( T_String const& name ); T_ShaderProgram program( T_FSPath const& name );
// Build a program from its source code // Build a program from its source code
T_ShaderProgram program( T_String const& name , T_ShaderProgram program( T_String const& name ,
E_ShaderType type , E_ShaderType type ,
@ -112,7 +112,7 @@ struct T_ShaderManager
struct T_Program_ struct T_Program_
{ {
T_String name; T_FSPath name;
T_Array< T_String > plReferences; T_Array< T_String > plReferences;
uint32_t saReferences{ 0 }; uint32_t saReferences{ 0 };
T_ShaderCode code; T_ShaderCode code;
@ -122,43 +122,43 @@ struct T_ShaderManager
bool uiEnabled_ = false; bool uiEnabled_ = false;
T_ObjectTable< T_String , T_Pipeline_ > pipelines_; T_ObjectTable< T_FSPath , T_Pipeline_ > pipelines_;
T_Array< T_Program_ > programs_; T_Array< T_Program_ > programs_;
T_KeyValueTable< T_String , uint32_t > programIndex_; T_KeyValueTable< T_FSPath , uint32_t > programIndex_;
T_KeyValueTable< T_String , P_ShaderInput > inputs_; T_KeyValueTable< T_FSPath , P_ShaderInput > inputs_;
T_KeyValueTable< T_String , T_Array< T_String > > missing_; T_KeyValueTable< T_FSPath , T_Array< T_FSPath > > missing_;
T_Array< T_String > updates_; T_Array< T_FSPath > updates_;
T_String cPipeline_{ }; T_String cPipeline_{ };
// Load/use existing program for use with pipelines // Load/use existing program for use with pipelines
void loadProgram( void loadProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ); T_FSPath const& name );
bool useExistingProgram( bool useExistingProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ); T_FSPath const& name );
// Load/use existing program for standalone use // Load/use existing program for standalone use
void loadProgram( T_String const& name ); void loadProgram( T_FSPath const& name );
void loadBuiltinProgram( void loadBuiltinProgram(
T_String const& name , T_String const& name ,
E_ShaderType type , E_ShaderType type ,
char const* source ); char const* source );
bool useExistingProgram( T_String const& name ); bool useExistingProgram( T_FSPath const& name );
// Program management // Program management
T_Program_& initProgramRecord( // Init management data T_Program_& initProgramRecord( // Init management data
T_String const& record , T_FSPath const& record ,
E_ShaderType type = E_ShaderType::__COUNT__ , E_ShaderType type = E_ShaderType::__COUNT__ ,
char const* source = nullptr ); char const* source = nullptr );
uint32_t newProgramRecord( ); // Allocate entry in index uint32_t newProgramRecord( ); // Allocate entry in index
T_ShaderInput const* getInput( T_ShaderInput const* getInput(
T_String const& name ); T_FSPath const& name );
void dereferencePipeline( T_String const& id ); void dereferencePipeline( T_String const& id );
void dereferenceProgram( void dereferenceProgram(
@ -178,6 +178,6 @@ struct T_ShaderManager
T_ShaderCode& code , T_ShaderCode& code ,
char const* errorLine ); char const* errorLine );
void programUpdated( T_String const& name ); void programUpdated( T_FSPath const& name );
void resetProgram( T_Program_& program ); void resetProgram( T_Program_& program );
}; };