Merge "This is a hotfix for side effect on Scrolling, LineWrap and Invalid position...
authorBowon Ryu <bowon.ryu@samsung.com>
Mon, 26 Apr 2021 05:18:15 +0000 (05:18 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 26 Apr 2021 05:18:15 +0000 (05:18 +0000)
14 files changed:
automated-tests/.gitignore
automated-tests/src/dali-shader-generator/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-shader-generator/shader/fragment-shader.frag [new file with mode: 0644]
automated-tests/src/dali-shader-generator/shader/shader-define.def [new file with mode: 0644]
automated-tests/src/dali-shader-generator/shader/vertex-shader.vert [new file with mode: 0644]
automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp [new file with mode: 0644]
build/tizen/.gitignore
build/tizen/CMakeLists.txt
build/tizen/dali-scene-loader/CMakeLists.txt
build/tizen/shader-generator.sh [deleted file]
dali-toolkit/internal/file.list
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/shader-generator/shader-generator.cpp [new file with mode: 0644]
packaging/dali-toolkit.spec

index b12e784..17d54d9 100644 (file)
@@ -2,5 +2,5 @@
 build
 build.log
 tct*core.h
-CMakeLists.txt
+/CMakeLists.txt
 results_xml.*
diff --git a/automated-tests/src/dali-shader-generator/CMakeLists.txt b/automated-tests/src/dali-shader-generator/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7057a36
--- /dev/null
@@ -0,0 +1,49 @@
+SET(PKG_NAME "dali-shader-generator")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+
+PKG_CHECK_MODULES(${EXEC_NAME} REQUIRED
+  dali2-toolkit
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
+
+SET(SHADER_GENERATOR dali-shader-generator)
+SET(GENERATED_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/shader/generated)
+SET(SHADER_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/shader)
+
+ADD_CUSTOM_TARGET(test_help ALL COMMAND ${SHADER_GENERATOR} -h | grep "DALi Shader Generator" > /dev/null 2>&1 && echo "test_help Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(test_no_params ALL COMMAND ${SHADER_GENERATOR} > /dev/null 2>&1 || echo "test_no_params Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(test_version ALL COMMAND ${SHADER_GENERATOR} -v | wc -l | grep 1 > /dev/null 2>&1 && echo "test_version Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(test_invalid_option ALL COMMAND ${SHADER_GENERATOR} --undeclared > /dev/null 2>&1 || echo "test_invalid_option Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(test_too_many_params ALL COMMAND ${SHADER_GENERATOR} ONE TWO THREE > /dev/null 2>&1 || echo "test_too_many_params Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(test_invalid_indir ALL COMMAND ${SHADER_GENERATOR} ONE TWO > /dev/null 2>&1 || echo "test_invalid_indir Succeeded" VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_check_built_in_created
+  ALL
+  COMMAND ${SHADER_GENERATOR} . ${GENERATED_FOLDER} | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded"
+  VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_check_built_in_not_created
+  ALL
+  COMMAND ${SHADER_GENERATOR} --skip . ${GENERATED_FOLDER} | grep builtin-shader > /dev/null 2>&1 || echo "test_check_built_in_not_created Succeeded"
+  VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_frag_correct
+  ALL
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded"
+  VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_vert_correct
+  ALL
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded"
+  VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_def_correct
+  ALL
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded"
+  VERBATIM)
diff --git a/automated-tests/src/dali-shader-generator/shader/fragment-shader.frag b/automated-tests/src/dali-shader-generator/shader/fragment-shader.frag
new file mode 100644 (file)
index 0000000..d9b3d5a
--- /dev/null
@@ -0,0 +1,14 @@
+varying mediump vec2 vTexCoord;
+
+uniform sampler2D sTexture;
+uniform lowp vec4 uColor;
+
+void main()
+{
+  mediump vec4 color = texture2D( sTexture, vTexCoord );
+  if(color.a <= 0.0001)
+  {
+    discard;
+  }
+  gl_FragColor = color * uColor;
+}
diff --git a/automated-tests/src/dali-shader-generator/shader/shader-define.def b/automated-tests/src/dali-shader-generator/shader/shader-define.def
new file mode 100644 (file)
index 0000000..c6e148b
--- /dev/null
@@ -0,0 +1,2 @@
+#version 300 es
+precision highp float;
diff --git a/automated-tests/src/dali-shader-generator/shader/vertex-shader.vert b/automated-tests/src/dali-shader-generator/shader/vertex-shader.vert
new file mode 100644 (file)
index 0000000..e5cbaa7
--- /dev/null
@@ -0,0 +1,59 @@
+attribute mediump vec2 aPosition;
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+
+uniform mediump vec2 start_point;
+uniform mediump vec2 end_point;
+uniform mediump vec2 rotate_center;
+uniform mediump float rotate_angle;
+
+varying mediump vec2 vTexCoord;
+varying mediump vec2 vStart;
+varying mediump vec2 vEnd;
+
+vec2 rotate(vec2 x, vec2 c, float a)
+{
+  vec2 d = x - c;
+  vec2 r = vec2(d.x * cos(a) - d.y * sin(a), d.x * sin(a) + d.y * cos(a));
+
+#ifdef UNIT_TYPE_BOUNDING_BOX
+  return r + c;
+#endif
+
+  /* UnitType::OBJECT_BOUNDING_BOX */
+#ifdef UNIT_TYPE_USER
+  return (r + c) / uSize.x;
+#endif
+  /* UnitType::USER_SPACE*/
+}
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+
+vec4 ComputeVertexPosition()
+{
+  vec2 visualSize = mix( uSize.xy*size, size, offsetSizeMode.zw );
+  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );
+  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+}
+
+void main()
+{
+  vStart = rotate( start_point, rotate_center, rotate_angle );
+  vEnd = rotate( end_point, rotate_center, rotate_angle );
+  gl_Position = uMvpMatrix * ComputeVertexPosition();
+
+#ifdef UNIT_TYPE_BOUNDING_BOX
+  vTexCoord = vec2(aPosition.x, -aPosition.y);
+#endif
+/* UnitType::OBJECT_BOUNDING_BOX */
+
+#ifdef UNIT_TYPE_USER
+  vTexCoord = vec2(aPosition.x, -aPosition.y * uSize.y / uSize.x);
+#endif
+/* UnitType::USER_SPACE*/
+}
diff --git a/automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp b/automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp
new file mode 100644 (file)
index 0000000..842fd98
--- /dev/null
@@ -0,0 +1,6 @@
+#include <iostream>
+int main(int argc, char * const argv[])
+{
+  std::cout << "All tests run as part of Cmake build." << std::endl;
+  return 0;
+}
index e59a17f..2d253c9 100644 (file)
@@ -2,4 +2,5 @@ build
 dali.info
 *.dylib
 dali2-*-config.cmake
-libdali2-scene-loader.so*
\ No newline at end of file
+libdali2-scene-loader.so*
+dali-shader-generator
index 8be2625..906453d 100644 (file)
@@ -286,13 +286,40 @@ ENDIF()
 # Generate source files for shaders
 SET(SHADER_SOURCE_DIR "${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/shaders/")
 SET(SHADER_GENERATED_DIR "${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/generated")
-EXECUTE_PROCESS( COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/shader-generator.sh ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}" )
 
 SET(GENERATED_SHADER_DIR ${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/)
 SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
              "${GENERATED_SHADER_DIR}/generated/"
              "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h")
 
+SET(SHADER_GENERATOR_NAME dali-shader-generator)
+SET(SHADER_GENERATOR_SOURCES ${ROOT_SRC_DIR}/dali-toolkit/shader-generator/shader-generator.cpp)
+
+IF(NOT ANDROID)
+  ADD_EXECUTABLE(${SHADER_GENERATOR_NAME} ${SHADER_GENERATOR_SOURCES})
+  INSTALL(TARGETS ${SHADER_GENERATOR_NAME} DESTINATION ${BINDIR})
+ELSE()
+  # Need to build dali-shader-generator using the host compiler, not the android cross-compiler so
+  # that it can be run on the host machine
+  OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory for Android")
+  IF(${ANDROID_HOST_COMPILER} STREQUAL "OFF")
+    MESSAGE(FATAL_ERROR "-DANDROID_HOST_COMPILER=\"Compiler\" must be set")
+  ENDIF()
+
+  ADD_CUSTOM_COMMAND(OUTPUT ${SHADER_GENERATOR_NAME}
+                     COMMAND ${ANDROID_HOST_COMPILER} -o ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} -std=c++17 ${SHADER_GENERATOR_SOURCES})
+  INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME}
+          PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+          DESTINATION bin)
+ENDIF()
+
+SET(BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
+ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
+                   DEPENDS ${SHADER_GENERATOR_NAME}
+                   COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+
+SET(SOURCES ${SOURCES} ${BUILT_IN_SHADER_GEN_CPP})
+
 IF( WIN32 OR APPLE )
   SET( DALICORE_LDFLAGS
         "${DALICORE_LDFLAGS}"
index ae7fea2..7789dda 100644 (file)
@@ -77,6 +77,22 @@ include_directories(${repo_root_dir}
        ${prefix_include_dir}
 )
 
+# Generate source files for shaders
+SET(SHADER_SOURCE_DIR "${scene_loader_dir}/internal/graphics/shaders/")
+SET(SHADER_GENERATED_DIR "${scene_loader_dir}/internal/graphics/generated")
+
+SET(GENERATED_SHADER_DIR ${scene_loader_dir}/internal/graphics/)
+SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+             "${GENERATED_SHADER_DIR}/generated/"
+             "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h")
+
+SET( BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
+ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
+                   DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME}
+                   COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+
+SET( scene_loader_src_files ${scene_loader_src_files} ${BUILT_IN_SHADER_GEN_CPP} )
+
 add_library(${name} SHARED ${scene_loader_src_files})
 
 target_link_libraries(${name} ${DALICORE_LDFLAGS} ${DALIADAPTOR_LDFLAGS}
@@ -87,16 +103,6 @@ if( ANDROID )
        target_link_libraries(${name} log)
 endif()
 
-# Generate source files for shaders
-SET(SHADER_SOURCE_DIR "${scene_loader_dir}/internal/graphics/shaders/")
-SET(SHADER_GENERATED_DIR "${scene_loader_dir}/internal/graphics/generated")
-EXECUTE_PROCESS( COMMAND bash -c "${repo_root_dir}/build/tizen/shader-generator.sh ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}" )
-
-SET(GENERATED_SHADER_DIR ${scene_loader_dir}/internal/graphics/)
-SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
-             "${GENERATED_SHADER_DIR}/generated/"
-             "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h")
-
 IF( INSTALL_CMAKE_MODULES )
        SET_TARGET_PROPERTIES( ${name}
                PROPERTIES
diff --git a/build/tizen/shader-generator.sh b/build/tizen/shader-generator.sh
deleted file mode 100755 (executable)
index 7b6b2fc..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-
-indir=$1
-outdir=$2
-
-mkdir -p $outdir
-
-if [ ! -e $indir ] ; then
-    echo "Error! "$indir" not found!"
-    exit 0
-fi
-
-cd $indir
-all_shaders=$(ls -1 *.{vert,frag,def})
-cd $OLDPWD
-
-# Generate one header file per shader which is defined as a const std::string_view
-for name in $all_shaders ; do
-  echo "Generating header files for $name..."
-  varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;')
-
-  newname=$(echo ${name} | sed -e 's/\./-/;')".h"
-  echo Writing $newname
-
-  shader_fullpath=$(echo ${indir})$name
-
-  header_name="${varname}_GEN_H"
-  echo "const std::string_view" "$varname""{" > $outdir/$newname
-  cat $shader_fullpath | sed -e 's/^..*$/"&\\n"/' >> $outdir/$newname
-  echo "};" >> $outdir/$newname
-done
-
-# Generate one cpp file that includes all the previously generated string_views for shaders
-echo "Generating cpp file..."
-echo -e "#include \"../builtin-shader-extern-gen.h\"\n" > $outdir/builtin-shader-gen.cpp
-
-varnames=
-for name in $all_shaders ; do
-    varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;')
-    newname=$(echo ${name} | sed -e 's/\./-/;')".h"
-    varnames="${varnames} $varname"
-    echo "#include \"$newname\"" >> $outdir/builtin-shader-gen.cpp
-done
-
-# Generate one header file that defines all the shader string_views as extern variables
-echo "Generating extern header file ( for external use )..."
-echo "#ifndef GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H" > $outdir/../builtin-shader-extern-gen.h
-echo -e "#define GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H\n" >> $outdir/../builtin-shader-extern-gen.h
-
-echo "#include <string_view>" >> $outdir/../builtin-shader-extern-gen.h
-echo "" >> $outdir/../builtin-shader-extern-gen.h
-
-for name in $all_shaders ; do
-    varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;')
-    newname=$(echo ${name} | sed -e 's/\./-/;')".h"
-    echo "extern const std::string_view $varname;" >> $outdir/../builtin-shader-extern-gen.h
-done
-cat >> $outdir/../builtin-shader-extern-gen.h << EOF
-
-#endif // GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H
-EOF
-
index ede26c1..35ac87b 100644 (file)
@@ -182,7 +182,6 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/transition-effects/cube-transition-wave-effect-impl.cpp
    ${toolkit_src_dir}/text/xhtml-entities.cpp
    ${toolkit_src_dir}/drag-drop-detector/drag-and-drop-detector-impl.cpp
-   ${toolkit_src_dir}/graphics/generated/builtin-shader-gen.cpp
 )
 
 SET( SOURCES ${SOURCES}
index 7d2ab8a..2f475a2 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 22;
+const unsigned int TOOLKIT_MICRO_VERSION = 23;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
diff --git a/dali-toolkit/shader-generator/shader-generator.cpp b/dali-toolkit/shader-generator/shader-generator.cpp
new file mode 100644 (file)
index 0000000..d386fb3
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <string_view>
+#include <vector>
+
+using namespace std;
+namespace fs = filesystem;
+
+namespace
+{
+///////////////////////////////////////////////////////////////////////////////////////////////////
+string      PROGRAM_NAME; ///< We set the program name on this global early on for use in Usage.
+string_view VERSION = "1.0.0";
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Supported extensions for the files in the input directory.
+// clang-format off
+constexpr string_view SHADER_EXTENSIONS[] =
+{
+  ".vert",
+  ".frag",
+  ".def"
+};
+// clang-format on
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Function & variable to retrieve the size of the extension with the largest string size.
+constexpr auto GetShaderExtensionMaxSize()
+{
+  auto maxSize = 0u;
+  for(const auto& extension : SHADER_EXTENSIONS)
+  {
+    if(extension.size() > maxSize)
+    {
+      maxSize = extension.size();
+    }
+  }
+  return maxSize;
+}
+constexpr const int SHADER_MAX_EXTENSION_SIZE(GetShaderExtensionMaxSize());
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Prints out the Usage to standard output.
+void Usage()
+{
+  cout << "Usage: " << PROGRAM_NAME << " [OPTIONS] [IN_DIR] [OUT_DIR]" << endl;
+  cout << "  IN_DIR:  Input Directory which has all the shader files." << endl;
+  cout << "           Supported extensions:";
+  string extensions;
+  for(const auto& extension : SHADER_EXTENSIONS)
+  {
+    extensions = extensions + " \"" + string(extension) + "\",";
+  }
+  extensions.pop_back(); // Remove the last comma.
+  cout << extensions << "." << endl;
+  cout << "  OUT_DIR: Directory where the generated shader source code will be outputted to." << endl;
+  cout << "           This directory will be created if it does not exist." << endl;
+  cout << "           Any existing files of the same name in the directory will be overwritten." << endl;
+  cout << "  Options: " << endl;
+  cout << "     -s|--skip     Skips the generation of the built-in header and source files" << endl;
+  cout << "     -v|--version  Prints out the version" << endl;
+  cout << "     -h|--help     Help" << endl;
+  cout << "  NOTE: The options can be placed after the IN_DIR & OUT_DIR as well" << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Uses the filename to generate the shader variable name to use in source code.
+/// @param[in]  filename  The filename of the shader (including the extension)
+/// @return The shader variable name
+string GetShaderVariableName(const string& filename)
+{
+  string shaderVariableName("SHADER_" + filename);
+  for_each(
+    shaderVariableName.begin(),
+    shaderVariableName.end(),
+    [](char& character) {
+      switch(character)
+      {
+        case '-':
+        case '.':
+        {
+          character = '_';
+          break;
+        }
+
+        default:
+        {
+          character = ::toupper(character);
+          break;
+        }
+      }
+    });
+  return shaderVariableName;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Uses the ourDir & filename to generate the path of the output header file for the shader.
+/// @param[in]  outDir    The directory where the readable shaders will be outputted to
+/// @param[in]  filename  The filename of the shader (including the extension)
+/// @return The path to the output file
+fs::path GetShaderOutputFilePath(fs::path& outDir, const string& filename)
+{
+  string outFilename(filename);
+  replace(outFilename.end() - SHADER_MAX_EXTENSION_SIZE, outFilename.end(), '.', '-');
+  outFilename = outDir.string() + "/" + outFilename + ".h";
+  return outFilename;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Generates the header file from the input shader file.
+/// @param[in]  shaderFile          The full path of the input shader file
+/// @param[in]  shaderVariableName  The variable name to use for the string_view
+/// @param[in]  outFilePath         The full path to the output file
+void GenerateHeaderFile(
+  ifstream&       shaderFile,
+  const string&   shaderVariableName,
+  const fs::path& outFilePath)
+{
+  cout << "  Generating \"" << shaderVariableName << "\" in " << outFilePath.filename();
+  ofstream outFile(outFilePath);
+  if(outFile.is_open())
+  {
+    outFile << "#pragma once" << endl
+            << endl;
+    outFile << "const std::string_view " << shaderVariableName << endl;
+    outFile << "{" << endl;
+    string line;
+    while(getline(shaderFile, line))
+    {
+      outFile << "\"" << line << "\\n\"" << endl;
+    }
+    outFile << "};" << endl;
+    cout << " [OK]" << endl;
+  }
+  else
+  {
+    cout << " [FAIL]" << endl;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// If required, this accumulates data about all the shaders & generates the built-in cpp & header
+class BuiltInFilesGenerator
+{
+public:
+  /// Constructor
+  /// @param[in]  outDir  The path to the output directory
+  BuiltInFilesGenerator(const fs::path& outDir)
+  : mHeaderFilePath(outDir.string() + "/../" + string(HEADER_FILE_NAME)),
+    mSourceFilePath(outDir.string() + "/" + string(SOURCE_FILE_NAME))
+  {
+  }
+
+  /// Default destructor
+  ~BuiltInFilesGenerator() = default;
+
+  /// Adds the variable and the header file name to the appropriate vectors.
+  /// @param[in]  variableName    The string_view variable name used
+  /// @param[in]  headerFileName  The name of the header used
+  void Add(string&& variableName, const std::string& headerFilename)
+  {
+    mVariableNames.emplace_back(variableName);
+    mHeaderFileNames.emplace_back(headerFilename);
+  }
+
+  // Generates the built in files.
+  void Generate()
+  {
+    GenerateFile(
+      mVariableNames,
+      mHeaderFilePath,
+      "#pragma once\n\n#include <string_view>\n\n",
+      "extern const std::string_view ",
+      ";");
+
+    GenerateFile(
+      mHeaderFileNames,
+      mSourceFilePath,
+      "#include \"../" + string(HEADER_FILE_NAME) + "\"\n\n",
+      "#include \"",
+      "\"");
+  }
+
+private:
+  /// Generates the required file.
+  /// @param[in]  strings   A reference to the vector to parse
+  /// @param[in]  filePath  Outputs the data to this file
+  /// @param[in]  header    Puts this before parsing any of the vector
+  /// @param[in]  before    For each string, puts this string before it on every line
+  /// @param[in]  after     For each string, puts this string after it on every line
+  void GenerateFile(
+    vector<string>&   strings,
+    const string&     filePath,
+    const string_view header,
+    const string_view before,
+    const string_view after)
+  {
+    sort(strings.begin(), strings.end());
+    cout << "  Generating \"" << filePath << "\"";
+    ofstream outFile(filePath);
+    if(outFile)
+    {
+      outFile << header;
+      for(auto& current : strings)
+      {
+        outFile << before << current << after << endl;
+      }
+      cout << " [OK]" << endl;
+    }
+    else
+    {
+      cout << " [FAIL]" << endl;
+    }
+  }
+
+  constexpr static string_view HEADER_FILE_NAME = "builtin-shader-extern-gen.h";
+  constexpr static string_view SOURCE_FILE_NAME = "builtin-shader-gen.cpp";
+
+  const string   mHeaderFilePath;  ///< Path to the header file to generate
+  const string   mSourceFilePath;  ///< Path to the source file to generate
+  vector<string> mVariableNames;   ///< Holds all the variable names added through Add
+  vector<string> mHeaderFileNames; ///< Holds all the header file names added through Add
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// Generates the header files from the shaders in the input directory & built-in files if reqruied.
+///
+/// @param[in]  inDir                 The directory where all the input shader source is
+/// @param[in]  outDir                The directory where the readable shaders will be outputted to
+/// @param[in]  generateBuiltInFiles  If true, we generate the built-in files as well
+/// @return 0 if successful, 1 if failure
+int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBuiltInFiles)
+{
+  if(!fs::is_directory(inDir))
+  {
+    cerr << "ERROR: " << inDir << " is not a valid directory" << endl;
+    Usage();
+    return 1;
+  }
+
+  try
+  {
+    fs::create_directories(outDir);
+  }
+  catch(...)
+  {
+    cerr << "ERROR: Unable to create directory " << outDir << endl;
+    return 1;
+  }
+
+  cout << "====================================================================" << endl;
+  cout << "Shader Input Directory:  " << inDir << endl;
+  cout << "Shader Output Directory: " << outDir << endl;
+  cout << "====================================================================" << endl;
+
+  BuiltInFilesGenerator generator(outDir);
+
+  for(auto& file : fs::directory_iterator(inDir))
+  {
+    if(file.is_regular_file())
+    {
+      for(const auto& extension : SHADER_EXTENSIONS)
+      {
+        if(file.path().extension() == extension)
+        {
+          const fs::path& path(file.path());
+          const string    filename(path.filename().string());
+          string          shaderVariableName(GetShaderVariableName(filename));
+          ifstream        shaderFile(path);
+          if(shaderFile.is_open())
+          {
+            fs::path outFilePath(GetShaderOutputFilePath(outDir, filename));
+            GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
+            generator.Add(std::move(shaderVariableName), outFilePath.filename().string());
+          }
+          break;
+        }
+      }
+    }
+  }
+
+  if(generateBuiltInFiles)
+  {
+    generator.Generate();
+  }
+
+  cout << "====================================================================" << endl;
+  return 0;
+}
+
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/// MAIN.
+int main(int argc, char* argv[])
+{
+  PROGRAM_NAME = argv[0];
+
+  bool generateBuiltInFiles = true;
+
+  string inDir;
+  string outDir;
+
+  for(auto i = 1; i < argc; ++i)
+  {
+    string option(argv[i]);
+    if(option == "--skip" || option == "-s")
+    {
+      generateBuiltInFiles = false;
+    }
+    else if(option == "--help" || option == "-h")
+    {
+      cout << "DALi Shader Generator v" << VERSION << endl
+           << endl;
+      Usage();
+      return 0;
+    }
+    else if(option == "--version" || option == "-v")
+    {
+      cout << VERSION << endl;
+      return 0;
+    }
+    else if(*option.begin() == '-')
+    {
+      cerr << "ERROR: " << option << " is not a supported option" << endl;
+      Usage();
+      return 1;
+    }
+    else if(inDir.empty())
+    {
+      inDir = option;
+    }
+    else if(outDir.empty())
+    {
+      outDir = option;
+    }
+    else if(inDir.size() && outDir.size())
+    {
+      cerr << "ERROR: Too many options" << endl;
+      Usage();
+      return 1;
+    }
+  }
+
+  if(inDir.empty() || outDir.empty())
+  {
+    cerr << "ERROR: Both IN_DIR & OUT_DIR not provided" << endl;
+    Usage();
+    return 1;
+  }
+
+  return GenerateShaderSources(inDir, outDir, generateBuiltInFiles);
+}
index 674addb..ba6c2b6 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.0.22
+Version:    2.0.23
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT
@@ -379,6 +379,7 @@ esac
 %defattr(-,root,root,-)
 %{dev_include_path}/dali-toolkit/*
 %{_libdir}/pkgconfig/dali2-toolkit.pc
+%{_bindir}/dali-shader-generator
 
 %files resources_360x360
 %manifest dali-toolkit-resources.manifest