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.
 
 
 

500 lines
13 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
*/
#include "parametertools.hpp"
#include "nvprint.hpp"
#include <algorithm>
namespace nvh {
ParameterList::ParameterList()
{
Callback helpCallback = [&](uint32_t) { print(); };
setHelp(add("help", helpCallback), "Print help");
setHelp(add("h", helpCallback), "Print help");
}
void ParameterList::tokenizeString(std::string& content, std::vector<const char*>& args)
{
bool wasSpace = true;
bool inQuotes = false;
bool inComment = false;
bool wasQuote = false;
bool wasEscape = false;
for(size_t i = 0; i < content.size(); i++)
{
char* token = &content[i];
char current = content[i];
bool isEndline = current == '\n';
bool isSpace = (current == ' ' || current == '\t' || current == '\n');
bool isQuote = current == '"';
bool isComment = current == '#';
bool isEscape = current == '\\';
if(isEndline && inComment)
{
inComment = false;
}
if(isComment && !inQuotes)
{
content[i] = 0;
inComment = true;
}
if(inComment)
continue;
if(inQuotes)
{
if(wasEscape && (current == 'n' || current == 't'))
{
content[i] = current == 'n' ? '\n' : '\t';
content[i - 1] = ' ';
}
}
if(isQuote)
{
inQuotes = !inQuotes;
// treat as space
content[i] = 0;
isSpace = true;
}
else if(isSpace)
{
// turn space to a terminator
if(!inQuotes)
{
content[i] = 0;
}
}
else if(wasSpace && (!inQuotes || wasQuote))
{
// start a new arg unless comment
args.push_back(token);
}
wasSpace = isSpace;
wasQuote = isQuote;
wasEscape = isEscape;
}
}
ParameterList::Parameter::Parameter(Type atype, const char* aname, Callback acallback, void* adestination, uint32_t areadLength, uint32_t awriteLength)
{
type = atype;
callback = acallback;
readLength = areadLength;
writeLength = awriteLength;
destination.ptr = adestination;
// Set name and if specified, helptext
// Split at delimiter '|'
std::string sname = std::string(aname);
size_t delimiterPos = sname.find_first_of('|');
if(delimiterPos != std::string::npos)
{
name = sname.substr(0, delimiterPos);
helptext = sname.substr(delimiterPos + 1);
}
else
{
name = sname;
helptext = "";
}
}
uint32_t ParameterList::append(const ParameterList& list)
{
uint32_t index = uint32_t(m_parameters.size());
m_parameters.insert(m_parameters.end(), list.m_parameters.begin(), list.m_parameters.end());
return index;
}
uint32_t ParameterList::add(const char* name, float* destination, Callback callback, uint32_t length /*= 1*/, float min /*= -FLT_MAX*/, float max /*= FLT_MAX*/)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_FLOAT, name, callback, destination, length, length);
param.minmax[0].f32 = min;
param.minmax[1].f32 = max;
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, int32_t* destination, Callback callback, uint32_t length /*= 1*/, int32_t min /*= -INT_MAX*/, int32_t max /*= +INT_MAX*/)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_INT, name, callback, destination, length, length);
param.minmax[0].s32 = min;
param.minmax[1].s32 = max;
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, uint32_t* destination, Callback callback, uint32_t length /*= 1*/, uint32_t min /*= 0*/, uint32_t max /*= 0xFFFFFFFF*/)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_UINT, name, callback, destination, length, length);
param.minmax[0].u32 = min;
param.minmax[1].u32 = max;
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, bool* destination, Callback callback, uint32_t length /*= 1*/)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_BOOL, name, callback, destination, length, length);
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, bool* destination, bool value, Callback callback /*= nullptr*/, uint32_t length /*= 1*/)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_BOOL_VALUE, name, callback, destination, 0, length);
param.minmax[0].b = value;
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, std::string* destination, Callback callback, uint32_t length)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_STRING, name, callback, destination, length, length);
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::add(const char* name, Callback callback, uint32_t length)
{
uint32_t index = uint32_t(m_parameters.size());
Parameter param(TYPE_TRIGGER, name, callback, nullptr, length, length);
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::addFilename(const char* name, std::string* destination, Callback callback)
{
uint32_t index = uint32_t(m_parameters.size());
// special case "." searches for specific filenames
Parameter param(TYPE_FILENAME, name, callback, destination, name[0] == '.' ? 0 : 1, 1);
m_parameters.push_back(param);
return index;
}
uint32_t ParameterList::setHelp(uint32_t parameterIndex, const char* helptext)
{
this->m_parameters[parameterIndex].helptext = helptext;
return parameterIndex;
}
static bool endsWith(std::string const& s, std::string const& end)
{
if(s.length() >= end.length())
{
return (0 == s.compare(s.length() - end.length(), end.length(), end));
}
else
{
return false;
}
}
bool ParameterList::applyParameters(uint32_t argc,
const char** argv,
uint32_t& a,
const char* paramPrefix /*= nullptr*/,
const char* defaultFilePath /*= nullptr*/) const
{
std::string prefixStr(paramPrefix ? paramPrefix : "");
std::string defaultPathStr(defaultFilePath ? defaultFilePath : "");
for(uint32_t p = 0; p < uint32_t(m_parameters.size()); p++)
{
const Parameter& param = m_parameters[p];
std::string combined = prefixStr + param.name;
bool searchFileEnding = (param.type == TYPE_FILENAME) && (param.readLength == 0);
bool matched = searchFileEnding ? endsWith(argv[a], param.name) : (strcmp(argv[a], combined.c_str()) == 0);
if(matched && a + param.readLength < argc)
{
switch(param.type)
{
case TYPE_FLOAT: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.f32[i] =
std::min(std::max(float(atof(argv[a + i + 1])), param.minmax[0].f32), param.minmax[1].f32);
}
}
break;
case TYPE_UINT: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.u32[i] =
std::min(std::max(uint32_t(atoi(argv[a + i + 1])), param.minmax[0].u32), param.minmax[1].u32);
}
}
break;
case TYPE_INT: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.s32[i] =
std::min(std::max(int32_t(atoi(argv[a + i + 1])), param.minmax[0].s32), param.minmax[1].s32);
}
}
break;
case TYPE_BOOL: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.b[i] = atoi(argv[a + i + 1]) != 0;
}
}
break;
case TYPE_BOOL_VALUE: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.b[i] = param.minmax[0].b;
}
}
break;
case TYPE_STRING: {
for(uint32_t i = 0; i < param.writeLength; i++)
{
param.destination.str[i] = std::string(argv[a + i + 1]);
}
}
break;
case TYPE_FILENAME: {
std::string filename(argv[a + param.readLength]);
if(
#ifdef _WIN32
filename.find(':') != std::string::npos
#else
!filename.empty() && filename[0] == '/'
#endif
)
{
param.destination.str[0] = filename;
}
else
{
param.destination.str[0] = defaultPathStr + "/" + filename;
}
}
break;
case TYPE_TRIGGER: {
}
break;
}
if(param.callback)
{
param.callback(p);
}
if(searchFileEnding)
{
LOGI(" %s \"%s\"\n", param.name.c_str(), argv[a]);
}
else
{
LOGI(" ");
for(uint32_t i = 0; i < param.readLength + 1; i++)
{
bool isString = i > 0 && (param.type == TYPE_FILENAME || param.type == TYPE_STRING);
if(isString)
{
LOGI(" \"%s\"", argv[a + i]);
}
else
{
LOGI(" %s", argv[a + i]);
}
}
LOGI("\n");
}
a += param.readLength;
return true;
}
}
return false;
}
const char* ParameterList::toString(Type typ)
{
switch(typ)
{
case TYPE_FLOAT:
return "float ";
case TYPE_INT:
return "int ";
case TYPE_UINT:
return "uint ";
case TYPE_BOOL:
return "bool ";
case TYPE_BOOL_VALUE:
return "value ";
case TYPE_STRING:
return "string ";
case TYPE_FILENAME:
return "filename";
case TYPE_TRIGGER:
return "trigger ";
}
return "unknown";
}
void ParameterList::print() const
{
// Get maximum parameter name length
uint32_t maxParamNameLength = 0;
for(const auto& it : m_parameters)
{
maxParamNameLength = std::max(uint32_t(it.name.size()), maxParamNameLength);
}
// Print header
LOGI("parameterlist:\n");
LOGI(" type [args] %-*s helptext\n", maxParamNameLength, "helptext"); // Pad helptext column with blanks
// Print underline. Format: -----
LOGI(" ");
for(uint32_t i = 0; i < maxParamNameLength + 23; i++)
{
LOGI("-");
}
LOGI("\n");
// Print command line arguments
for(const auto& it : m_parameters)
{
// Log param type, [args], name
LOGI(" %s[%d] %-*s", toString(it.type), it.readLength, maxParamNameLength, it.name.c_str());
if(it.helptext != "")
{
// Log helptext
LOGI(" - %s", it.helptext.c_str());
}
// Newline
LOGI("\n");
}
LOGI("\n");
}
uint32_t ParameterList::applyTokens(uint32_t argc, const char** argv, const char* prefix, const char* defaultPath) const
{
uint32_t found = 0;
for(uint32_t a = 0; a < argc; a++)
{
if(applyParameters(argc, argv, a, prefix, defaultPath))
{
found++;
}
else
{
LOGI(" unhandled argument: %s\n", argv[a])
}
}
return found;
}
bool ParameterSequence::advanceIteration(const char* separator, uint32_t separatorArgLength, uint32_t& argBegin, uint32_t& argCount)
{
if(!m_list || m_index >= m_tokens.size())
return true;
size_t begin = m_index;
size_t end = begin;
m_separator = ~0;
for(size_t i = m_index; i < m_tokens.size(); i++)
{
if(strcmp(m_tokens[i], separator) == 0 && i + separatorArgLength < m_tokens.size())
{
end = i - 1;
m_separator = i;
m_index = i + separatorArgLength + 1;
break;
}
end = i;
}
if(m_separator == ~0)
return true;
uint32_t count = uint32_t(1 + end - begin);
if(count)
{
argCount = count;
argBegin = uint32_t(begin);
m_iteration++;
return false;
}
else
{
return true;
}
}
bool ParameterSequence::applyIteration(const char* separator,
uint32_t separatorLength,
const char* paramPrefix /*= nullptr*/,
const char* defaultFilePath /*= nullptr*/)
{
uint32_t argBegin;
uint32_t argCount;
if(!advanceIteration(separator, separatorLength, argBegin, argCount))
{
m_list->applyTokens(argCount, (const char**)&m_tokens[argBegin], paramPrefix, defaultFilePath);
return false;
}
else
{
// check if there is any parameters left
if(m_index < m_tokens.size())
{
uint32_t argBegin = uint32_t(m_index);
uint32_t argCount = uint32_t(m_tokens.size() - m_index);
m_list->applyTokens(argCount, (const char**)&m_tokens[argBegin], paramPrefix, defaultFilePath);
}
return true;
}
}
void ParameterSequence::resetIteration()
{
m_index = 0;
m_iteration = 0;
}
} // namespace nvh