Implicit surface rendering via ray tracing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

317 lines
8.1 KiB

/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This file contains code derived from glf by Christophe Riccio, www.g-truc.net
* Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
* https://github.com/g-truc/ogl-samples/blob/master/framework/compiler.cpp
*/
#include "shaderfilemanager.hpp"
#include <algorithm>
#include <assert.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdarg.h>
#include <stdio.h>
#include "fileoperations.hpp"
namespace nvh {
std::string ShaderFileManager::format(const char* msg, ...)
{
char text[8192];
va_list list;
if(msg == 0)
return std::string();
va_start(list, msg);
vsnprintf(text, sizeof(text), msg, list);
va_end(list);
return std::string(text);
}
inline std::string ShaderFileManager::markerString(int line, std::string const& filename, int fileid)
{
if(m_supportsExtendedInclude || m_forceLineFilenames)
{
#if defined(_WIN32) && 1
std::string fixedname;
for(size_t i = 0; i < filename.size(); i++)
{
char c = filename[i];
if(c == '/' || c == '\\')
{
fixedname.append("\\\\");
}
else
{
fixedname.append(1, c);
}
}
#else
std::string fixedname = filename;
#endif
return ShaderFileManager::format("#line %d \"", line) + fixedname + std::string("\"\n");
}
else
{
return ShaderFileManager::format("#line %d %d\n", line, fileid);
}
}
std::string ShaderFileManager::getIncludeContent(IncludeID idx, std::string& filename)
{
IncludeEntry& entry = m_includes[idx];
filename = entry.filename;
if(m_forceIncludeContent)
{
return entry.content;
}
if(!entry.content.empty() && !findFile(entry.filename, m_directories).empty())
{
return entry.content;
}
std::string content = loadFile(entry.filename, false, m_directories, filename, true);
return content.empty() ? entry.content : content;
}
std::string ShaderFileManager::getContent(std::string const& filename, std::string& filenameFound)
{
if(filename.empty())
{
return std::string();
}
IncludeID idx = findInclude(filename);
if(idx.isValid())
{
return getIncludeContent(idx, filenameFound);
}
// fall back
filenameFound = filename;
return loadFile(filename, false, m_directories, filenameFound, true);
}
std::string ShaderFileManager::getContentWithRequestingSourceDirectory(std::string const& filename,
std::string& filenameFound,
std::string const& requestingSource)
{
if(filename.empty())
{
return std::string();
}
IncludeID idx = findInclude(filename);
if(idx.isValid())
{
return getIncludeContent(idx, filenameFound);
}
// fall back; check requestingSource's directory first.
filenameFound = filename;
m_extendedDirectories.resize(m_directories.size() + 1);
m_extendedDirectories[0] = getDirectoryComponent(requestingSource);
for(size_t i = 0; i < m_directories.size(); ++i)
{
m_extendedDirectories[i + 1] = m_directories[i];
}
return loadFile(filename, false, m_extendedDirectories, filenameFound, true);
}
std::string ShaderFileManager::getDirectoryComponent(std::string filename)
{
while(!filename.empty())
{
auto popped = filename.back();
filename.pop_back();
switch(popped)
{
case '/':
goto exitLoop;
#if defined(_WIN32)
case '\\':
goto exitLoop;
#endif
}
}
exitLoop:
if(filename.empty())
filename.push_back('.');
return filename;
}
std::string ShaderFileManager::manualInclude(std::string const& filename, std::string& filenameFound, std::string const& prepend, bool foundVersion)
{
std::string source = getContent(filename, filenameFound);
return manualIncludeText(source, filenameFound, prepend, foundVersion);
}
std::string ShaderFileManager::manualIncludeText(std::string const& sourceText, std::string const& textFilename, std::string const& prepend, bool foundVersion)
{
if(sourceText.empty())
{
return std::string();
}
std::stringstream stream;
stream << sourceText;
std::string line, text;
// Handle command line defines
text += prepend;
if(m_lineMarkers)
{
text += markerString(1, textFilename, 0);
}
int lineCount = 0;
while(std::getline(stream, line))
{
std::size_t offset = 0;
lineCount++;
// Version
offset = line.find("#version");
if(offset != std::string::npos)
{
std::size_t commentOffset = line.find("//");
if(commentOffset != std::string::npos && commentOffset < offset)
continue;
if(foundVersion)
{
// someone else already set the version, so just comment out
text += std::string("//") + line + std::string("\n");
}
else
{
// Reorder so that the #version line is always the first of a shader text
text = line + std::string("\n") + text + std::string("//") + line + std::string("\n");
foundVersion = true;
}
continue;
}
// Handle replacing #include with text if configured to do so.
// Otherwise just insert the #include command verbatim, for shaderc to handle.
if(m_handleIncludePasting)
{
offset = line.find("#include");
if(offset != std::string::npos)
{
std::size_t commentOffset = line.find("//");
if(commentOffset != std::string::npos && commentOffset < offset)
continue;
size_t firstQuote = line.find("\"", offset);
size_t secondQuote = line.find("\"", firstQuote + 1);
std::string include = line.substr(firstQuote + 1, secondQuote - firstQuote - 1);
std::string includeFound;
std::string includeContent = manualInclude(include, includeFound, std::string(), foundVersion);
if(!includeContent.empty())
{
text += includeContent;
if(m_lineMarkers)
{
text += std::string("\n") + markerString(lineCount + 1, textFilename, 0);
}
}
continue; // Skip adding the original #include line.
}
}
text += line + "\n";
}
return text;
}
ShaderFileManager::IncludeID ShaderFileManager::registerInclude(std::string const& name, std::string const& filename, std::string const& content)
{
// find if already registered
for(size_t i = 0; i < m_includes.size(); i++)
{
if(m_includes[i].name == name)
{
m_includes[i].content = content;
return i;
}
}
IncludeEntry entry;
entry.name = name;
entry.filename = filename.empty() ? name : filename;
entry.content = content;
m_includes.push_back(entry);
return m_includes.size() - 1;
}
ShaderFileManager::IncludeID ShaderFileManager::findInclude(std::string const& name) const
{
// check registered includes first
for(std::size_t i = 0; i < m_includes.size(); ++i)
{
if(m_includes[i].name == name)
{
return IncludeID(i);
}
}
return IncludeID();
}
bool ShaderFileManager::loadIncludeContent(IncludeID idx)
{
std::string filenameFound;
m_includes[idx].content = getIncludeContent(idx, filenameFound);
return !m_includes[idx].content.empty();
}
const ShaderFileManager::IncludeEntry& ShaderFileManager::getIncludeEntry(IncludeID idx) const
{
return m_includes[idx];
}
std::string ShaderFileManager::getProcessedContent(std::string const& filename, std::string& filenameFound)
{
return manualInclude(filename, filenameFound, "", false);
}
} // namespace nvh