diff --git a/hlslparser/src/CodeWriter.cpp b/hlslparser/src/CodeWriter.cpp index 046219f4..c8af3706 100644 --- a/hlslparser/src/CodeWriter.cpp +++ b/hlslparser/src/CodeWriter.cpp @@ -7,52 +7,46 @@ // //============================================================================= -#include "Engine.h" - #include "CodeWriter.h" #include -namespace M4 -{ +#include "Engine.h" + +namespace M4 { CodeWriter::CodeWriter() { - m_currentLine = 1; - m_currentFileName = NULL; - m_spacesPerIndent = 4; - m_writeFileLine = false; + m_currentLine = 1; + m_currentFileName = NULL; + m_spacesPerIndent = 4; + m_writeFileLine = false; } void CodeWriter::BeginLine(int indent, const char* fileName, int lineNumber) { // probably missing an EndLine ASSERT(m_currentIndent == 0); - - if (m_writeFileLine) - { + + if (m_writeFileLine) { bool outputLine = false; bool outputFile = false; // Output a line number pragma if necessary. - if (fileName != NULL && m_currentFileName != fileName) - { + if (fileName != NULL && m_currentFileName != fileName) { m_currentFileName = fileName; fileName = m_currentFileName; outputFile = true; } - if (lineNumber != -1 && m_currentLine != lineNumber) - { + if (lineNumber != -1 && m_currentLine != lineNumber) { m_currentLine = lineNumber; outputLine = true; } // if previous filename is same, only output line - if (outputFile) - { + if (outputFile) { String_Printf(m_buffer, "#line %d \"%s\"\n", lineNumber, fileName); } - else if (outputLine) - { + else if (outputLine) { String_Printf(m_buffer, "#line %d\n", lineNumber); } } @@ -60,20 +54,18 @@ void CodeWriter::BeginLine(int indent, const char* fileName, int lineNumber) // Handle the indentation. if (indent) Write("%*s", indent * m_spacesPerIndent, ""); - + m_currentIndent = indent; - } int CodeWriter::EndLine(const char* text) { - if (text != NULL) - { + if (text != NULL) { m_buffer += text; } m_buffer += "\n"; ++m_currentLine; - + // so can EndLine/BeginLine int indent = m_currentIndent; m_currentIndent = 0; @@ -93,13 +85,13 @@ void CodeWriter::WriteLine(int indent, const char* format, ...) { if (indent) Write("%*s", indent * m_spacesPerIndent, ""); - + va_list args; va_start(args, format); int result = String_PrintfArgList(m_buffer, format, args); ASSERT(result != -1); va_end(args); - + EndLine(); } @@ -107,13 +99,13 @@ void CodeWriter::WriteLineTagged(int indent, const char* fileName, int lineNumbe { // TODO: this should make sure that line isn't already Begu BeginLine(indent, fileName, lineNumber); - + va_list args; va_start(args, format); int result = String_PrintfArgList(m_buffer, format, args); ASSERT(result != -1); va_end(args); - + EndLine(); } @@ -127,4 +119,4 @@ void CodeWriter::Reset() m_buffer.clear(); } -} +} //namespace M4 diff --git a/hlslparser/src/CodeWriter.h b/hlslparser/src/CodeWriter.h index f9d27b7e..5454fd71 100644 --- a/hlslparser/src/CodeWriter.h +++ b/hlslparser/src/CodeWriter.h @@ -14,8 +14,7 @@ // stl #include -namespace M4 -{ +namespace M4 { class Allocator; @@ -23,34 +22,29 @@ class Allocator; * This class is used for outputting code. It handles indentation and inserting #line markers * to match the desired output line numbers. */ -class CodeWriter -{ - +class CodeWriter { public: CodeWriter(); void SetWriteFileLine(bool enable) { m_writeFileLine = enable; } - + void BeginLine(int indent, const char* fileName = NULL, int lineNumber = -1); void Write(const char* format, ...) M4_PRINTF_ATTR(2, 3); int EndLine(const char* text = NULL); void WriteLine(int indent, const char* format, ...) M4_PRINTF_ATTR(3, 4); - void WriteLineTagged(int indent, const char* fileName, int lineNumber, const char* format, ...) M4_PRINTF_ATTR(5, 6) ; + void WriteLineTagged(int indent, const char* fileName, int lineNumber, const char* format, ...) M4_PRINTF_ATTR(5, 6); const char* GetResult() const; void Reset(); private: - - std::string m_buffer; - int m_currentLine; - const char* m_currentFileName; - int m_spacesPerIndent; - int m_currentIndent; - bool m_writeFileLine; - + std::string m_buffer; + int m_currentLine; + const char* m_currentFileName; + int m_spacesPerIndent; + int m_currentIndent; + bool m_writeFileLine; }; -} - +} //namespace M4 diff --git a/hlslparser/src/Engine.cpp b/hlslparser/src/Engine.cpp old mode 100755 new mode 100644 index 49bdd1c0..85b1c1c2 --- a/hlslparser/src/Engine.cpp +++ b/hlslparser/src/Engine.cpp @@ -1,9 +1,9 @@ #include "Engine.h" -#include // vsnprintf +#include // vsnprintf +#include // strtod, strtol #include // strcmp, strcasecmp -#include // strtod, strtol // this is usually just an unordered_map internally #include @@ -16,23 +16,22 @@ void String_Copy(char* str, const char* b, uint32_t size) { #ifdef WIN32 strncpy(str, b, size); - str[size-1] = 0; + str[size - 1] = 0; #else strlcpy(str, b, size); #endif } // This version doesn't truncate and is simpler -int String_PrintfArgList(std::string& buffer, const char * format, va_list args) { +int String_PrintfArgList(std::string& buffer, const char* format, va_list args) +{ int n = 0; - - if (!String_HasChar(format, '%')) - { + + if (!String_HasChar(format, '%')) { buffer += format; n = (uint32_t)strlen(format); } - else if (String_Equal(format, "%s")) - { + else if (String_Equal(format, "%s")) { va_list tmp; va_copy(tmp, args); const char* text = va_arg(args, const char*); @@ -40,50 +39,46 @@ int String_PrintfArgList(std::string& buffer, const char * format, va_list args) buffer += text; va_end(tmp); } - else - { + else { va_list tmp; va_copy(tmp, args); - + int len = vsnprintf(nullptr, 0, format, tmp); - if (len >= 0) - { + if (len >= 0) { size_t bufferLength = buffer.length(); - buffer.resize(bufferLength+len); - vsnprintf((char*)buffer.data() + bufferLength, len+1, format, tmp); - + buffer.resize(bufferLength + len); + vsnprintf((char*)buffer.data() + bufferLength, len + 1, format, tmp); + n = len; } va_end(tmp); } - + return n; } // This version truncates but works on stack -int String_PrintfArgList(char* buffer, int size, const char * format, va_list args) { +int String_PrintfArgList(char* buffer, int size, const char* format, va_list args) +{ int n; - - if (!String_HasChar(format, '%')) - { + + if (!String_HasChar(format, '%')) { String_Copy(buffer, format, size); - + // truncation or not n = (int)strlen(format); } - else if (String_Equal(format, "%s")) - { + else if (String_Equal(format, "%s")) { va_list tmp; va_copy(tmp, args); const char* text = va_arg(args, const char*); n = (int)strlen(text); - + // truncation String_Copy(buffer, text, size); va_end(tmp); } - else - { + else { va_list tmp; va_copy(tmp, args); @@ -92,15 +87,15 @@ int String_PrintfArgList(char* buffer, int size, const char * format, va_list ar n = vsnprintf(buffer, size, format, tmp); va_end(tmp); } - - if (n < 0 || (n+1) > size) + + if (n < 0 || (n + 1) > size) return -1; - + return n; } -int String_Printf(std::string& buffer, const char * format, ...) { - +int String_Printf(std::string& buffer, const char* format, ...) +{ va_list args; va_start(args, format); @@ -111,8 +106,8 @@ int String_Printf(std::string& buffer, const char * format, ...) { return n; } -int String_Printf(char * buffer, int size, const char * format, ...) { - +int String_Printf(char* buffer, int size, const char* format, ...) +{ va_list args; va_start(args, format); @@ -120,109 +115,112 @@ int String_Printf(char * buffer, int size, const char * format, ...) { va_end(args); - return n; + return n; } -int String_FormatFloat(char * buffer, int size, float value) { +int String_FormatFloat(char* buffer, int size, float value) +{ return String_Printf(buffer, size, "%.6f", value); } -bool String_HasChar(const char* str, char c) { +bool String_HasChar(const char* str, char c) +{ return strchr(str, c) != NULL; } -bool String_HasString(const char* str, const char* search) { +bool String_HasString(const char* str, const char* search) +{ return strstr(str, search) != NULL; } -bool String_Equal(const char * a, const char * b) { - if (a == b) return true; - if (a == NULL || b == NULL) return false; - return strcmp(a, b) == 0; +bool String_Equal(const char* a, const char* b) +{ + if (a == b) return true; + if (a == NULL || b == NULL) return false; + return strcmp(a, b) == 0; } -bool String_EqualNoCase(const char * a, const char * b) { - if (a == b) return true; - if (a == NULL || b == NULL) return false; +bool String_EqualNoCase(const char* a, const char* b) +{ + if (a == b) return true; + if (a == NULL || b == NULL) return false; #if _MSC_VER - return _stricmp(a, b) == 0; + return _stricmp(a, b) == 0; #else - return strcasecmp(a, b) == 0; + return strcasecmp(a, b) == 0; #endif } -double String_ToDouble(const char * str, char ** endptr) { - return strtod(str, endptr); +double String_ToDouble(const char* str, char** endptr) +{ + return strtod(str, endptr); } -float String_ToFloat(const char * str, char ** endptr) { +float String_ToFloat(const char* str, char** endptr) +{ return strtof(str, endptr); } static const int kBase10 = 10; static const int kBase16 = 16; -int32_t String_ToIntHex(const char * str, char ** endptr) { +int32_t String_ToIntHex(const char* str, char** endptr) +{ return (int)strtol(str, endptr, kBase16); } -int32_t String_ToInt(const char * str, char ** endptr) { - return (int)strtol(str, endptr, kBase10); +int32_t String_ToInt(const char* str, char** endptr) +{ + return (int)strtol(str, endptr, kBase10); } -uint32_t String_ToUint(const char * str, char ** endptr) { +uint32_t String_ToUint(const char* str, char** endptr) +{ return (int)strtoul(str, endptr, kBase10); } -uint64_t String_ToUlong(const char * str, char ** endptr) { +uint64_t String_ToUlong(const char* str, char** endptr) +{ return (int)strtoull(str, endptr, kBase10); } -int64_t String_ToLong(const char * str, char ** endptr) { +int64_t String_ToLong(const char* str, char** endptr) +{ return (int)strtoll(str, endptr, kBase10); } - - - - - - void String_StripTrailingFloatZeroes(char* buffer) { const char* dotPos = strrchr(buffer, '.'); if (dotPos == nullptr) return; - + uint32_t bufferLen = (uint32_t)strlen(buffer); - + // strip trailing zeroes - while (bufferLen > 0) - { - char& c = buffer[bufferLen-1]; - if (c == '0') - { + while (bufferLen > 0) { + char& c = buffer[bufferLen - 1]; + if (c == '0') { c = 0; bufferLen--; } - else - { + else { break; } } - + // This breaks appending h to a number in MSL // strip the period (only for MSL) -// char& c = buffer[bufferLen-1]; -// if (dotPos == &c) -// { -// c = 0; -// bufferLen--; -// } + // char& c = buffer[bufferLen-1]; + // if (dotPos == &c) + // { + // c = 0; + // bufferLen--; + // } } // Engine/Log.cpp -void Log_Error(const char * format, ...) +void Log_Error(const char* format, ...) { va_list args; va_start(args, format); @@ -230,82 +228,83 @@ void Log_Error(const char * format, ...) va_end(args); } -void Log_ErrorArgList(const char * format, va_list args, const char* filename, uint32_t line) +void Log_ErrorArgList(const char* format, va_list args, const char* filename, uint32_t line) { va_list tmp; va_copy(tmp, args); - + // Not thread-safe static std::string buffer; buffer.clear(); String_PrintfArgList(buffer, format, tmp); - + // TODO: this doesn't work on Win/Android // use a real log abstraction to ODS/etc from Kram if (filename) - fprintf( stderr, "%s:%d: error: %s", filename, line, buffer.c_str()); + fprintf(stderr, "%s:%d: error: %s", filename, line, buffer.c_str()); else - fprintf( stderr, "error: %s", buffer.c_str()); - - va_end(tmp); + fprintf(stderr, "error: %s", buffer.c_str()); + va_end(tmp); } - // Engine/StringPool.cpp using StringPoolSet = std::unordered_set; #define CastImpl(imp) (StringPoolSet*)imp -StringPool::StringPool(Allocator * allocator) { +StringPool::StringPool(Allocator* allocator) +{ // NOTE: allocator not used - + m_impl = new StringPoolSet(); } -StringPool::~StringPool() { +StringPool::~StringPool() +{ auto* impl = CastImpl(m_impl); - + // delete the strings for (auto it : *impl) { const char* text = it; free((char*)text); } - + delete impl; } -const char * StringPool::AddString(const char * text) { +const char* StringPool::AddString(const char* text) +{ auto* impl = CastImpl(m_impl); auto it = impl->find(text); if (it != impl->end()) return *it; - + // _strdup doesn't go through allocator either #if _MSC_VER - const char * dup = _strdup(text); + const char* dup = _strdup(text); #else - const char * dup = strdup(text); + const char* dup = strdup(text); #endif - + impl->insert(dup); return dup; } -const char* StringPool::PrintFormattedVaList(const char* fmt, va_list args) { +const char* StringPool::PrintFormattedVaList(const char* fmt, va_list args) +{ char* res = nullptr; - + va_list tmp; // va_copy needed? va_copy(tmp, args); - + // just call 2x, once for len int len = vsnprintf(nullptr, 0, fmt, tmp); - if (len >= 0) - { - res = (char*)malloc(len+1); - vsnprintf(res, len+1, fmt, tmp); + if (len >= 0) { + res = (char*)malloc(len + 1); + vsnprintf(res, len + 1, fmt, tmp); } va_end(tmp); @@ -313,41 +312,43 @@ const char* StringPool::PrintFormattedVaList(const char* fmt, va_list args) { return res; } -const char * StringPool::AddStringFormatList(const char * format, va_list args) { +const char* StringPool::AddStringFormatList(const char* format, va_list args) +{ // don't format if no tokens va_list tmp; va_copy(tmp, args); - const char * text = PrintFormattedVaList(format, tmp); + const char* text = PrintFormattedVaList(format, tmp); va_end(tmp); auto* impl = CastImpl(m_impl); - + // add it if not found auto it = impl->find(text); - if (it == impl->end()) - { + if (it == impl->end()) { impl->insert(text); return text; } - + // allocated inside PrintFormattedVaList free((char*)text); return *it; } -const char * StringPool::AddStringFormat(const char * format, ...) { +const char* StringPool::AddStringFormat(const char* format, ...) +{ // TODO: don't format if no tokens va_list args; va_start(args, format); - const char * string = AddStringFormatList(format, args); + const char* string = AddStringFormatList(format, args); va_end(args); return string; } -bool StringPool::GetContainsString(const char * text) const { +bool StringPool::GetContainsString(const char* text) const +{ const auto* impl = CastImpl(m_impl); return impl->find(text) != impl->end(); } -} // M4 namespace +} //namespace M4 diff --git a/hlslparser/src/Engine.h b/hlslparser/src/Engine.h old mode 100755 new mode 100644 index ea3eeb2c..43535cd9 --- a/hlslparser/src/Engine.h +++ b/hlslparser/src/Engine.h @@ -6,13 +6,14 @@ #include // va_list, vsnprintf #include // malloc + #include // for placement new // stl #include #ifndef NULL -#define NULL 0 +#define NULL 0 #endif #ifndef va_copy @@ -33,7 +34,6 @@ namespace M4 { - // Engine/Allocator.h // This doesn't do placement new/delete, but is only @@ -42,50 +42,55 @@ namespace M4 { // there default ctor variable initializers are safe to use. class Allocator { public: - template T * New() { - return (T *)malloc(sizeof(T)); + template + T* New() + { + return (T*)malloc(sizeof(T)); } - template T * New(size_t count) { - return (T *)malloc(sizeof(T) * count); + template + T* New(size_t count) + { + return (T*)malloc(sizeof(T) * count); } - template void Delete(T * ptr) { - free((void *)ptr); + template + void Delete(T* ptr) + { + free((void*)ptr); } - template T * Realloc(T * ptr, size_t count) { - return (T *)realloc(ptr, sizeof(T) * count); + template + T* Realloc(T* ptr, size_t count) + { + return (T*)realloc(ptr, sizeof(T) * count); } }; - // Engine/String.h +int String_FormatFloat(char* buffer, int size, float value); +bool String_Equal(const char* a, const char* b); +bool String_EqualNoCase(const char* a, const char* b); - -int String_FormatFloat(char * buffer, int size, float value); -bool String_Equal(const char * a, const char * b); -bool String_EqualNoCase(const char * a, const char * b); - -double String_ToDouble(const char * str, char ** end); -float String_ToFloat(const char * str, char ** end); +double String_ToDouble(const char* str, char** end); +float String_ToFloat(const char* str, char** end); // no half -int32_t String_ToIntHex(const char * str, char ** end); -int32_t String_ToInt(const char * str, char ** end); -uint32_t String_ToUint(const char * str, char ** end); +int32_t String_ToIntHex(const char* str, char** end); +int32_t String_ToInt(const char* str, char** end); +uint32_t String_ToUint(const char* str, char** end); -uint64_t String_ToUlong(const char * str, char ** end); -int64_t String_ToLong(const char * str, char ** end); +uint64_t String_ToUlong(const char* str, char** end); +int64_t String_ToLong(const char* str, char** end); bool String_HasChar(const char* str, char c); bool String_HasString(const char* str, const char* search); // just use these, it's way easier than using fixed buffers -int String_PrintfArgList(std::string& buffer, const char * format, va_list args); -int String_Printf(std::string& buffer, const char * format, ...) M4_PRINTF_ATTR(2, 3); +int String_PrintfArgList(std::string& buffer, const char* format, va_list args); +int String_Printf(std::string& buffer, const char* format, ...) M4_PRINTF_ATTR(2, 3); // These 3 calls have truncation issues -int String_Printf(char * buffer, int size, const char * format, ...) M4_PRINTF_ATTR(3, 4); -int String_PrintfArgList(char * buffer, int size, const char * format, va_list args); +int String_Printf(char* buffer, int size, const char* format, ...) M4_PRINTF_ATTR(3, 4); +int String_PrintfArgList(char* buffer, int size, const char* format, va_list args); void String_Copy(char* str, const char* b, uint32_t size); void String_StripTrailingFloatZeroes(char* buffer); @@ -94,23 +99,24 @@ void String_StripTrailingFloatZeroes(char* buffer); // case sensitive fnv1a hash, can pass existing hash to continue a hash inline uint32_t HashFnv1a(const char* val, uint32_t hash = 0x811c9dc5) { - const uint32_t prime = 0x01000193; // 16777619 (32-bit) - while (*val) - { + const uint32_t prime = 0x01000193; // 16777619 (32-bit) + while (*val) { hash = (hash * prime) ^ (uint32_t)*val++; } return hash; } // this compares string stored as const char* -struct CompareAndHandStrings -{ +struct CompareAndHandStrings { template bool operator()(const _Tp& __x, const _Tp& __y) const - { return String_Equal( __x, __y ); } - + { + return String_Equal(__x, __y); + } + template - size_t operator()(const _Tp& __x) const { + size_t operator()(const _Tp& __x) const + { // assumes 32-bit hash to int64 conversion here return (size_t)HashFnv1a(__x); } @@ -118,42 +124,44 @@ struct CompareAndHandStrings // Engine/Log.h -void Log_Error(const char * format, ...) M4_PRINTF_ATTR(1, 2); - -void Log_ErrorArgList(const char * format, va_list args, const char* filename = NULL, uint32_t line = 0); +void Log_Error(const char* format, ...) M4_PRINTF_ATTR(1, 2); +void Log_ErrorArgList(const char* format, va_list args, const char* filename = NULL, uint32_t line = 0); // Engine/Array.h template -void ConstructRange(T * buffer, int new_size, int old_size) { +void ConstructRange(T* buffer, int new_size, int old_size) +{ for (int i = old_size; i < new_size; i++) { - new(buffer+i) T; // placement new + new (buffer + i) T; // placement new } } template -void ConstructRange(T * buffer, int new_size, int old_size, const T & val) { +void ConstructRange(T* buffer, int new_size, int old_size, const T& val) +{ for (int i = old_size; i < new_size; i++) { - new(buffer+i) T(val); // placement new + new (buffer + i) T(val); // placement new } } template -void DestroyRange(T * buffer, int new_size, int old_size) { +void DestroyRange(T* buffer, int new_size, int old_size) +{ for (int i = new_size; i < old_size; i++) { - (buffer+i)->~T(); // Explicit call to the destructor + (buffer + i)->~T(); // Explicit call to the destructor } } - template class Array { public: - Array(Allocator * allocator) : allocator(allocator), buffer(NULL), size(0), capacity(0) {} + Array(Allocator* allocator) : allocator(allocator), buffer(NULL), size(0), capacity(0) {} - void PushBack(const T & val) { - ASSERT(&val < buffer || &val >= buffer+size); + void PushBack(const T& val) + { + ASSERT(&val < buffer || &val >= buffer + size); int old_size = size; int new_size = size + 1; @@ -162,7 +170,8 @@ class Array { ConstructRange(buffer, new_size, old_size, val); } - T & PushBackNew() { + T& PushBackNew() + { int old_size = size; int new_size = size + 1; @@ -172,7 +181,8 @@ class Array { return buffer[old_size]; } - void Resize(int new_size) { + void Resize(int new_size) + { int old_size = size; DestroyRange(buffer, new_size, old_size); @@ -183,13 +193,21 @@ class Array { } int GetSize() const { return size; } - const T & operator[](int i) const { ASSERT(i < size); return buffer[i]; } - T & operator[](int i) { ASSERT(i < size); return buffer[i]; } + const T& operator[](int i) const + { + ASSERT(i < size); + return buffer[i]; + } + T& operator[](int i) + { + ASSERT(i < size); + return buffer[i]; + } private: - // Change array size. - void SetSize(int new_size) { + void SetSize(int new_size) + { size = new_size; if (new_size > capacity) { @@ -208,7 +226,8 @@ class Array { } // Change array capacity. - void SetCapacity(int new_capacity) { + void SetCapacity(int new_capacity) + { ASSERT(new_capacity >= size); if (new_capacity == 0) { @@ -226,30 +245,28 @@ class Array { capacity = new_capacity; } - private: - Allocator * allocator; // @@ Do we really have to keep a pointer to this? - T * buffer; + Allocator* allocator; // @@ Do we really have to keep a pointer to this? + T* buffer; int size; int capacity; }; - // Engine/StringPool.h // @@ Implement this with a hash table! struct StringPool { - StringPool(Allocator * allocator); + StringPool(Allocator* allocator); ~StringPool(); - const char * AddString(const char * text); - const char * AddStringFormat(const char * fmt, ...) M4_PRINTF_ATTR(2, 3); - const char * AddStringFormatList(const char * fmt, va_list args); - bool GetContainsString(const char * text) const; + const char* AddString(const char* text); + const char* AddStringFormat(const char* fmt, ...) M4_PRINTF_ATTR(2, 3); + const char* AddStringFormatList(const char* fmt, va_list args); + bool GetContainsString(const char* text) const; + private: - const char*PrintFormattedVaList(const char* fmt, va_list args); + const char* PrintFormattedVaList(const char* fmt, va_list args); void* m_impl = NULL; }; - -} // M4 namespace +} //namespace M4 diff --git a/hlslparser/src/HLSLGenerator.cpp b/hlslparser/src/HLSLGenerator.cpp index 2565098c..9c78e26c 100644 --- a/hlslparser/src/HLSLGenerator.cpp +++ b/hlslparser/src/HLSLGenerator.cpp @@ -13,8 +13,7 @@ #include "HLSLParser.h" #include "HLSLTree.h" -namespace M4 -{ +namespace M4 { const char* HLSLGenerator::GetTypeName(const HLSLType& type) { @@ -23,45 +22,42 @@ const char* HLSLGenerator::GetTypeName(const HLSLType& type) // number bool isHalfNumerics = promote && !m_options.treatHalfAsFloat; HLSLBaseType baseType = type.baseType; - + // Note: these conversions should really be done during parsing // so that casting gets applied. if (!isHalfNumerics) baseType = HalfToFloatBaseType(baseType); - + // MSL doesn't support double, and many HLSL cards don't either. //if (IsDouble(baseType)) // baseType = DoubleToFloatBaseType(baseType); - + HLSLType remappedType(type); remappedType.baseType = baseType; - + // DONE: these can all just use a table entry, have another slot for MSL // Functions can return void, especially with compute if (IsTextureType(baseType) || IsSamplerType(baseType) || IsNumericType(baseType) || baseType == HLSLBaseType_Void || baseType == HLSLBaseType_UserDefined) return GetTypeNameHLSL(remappedType); - + Error("Unknown type"); return NULL; } // TODO: copied from MSLGenerator // @@ We could be a lot smarter removing parenthesis based on the operator precedence of the parent expression. -static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentExpression) { - +static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentExpression) +{ // For now we just omit the parenthesis if there's no parent expression. - if (parentExpression == NULL) - { + if (parentExpression == NULL) { return false; } // One more special case that's pretty common. - if (parentExpression->nodeType == HLSLNodeType_MemberAccess) - { + if (parentExpression->nodeType == HLSLNodeType_MemberAccess) { if (expression->nodeType == HLSLNodeType_IdentifierExpression || expression->nodeType == HLSLNodeType_ArrayAccess || - expression->nodeType == HLSLNodeType_MemberAccess) - { + expression->nodeType == HLSLNodeType_MemberAccess) { return false; } } @@ -89,62 +85,49 @@ static int GetFunctionArguments(HLSLFunctionCall* functionCall, HLSLExpression* HLSLGenerator::HLSLGenerator() { - m_tree = NULL; - m_entryName = NULL; - m_target = HLSLTarget_VertexShader; - m_isInsideBuffer = false; - m_error = false; + m_tree = NULL; + m_entryName = NULL; + m_target = HLSLTarget_VertexShader; + m_isInsideBuffer = false; + m_error = false; } // @@ We need a better way of doing semantic replacement: // - Look at the function being generated. // - Return semantic, semantics associated to fields of the return structure, or output arguments, or fields of structures associated to output arguments -> output semantic replacement. // - Semantics associated input arguments or fields of the input arguments -> input semantic replacement. -static const char * TranslateSemantic(const char* semantic, bool output, HLSLTarget target) +static const char* TranslateSemantic(const char* semantic, bool output, HLSLTarget target) { // Note: these are all just passthrough of the DX10 semantics // except for BASEVERTEX/INSTANCE which doesn't seem to dxc compile. - - if (target == HLSLTarget_VertexShader) - { - if (output) - { + if (target == HLSLTarget_VertexShader) { + if (output) { } else { // see here for sample of builtin notation // https://github.com/microsoft/DirectXShaderCompiler/commit/b6fe9886ad - + // Vulkan/MSL only, requires ext DrawParameters // [[vk::builtin(\"BaseVertex\")]] uint baseVertex : // [[vk::builtin(\"BaseInstance\")]] uint instance : SV_BaseInstance - + if (String_Equal(semantic, "BASEVERTEX")) - return "BaseVertex"; // vulkan only + return "BaseVertex"; // vulkan only if (String_Equal(semantic, "BASEINSTANCE")) - return "BaseInstance"; // vulkan only + return "BaseInstance"; // vulkan only } } - else if (target == HLSLTarget_PixelShader) - { - if (output) - { - + else if (target == HLSLTarget_PixelShader) { + if (output) { } - else - { - + else { } } - else if (target == HLSLTarget_ComputeShader) - { - if (output) - { - + else if (target == HLSLTarget_ComputeShader) { + if (output) { } - else - { - + else { } } return NULL; @@ -155,8 +138,7 @@ void HLSLGenerator::Error(const char* format, ...) // It's not always convenient to stop executing when an error occurs, // so just track once we've hit an error and stop reporting them until // we successfully bail out of execution. - if (m_error) - { + if (m_error) { return; } m_error = true; @@ -169,21 +151,19 @@ void HLSLGenerator::Error(const char* format, ...) bool HLSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entryName, const HLSLOptions& options) { - - m_tree = tree; + m_tree = tree; m_entryName = entryName; - m_target = target; + m_target = target; m_isInsideBuffer = false; - m_options = options; + m_options = options; m_writer.SetWriteFileLine(options.writeFileLine); - + m_writer.Reset(); // Find entry point function HLSLFunction* entryFunction = tree->FindFunction(entryName); - if (entryFunction == NULL) - { + if (entryFunction == NULL) { Error("Entry point '%s' doesn't exist\n", entryName); return false; } @@ -191,88 +171,90 @@ bool HLSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entr // PruneTree resets hidden flags to true, then marks visible elements // based on whether entry point visits them. PruneTree(tree, entryFunction->name); // Note: takes second entry - + // This sorts tree by type, but keeps ordering SortTree(tree); - + // This strips any unused inputs to the entry point function HideUnusedArguments(entryFunction); - + // Is this needed FlattenExpressions(tree); - + m_writer.WriteLine(0, "#include \"ShaderHLSL.h\""); - + // @@ Should we generate an entirely new copy of the tree so that we can modify it in place? //if (!legacy) { - HLSLFunction * function = tree->FindFunction(entryName); + HLSLFunction* function = tree->FindFunction(entryName); // Handle return value semantics if (function->semantic != NULL) { function->sv_semantic = TranslateSemantic(function->semantic, /*output=*/true, target); } if (function->returnType.baseType == HLSLBaseType_UserDefined) { - HLSLStruct * s = tree->FindGlobalStruct(function->returnType.typeName); + HLSLStruct* s = tree->FindGlobalStruct(function->returnType.typeName); - HLSLStructField * sv_fields = NULL; + HLSLStructField* sv_fields = NULL; - HLSLStructField * lastField = NULL; - HLSLStructField * field = s->field; + HLSLStructField* lastField = NULL; + HLSLStructField* field = s->field; while (field) { - HLSLStructField * nextField = field->nextField; + HLSLStructField* nextField = field->nextField; // TODO: may have to be careful with SV_Position, since this puts // those last. SSBO won't use those semantics, so should be okay. - + if (field->semantic) { - field->hidden = false; + field->hidden = false; field->sv_semantic = TranslateSemantic(field->semantic, /*output=*/true, target); - // Fields with SV semantics are stored at the end to avoid linkage problems. - if (field->sv_semantic != NULL) { - // Unlink from last. - if (lastField != NULL) lastField->nextField = nextField; - else s->field = nextField; - - // Add to sv_fields. - field->nextField = sv_fields; - sv_fields = field; - } + // Fields with SV semantics are stored at the end to avoid linkage problems. + if (field->sv_semantic != NULL) { + // Unlink from last. + if (lastField != NULL) + lastField->nextField = nextField; + else + s->field = nextField; + + // Add to sv_fields. + field->nextField = sv_fields; + sv_fields = field; + } } - if (field != sv_fields) lastField = field; + if (field != sv_fields) lastField = field; field = nextField; } - // Append SV fields at the end. - if (sv_fields != NULL) { - if (lastField == NULL) { - s->field = sv_fields; - } - else { - ASSERT(lastField->nextField == NULL); - lastField->nextField = sv_fields; - } - } + // Append SV fields at the end. + if (sv_fields != NULL) { + if (lastField == NULL) { + s->field = sv_fields; + } + else { + ASSERT(lastField->nextField == NULL); + lastField->nextField = sv_fields; + } + } } // Handle argument semantics. // @@ It would be nice to flag arguments that are used by the program and skip or hide the unused ones. - HLSLArgument * argument = function->argument; + HLSLArgument* argument = function->argument; while (argument) { bool output = argument->modifier == HLSLArgumentModifier_Out; if (argument->semantic) { - argument->sv_semantic = TranslateSemantic(argument->semantic, output, target); + argument->sv_semantic = TranslateSemantic(argument->semantic, output, target); } if (argument->type.baseType == HLSLBaseType_UserDefined) { - HLSLStruct * s = tree->FindGlobalStruct(argument->type.typeName); + HLSLStruct* s = tree->FindGlobalStruct(argument->type.typeName); - HLSLStructField * field = s->field; + HLSLStructField* field = s->field; while (field) { if (field->semantic) { - field->hidden = false; + field->hidden = false; field->sv_semantic = TranslateSemantic(field->semantic, output, target); } @@ -283,7 +265,7 @@ bool HLSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entr argument = argument->nextArgument; } } - + HLSLRoot* root = m_tree->GetRoot(); OutputStatements(0, root->statement); @@ -299,10 +281,8 @@ const char* HLSLGenerator::GetResult() const void HLSLGenerator::OutputExpressionList(HLSLExpression* expression) { int numExpressions = 0; - while (expression != NULL) - { - if (numExpressions > 0) - { + while (expression != NULL) { + if (numExpressions > 0) { m_writer.Write(", "); } OutputExpression(expression); @@ -311,154 +291,196 @@ void HLSLGenerator::OutputExpressionList(HLSLExpression* expression) } } - - void HLSLGenerator::OutputExpression(HLSLExpression* expression) { - if (expression->nodeType == HLSLNodeType_IdentifierExpression) - { + if (expression->nodeType == HLSLNodeType_IdentifierExpression) { HLSLIdentifierExpression* identifierExpression = static_cast(expression); const char* name = identifierExpression->name; - + m_writer.Write("%s", name); } - else if (expression->nodeType == HLSLNodeType_CastingExpression) - { + else if (expression->nodeType == HLSLNodeType_CastingExpression) { HLSLCastingExpression* castingExpression = static_cast(expression); m_writer.Write("("); // OutputDeclaration(castingExpression->type, ""); // old - adds space after type - OutputDeclarationType(castingExpression->type, true/*isTypeCast*/); // new + OutputDeclarationType(castingExpression->type, true /*isTypeCast*/); // new m_writer.Write(")"); - + // These parens may not be needed m_writer.Write("("); OutputExpression(castingExpression->expression); m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_ConstructorExpression) - { + else if (expression->nodeType == HLSLNodeType_ConstructorExpression) { HLSLConstructorExpression* constructorExpression = static_cast(expression); m_writer.Write("%s(", GetTypeName(constructorExpression->type)); OutputExpressionList(constructorExpression->argument); m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_LiteralExpression) - { + else if (expression->nodeType == HLSLNodeType_LiteralExpression) { HLSLLiteralExpression* literalExpression = static_cast(expression); - + HLSLBaseType type = literalExpression->type; if (m_options.treatHalfAsFloat && IsHalf(type)) type = HLSLBaseType_Float; - - switch (type) - { - case HLSLBaseType_Half: - case HLSLBaseType_Float: - case HLSLBaseType_Double: - { + + switch (type) { + case HLSLBaseType_Half: + case HLSLBaseType_Float: + case HLSLBaseType_Double: { // Don't use printf directly so that we don't use the system locale. char buffer[64]; String_FormatFloat(buffer, sizeof(buffer), literalExpression->fValue); String_StripTrailingFloatZeroes(buffer); - m_writer.Write("%s%s", buffer, type == HLSLBaseType_Half ? "h" : "" ); - } - break; - - case HLSLBaseType_Short: - case HLSLBaseType_Ulong: - case HLSLBaseType_Int: - m_writer.Write("%d", literalExpression->iValue); - break; - // TODO: missing uint, u/short, u/long double - - case HLSLBaseType_Bool: - m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); - break; - default: - Error("Unhandled literal"); - //ASSERT(false); + m_writer.Write("%s%s", buffer, type == HLSLBaseType_Half ? "h" : ""); + } break; + + case HLSLBaseType_Short: + case HLSLBaseType_Ulong: + case HLSLBaseType_Int: + m_writer.Write("%d", literalExpression->iValue); + break; + // TODO: missing uint, u/short, u/long double + + case HLSLBaseType_Bool: + m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); + break; + default: + Error("Unhandled literal"); + //ASSERT(false); } } - else if (expression->nodeType == HLSLNodeType_UnaryExpression) - { + else if (expression->nodeType == HLSLNodeType_UnaryExpression) { HLSLUnaryExpression* unaryExpression = static_cast(expression); const char* op = "?"; bool pre = true; - switch (unaryExpression->unaryOp) - { - case HLSLUnaryOp_Negative: op = "-"; break; - case HLSLUnaryOp_Positive: op = "+"; break; - case HLSLUnaryOp_Not: op = "!"; break; - case HLSLUnaryOp_PreIncrement: op = "++"; break; - case HLSLUnaryOp_PreDecrement: op = "--"; break; - case HLSLUnaryOp_PostIncrement: op = "++"; pre = false; break; - case HLSLUnaryOp_PostDecrement: op = "--"; pre = false; break; - case HLSLUnaryOp_BitNot: op = "~"; break; + switch (unaryExpression->unaryOp) { + case HLSLUnaryOp_Negative: + op = "-"; + break; + case HLSLUnaryOp_Positive: + op = "+"; + break; + case HLSLUnaryOp_Not: + op = "!"; + break; + case HLSLUnaryOp_PreIncrement: + op = "++"; + break; + case HLSLUnaryOp_PreDecrement: + op = "--"; + break; + case HLSLUnaryOp_PostIncrement: + op = "++"; + pre = false; + break; + case HLSLUnaryOp_PostDecrement: + op = "--"; + pre = false; + break; + case HLSLUnaryOp_BitNot: + op = "~"; + break; } - + // eliminate () if pure characters bool addParenthesis = NeedsParenthesis(unaryExpression->expression, expression); if (addParenthesis) m_writer.Write("("); - - if (pre) - { + + if (pre) { m_writer.Write("%s", op); OutputExpression(unaryExpression->expression); } - else - { + else { OutputExpression(unaryExpression->expression); m_writer.Write("%s", op); } if (addParenthesis) m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_BinaryExpression) - { + else if (expression->nodeType == HLSLNodeType_BinaryExpression) { HLSLBinaryExpression* binaryExpression = static_cast(expression); - + // TODO: to fix this need to pass in parentExpression to // the call. And MSLGenerator passes NULL for most of these. // TODO: eliminate () if pure characters - + bool addParenthesis = false; // NeedsParenthesis(expression, parentExpression); if (addParenthesis) m_writer.Write("("); - + OutputExpression(binaryExpression->expression1); const char* op = "?"; - switch (binaryExpression->binaryOp) - { - case HLSLBinaryOp_Add: op = " + "; break; - case HLSLBinaryOp_Sub: op = " - "; break; - case HLSLBinaryOp_Mul: op = " * "; break; - case HLSLBinaryOp_Div: op = " / "; break; - case HLSLBinaryOp_Less: op = " < "; break; - case HLSLBinaryOp_Greater: op = " > "; break; - case HLSLBinaryOp_LessEqual: op = " <= "; break; - case HLSLBinaryOp_GreaterEqual: op = " >= "; break; - case HLSLBinaryOp_Equal: op = " == "; break; - case HLSLBinaryOp_NotEqual: op = " != "; break; - case HLSLBinaryOp_Assign: op = " = "; break; - case HLSLBinaryOp_AddAssign: op = " += "; break; - case HLSLBinaryOp_SubAssign: op = " -= "; break; - case HLSLBinaryOp_MulAssign: op = " *= "; break; - case HLSLBinaryOp_DivAssign: op = " /= "; break; - case HLSLBinaryOp_And: op = " && "; break; - case HLSLBinaryOp_Or: op = " || "; break; - case HLSLBinaryOp_BitAnd: op = " & "; break; - case HLSLBinaryOp_BitOr: op = " | "; break; - case HLSLBinaryOp_BitXor: op = " ^ "; break; - default: - Error("Unhandled binary op"); - //ASSERT(false); + switch (binaryExpression->binaryOp) { + case HLSLBinaryOp_Add: + op = " + "; + break; + case HLSLBinaryOp_Sub: + op = " - "; + break; + case HLSLBinaryOp_Mul: + op = " * "; + break; + case HLSLBinaryOp_Div: + op = " / "; + break; + case HLSLBinaryOp_Less: + op = " < "; + break; + case HLSLBinaryOp_Greater: + op = " > "; + break; + case HLSLBinaryOp_LessEqual: + op = " <= "; + break; + case HLSLBinaryOp_GreaterEqual: + op = " >= "; + break; + case HLSLBinaryOp_Equal: + op = " == "; + break; + case HLSLBinaryOp_NotEqual: + op = " != "; + break; + case HLSLBinaryOp_Assign: + op = " = "; + break; + case HLSLBinaryOp_AddAssign: + op = " += "; + break; + case HLSLBinaryOp_SubAssign: + op = " -= "; + break; + case HLSLBinaryOp_MulAssign: + op = " *= "; + break; + case HLSLBinaryOp_DivAssign: + op = " /= "; + break; + case HLSLBinaryOp_And: + op = " && "; + break; + case HLSLBinaryOp_Or: + op = " || "; + break; + case HLSLBinaryOp_BitAnd: + op = " & "; + break; + case HLSLBinaryOp_BitOr: + op = " | "; + break; + case HLSLBinaryOp_BitXor: + op = " ^ "; + break; + default: + Error("Unhandled binary op"); + //ASSERT(false); } m_writer.Write("%s", op); OutputExpression(binaryExpression->expression2); if (addParenthesis) m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_ConditionalExpression) - { + else if (expression->nodeType == HLSLNodeType_ConditionalExpression) { HLSLConditionalExpression* conditionalExpression = static_cast(expression); - + // TODO: eliminate () if pure characters m_writer.Write("(("); OutputExpression(conditionalExpression->condition); @@ -468,56 +490,50 @@ void HLSLGenerator::OutputExpression(HLSLExpression* expression) OutputExpression(conditionalExpression->falseExpression); m_writer.Write("))"); } - else if (expression->nodeType == HLSLNodeType_MemberAccess) - { + else if (expression->nodeType == HLSLNodeType_MemberAccess) { HLSLMemberAccess* memberAccess = static_cast(expression); - + bool addParenthesis = NeedsParenthesis(memberAccess->object, expression); - + // eliminate () if pure characters - if ( addParenthesis ) m_writer.Write("("); + if (addParenthesis) m_writer.Write("("); OutputExpression(memberAccess->object); - if ( addParenthesis ) m_writer.Write(")"); + if (addParenthesis) m_writer.Write(")"); m_writer.Write(".%s", memberAccess->field); } - else if (expression->nodeType == HLSLNodeType_ArrayAccess) - { + else if (expression->nodeType == HLSLNodeType_ArrayAccess) { HLSLArrayAccess* arrayAccess = static_cast(expression); OutputExpression(arrayAccess->array); m_writer.Write("["); OutputExpression(arrayAccess->index); m_writer.Write("]"); } - else if (expression->nodeType == HLSLNodeType_FunctionCall) - { + else if (expression->nodeType == HLSLNodeType_FunctionCall) { HLSLFunctionCall* functionCall = static_cast(expression); const char* name = functionCall->function->name; m_writer.Write("%s(", name); OutputExpressionList(functionCall->argument); m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_MemberFunctionCall) - { + else if (expression->nodeType == HLSLNodeType_MemberFunctionCall) { HLSLMemberFunctionCall* functionCall = static_cast(expression); - + // Spriv only supports fp32 or i32/i64 OpTypeImage - if (IsHalf(functionCall->function->returnType.baseType) && m_options.writeVulkan) - { + if (IsHalf(functionCall->function->returnType.baseType) && m_options.writeVulkan) { // TODO: may need parens m_writer.Write("(half4)"); } - + // Write out the member identifier m_writer.Write("%s.", functionCall->memberIdentifier->name); - + // Same as FunctionCall const char* name = functionCall->function->name; m_writer.Write("%s(", name); OutputExpressionList(functionCall->argument); m_writer.Write(")"); } - else - { + else { Error("unknown expression"); } } @@ -525,19 +541,16 @@ void HLSLGenerator::OutputExpression(HLSLExpression* expression) void HLSLGenerator::OutputArguments(HLSLArgument* argument) { int numArgs = 0; - while (argument != NULL) - { - if (numArgs > 0) - { + while (argument != NULL) { + if (numArgs > 0) { int indent = m_writer.EndLine(","); m_writer.BeginLine(indent); } - const char * semantic = argument->sv_semantic ? argument->sv_semantic : argument->semantic; + const char* semantic = argument->sv_semantic ? argument->sv_semantic : argument->semantic; // Have to inject vulkan - if (semantic && m_options.writeVulkan) - { + if (semantic && m_options.writeVulkan) { if (String_Equal(semantic, "PSIZE")) m_writer.Write("%s ", "[[vk::builtin(\"PointSize\")]]"); else if (String_Equal(semantic, "BaseVertex")) @@ -545,34 +558,33 @@ void HLSLGenerator::OutputArguments(HLSLArgument* argument) else if (String_Equal(semantic, "BaseInstance")) m_writer.Write("%s ", "[[vk::builtin(\"BaseInstance\")]]"); } - + // Then modifier - switch (argument->modifier) - { - case HLSLArgumentModifier_In: - m_writer.Write("in "); - break; - case HLSLArgumentModifier_Out: - m_writer.Write("out "); - break; - case HLSLArgumentModifier_Inout: - m_writer.Write("inout "); - break; - case HLSLArgumentModifier_Uniform: - m_writer.Write("uniform "); - break; - default: - break; + switch (argument->modifier) { + case HLSLArgumentModifier_In: + m_writer.Write("in "); + break; + case HLSLArgumentModifier_Out: + m_writer.Write("out "); + break; + case HLSLArgumentModifier_Inout: + m_writer.Write("inout "); + break; + case HLSLArgumentModifier_Uniform: + m_writer.Write("uniform "); + break; + default: + break; } - + OutputDeclaration(argument->type, argument->name, semantic, /*registerName=*/NULL, argument->defaultValue); - + argument = argument->nextArgument; ++numArgs; } } -static const char * GetAttributeName(HLSLAttributeType attributeType) +static const char* GetAttributeName(HLSLAttributeType attributeType) { if (attributeType == HLSLAttributeType_Unroll) return "unroll"; if (attributeType == HLSLAttributeType_Branch) return "branch"; @@ -582,12 +594,10 @@ static const char * GetAttributeName(HLSLAttributeType attributeType) void HLSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) { - while (attribute != NULL) - { - const char * attributeName = GetAttributeName(attribute->attributeType); - - if (attributeName != NULL) - { + while (attribute != NULL) { + const char* attributeName = GetAttributeName(attribute->attributeType); + + if (attributeName != NULL) { m_writer.WriteLineTagged(indent, attribute->fileName, attribute->line, "[%s]", attributeName); } @@ -598,93 +608,95 @@ void HLSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) static const char* BufferTypeToName(HLSLBufferType bufferType) { const char* name = ""; - switch(bufferType) - { - case HLSLBufferType_CBuffer: name = "cbuffer"; break; - case HLSLBufferType_TBuffer: name = "tbuffer"; break; - - case HLSLBufferType_ConstantBuffer: name = "ConstantBuffer"; break; - case HLSLBufferType_StructuredBuffer: name = "StructuredBuffer"; break; - case HLSLBufferType_RWStructuredBuffer: name = "RWStructuredBuffer"; break; - case HLSLBufferType_ByteAddressBuffer: name = "ByteAddressBuffer"; break; - case HLSLBufferType_RWByteAddressBuffer: name = "RWByteAddresssBuffer"; break; + switch (bufferType) { + case HLSLBufferType_CBuffer: + name = "cbuffer"; + break; + case HLSLBufferType_TBuffer: + name = "tbuffer"; + break; + + case HLSLBufferType_ConstantBuffer: + name = "ConstantBuffer"; + break; + case HLSLBufferType_StructuredBuffer: + name = "StructuredBuffer"; + break; + case HLSLBufferType_RWStructuredBuffer: + name = "RWStructuredBuffer"; + break; + case HLSLBufferType_ByteAddressBuffer: + name = "ByteAddressBuffer"; + break; + case HLSLBufferType_RWByteAddressBuffer: + name = "RWByteAddresssBuffer"; + break; } - + return name; } bool HLSLGenerator::CanSkipWrittenStatement(const HLSLStatement* statement) const { if (!statement->written) return false; - + // only write these once for multi-entrypoint if (statement->nodeType == HLSLNodeType_Comment || - statement->nodeType == HLSLNodeType_Buffer || - statement->nodeType == HLSLNodeType_Struct) + statement->nodeType == HLSLNodeType_Buffer || + statement->nodeType == HLSLNodeType_Struct) return true; - + // only write const scalars out once, so they don't conflict - if (statement->nodeType == HLSLNodeType_Declaration) - { + if (statement->nodeType == HLSLNodeType_Declaration) { const HLSLDeclaration* decl = (const HLSLDeclaration*)statement; - if (IsScalarType(decl->type.baseType) && decl->type.flags & HLSLTypeFlag_Const) - { + if (IsScalarType(decl->type.baseType) && decl->type.flags & HLSLTypeFlag_Const) { return true; } } - + // Helper functions should be skipped once written out - if (statement->nodeType == HLSLNodeType_Function) - { + if (statement->nodeType == HLSLNodeType_Function) { return true; } - + return false; } void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) { - while (statement != NULL) - { + while (statement != NULL) { // skip pruned statements - if (statement->hidden) - { + if (statement->hidden) { statement = statement->nextStatement; continue; } // skip writing some types across multiple entry points - if (CanSkipWrittenStatement(statement)) - { + if (CanSkipWrittenStatement(statement)) { statement = statement->nextStatement; continue; } statement->written = true; - + OutputAttributes(indent, statement->attributes); - if (statement->nodeType == HLSLNodeType_Comment) - { + if (statement->nodeType == HLSLNodeType_Comment) { HLSLComment* comment = static_cast(statement); m_writer.WriteLine(indent, "//%s", comment->text); } - else if (statement->nodeType == HLSLNodeType_Declaration) - { + else if (statement->nodeType == HLSLNodeType_Declaration) { HLSLDeclaration* declaration = static_cast(statement); m_writer.BeginLine(indent, declaration->fileName, declaration->line); OutputDeclaration(declaration); m_writer.EndLine(";"); } - else if (statement->nodeType == HLSLNodeType_Struct) - { + else if (statement->nodeType == HLSLNodeType_Struct) { HLSLStruct* structure = static_cast(statement); m_writer.WriteLineTagged(indent, structure->fileName, structure->line, "struct %s {", structure->name); HLSLStructField* field = structure->field; - while (field != NULL) - { - if (!field->hidden) - { + while (field != NULL) { + if (!field->hidden) { m_writer.BeginLine(indent + 1, field->fileName, field->line); - const char * semantic = field->sv_semantic ? field->sv_semantic : field->semantic; + const char* semantic = field->sv_semantic ? field->sv_semantic : field->semantic; OutputDeclaration(field->type, field->name, semantic); m_writer.Write(";"); m_writer.EndLine(); @@ -693,95 +705,83 @@ void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) } m_writer.WriteLine(indent, "};"); } - else if (statement->nodeType == HLSLNodeType_Buffer) - { + else if (statement->nodeType == HLSLNodeType_Buffer) { HLSLBuffer* buffer = static_cast(statement); HLSLDeclaration* field = buffer->field; - if (!buffer->IsGlobalFields()) - { + if (!buffer->IsGlobalFields()) { // Constant/Structured/ByteAdddressBuffer m_writer.BeginLine(indent, buffer->fileName, buffer->line); - + // Handle push constant for Vulkan. // This is just a buffer to MSL. // VK is limited to 1 buffer as a result. Cannot contain half on AMD. - if (buffer->bufferType == HLSLBufferType_ConstantBuffer) - { + if (buffer->bufferType == HLSLBufferType_ConstantBuffer) { if (m_options.writeVulkan && (String_HasString(buffer->name, "Push") || - String_HasString(buffer->name, "push"))) - { + String_HasString(buffer->name, "push"))) { m_writer.Write("[[vk::push_constant]] "); } } - + // write out template m_writer.Write("%s<%s> %s", BufferTypeToName(buffer->bufferType), buffer->bufferStruct->name, buffer->name); - + // write out optinal register - if (buffer->registerName != NULL) - { - m_writer.Write(" : register(%s)", buffer->registerName); + if (buffer->registerName != NULL) { + m_writer.Write(" : register(%s)", buffer->registerName); } - + m_writer.Write(";"); m_writer.EndLine(); } - else - { + else { // c/tbuffer m_writer.BeginLine(indent, buffer->fileName, buffer->line); - + // not templated m_writer.Write("%s %s", BufferTypeToName(buffer->bufferType), buffer->name); - + // write out optional register - if (buffer->registerName != NULL) - { - m_writer.Write(" : register(%s)", buffer->registerName); + if (buffer->registerName != NULL) { + m_writer.Write(" : register(%s)", buffer->registerName); } - + m_writer.EndLine(" {"); m_isInsideBuffer = true; - - while (field != NULL) - { - if (!field->hidden) - { + + while (field != NULL) { + if (!field->hidden) { m_writer.BeginLine(indent + 1, field->fileName, field->line); - OutputDeclaration(field->type, field->name, /*semantic=*/NULL, /*registerName*/field->registerName, field->assignment); + OutputDeclaration(field->type, field->name, /*semantic=*/NULL, /*registerName*/ field->registerName, field->assignment); m_writer.Write(";"); m_writer.EndLine(); } field = (HLSLDeclaration*)field->nextStatement; } - + m_isInsideBuffer = false; - + m_writer.WriteLine(indent, "};"); } } - else if (statement->nodeType == HLSLNodeType_Function) - { + else if (statement->nodeType == HLSLNodeType_Function) { HLSLFunction* function = static_cast(statement); // Use an alternate name for the function which is supposed to be entry point // so that we can supply our own function which will be the actual entry point. - const char* functionName = function->name; + const char* functionName = function->name; const char* returnTypeName = GetTypeName(function->returnType); bool isEntryPoint = String_Equal(functionName, m_entryName); - if (isEntryPoint) - { + if (isEntryPoint) { // This is a SM6.x construct for tagging entry points - switch(m_target) - { + switch (m_target) { case HLSLTarget_VertexShader: m_writer.WriteLine(indent, "[shader(\"vertex\")] "); break; @@ -795,19 +795,17 @@ void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) break; } } - + m_writer.BeginLine(indent, function->fileName, function->line); m_writer.Write("%s %s(", returnTypeName, functionName); OutputArguments(function->argument); - const char * semantic = function->sv_semantic ? function->sv_semantic : function->semantic; - if (semantic != NULL) - { + const char* semantic = function->sv_semantic ? function->sv_semantic : function->semantic; + if (semantic != NULL) { m_writer.Write(") : %s {", semantic); } - else - { + else { m_writer.Write(") {"); } @@ -816,45 +814,37 @@ void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) OutputStatements(indent + 1, function->statement); m_writer.WriteLine(indent, "};"); } - else if (statement->nodeType == HLSLNodeType_ExpressionStatement) - { + else if (statement->nodeType == HLSLNodeType_ExpressionStatement) { HLSLExpressionStatement* expressionStatement = static_cast(statement); m_writer.BeginLine(indent, statement->fileName, statement->line); OutputExpression(expressionStatement->expression); m_writer.EndLine(";"); } - else if (statement->nodeType == HLSLNodeType_ReturnStatement) - { + else if (statement->nodeType == HLSLNodeType_ReturnStatement) { HLSLReturnStatement* returnStatement = static_cast(statement); - if (returnStatement->expression != NULL) - { + if (returnStatement->expression != NULL) { m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); m_writer.Write("return "); OutputExpression(returnStatement->expression); m_writer.EndLine(";"); } - else - { + else { m_writer.WriteLineTagged(indent, returnStatement->fileName, returnStatement->line, "return;"); } } - else if (statement->nodeType == HLSLNodeType_DiscardStatement) - { + else if (statement->nodeType == HLSLNodeType_DiscardStatement) { HLSLDiscardStatement* discardStatement = static_cast(statement); m_writer.WriteLineTagged(indent, discardStatement->fileName, discardStatement->line, "discard;"); } - else if (statement->nodeType == HLSLNodeType_BreakStatement) - { + else if (statement->nodeType == HLSLNodeType_BreakStatement) { HLSLBreakStatement* breakStatement = static_cast(statement); m_writer.WriteLineTagged(indent, breakStatement->fileName, breakStatement->line, "break;"); } - else if (statement->nodeType == HLSLNodeType_ContinueStatement) - { + else if (statement->nodeType == HLSLNodeType_ContinueStatement) { HLSLContinueStatement* continueStatement = static_cast(statement); m_writer.WriteLineTagged(indent, continueStatement->fileName, continueStatement->line, "continue;"); } - else if (statement->nodeType == HLSLNodeType_IfStatement) - { + else if (statement->nodeType == HLSLNodeType_IfStatement) { HLSLIfStatement* ifStatement = static_cast(statement); m_writer.BeginLine(indent, ifStatement->fileName, ifStatement->line); m_writer.Write("if ("); @@ -863,15 +853,13 @@ void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) m_writer.EndLine(); OutputStatements(indent + 1, ifStatement->statement); m_writer.WriteLine(indent, "}"); - if (ifStatement->elseStatement != NULL) - { + if (ifStatement->elseStatement != NULL) { m_writer.WriteLine(indent, "else {"); OutputStatements(indent + 1, ifStatement->elseStatement); m_writer.WriteLine(indent, "}"); } } - else if (statement->nodeType == HLSLNodeType_ForStatement) - { + else if (statement->nodeType == HLSLNodeType_ForStatement) { HLSLForStatement* forStatement = static_cast(statement); m_writer.BeginLine(indent, forStatement->fileName, forStatement->line); m_writer.Write("for ("); @@ -885,24 +873,22 @@ void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) OutputStatements(indent + 1, forStatement->statement); m_writer.WriteLine(indent, "}"); } - else if (statement->nodeType == HLSLNodeType_BlockStatement) - { + else if (statement->nodeType == HLSLNodeType_BlockStatement) { HLSLBlockStatement* blockStatement = static_cast(statement); m_writer.WriteLineTagged(indent, blockStatement->fileName, blockStatement->line, "{"); OutputStatements(indent + 1, blockStatement->statement); m_writer.WriteLine(indent, "}"); } // FX file constructs -// else if (statement->nodeType == HLSLNodeType_Technique) -// { -// // Techniques are ignored. -// } -// else if (statement->nodeType == HLSLNodeType_Pipeline) -// { -// // Pipelines are ignored. -// } - else - { + // else if (statement->nodeType == HLSLNodeType_Technique) + // { + // // Techniques are ignored. + // } + // else if (statement->nodeType == HLSLNodeType_Pipeline) + // { + // // Pipelines are ignored. + // } + else { // Unhanded statement type. Error("Unhandled statement"); //ASSERT(false); @@ -917,73 +903,62 @@ const char* HLSLGenerator::GetFormatName(HLSLBaseType bufferOrTextureType, HLSLB { // TODO: have a way to disable use of half (like on MSLGenerator) bool isHalf = IsHalf(formatType); - + // Can't use half4 textures with spirv. Can only cast from full float sampler. // Can tell Vulkan was written by/for desktop IHVs. // https://github.com/microsoft/DirectXShaderCompiler/issues/2711 bool isSpirvTarget = m_options.writeVulkan; if (isSpirvTarget) isHalf = false; - + const char* formatName = isHalf ? "half4" : "float4"; - + // MSL only uses half/float mostly. With HLSL, this is a full // template format of float/2/3/4. - + return formatName; } - void HLSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) { - if (IsSamplerType(declaration->type)) - { + if (IsSamplerType(declaration->type)) { int reg = -1; - if (declaration->registerName != NULL) - { + if (declaration->registerName != NULL) { sscanf(declaration->registerName, "s%d", ®); } - + // sampler const char* samplerTypeName = GetTypeName(declaration->type); - if (samplerTypeName) - { - if (reg != -1) - { + if (samplerTypeName) { + if (reg != -1) { m_writer.Write("%s %s : register(s%d)", samplerTypeName, declaration->name, reg); } - else - { + else { m_writer.Write("%s %s", samplerTypeName, declaration->name); } } return; } - if (IsTextureType(declaration->type)) - { + if (IsTextureType(declaration->type)) { int reg = -1; - if (declaration->registerName != NULL) - { + if (declaration->registerName != NULL) { sscanf(declaration->registerName, "t%d", ®); } HLSLBaseType formatType = declaration->type.formatType; if (m_options.treatHalfAsFloat && IsHalf(formatType)) formatType = HalfToFloatBaseType(formatType); - + const char* formatTypeName = GetFormatName(declaration->type.baseType, formatType); - + // texture carts the dimension and format const char* textureTypeName = GetTypeName(declaration->type); - - if (textureTypeName != NULL) - { - if (reg != -1) - { + + if (textureTypeName != NULL) { + if (reg != -1) { m_writer.Write("%s<%s> %s : register(t%d)", textureTypeName, formatTypeName, declaration->name, reg); } - else - { + else { m_writer.Write("%s<%s> %s", textureTypeName, formatTypeName, declaration->name); } } @@ -994,7 +969,7 @@ void HLSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); declaration = declaration->nextDeclaration; - while(declaration != NULL) { + while (declaration != NULL) { m_writer.Write(", "); OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); declaration = declaration->nextDeclaration; @@ -1005,39 +980,32 @@ void HLSLGenerator::OutputDeclarationType(const HLSLType& type, bool isTypeCast) { const char* typeName = GetTypeName(type); - if (isTypeCast) - { + if (isTypeCast) { m_writer.Write("%s", typeName); return; } - - if (type.flags & HLSLTypeFlag_Static) - { + + if (type.flags & HLSLTypeFlag_Static) { m_writer.Write("static "); } - if (type.flags & HLSLTypeFlag_Const) - { + if (type.flags & HLSLTypeFlag_Const) { m_writer.Write("const "); } - + // Interpolation modifiers. - if (type.flags & HLSLTypeFlag_Centroid) - { + if (type.flags & HLSLTypeFlag_Centroid) { m_writer.Write("centroid "); } - if (type.flags & HLSLTypeFlag_Linear) - { + if (type.flags & HLSLTypeFlag_Linear) { m_writer.Write("linear "); } - if (type.flags & HLSLTypeFlag_NoInterpolation) - { + if (type.flags & HLSLTypeFlag_NoInterpolation) { m_writer.Write("nointerpolation "); } - if (type.flags & HLSLTypeFlag_NoPerspective) - { + if (type.flags & HLSLTypeFlag_NoPerspective) { m_writer.Write("noperspective "); } - if (type.flags & HLSLTypeFlag_Sample) // @@ Only in shader model >= 4.1 + if (type.flags & HLSLTypeFlag_Sample) // @@ Only in shader model >= 4.1 { m_writer.Write("sample "); } @@ -1045,55 +1013,46 @@ void HLSLGenerator::OutputDeclarationType(const HLSLType& type, bool isTypeCast) m_writer.Write("%s ", typeName); } -void HLSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) +void HLSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic /*=NULL*/, const char* registerName /*=NULL*/, HLSLExpression* assignment /*=NULL*/) { m_writer.Write("%s", name); - if (type.array) - { + if (type.array) { ASSERT(semantic == NULL); m_writer.Write("["); - if (type.arraySize != NULL) - { + if (type.arraySize != NULL) { OutputExpression(type.arraySize); } m_writer.Write("]"); } - if (semantic != NULL) - { + if (semantic != NULL) { m_writer.Write(" : %s", semantic); } - if (registerName != NULL) - { - if (m_isInsideBuffer) - { + if (registerName != NULL) { + if (m_isInsideBuffer) { m_writer.Write(" : packoffset(%s)", registerName); } - else - { + else { m_writer.Write(" : register(%s)", registerName); } } - if (assignment != NULL && !IsSamplerType(type)) - { + if (assignment != NULL && !IsSamplerType(type)) { m_writer.Write(" = "); - if (type.array) - { + if (type.array) { m_writer.Write("{ "); OutputExpressionList(assignment); m_writer.Write(" }"); } - else - { + else { OutputExpression(assignment); } } } -void HLSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) +void HLSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, const char* semantic /*=NULL*/, const char* registerName /*=NULL*/, HLSLExpression* assignment /*=NULL*/) { OutputDeclarationType(type); OutputDeclarationBody(type, name, semantic, registerName, assignment); @@ -1103,20 +1062,17 @@ bool HLSLGenerator::ChooseUniqueName(const char* base, char* dst, int dstLength) { // IC: Try without suffix first. String_Printf(dst, dstLength, "%s", base); - if (!m_tree->GetContainsString(base)) - { + if (!m_tree->GetContainsString(base)) { return true; } - for (int i = 1; i < 1024; ++i) - { + for (int i = 1; i < 1024; ++i) { String_Printf(dst, dstLength, "%s%d", base, i); - if (!m_tree->GetContainsString(dst)) - { + if (!m_tree->GetContainsString(dst)) { return true; } } return false; } -} +} //namespace M4 diff --git a/hlslparser/src/HLSLGenerator.h b/hlslparser/src/HLSLGenerator.h index a909d0ca..5ad6b711 100644 --- a/hlslparser/src/HLSLGenerator.h +++ b/hlslparser/src/HLSLGenerator.h @@ -12,25 +12,23 @@ #include "CodeWriter.h" #include "HLSLTree.h" -namespace M4 -{ +namespace M4 { -class HLSLTree; +class HLSLTree; struct HLSLFunction; struct HLSLStruct; // TODO: try to unify some options with MSLGenerator -struct HLSLOptions -{ +struct HLSLOptions { // int (*attributeCallback)(const char* name, uint32_t index) = NULL; // uint32_t bufferRegisterOffset = 0; - + bool writeFileLine = false; - + bool treatHalfAsFloat = false; // TODO: hook this up // bool treatDoubleAsFloat = true; - + // add vk constructions to HLSL source to convert to Spriv bool writeVulkan = false; }; @@ -39,19 +37,14 @@ struct HLSLOptions * This class is used to generate HLSL which is compatible with the D3D9 * compiler (i.e. no cbuffers). */ -class HLSLGenerator -{ - +class HLSLGenerator { public: HLSLGenerator(); - - - - bool Generate(HLSLTree* tree, HLSLTarget target, const char* entryName, const HLSLOptions& options = HLSLOptions() ); + + bool Generate(HLSLTree* tree, HLSLTarget target, const char* entryName, const HLSLOptions& options = HLSLOptions()); const char* GetResult() const; private: - void OutputExpressionList(HLSLExpression* expression); void OutputExpression(HLSLExpression* expression); void OutputArguments(HLSLArgument* argument); @@ -60,7 +53,7 @@ class HLSLGenerator void OutputDeclaration(HLSLDeclaration* declaration); void OutputDeclaration(const HLSLType& type, const char* name, const char* semantic = NULL, const char* registerName = NULL, HLSLExpression* defaultValue = NULL); void OutputDeclarationType(const HLSLType& type, bool isTypeCast = false); - void OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic =NULL, const char* registerName = NULL, HLSLExpression * assignment = NULL); + void OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic = NULL, const char* registerName = NULL, HLSLExpression* assignment = NULL); /** Generates a name of the format "base+n" where n is an integer such that the name * isn't used in the syntax tree. */ @@ -69,20 +62,19 @@ class HLSLGenerator const char* GetTypeName(const HLSLType& type); void Error(const char* format, ...) M4_PRINTF_ATTR(2, 3); - + const char* GetFormatName(HLSLBaseType bufferOrTextureType, HLSLBaseType formatType); bool CanSkipWrittenStatement(const HLSLStatement* statement) const; private: - - CodeWriter m_writer; + CodeWriter m_writer; const HLSLTree* m_tree; - const char* m_entryName; - HLSLTarget m_target; - bool m_isInsideBuffer; - bool m_error; - HLSLOptions m_options; + const char* m_entryName; + HLSLTarget m_target; + bool m_isInsideBuffer; + bool m_error; + HLSLOptions m_options; }; -} // M4 +} //namespace M4 diff --git a/hlslparser/src/HLSLParser.cpp b/hlslparser/src/HLSLParser.cpp index b3dd5086..46580c57 100644 --- a/hlslparser/src/HLSLParser.cpp +++ b/hlslparser/src/HLSLParser.cpp @@ -10,7 +10,6 @@ #include "HLSLParser.h" #include "Engine.h" - #include "HLSLTree.h" #ifdef _WIN32 @@ -21,27 +20,24 @@ // stl #include -#include #include +#include -namespace M4 -{ +namespace M4 { -enum CompareFunctionsResult -{ +enum CompareFunctionsResult { FunctionsEqual, Function1Better, Function2Better }; -enum CoreType -{ +enum CoreType { CoreType_None, - + CoreType_Scalar, CoreType_Vector, CoreType_Matrix, - + CoreType_Sampler, CoreType_Texture, CoreType_Struct, @@ -49,12 +45,11 @@ enum CoreType CoreType_Expression, CoreType_Comment, CoreType_Buffer, - + CoreType_Count // must be last }; -enum DimensionType -{ +enum DimensionType { DimensionType_None, DimensionType_Scalar, @@ -66,29 +61,28 @@ enum DimensionType DimensionType_Matrix2x2, DimensionType_Matrix3x3, DimensionType_Matrix4x4, - + //DimensionType_Matrix4x3, // TODO: no 3x4 //DimensionType_Matrix4x2 }; // Can use this to break apart type to useful constructs -struct BaseTypeDescription -{ - const char* typeName = ""; - const char* typeNameMetal = ""; - - HLSLBaseType baseType = HLSLBaseType_Unknown; - CoreType coreType = CoreType_None; - DimensionType dimensionType = DimensionType_None; - NumericType numericType = NumericType_NaN; - +struct BaseTypeDescription { + const char* typeName = ""; + const char* typeNameMetal = ""; + + HLSLBaseType baseType = HLSLBaseType_Unknown; + CoreType coreType = CoreType_None; + DimensionType dimensionType = DimensionType_None; + NumericType numericType = NumericType_NaN; + // TODO: is this useful ? - // int numDimensions; // scalar = 0, vector = 1, matrix = 2 - uint8_t numDimensions = 0; - uint8_t numComponents = 0; - uint8_t height = 0; - - int8_t binaryOpRank = -1; // or was this supposed to be max (-1 in uint8_t) + // int numDimensions; // scalar = 0, vector = 1, matrix = 2 + uint8_t numDimensions = 0; + uint8_t numComponents = 0; + uint8_t height = 0; + + int8_t binaryOpRank = -1; // or was this supposed to be max (-1 in uint8_t) }; // really const @@ -122,18 +116,16 @@ bool IsTextureType(HLSLBaseType baseType) bool IsDepthTextureType(HLSLBaseType baseType) { // return baseTypeDescriptions[baseType].coreType == CoreType_DepthTexture; - return baseType == HLSLBaseType_Depth2D || - baseType == HLSLBaseType_Depth2DArray || - baseType == HLSLBaseType_DepthCube; + return baseType == HLSLBaseType_Depth2D || + baseType == HLSLBaseType_Depth2DArray || + baseType == HLSLBaseType_DepthCube; } - bool IsBufferType(HLSLBaseType baseType) { return baseTypeDescriptions[baseType].coreType == CoreType_Buffer; } - bool IsCoreTypeEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) { return baseTypeDescriptions[lhsType].coreType == @@ -143,9 +135,9 @@ bool IsCoreTypeEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) bool IsDimensionEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) { return baseTypeDescriptions[lhsType].numComponents == - baseTypeDescriptions[rhsType].numComponents && + baseTypeDescriptions[rhsType].numComponents && baseTypeDescriptions[lhsType].height == - baseTypeDescriptions[rhsType].height; + baseTypeDescriptions[rhsType].height; } bool IsCrossDimensionEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) @@ -154,7 +146,6 @@ bool IsCrossDimensionEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) baseTypeDescriptions[rhsType].numComponents; } - bool IsNumericTypeEqual(HLSLBaseType lhsType, HLSLBaseType rhsType) { return baseTypeDescriptions[lhsType].numericType == @@ -191,7 +182,6 @@ bool IsIntegerType(HLSLBaseType type) n == NumericType_Long || n == NumericType_Ulong; } - bool IsInt(HLSLBaseType type) { return baseTypeDescriptions[type].numericType == NumericType_Int; @@ -225,31 +215,27 @@ bool IsBool(HLSLBaseType type) return baseTypeDescriptions[type].numericType == NumericType_Bool; } - - - - -bool IsSamplerType(const HLSLType & type) +bool IsSamplerType(const HLSLType& type) { return IsSamplerType(type.baseType); } -bool IsScalarType(const HLSLType & type) +bool IsScalarType(const HLSLType& type) { return IsScalarType(type.baseType); } -bool IsVectorType(const HLSLType & type) +bool IsVectorType(const HLSLType& type) { return IsVectorType(type.baseType); } -bool IsMatrixType(const HLSLType & type) +bool IsMatrixType(const HLSLType& type) { return IsMatrixType(type.baseType); } -bool IsTextureType(const HLSLType & type) +bool IsTextureType(const HLSLType& type) { return IsTextureType(type.baseType); } @@ -262,55 +248,80 @@ bool IsNumericType(HLSLBaseType baseType) HLSLBufferType ConvertTokenToBufferType(HLSLToken token) { HLSLBufferType type = HLSLBufferType_CBuffer; - - switch(token) - { + + switch (token) { // DX9 case HLSLToken_CBuffer: - type = HLSLBufferType_CBuffer; break; + type = HLSLBufferType_CBuffer; + break; case HLSLToken_TBuffer: - type = HLSLBufferType_TBuffer; break; - + type = HLSLBufferType_TBuffer; + break; + // DX10 case HLSLToken_ConstantBuffer: - type = HLSLBufferType_ConstantBuffer; break; + type = HLSLBufferType_ConstantBuffer; + break; case HLSLToken_StructuredBuffer: - type = HLSLBufferType_StructuredBuffer; break; + type = HLSLBufferType_StructuredBuffer; + break; case HLSLToken_RWStructuredBuffer: - type = HLSLBufferType_RWStructuredBuffer; break; + type = HLSLBufferType_RWStructuredBuffer; + break; case HLSLToken_ByteAddressBuffer: - type = HLSLBufferType_ByteAddressBuffer; break; + type = HLSLBufferType_ByteAddressBuffer; + break; case HLSLToken_RWByteAddressBuffer: - type = HLSLBufferType_RWByteAddressBuffer; break; - + type = HLSLBufferType_RWByteAddressBuffer; + break; + default: break; } - + return type; } HLSLBaseType NumericToBaseType(NumericType numericType) { HLSLBaseType baseType = HLSLBaseType_Unknown; - switch(numericType) - { - case NumericType_Float: baseType = HLSLBaseType_Float; break; - case NumericType_Half: baseType = HLSLBaseType_Half; break; - case NumericType_Double: baseType = HLSLBaseType_Bool; break; - - case NumericType_Int: baseType = HLSLBaseType_Int; break; - case NumericType_Uint: baseType = HLSLBaseType_Uint; break; - case NumericType_Ushort: baseType = HLSLBaseType_Ushort; break; - case NumericType_Short: baseType = HLSLBaseType_Short; break; - case NumericType_Ulong: baseType = HLSLBaseType_Ulong; break; - case NumericType_Long: baseType = HLSLBaseType_Long; break; - case NumericType_Bool: baseType = HLSLBaseType_Bool; break; - - // MSL has 8-bit, but HLSL/Vulkan don't - //case NumericType_Uint8: baseType = HLSLBaseType_Uint8; break; - //case NumericType_Int8: baseType = HLSLBaseType_Int8; break; - + switch (numericType) { + case NumericType_Float: + baseType = HLSLBaseType_Float; + break; + case NumericType_Half: + baseType = HLSLBaseType_Half; + break; + case NumericType_Double: + baseType = HLSLBaseType_Bool; + break; + + case NumericType_Int: + baseType = HLSLBaseType_Int; + break; + case NumericType_Uint: + baseType = HLSLBaseType_Uint; + break; + case NumericType_Ushort: + baseType = HLSLBaseType_Ushort; + break; + case NumericType_Short: + baseType = HLSLBaseType_Short; + break; + case NumericType_Ulong: + baseType = HLSLBaseType_Ulong; + break; + case NumericType_Long: + baseType = HLSLBaseType_Long; + break; + case NumericType_Bool: + baseType = HLSLBaseType_Bool; + break; + + // MSL has 8-bit, but HLSL/Vulkan don't + //case NumericType_Uint8: baseType = HLSLBaseType_Uint8; break; + //case NumericType_Int8: baseType = HLSLBaseType_Int8; break; + default: break; } @@ -327,7 +338,7 @@ int32_t GetVectorDimension(HLSLBaseType type) { if (IsScalarType(type)) return 1; if (!IsVectorType(type)) return 0; - + return baseTypeDescriptions[type].numComponents; } @@ -345,14 +356,13 @@ HLSLBaseType DoubleToFloatBaseType(HLSLBaseType type) return type; } - static HLSLBaseType ArithmeticOpResultType(HLSLBinaryOp binaryOp, HLSLBaseType t1, HLSLBaseType t2); const char* GetNumericTypeName(HLSLBaseType type) { if (!IsNumericType(type)) return nullptr; - + // MSL/HLSL share the same type names const auto& b = baseTypeDescriptions[type]; return b.typeName; @@ -364,47 +374,41 @@ HLSLBaseType PromoteType(HLSLBaseType toType, HLSLBaseType type) baseTypeDescriptions[type].dimensionType - DimensionType_Scalar); } - - /** This structure stores a HLSLFunction-like declaration for an intrinsic function */ -struct Intrinsic -{ +struct Intrinsic { explicit Intrinsic(const char* name, uint32_t numArgs) { - function.name = name; + function.name = name; function.numArguments = numArgs; - + if (numArgs == 0) return; - - for (uint32_t i = 0; i < numArgs; ++i) - { + + for (uint32_t i = 0; i < numArgs; ++i) { argument[i].type.flags = HLSLTypeFlag_Const; } } - + void ChainArgumentPointers() { function.argument = argument + 0; - + uint32_t numArgs = function.numArguments; // This chain pf pointers won't surive copy - for (uint32_t i = 0; i < numArgs; ++i) - { + for (uint32_t i = 0; i < numArgs; ++i) { if (i < numArgs - 1) argument[i].nextArgument = argument + i + 1; } } - + void SetArgumentTypes(HLSLBaseType returnType, HLSLBaseType args[4]) { function.returnType.baseType = returnType; - for (uint32_t i = 0; i < function.numArguments; ++i) - { + for (uint32_t i = 0; i < function.numArguments; ++i) { ASSERT(args[i] != HLSLBaseType_Unknown); argument[i].type.baseType = args[i]; } } - + void ArgsToArray(HLSLBaseType args[4], uint32_t& numArgs, HLSLBaseType arg1, HLSLBaseType arg2, HLSLBaseType arg3, HLSLBaseType arg4) { numArgs = 0; @@ -417,24 +421,24 @@ struct Intrinsic if (arg4 == HLSLBaseType_Unknown) return; args[numArgs++] = arg4; } - + explicit Intrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1 = HLSLBaseType_Unknown, HLSLBaseType arg2 = HLSLBaseType_Unknown, HLSLBaseType arg3 = HLSLBaseType_Unknown, HLSLBaseType arg4 = HLSLBaseType_Unknown) { - function.name = name; - + function.name = name; + HLSLBaseType argumentTypes[4]; uint32_t numArgs = 0; ArgsToArray(argumentTypes, numArgs, arg1, arg2, arg3, arg4); - + *this = Intrinsic(name, numArgs); SetArgumentTypes(returnType, argumentTypes); } - + // TODO: allow member function intrinsices on buffers/textures - HLSLFunction function; - HLSLArgument argument[4]; + HLSLFunction function; + HLSLArgument argument[4]; }; - + // So many calls are member functions in modern HLSL/MSL. // This means the parser has to work harder to write out these intrinsics // since some have default args, and some need level(), bias() wrappers in MSL. @@ -449,12 +453,12 @@ void AddTextureLoadIntrinsic(const char* name, HLSLBaseType returnType, HLSLBase Intrinsic i(name, returnType, uvType, arg3, arg4); i.function.memberType = textureType; // extract formatType from return type #else -// Intrinsic i(name, returnType, textureType, uvType); +// Intrinsic i(name, returnType, textureType, uvType); // -// // classify textureType subtype off scalar -// i.argument[0].type.formatType = GetScalarType(returnType); +// // classify textureType subtype off scalar +// i.argument[0].type.formatType = GetScalarType(returnType); #endif - + AddIntrinsic(i); } @@ -464,37 +468,36 @@ void AddTextureIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType Intrinsic i(name, returnType, HLSLBaseType_SamplerState, uvType, arg3, arg4); i.function.memberType = textureType; #else -// Intrinsic i(name, returnType, textureType, HLSLBaseType_SamplerState, uvType); +// Intrinsic i(name, returnType, textureType, HLSLBaseType_SamplerState, uvType); // -// // classify textureType subtype off scalar -// i.argument[0].type.formatType = GetScalarType(returnType); +// // classify textureType subtype off scalar +// i.argument[0].type.formatType = GetScalarType(returnType); #endif - + AddIntrinsic(i); } void AddTextureIntrinsics(const char* name, HLSLBaseType textureType, HLSLBaseType uvType, HLSLBaseType arg3 = HLSLBaseType_Unknown, HLSLBaseType arg4 = HLSLBaseType_Unknown) { - AddTextureIntrinsic( name, HLSLBaseType_Float4, textureType, uvType, arg3, arg4); - AddTextureIntrinsic( name, HLSLBaseType_Half4, textureType, uvType, arg3, arg4); + AddTextureIntrinsic(name, HLSLBaseType_Float4, textureType, uvType, arg3, arg4); + AddTextureIntrinsic(name, HLSLBaseType_Half4, textureType, uvType, arg3, arg4); } - // DepthCmp takes additional arg for comparison value, but this rolls it into uv void AddDepthIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType textureType, HLSLBaseType uvType, HLSLBaseType arg3 = HLSLBaseType_Unknown, HLSLBaseType arg4 = HLSLBaseType_Unknown) { // ComparisonState is only for SampleCmp/GatherCmp bool isCompare = String_Equal(name, "GatherCmp") || String_Equal(name, "SampleCmp"); HLSLBaseType samplerType = isCompare ? HLSLBaseType_SamplerComparisonState : HLSLBaseType_SamplerState; - + #if USE_MEMBER_FUNCTIONS Intrinsic i(name, returnType, samplerType, uvType, arg3, arg4); i.function.memberType = textureType; #else -// Intrinsic i(name, returnType, textureType, samplerType, uvType); -// i.argument[0].type.formatType = GetScalarType(returnType); +// Intrinsic i(name, returnType, textureType, samplerType, uvType); +// i.argument[0].type.formatType = GetScalarType(returnType); #endif - + AddIntrinsic(i); } @@ -503,23 +506,22 @@ void AddDepthIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType t // AddTextureIntrinsic( name, HLSLBaseType_Float4, textureType, uvType) \ // AddTextureIntrinsic( name, HLSLBaseType_Half4, textureType, uvType ) +static const int _numberTypeRank[NumericType_Count][NumericType_Count] = + { + // across is what type list on right is converted into (5 means don't, 0 means best) + //F H D B I UI S US L UL + {0, 3, 3, 4, 4, 4, 4, 4, 4, 4}, // NumericType_Float + {2, 0, 4, 4, 4, 4, 4, 4, 4, 4}, // NumericType_Half + {1, 4, 0, 4, 4, 4, 4, 4, 4, 4}, // NumericType_Double -static const int _numberTypeRank[NumericType_Count][NumericType_Count] = -{ - // across is what type list on right is converted into (5 means don't, 0 means best) - //F H D B I UI S US L UL - { 0, 3, 3, 4, 4, 4, 4, 4, 4, 4 }, // NumericType_Float - { 2, 0, 4, 4, 4, 4, 4, 4, 4, 4 }, // NumericType_Half - { 1, 4, 0, 4, 4, 4, 4, 4, 4, 4 }, // NumericType_Double - - { 5, 5, 5, 0, 5, 5, 5, 5, 5, 5 }, // NumericType_Bool - { 5, 5, 5, 4, 0, 3, 4, 3, 5, 5 }, // NumericType_Int - { 5, 5, 5, 4, 2, 0, 3, 4, 5, 5 }, // NumericType_Uint - { 5, 5, 5, 4, 0, 3, 0, 5, 5, 5 }, // NumericType_Short - { 5, 5, 5, 4, 2, 0, 5, 0, 5, 5 }, // NumericType_Ushort - - { 5, 5, 5, 4, 0, 3, 5, 5, 0, 5 }, // NumericType_Long - { 5, 5, 5, 4, 2, 0, 5, 5, 5, 0 }, // NumericType_Ulong + {5, 5, 5, 0, 5, 5, 5, 5, 5, 5}, // NumericType_Bool + {5, 5, 5, 4, 0, 3, 4, 3, 5, 5}, // NumericType_Int + {5, 5, 5, 4, 2, 0, 3, 4, 5, 5}, // NumericType_Uint + {5, 5, 5, 4, 0, 3, 0, 5, 5, 5}, // NumericType_Short + {5, 5, 5, 4, 2, 0, 5, 0, 5, 5}, // NumericType_Ushort + + {5, 5, 5, 4, 0, 3, 5, 5, 0, 5}, // NumericType_Long + {5, 5, 5, 4, 2, 0, 5, 5, 5, 0}, // NumericType_Ulong }; /* All FX state @@ -774,34 +776,32 @@ static const EffectState pipelineStates[] = { // Note: these strings need to live until end of the app StringPool gStringPool(NULL); -enum All -{ - AllHalf = (1<<0), - AllFloat = (1<<1), - AllDouble = (1<<2), - +enum All { + AllHalf = (1 << 0), + AllFloat = (1 << 1), + AllDouble = (1 << 2), + AllFloats = AllHalf | AllFloat | AllDouble, - - AllUint = (1<<3), - AllInt = (1<<4), - AllShort = (1<<5), - AllUshort = (1<<6), - AllLong = (1<<7), - AllUlong = (1<<8), - AllBool = (1<<9), - + + AllUint = (1 << 3), + AllInt = (1 << 4), + AllShort = (1 << 5), + AllUshort = (1 << 6), + AllLong = (1 << 7), + AllUlong = (1 << 8), + AllBool = (1 << 9), + AllInts = AllUint | AllInt | AllShort | AllUshort | AllLong | AllUlong | AllBool, - + //AllScalar = (1<<15), - AllVecs = (1<<16), - AllMats = (1<<17), + AllVecs = (1 << 16), + AllMats = (1 << 17), AllDims = AllVecs | AllMats, }; using AllMask = uint32_t; // TODO: want to use Array, but it needs Allocator passed -struct Range -{ +struct Range { uint32_t start; uint32_t count; }; @@ -815,30 +815,28 @@ static IntrinsicRangeMap _intrinsicRangeMap; static void AddIntrinsic(const Intrinsic& intrinsic) { const char* name = intrinsic.function.name; - + // Put in string pool since using this as a key. Also means equals just ptr compar. - name = gStringPool.AddString(name); - + name = gStringPool.AddString(name); + // track intrinsic range in a map, also the name lookup helps speed the parser up auto it = _intrinsicRangeMap.find(name); - if (it != _intrinsicRangeMap.end()) - { + if (it != _intrinsicRangeMap.end()) { it->second.count++; } - else - { - _intrinsicRangeMap[name] = { (uint32_t)_intrinsics.size(), 1 }; + else { + _intrinsicRangeMap[name] = {(uint32_t)_intrinsics.size(), 1}; } - + // To avoid having growth destroy the argument chains const uint32_t kMaxIntrinsics = 10000; // TODO: reduce once count is known if (_intrinsics.empty()) _intrinsics.reserve(kMaxIntrinsics); ASSERT(_intrinsics.size() < kMaxIntrinsics); - + _intrinsics.push_back(intrinsic); _intrinsics.back().function.name = name; - + // These pointers change when copied or when vector grows, so do a reserve _intrinsics.back().ChainArgumentPointers(); } @@ -852,16 +850,15 @@ void AddIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1 = void RegisterBaseTypeIntrinsic(Intrinsic& intrinsic, uint32_t numArgs, HLSLBaseType returnType, HLSLBaseType baseType, uint32_t start, uint32_t end) { HLSLBaseType args[4] = {}; - - for (uint32_t i = start; i < end; ++i) - { + + for (uint32_t i = start; i < end; ++i) { HLSLBaseType baseTypeIter = (HLSLBaseType)(baseType + i); - + HLSLBaseType newReturnType = (returnType == HLSLBaseType_Unknown) ? baseTypeIter : returnType; - + for (uint32_t a = 0; a < numArgs; ++a) args[a] = baseTypeIter; - + intrinsic.SetArgumentTypes(newReturnType, args); AddIntrinsic(intrinsic); } @@ -878,8 +875,8 @@ void RegisterIntrinsics(const char* name, uint32_t numArgs, AllMask mask, HLSLBa { const uint32_t kNumTypes = 3; - HLSLBaseType baseTypes[kNumTypes] = { HLSLBaseType_Float, HLSLBaseType_Half, HLSLBaseType_Double }; - + HLSLBaseType baseTypes[kNumTypes] = {HLSLBaseType_Float, HLSLBaseType_Half, HLSLBaseType_Double}; + bool skip[kNumTypes] = {}; if (!TestBits(mask, AllFloat)) skip[0] = true; @@ -887,12 +884,11 @@ void RegisterIntrinsics(const char* name, uint32_t numArgs, AllMask mask, HLSLBa skip[1] = true; if (!TestBits(mask, AllDouble)) skip[2] = true; - - for (uint32_t i = 0; i < kNumTypes; ++i) - { + + for (uint32_t i = 0; i < kNumTypes; ++i) { if (skip[i]) continue; HLSLBaseType baseType = baseTypes[i]; - + if (mask & AllVecs) RegisterBaseTypeIntrinsic(intrinsic, numArgs, returnType, baseType, 0, 4); if (mask & AllMats) @@ -900,16 +896,14 @@ void RegisterIntrinsics(const char* name, uint32_t numArgs, AllMask mask, HLSLBa } } - if ((mask & AllInts) == AllInts) - { + if ((mask & AllInts) == AllInts) { const uint32_t kNumTypes = 7; HLSLBaseType baseTypes[kNumTypes] = { HLSLBaseType_Long, HLSLBaseType_Ulong, - HLSLBaseType_Int, HLSLBaseType_Uint, + HLSLBaseType_Int, HLSLBaseType_Uint, HLSLBaseType_Short, HLSLBaseType_Ushort, - HLSLBaseType_Bool - }; - + HLSLBaseType_Bool}; + bool skip[kNumTypes] = {}; if (!TestBits(mask, AllLong)) skip[0] = true; @@ -925,15 +919,14 @@ void RegisterIntrinsics(const char* name, uint32_t numArgs, AllMask mask, HLSLBa skip[5] = true; if (!TestBits(mask, AllBool)) skip[6] = true; - - for (uint32_t i = 0; i < kNumTypes; ++i) - { + + for (uint32_t i = 0; i < kNumTypes; ++i) { if (skip[i]) continue; HLSLBaseType baseType = baseTypes[i]; - + if (mask & AllVecs) RegisterBaseTypeIntrinsic(intrinsic, numArgs, returnType, baseType, 0, 4); - + // TODO: No int matrices yet, but could add them //if (mask & AllMats) // RegisterBaseTypeIntrinsic(intrinsic, numArgs, returnType, 4, 7); @@ -941,7 +934,7 @@ void RegisterIntrinsics(const char* name, uint32_t numArgs, AllMask mask, HLSLBa } } -#define ArrayCount(array) (sizeof(array) / sizeof(array[0]) ) +#define ArrayCount(array) (sizeof(array) / sizeof(array[0])) bool InitIntrinsics() { @@ -949,7 +942,7 @@ bool InitIntrinsics() // since an unordered map is used for lookup. But do need // all intrinsics of the same name to be defined together in // a single range. - + const char* kVecOps1[] = { "acos", "asin", "atan", "cos", "sin", "tan", @@ -962,33 +955,38 @@ bool InitIntrinsics() "isnan", "isinf", "isfinite", "degrees", "radians" // emulated in MSL }; - + // apply to float/int const char* kVecOps1All[] = { "abs", }; - + const char* kVecOps2[] = { - "atan2", "pow", // can't pow take scalar? - "step", "frexp", + "atan2", + "pow", // can't pow take scalar? + "step", + "frexp", }; - + // apply to float/int const char* kVecOps2All[] = { - "min", "max", + "min", + "max", }; - + const char* kVecOps3[] = { "lerp", // can clamp and lerp take a scalar for last args/arg? - "smoothstep", "fma", + "smoothstep", + "fma", }; // apply to float/int const char* kVecOps3All[] = { "clamp", - "min3", "max3", + "min3", + "max3", }; - + // HLSL intrinsics // // not going to support due to swizzle, just have similar routine for half @@ -1012,156 +1010,147 @@ bool InitIntrinsics() // absdiff, hadd(x,y), // is_null_texture(tex) // tex.fence() - - - AllMask mask = AllFloats | AllVecs; - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps1); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps1[i], 1, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps1); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps1[i], 1, mask); } - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps2); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps2[i], 2, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps2); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps2[i], 2, mask); } - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps3); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps3[i], 3, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps3); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps3[i], 3, mask); } - + mask = AllFloats | AllInts | AllVecs; - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps1All); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps1All[i], 1, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps1All); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps1All[i], 1, mask); } - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps2All); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps2All[i], 2, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps2All); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps2All[i], 2, mask); } - for (uint32_t i = 0, iEnd = ArrayCount(kVecOps3All); i < iEnd; ++i) - { - RegisterIntrinsics( kVecOps3All[i], 3, mask ); + for (uint32_t i = 0, iEnd = ArrayCount(kVecOps3All); i < iEnd; ++i) { + RegisterIntrinsics(kVecOps3All[i], 3, mask); } - + // bit counting - RegisterIntrinsics( "countbits", 1, AllInts | AllVecs); // popcount in MSL - RegisterIntrinsics( "firstbithigh", 1, AllInts | AllVecs); // clz in MSL - RegisterIntrinsics( "firstbitlow", 1, AllInts | AllVecs); // ctz in MSL - RegisterIntrinsics( "reversebits", 1, AllInts | AllVecs); // ctz in MSL - - RegisterIntrinsics( "sincos", 2, AllFloats | AllVecs, HLSLBaseType_Void); + RegisterIntrinsics("countbits", 1, AllInts | AllVecs); // popcount in MSL + RegisterIntrinsics("firstbithigh", 1, AllInts | AllVecs); // clz in MSL + RegisterIntrinsics("firstbitlow", 1, AllInts | AllVecs); // ctz in MSL + RegisterIntrinsics("reversebits", 1, AllInts | AllVecs); // ctz in MSL + + RegisterIntrinsics("sincos", 2, AllFloats | AllVecs, HLSLBaseType_Void); + + RegisterIntrinsics("mad", 3, AllFloats | AllVecs); + + RegisterIntrinsics("any", 1, AllFloats | AllInts | AllVecs, HLSLBaseType_Bool); + RegisterIntrinsics("all", 1, AllFloats | AllInts | AllVecs, HLSLBaseType_Bool); + + RegisterIntrinsics("clip", 1, AllFloats | AllVecs, HLSLBaseType_Void); + + RegisterIntrinsics("dot", 2, AllHalf | AllVecs, HLSLBaseType_Half); + RegisterIntrinsics("dot", 2, AllFloat | AllVecs, HLSLBaseType_Float); + RegisterIntrinsics("dot", 2, AllDouble | AllVecs, HLSLBaseType_Double); - RegisterIntrinsics( "mad", 3, AllFloats | AllVecs); - - RegisterIntrinsics( "any", 1, AllFloats | AllInts | AllVecs, HLSLBaseType_Bool); - RegisterIntrinsics( "all", 1, AllFloats | AllInts | AllVecs, HLSLBaseType_Bool); - - RegisterIntrinsics( "clip", 1, AllFloats | AllVecs, HLSLBaseType_Void); - - RegisterIntrinsics( "dot", 2, AllHalf | AllVecs, HLSLBaseType_Half); - RegisterIntrinsics( "dot", 2, AllFloat | AllVecs, HLSLBaseType_Float); - RegisterIntrinsics( "dot", 2, AllDouble | AllVecs, HLSLBaseType_Double); - // 3d cross product only - AddIntrinsic( "cross", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ); - AddIntrinsic( "cross", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3 ); - AddIntrinsic( "cross", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3 ); - - AddIntrinsic( "reflect", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ); - AddIntrinsic( "reflect", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3 ); - AddIntrinsic( "reflect", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3 ); - - AddIntrinsic( "refract", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float ); - AddIntrinsic( "refract", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half ); - AddIntrinsic( "refract", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double ); - - RegisterIntrinsics( "length", 1, AllHalf | AllVecs, HLSLBaseType_Half); - RegisterIntrinsics( "length", 1, AllFloat | AllVecs, HLSLBaseType_Float); - RegisterIntrinsics( "length", 1, AllDouble | AllVecs, HLSLBaseType_Double); - + AddIntrinsic("cross", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3); + AddIntrinsic("cross", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3); + AddIntrinsic("cross", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3); + + AddIntrinsic("reflect", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3); + AddIntrinsic("reflect", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3); + AddIntrinsic("reflect", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3); + + AddIntrinsic("refract", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float); + AddIntrinsic("refract", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half); + AddIntrinsic("refract", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double); + + RegisterIntrinsics("length", 1, AllHalf | AllVecs, HLSLBaseType_Half); + RegisterIntrinsics("length", 1, AllFloat | AllVecs, HLSLBaseType_Float); + RegisterIntrinsics("length", 1, AllDouble | AllVecs, HLSLBaseType_Double); + // MSL construct - RegisterIntrinsics( "length_squared", 1, AllHalf | AllVecs, HLSLBaseType_Half); - RegisterIntrinsics( "length_squared", 1, AllFloat | AllVecs, HLSLBaseType_Float); - RegisterIntrinsics( "length_squared", 1, AllDouble | AllVecs, HLSLBaseType_Double); + RegisterIntrinsics("length_squared", 1, AllHalf | AllVecs, HLSLBaseType_Half); + RegisterIntrinsics("length_squared", 1, AllFloat | AllVecs, HLSLBaseType_Float); + RegisterIntrinsics("length_squared", 1, AllDouble | AllVecs, HLSLBaseType_Double); - RegisterIntrinsics( "distance", 1, AllHalf | AllVecs, HLSLBaseType_Half); - RegisterIntrinsics( "distance", 1, AllFloat | AllVecs, HLSLBaseType_Float); - RegisterIntrinsics( "distance", 1, AllDouble | AllVecs, HLSLBaseType_Double); + RegisterIntrinsics("distance", 1, AllHalf | AllVecs, HLSLBaseType_Half); + RegisterIntrinsics("distance", 1, AllFloat | AllVecs, HLSLBaseType_Float); + RegisterIntrinsics("distance", 1, AllDouble | AllVecs, HLSLBaseType_Double); - RegisterIntrinsics( "distance_squared", 1, AllHalf | AllVecs, HLSLBaseType_Half); - RegisterIntrinsics( "distance_squared", 1, AllFloat | AllVecs, HLSLBaseType_Float); - RegisterIntrinsics( "distance_squared", 1, AllDouble | AllVecs, HLSLBaseType_Double); + RegisterIntrinsics("distance_squared", 1, AllHalf | AllVecs, HLSLBaseType_Half); + RegisterIntrinsics("distance_squared", 1, AllFloat | AllVecs, HLSLBaseType_Float); + RegisterIntrinsics("distance_squared", 1, AllDouble | AllVecs, HLSLBaseType_Double); // ps only - AddIntrinsic( "fwidth", HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float2 ); - + AddIntrinsic("fwidth", HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float2); + // scalar/vec ops - RegisterIntrinsics( "mul", 2, AllFloat | AllVecs | AllMats ); - + RegisterIntrinsics("mul", 2, AllFloat | AllVecs | AllMats); + // scalar mul, since * isn't working on Metal properly // m = s * m - AddIntrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float, HLSLBaseType_Float2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float, HLSLBaseType_Float3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float, HLSLBaseType_Float4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2, HLSLBaseType_Float ); - AddIntrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3, HLSLBaseType_Float ); - AddIntrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4, HLSLBaseType_Float ); - + AddIntrinsic("mul", HLSLBaseType_Float2x2, HLSLBaseType_Float, HLSLBaseType_Float2x2); + AddIntrinsic("mul", HLSLBaseType_Float3x3, HLSLBaseType_Float, HLSLBaseType_Float3x3); + AddIntrinsic("mul", HLSLBaseType_Float4x4, HLSLBaseType_Float, HLSLBaseType_Float4x4); + AddIntrinsic("mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2, HLSLBaseType_Float); + AddIntrinsic("mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3, HLSLBaseType_Float); + AddIntrinsic("mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4, HLSLBaseType_Float); + // v = v * m - AddIntrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2x2, HLSLBaseType_Float2 ); - AddIntrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3x3, HLSLBaseType_Float3 ); - AddIntrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4x4, HLSLBaseType_Float4 ); - + AddIntrinsic("mul", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2x2); + AddIntrinsic("mul", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3x3); + AddIntrinsic("mul", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4x4); + AddIntrinsic("mul", HLSLBaseType_Float2, HLSLBaseType_Float2x2, HLSLBaseType_Float2); + AddIntrinsic("mul", HLSLBaseType_Float3, HLSLBaseType_Float3x3, HLSLBaseType_Float3); + AddIntrinsic("mul", HLSLBaseType_Float4, HLSLBaseType_Float4x4, HLSLBaseType_Float4); + // m = s * m - AddIntrinsic( "mul", HLSLBaseType_Half2x2, HLSLBaseType_Half, HLSLBaseType_Half2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Half3x3, HLSLBaseType_Half, HLSLBaseType_Half3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Half4x4, HLSLBaseType_Half, HLSLBaseType_Half4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Half2x2, HLSLBaseType_Half2x2, HLSLBaseType_Half ); - AddIntrinsic( "mul", HLSLBaseType_Half3x3, HLSLBaseType_Half3x3, HLSLBaseType_Half ); - AddIntrinsic( "mul", HLSLBaseType_Half4x4, HLSLBaseType_Half4x4, HLSLBaseType_Half ); - + AddIntrinsic("mul", HLSLBaseType_Half2x2, HLSLBaseType_Half, HLSLBaseType_Half2x2); + AddIntrinsic("mul", HLSLBaseType_Half3x3, HLSLBaseType_Half, HLSLBaseType_Half3x3); + AddIntrinsic("mul", HLSLBaseType_Half4x4, HLSLBaseType_Half, HLSLBaseType_Half4x4); + AddIntrinsic("mul", HLSLBaseType_Half2x2, HLSLBaseType_Half2x2, HLSLBaseType_Half); + AddIntrinsic("mul", HLSLBaseType_Half3x3, HLSLBaseType_Half3x3, HLSLBaseType_Half); + AddIntrinsic("mul", HLSLBaseType_Half4x4, HLSLBaseType_Half4x4, HLSLBaseType_Half); + // v = v * m - AddIntrinsic( "mul", HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Half4, HLSLBaseType_Half4, HLSLBaseType_Half4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Half2, HLSLBaseType_Half2x2, HLSLBaseType_Half2 ); - AddIntrinsic( "mul", HLSLBaseType_Half3, HLSLBaseType_Half3x3, HLSLBaseType_Half3 ); - AddIntrinsic( "mul", HLSLBaseType_Half4, HLSLBaseType_Half4x4, HLSLBaseType_Half4 ); - + AddIntrinsic("mul", HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2x2); + AddIntrinsic("mul", HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3x3); + AddIntrinsic("mul", HLSLBaseType_Half4, HLSLBaseType_Half4, HLSLBaseType_Half4x4); + AddIntrinsic("mul", HLSLBaseType_Half2, HLSLBaseType_Half2x2, HLSLBaseType_Half2); + AddIntrinsic("mul", HLSLBaseType_Half3, HLSLBaseType_Half3x3, HLSLBaseType_Half3); + AddIntrinsic("mul", HLSLBaseType_Half4, HLSLBaseType_Half4x4, HLSLBaseType_Half4); + // m = s * m - AddIntrinsic( "mul", HLSLBaseType_Double2x2, HLSLBaseType_Double, HLSLBaseType_Double2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Double3x3, HLSLBaseType_Double, HLSLBaseType_Double3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Double4x4, HLSLBaseType_Double, HLSLBaseType_Double4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Double2x2, HLSLBaseType_Double2x2, HLSLBaseType_Double ); - AddIntrinsic( "mul", HLSLBaseType_Double3x3, HLSLBaseType_Double3x3, HLSLBaseType_Double ); - AddIntrinsic( "mul", HLSLBaseType_Double4x4, HLSLBaseType_Double4x4, HLSLBaseType_Double ); - + AddIntrinsic("mul", HLSLBaseType_Double2x2, HLSLBaseType_Double, HLSLBaseType_Double2x2); + AddIntrinsic("mul", HLSLBaseType_Double3x3, HLSLBaseType_Double, HLSLBaseType_Double3x3); + AddIntrinsic("mul", HLSLBaseType_Double4x4, HLSLBaseType_Double, HLSLBaseType_Double4x4); + AddIntrinsic("mul", HLSLBaseType_Double2x2, HLSLBaseType_Double2x2, HLSLBaseType_Double); + AddIntrinsic("mul", HLSLBaseType_Double3x3, HLSLBaseType_Double3x3, HLSLBaseType_Double); + AddIntrinsic("mul", HLSLBaseType_Double4x4, HLSLBaseType_Double4x4, HLSLBaseType_Double); + // v = v * m - AddIntrinsic( "mul", HLSLBaseType_Double2, HLSLBaseType_Double2, HLSLBaseType_Double2x2 ); - AddIntrinsic( "mul", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3x3 ); - AddIntrinsic( "mul", HLSLBaseType_Double4, HLSLBaseType_Double4, HLSLBaseType_Double4x4 ); - AddIntrinsic( "mul", HLSLBaseType_Double2, HLSLBaseType_Double2x2, HLSLBaseType_Double2 ); - AddIntrinsic( "mul", HLSLBaseType_Double3, HLSLBaseType_Double3x3, HLSLBaseType_Double3 ); - AddIntrinsic( "mul", HLSLBaseType_Double4, HLSLBaseType_Double4x4, HLSLBaseType_Double4 ); - + AddIntrinsic("mul", HLSLBaseType_Double2, HLSLBaseType_Double2, HLSLBaseType_Double2x2); + AddIntrinsic("mul", HLSLBaseType_Double3, HLSLBaseType_Double3, HLSLBaseType_Double3x3); + AddIntrinsic("mul", HLSLBaseType_Double4, HLSLBaseType_Double4, HLSLBaseType_Double4x4); + AddIntrinsic("mul", HLSLBaseType_Double2, HLSLBaseType_Double2x2, HLSLBaseType_Double2); + AddIntrinsic("mul", HLSLBaseType_Double3, HLSLBaseType_Double3x3, HLSLBaseType_Double3); + AddIntrinsic("mul", HLSLBaseType_Double4, HLSLBaseType_Double4x4, HLSLBaseType_Double4); + // matrix transpose RegisterIntrinsics("transpose", 1, AllFloats | AllMats); - + // determinant needs to return scalar for all 9 mat types - AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float2x2); - AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float3x3); - AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float4x4); - AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half2x2); - AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half3x3); - AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half4x4); + AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float2x2); + AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float3x3); + AddIntrinsic("determinant", HLSLBaseType_Float, HLSLBaseType_Float4x4); + AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half2x2); + AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half3x3); + AddIntrinsic("determinant", HLSLBaseType_Half, HLSLBaseType_Half4x4); AddIntrinsic("determinant", HLSLBaseType_Double, HLSLBaseType_Double2x2); AddIntrinsic("determinant", HLSLBaseType_Double, HLSLBaseType_Double3x3); AddIntrinsic("determinant", HLSLBaseType_Double, HLSLBaseType_Double4x4); - + #if 0 // TODO: more conversions fp16, double, etc. // MSL can just do simple casts. These are more for getting data in/out @@ -1186,7 +1175,7 @@ bool InitIntrinsics() AddIntrinsic("asuint", HLSLBaseType_Ulong, HLSLBaseType_Uint, HLSLBaseType_Uint); AddIntrinsic("asuint", HLSLBaseType_Uint, HLSLBaseType_Float); #endif - + #if 0 // TODO: get atomics working // these work on atomic_int/uint, then bool/ulong 2.4, @@ -1247,77 +1236,74 @@ bool InitIntrinsics() #endif - // TODO: split off sampler intrinsics from math above // these need to be member functions and have default arg value support - + //------------------------ - + // TODO: need optional offset - + // Cannot use Sample with 2DMS/Array AddTextureIntrinsics("Sample", HLSLBaseType_Texture2D, HLSLBaseType_Float2); // Int2 offset AddTextureIntrinsics("Sample", HLSLBaseType_Texture3D, HLSLBaseType_Float3); // Int3 offset AddTextureIntrinsics("Sample", HLSLBaseType_Texture2DArray, HLSLBaseType_Float3); // Int2 offset - + // these don't have offset AddTextureIntrinsics("Sample", HLSLBaseType_TextureCube, HLSLBaseType_Float3); AddTextureIntrinsics("Sample", HLSLBaseType_TextureCubeArray, HLSLBaseType_Float4); - + // Depth AddDepthIntrinsic("Sample", HLSLBaseType_Float, HLSLBaseType_Depth2D, HLSLBaseType_Float2); // Int2 offset - AddDepthIntrinsic("Sample", HLSLBaseType_Float, HLSLBaseType_Depth2DArray, HLSLBaseType_Float3); // Int2 offset - AddDepthIntrinsic("Sample", HLSLBaseType_Float, HLSLBaseType_DepthCube, HLSLBaseType_Float3); // no offset - + AddDepthIntrinsic("Sample", HLSLBaseType_Float, HLSLBaseType_Depth2DArray, HLSLBaseType_Float3); // Int2 offset + AddDepthIntrinsic("Sample", HLSLBaseType_Float, HLSLBaseType_DepthCube, HLSLBaseType_Float3); // no offset + AddDepthIntrinsic("SampleCmp", HLSLBaseType_Float, HLSLBaseType_Depth2D, HLSLBaseType_Float2, HLSLBaseType_Float); AddDepthIntrinsic("SampleCmp", HLSLBaseType_Float, HLSLBaseType_Depth2DArray, HLSLBaseType_Float3, HLSLBaseType_Float); AddDepthIntrinsic("SampleCmp", HLSLBaseType_Float, HLSLBaseType_DepthCube, HLSLBaseType_Float3, HLSLBaseType_Float); - + // returns float4 w/comparisons, probably only on mip0 // TODO: add GatherRed? to read 4 depth values AddDepthIntrinsic("GatherCmp", HLSLBaseType_Float4, HLSLBaseType_Depth2D, HLSLBaseType_Float2, HLSLBaseType_Float); AddDepthIntrinsic("GatherCmp", HLSLBaseType_Float4, HLSLBaseType_Depth2DArray, HLSLBaseType_Float3, HLSLBaseType_Float); AddDepthIntrinsic("GatherCmp", HLSLBaseType_Float4, HLSLBaseType_DepthCube, HLSLBaseType_Float3, HLSLBaseType_Float); - + // one more dimension than Sample AddTextureIntrinsics("SampleLevel", HLSLBaseType_Texture2D, HLSLBaseType_Float2, HLSLBaseType_Float); AddTextureIntrinsics("SampleLevel", HLSLBaseType_Texture3D, HLSLBaseType_Float3, HLSLBaseType_Float); AddTextureIntrinsics("SampleLevel", HLSLBaseType_Texture2DArray, HLSLBaseType_Float3, HLSLBaseType_Float); AddTextureIntrinsics("SampleLevel", HLSLBaseType_TextureCube, HLSLBaseType_Float3, HLSLBaseType_Float); // TEXTURE_INTRINSIC_FUNCTION("SampleLevel", HLSLBaseType_TextureCubeArray, HLSLBaseType_Float4, Float); - + // bias always in w AddTextureIntrinsics("SampleBias", HLSLBaseType_Texture2D, HLSLBaseType_Float2, HLSLBaseType_Float); AddTextureIntrinsics("SampleBias", HLSLBaseType_Texture3D, HLSLBaseType_Float3, HLSLBaseType_Float); AddTextureIntrinsics("SampleBias", HLSLBaseType_Texture2DArray, HLSLBaseType_Float3, HLSLBaseType_Float); - - + // no offset on cube/cubearray AddTextureIntrinsics("SampleBias", HLSLBaseType_TextureCube, HLSLBaseType_Float3, HLSLBaseType_Float); // AddTextureIntrinsics("SampleBias", HLSLBaseType_TextureCubeArray, HLSLBaseType_Float4, Float); - // TODO: for 2D tex (int2 offset is optional, how to indicate that?) // arguments have defaultValue that can be set. - - AddTextureIntrinsics("GatherRed", HLSLBaseType_Texture2D, HLSLBaseType_Float2); - AddTextureIntrinsics("GatherGreen", HLSLBaseType_Texture2D, HLSLBaseType_Float2); - AddTextureIntrinsics("GatherBlue", HLSLBaseType_Texture2D, HLSLBaseType_Float2); - AddTextureIntrinsics("GatherAlpha", HLSLBaseType_Texture2D, HLSLBaseType_Float2); - + + AddTextureIntrinsics("GatherRed", HLSLBaseType_Texture2D, HLSLBaseType_Float2); + AddTextureIntrinsics("GatherGreen", HLSLBaseType_Texture2D, HLSLBaseType_Float2); + AddTextureIntrinsics("GatherBlue", HLSLBaseType_Texture2D, HLSLBaseType_Float2); + AddTextureIntrinsics("GatherAlpha", HLSLBaseType_Texture2D, HLSLBaseType_Float2); + // TODO: add more types cube/3d takes gradient3d in MSL // The Intrinsic ctor would need to have 5 args instead 4 // first move to member functions, then add this with 4 args // AddTextureIntrinsics( "SampleGrad", HLSLBaseType_Texture2D, HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2); - + // These constructs are not declaring the lod or offset param which have default AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_Texture2D, HLSLBaseType_Int2); // TODO: needs lod AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_Texture3D, HLSLBaseType_Int3); // TODO: need lod AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_Texture2DArray, HLSLBaseType_Int2); // TODO: needs array, lod - // AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_TextureCube, HLSLBaseType_Int2); // TODO: needs face, lod - // AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_TextureCubeArray, HLSLBaseType_Int2); // TODO: needs face, lod, array + // AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_TextureCube, HLSLBaseType_Int2); // TODO: needs face, lod + // AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_TextureCubeArray, HLSLBaseType_Int2); // TODO: needs face, lod, array AddTextureLoadIntrinsic("Load", HLSLBaseType_Float4, HLSLBaseType_Texture2DMS, HLSLBaseType_Int2); // TODO: needs sampleIndex - + // TODO: aren't these uint instead of int? AddTextureIntrinsics("GetDimensions", HLSLBaseType_Texture2D, HLSLBaseType_Int2); AddTextureIntrinsics("GetDimensions", HLSLBaseType_Texture3D, HLSLBaseType_Int3); @@ -1325,90 +1311,87 @@ bool InitIntrinsics() AddTextureIntrinsics("GetDimensions", HLSLBaseType_TextureCube, HLSLBaseType_Int3); AddTextureIntrinsics("GetDimensions", HLSLBaseType_TextureCubeArray, HLSLBaseType_Int3); AddTextureIntrinsics("GetDimensions", HLSLBaseType_Texture2DMS, HLSLBaseType_Int2); - + return true; }; - // The order in this array must match up with HLSLBinaryOp const int _binaryOpPriority[] = { - 2, 1, // &&, || - 8, 8, // +, - - 9, 9, // *, / - 7, 7, // <, >, - 7, 7, // <=, >=, - 6, 6, // ==, != + 2, 1, // &&, || + 8, 8, // +, - + 9, 9, // *, / + 7, 7, // <, >, + 7, 7, // <=, >=, + 6, 6, // ==, != 5, 3, 4, // &, |, ^ - }; - - +}; BaseTypeDescription baseTypeDescriptions[HLSLBaseType_Count]; -void RegisterMatrix(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName, uint32_t dim1, uint32_t dim2) +void RegisterMatrix(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName, uint32_t dim1, uint32_t dim2) { char buf[32]; snprintf(buf, sizeof(buf), "%s%dx%d", typeName, dim1, dim2); const char* name = gStringPool.AddString(buf); - + HLSLBaseType baseType = (HLSLBaseType)(type + typeOffset); - + BaseTypeDescription& desc = baseTypeDescriptions[baseType]; desc.typeName = name; desc.typeNameMetal = name; - + desc.baseType = baseType; desc.coreType = CoreType_Matrix; desc.dimensionType = DimensionType(DimensionType_Matrix2x2 + (dim2 - 2)); desc.numericType = numericType; - + desc.numDimensions = 2; desc.numComponents = dim1; desc.height = dim2; desc.binaryOpRank = binaryOpRank; } -void RegisterVector(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName, uint32_t dim) +void RegisterVector(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName, uint32_t dim) { char buf[32]; snprintf(buf, sizeof(buf), "%s%d", typeName, dim); const char* name = gStringPool.AddString(buf); - + HLSLBaseType baseType = (HLSLBaseType)(type + typeOffset); - + BaseTypeDescription& desc = baseTypeDescriptions[type + typeOffset]; desc.typeName = name; desc.typeNameMetal = name; - + // 4 types desc.baseType = baseType; desc.coreType = CoreType_Vector; desc.dimensionType = DimensionType(DimensionType_Vector2 + (dim - 2)); desc.numericType = numericType; - + desc.numDimensions = 1; desc.numComponents = dim; desc.height = 1; desc.binaryOpRank = binaryOpRank; } -void RegisterScalar(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName) +void RegisterScalar(HLSLBaseType type, uint32_t typeOffset, NumericType numericType, int binaryOpRank, const char* typeName) { const char* name = gStringPool.AddString(typeName); - + HLSLBaseType baseType = (HLSLBaseType)(type + typeOffset); - + BaseTypeDescription& desc = baseTypeDescriptions[baseType]; desc.typeName = name; desc.typeNameMetal = name; - + // 4 types desc.baseType = baseType; desc.coreType = CoreType_Scalar; desc.dimensionType = DimensionType_Scalar; desc.numericType = numericType; - + desc.numDimensions = 0; desc.numComponents = 1; desc.height = 1; @@ -1421,7 +1404,7 @@ void RegisterTexture(HLSLBaseType baseType, const char* typeName, const char* ty desc.baseType = baseType; desc.typeName = typeName; desc.typeNameMetal = typeNameMetal; - + desc.coreType = CoreType_Texture; } @@ -1431,7 +1414,7 @@ void RegisterSampler(HLSLBaseType baseType, const char* typeName, const char* ty desc.baseType = baseType; desc.typeName = typeName; desc.typeNameMetal = typeNameMetal; - + desc.coreType = CoreType_Sampler; } @@ -1441,84 +1424,77 @@ void RegisterType(HLSLBaseType baseType, CoreType coreType, const char* typeName desc.baseType = baseType; desc.typeName = typeName; desc.typeNameMetal = typeName; - + desc.coreType = coreType; } - bool InitBaseTypeDescriptions() { { const uint32_t kNumTypes = 3; - const char* typeNames[kNumTypes] = { "float", "half", "double" }; - const HLSLBaseType baseTypes[kNumTypes] = { HLSLBaseType_Float, HLSLBaseType_Half, HLSLBaseType_Double }; - const NumericType numericTypes[kNumTypes] = { NumericType_Float, NumericType_Half, NumericType_Double }; - const int binaryOpRanks[kNumTypes] = { 0, 1, 2 }; - - for (uint32_t i = 0; i < kNumTypes; ++i) - { + const char* typeNames[kNumTypes] = {"float", "half", "double"}; + const HLSLBaseType baseTypes[kNumTypes] = {HLSLBaseType_Float, HLSLBaseType_Half, HLSLBaseType_Double}; + const NumericType numericTypes[kNumTypes] = {NumericType_Float, NumericType_Half, NumericType_Double}; + const int binaryOpRanks[kNumTypes] = {0, 1, 2}; + + for (uint32_t i = 0; i < kNumTypes; ++i) { const char* typeName = typeNames[i]; HLSLBaseType baseType = baseTypes[i]; NumericType numericType = numericTypes[i]; int binaryOpRank = binaryOpRanks[i]; - + RegisterScalar(baseType, 0, numericType, binaryOpRank, typeName); RegisterVector(baseType, 1, numericType, binaryOpRank, typeName, 2); RegisterVector(baseType, 2, numericType, binaryOpRank, typeName, 3); RegisterVector(baseType, 3, numericType, binaryOpRank, typeName, 4); - + RegisterMatrix(baseType, 4, numericType, binaryOpRank, typeName, 2, 2); RegisterMatrix(baseType, 5, numericType, binaryOpRank, typeName, 3, 3); RegisterMatrix(baseType, 6, numericType, binaryOpRank, typeName, 4, 4); } } - + { const uint32_t kNumTypes = 7; const char* typeNames[kNumTypes] = { "int", "uint", "long", "ulong", "short", "ushort", - "bool" - }; + "bool"}; const HLSLBaseType baseTypes[kNumTypes] = { - HLSLBaseType_Int, HLSLBaseType_Uint, + HLSLBaseType_Int, HLSLBaseType_Uint, HLSLBaseType_Long, HLSLBaseType_Ulong, HLSLBaseType_Short, HLSLBaseType_Ushort, - HLSLBaseType_Bool - }; + HLSLBaseType_Bool}; const NumericType numericTypes[kNumTypes] = { - NumericType_Int, NumericType_Uint, - NumericType_Long, NumericType_Ulong, + NumericType_Int, NumericType_Uint, + NumericType_Long, NumericType_Ulong, NumericType_Short, NumericType_Ushort, - NumericType_Bool - }; + NumericType_Bool}; const int binaryOpRanks[kNumTypes] = { 2, 1, // Note: int seems like it should be highest 3, 2, 4, 3, - 4 - }; - - for (uint32_t i = 0; i < kNumTypes; ++i) - { + 4}; + + for (uint32_t i = 0; i < kNumTypes; ++i) { const char* typeName = typeNames[i]; HLSLBaseType baseType = baseTypes[i]; NumericType numericType = numericTypes[i]; int binaryOpRank = binaryOpRanks[i]; - + RegisterScalar(baseType, 0, numericType, binaryOpRank, typeName); RegisterVector(baseType, 1, numericType, binaryOpRank, typeName, 2); RegisterVector(baseType, 2, numericType, binaryOpRank, typeName, 3); RegisterVector(baseType, 3, numericType, binaryOpRank, typeName, 4); } } - + // TODO: add u/char, but HLSL2021 doesn't have support, but MSL does - + // TODO: would it be better to use "texture" base type (see "buffer") // and then have a TextureSubType off that? - + // texutres RegisterTexture(HLSLBaseType_Texture2D, "Texture2D", "texture2d"); RegisterTexture(HLSLBaseType_Texture2DArray, "Texture2DArray", "texture2d_array"); @@ -1526,24 +1502,24 @@ bool InitBaseTypeDescriptions() RegisterTexture(HLSLBaseType_TextureCube, "TextureCube", "texturecube"); RegisterTexture(HLSLBaseType_TextureCubeArray, "TextureCubeArray", "texturecube_rray"); RegisterTexture(HLSLBaseType_Texture2DMS, "Texture2DMS", "texture2d_ms"); - + RegisterTexture(HLSLBaseType_Depth2D, "Depth2D", "depth2d"); RegisterTexture(HLSLBaseType_Depth2DArray, "Depth2DArray", "depth2d_array"); RegisterTexture(HLSLBaseType_DepthCube, "DepthCube", "depthcube"); - + RegisterTexture(HLSLBaseType_RWTexture2D, "RWTexture2D", "texture2d"); - + // samplers RegisterSampler(HLSLBaseType_SamplerState, "SamplerState", "sampler"); RegisterSampler(HLSLBaseType_SamplerComparisonState, "SamplerComparisonState", "sampler"); - + RegisterType(HLSLBaseType_UserDefined, CoreType_Struct, "struct"); RegisterType(HLSLBaseType_Void, CoreType_Void, "void"); RegisterType(HLSLBaseType_Unknown, CoreType_None, "unknown"); RegisterType(HLSLBaseType_Expression, CoreType_Expression, "expression"); RegisterType(HLSLBaseType_Comment, CoreType_Comment, "comment"); RegisterType(HLSLBaseType_Buffer, CoreType_Buffer, "buffer"); - + return true; } @@ -1555,124 +1531,129 @@ static bool _initIntrinsics = InitIntrinsics(); HLSLBaseType ArithmeticOpResultType(HLSLBinaryOp binaryOp, HLSLBaseType t1, HLSLBaseType t2) { // check that both are same numeric types - + // add, sub, div are similar // mul is it's own test // most mixing of types is invalid here - - if (IsNumericTypeEqual(t1, t2)) - { + + if (IsNumericTypeEqual(t1, t2)) { bool isSameDimensions = IsDimensionEqual(t1, t2); - - if (IsScalarType(t1) && IsScalarType(t2)) - { + + if (IsScalarType(t1) && IsScalarType(t2)) { if (isSameDimensions) return t1; } - else if (IsVectorType(t1) && IsVectorType(t2)) - { + else if (IsVectorType(t1) && IsVectorType(t2)) { if (isSameDimensions) return t1; } - else if (IsMatrixType(t1) && IsMatrixType(t2)) - { + else if (IsMatrixType(t1) && IsMatrixType(t2)) { if (isSameDimensions) return t1; } - + else if ((binaryOp == HLSLBinaryOp_Add || binaryOp == HLSLBinaryOp_Sub) && - (IsScalarType(t1) || IsScalarType(t2))) - { + (IsScalarType(t1) || IsScalarType(t2))) { // allow v + 1, and 1 - v return (IsVectorType(t1) || IsMatrixType(t1)) ? t1 : t2; } - + else if ((binaryOp == HLSLBinaryOp_Mul || binaryOp == HLSLBinaryOp_Div) && - (IsScalarType(t1) || IsScalarType(t2))) - { + (IsScalarType(t1) || IsScalarType(t2))) { // v * s return (IsVectorType(t1) || IsMatrixType(t1)) ? t1 : t2; } - + // this has to check dimension across the mul - else if (binaryOp == HLSLBinaryOp_Mul) - { + else if (binaryOp == HLSLBinaryOp_Mul) { bool isSameCrossDimension = IsCrossDimensionEqual(t1, t2); - - if (IsMatrixType(t1) && IsVectorType(t2)) - { + + if (IsMatrixType(t1) && IsVectorType(t2)) { if (isSameCrossDimension) return t2; } - else if (IsVectorType(t1) && IsMatrixType(t2)) - { + else if (IsVectorType(t1) && IsMatrixType(t2)) { if (isSameCrossDimension) return t1; } } } - + return HLSLBaseType_Unknown; } - + // Priority of the ? : operator. const int _conditionalOpPriority = 1; const char* GetTypeNameHLSL(const HLSLType& type) { - if (type.baseType == HLSLBaseType_UserDefined) - { + if (type.baseType == HLSLBaseType_UserDefined) { return type.typeName; } - else - { + else { return baseTypeDescriptions[type.baseType].typeName; } } const char* GetTypeNameMetal(const HLSLType& type) { - if (type.baseType == HLSLBaseType_UserDefined) - { + if (type.baseType == HLSLBaseType_UserDefined) { return type.typeName; } - else - { + else { return baseTypeDescriptions[type.baseType].typeNameMetal; } } static const char* GetBinaryOpName(HLSLBinaryOp binaryOp) { - switch (binaryOp) - { - case HLSLBinaryOp_And: return "&&"; - case HLSLBinaryOp_Or: return "||"; - - case HLSLBinaryOp_Add: return "+"; - case HLSLBinaryOp_Sub: return "-"; - case HLSLBinaryOp_Mul: return "*"; - case HLSLBinaryOp_Div: return "/"; - - case HLSLBinaryOp_Less: return "<"; - case HLSLBinaryOp_Greater: return ">"; - case HLSLBinaryOp_LessEqual: return "<="; - case HLSLBinaryOp_GreaterEqual: return ">="; - case HLSLBinaryOp_Equal: return "=="; - case HLSLBinaryOp_NotEqual: return "!="; - - case HLSLBinaryOp_BitAnd: return "&"; - case HLSLBinaryOp_BitOr: return "|"; - case HLSLBinaryOp_BitXor: return "^"; - - case HLSLBinaryOp_Assign: return "="; - case HLSLBinaryOp_AddAssign: return "+="; - case HLSLBinaryOp_SubAssign: return "-="; - case HLSLBinaryOp_MulAssign: return "*="; - case HLSLBinaryOp_DivAssign: return "/="; - default: - ASSERT(false); - return "???"; + switch (binaryOp) { + case HLSLBinaryOp_And: + return "&&"; + case HLSLBinaryOp_Or: + return "||"; + + case HLSLBinaryOp_Add: + return "+"; + case HLSLBinaryOp_Sub: + return "-"; + case HLSLBinaryOp_Mul: + return "*"; + case HLSLBinaryOp_Div: + return "/"; + + case HLSLBinaryOp_Less: + return "<"; + case HLSLBinaryOp_Greater: + return ">"; + case HLSLBinaryOp_LessEqual: + return "<="; + case HLSLBinaryOp_GreaterEqual: + return ">="; + case HLSLBinaryOp_Equal: + return "=="; + case HLSLBinaryOp_NotEqual: + return "!="; + + case HLSLBinaryOp_BitAnd: + return "&"; + case HLSLBinaryOp_BitOr: + return "|"; + case HLSLBinaryOp_BitXor: + return "^"; + + case HLSLBinaryOp_Assign: + return "="; + case HLSLBinaryOp_AddAssign: + return "+="; + case HLSLBinaryOp_SubAssign: + return "-="; + case HLSLBinaryOp_MulAssign: + return "*="; + case HLSLBinaryOp_DivAssign: + return "/="; + default: + ASSERT(false); + return "???"; } } - /* * 1.) Match * 2.) Scalar dimension promotion (scalar -> vector/matrix) @@ -1680,21 +1661,19 @@ static const char* GetBinaryOpName(HLSLBinaryOp binaryOp) * 4.) Conversion + scalar dimension promotion * 5.) Truncation (vector -> scalar or lower component vector, matrix -> scalar or lower component matrix) * 6.) Conversion + truncation - */ -static int GetTypeCastRank(HLSLTree * tree, const HLSLType& srcType, const HLSLType& dstType) + */ +static int GetTypeCastRank(HLSLTree* tree, const HLSLType& srcType, const HLSLType& dstType) { /*if (srcType.array != dstType.array || srcType.arraySize != dstType.arraySize) { return -1; }*/ - if (srcType.array != dstType.array) - { + if (srcType.array != dstType.array) { return -1; } - if (srcType.array == true) - { + if (srcType.array == true) { ASSERT(dstType.array == true); int srcArraySize = -1; int dstArraySize = -1; @@ -1707,103 +1686,86 @@ static int GetTypeCastRank(HLSLTree * tree, const HLSLType& srcType, const HLSLT } } - if (srcType.baseType == HLSLBaseType_UserDefined && dstType.baseType == HLSLBaseType_UserDefined) - { + if (srcType.baseType == HLSLBaseType_UserDefined && dstType.baseType == HLSLBaseType_UserDefined) { return String_Equal(srcType.typeName, dstType.typeName) ? 0 : -1; } - if (srcType.baseType == dstType.baseType) - { + if (srcType.baseType == dstType.baseType) { // This only works if textures are half or float, but not hwne // there are more varied texture that can be cast. - if (IsTextureType(srcType.baseType)) - { + if (IsTextureType(srcType.baseType)) { return srcType.formatType == dstType.formatType ? 0 : -1; } - + return 0; } const BaseTypeDescription& srcDesc = baseTypeDescriptions[srcType.baseType]; const BaseTypeDescription& dstDesc = baseTypeDescriptions[dstType.baseType]; - if (srcDesc.numericType == NumericType_NaN || dstDesc.numericType == NumericType_NaN) - { + if (srcDesc.numericType == NumericType_NaN || dstDesc.numericType == NumericType_NaN) { return -1; } // Result bits: T R R R P (T = truncation, R = conversion rank, P = dimension promotion) int result = _numberTypeRank[srcDesc.numericType][dstDesc.numericType] << 1; - if (srcDesc.numDimensions == 0 && dstDesc.numDimensions > 0) - { + if (srcDesc.numDimensions == 0 && dstDesc.numDimensions > 0) { // Scalar dimension promotion result |= (1 << 0); } else if ((srcDesc.numDimensions == dstDesc.numDimensions && (srcDesc.numComponents > dstDesc.numComponents || srcDesc.height > dstDesc.height)) || - (srcDesc.numDimensions > 0 && dstDesc.numDimensions == 0)) - { + (srcDesc.numDimensions > 0 && dstDesc.numDimensions == 0)) { // Truncation result |= (1 << 4); } else if (srcDesc.numDimensions != dstDesc.numDimensions || srcDesc.numComponents != dstDesc.numComponents || - srcDesc.height != dstDesc.height) - { + srcDesc.height != dstDesc.height) { // Can't convert return -1; } - + return result; - } static bool GetFunctionCallCastRanks(HLSLTree* tree, const HLSLFunctionCall* call, const HLSLFunction* function, int* rankBuffer) { - - if (function == NULL || function->numArguments < call->numArguments) - { + if (function == NULL || function->numArguments < call->numArguments) { // Function not viable return false; } const HLSLExpression* expression = call->argument; const HLSLArgument* argument = function->argument; - - for (int i = 0; i < call->numArguments; ++i) - { + + for (int i = 0; i < call->numArguments; ++i) { int rank = GetTypeCastRank(tree, expression->expressionType, argument->type); - if (rank == -1) - { + if (rank == -1) { return false; } rankBuffer[i] = rank; - + argument = argument->nextArgument; expression = expression->nextExpression; } - for (int i = call->numArguments; i < function->numArguments; ++i) - { - if (argument->defaultValue == NULL) - { + for (int i = call->numArguments; i < function->numArguments; ++i) { + if (argument->defaultValue == NULL) { // Function not viable. return false; } } return true; - } -struct CompareRanks -{ - bool operator() (const int& rank1, const int& rank2) { return rank1 > rank2; } +struct CompareRanks { + bool operator()(const int& rank1, const int& rank2) { return rank1 > rank2; } }; static CompareFunctionsResult CompareFunctions(HLSLTree* tree, const HLSLFunctionCall* call, const HLSLFunction* function1, const HLSLFunction* function2) -{ - +{ int* function1Ranks = static_cast(alloca(sizeof(int) * call->numArguments)); int* function2Ranks = static_cast(alloca(sizeof(int) * call->numArguments)); @@ -1811,85 +1773,70 @@ static CompareFunctionsResult CompareFunctions(HLSLTree* tree, const HLSLFunctio const bool function2Viable = GetFunctionCallCastRanks(tree, call, function2, function2Ranks); // Both functions have to be viable to be able to compare them - if (!(function1Viable && function2Viable)) - { - if (function1Viable) - { + if (!(function1Viable && function2Viable)) { + if (function1Viable) { return Function1Better; } - else if (function2Viable) - { + else if (function2Viable) { return Function2Better; } - else - { + else { return FunctionsEqual; } } std::sort(function1Ranks, function1Ranks + call->numArguments, CompareRanks()); std::sort(function2Ranks, function2Ranks + call->numArguments, CompareRanks()); - - for (int i = 0; i < call->numArguments; ++i) - { - if (function1Ranks[i] < function2Ranks[i]) - { + + for (int i = 0; i < call->numArguments; ++i) { + if (function1Ranks[i] < function2Ranks[i]) { return Function1Better; } - else if (function2Ranks[i] < function1Ranks[i]) - { + else if (function2Ranks[i] < function1Ranks[i]) { return Function2Better; } } return FunctionsEqual; - } static bool GetBinaryOpResultType(HLSLBinaryOp binaryOp, const HLSLType& type1, const HLSLType& type2, HLSLType& result) { // only allow numeric types for binary operators if (!IsNumericType(type1.baseType) || type1.array || - !IsNumericType(type2.baseType) || type2.array) - { - return false; + !IsNumericType(type2.baseType) || type2.array) { + return false; } - if (IsBitOp(binaryOp)) - { - if (!IsIntegerType(type1.baseType)) - { + if (IsBitOp(binaryOp)) { + if (!IsIntegerType(type1.baseType)) { return false; } } - if (IsLogicOp(binaryOp) || IsCompareOp(binaryOp)) - { - int numComponents = std::max( baseTypeDescriptions[ type1.baseType ].numComponents, baseTypeDescriptions[ type2.baseType ].numComponents ); - result.baseType = HLSLBaseType( HLSLBaseType_Bool + numComponents - 1 ); + if (IsLogicOp(binaryOp) || IsCompareOp(binaryOp)) { + int numComponents = std::max(baseTypeDescriptions[type1.baseType].numComponents, baseTypeDescriptions[type2.baseType].numComponents); + result.baseType = HLSLBaseType(HLSLBaseType_Bool + numComponents - 1); } - else - { + else { // TODO: allso mulAssign, ... assert(!IsAssignOp(binaryOp)); - + result.baseType = ArithmeticOpResultType(binaryOp, type1.baseType, type2.baseType); } - result.typeName = NULL; - result.array = false; - result.arraySize = NULL; - result.flags = (type1.flags & type2.flags) & HLSLTypeFlag_Const; // Propagate constness. - - return result.baseType != HLSLBaseType_Unknown; + result.typeName = NULL; + result.array = false; + result.arraySize = NULL; + result.flags = (type1.flags & type2.flags) & HLSLTypeFlag_Const; // Propagate constness. + return result.baseType != HLSLBaseType_Unknown; } -HLSLParser::HLSLParser(Allocator* allocator, const char* fileName, const char* buffer, size_t length) : - m_tokenizer(fileName, buffer, length), - m_userTypes(allocator), - m_variables(allocator), - m_functions(allocator) +HLSLParser::HLSLParser(Allocator* allocator, const char* fileName, const char* buffer, size_t length) : m_tokenizer(fileName, buffer, length), + m_userTypes(allocator), + m_variables(allocator), + m_functions(allocator) { m_numGlobals = 0; m_tree = NULL; @@ -1897,18 +1844,16 @@ HLSLParser::HLSLParser(Allocator* allocator, const char* fileName, const char* b bool HLSLParser::Accept(int token) { - if (m_tokenizer.GetToken() == token) - { - m_tokenizer.Next(); - return true; + if (m_tokenizer.GetToken() == token) { + m_tokenizer.Next(); + return true; } return false; } bool HLSLParser::Accept(const char* token) { - if (m_tokenizer.GetToken() == HLSLToken_Identifier && String_Equal( token, m_tokenizer.GetIdentifier() ) ) - { + if (m_tokenizer.GetToken() == HLSLToken_Identifier && String_Equal(token, m_tokenizer.GetIdentifier())) { m_tokenizer.Next(); return true; } @@ -1917,8 +1862,7 @@ bool HLSLParser::Accept(const char* token) bool HLSLParser::Expect(int token) { - if (!Accept(token)) - { + if (!Accept(token)) { char want[HLSLTokenizer::s_maxIdentifier]; m_tokenizer.GetTokenName(token, want); char near[HLSLTokenizer::s_maxIdentifier]; @@ -1929,11 +1873,10 @@ bool HLSLParser::Expect(int token) return true; } -bool HLSLParser::Expect(const char * token) +bool HLSLParser::Expect(const char* token) { - if (!Accept(token)) - { - const char * want = token; + if (!Accept(token)) { + const char* want = token; char near[HLSLTokenizer::s_maxIdentifier]; m_tokenizer.GetTokenName(near); m_tokenizer.Error("Syntax error: expected '%s' near '%s'", want, near); @@ -1942,12 +1885,10 @@ bool HLSLParser::Expect(const char * token) return true; } - bool HLSLParser::AcceptIdentifier(const char*& identifier) { - if (m_tokenizer.GetToken() == HLSLToken_Identifier) - { - identifier = m_tree->AddString( m_tokenizer.GetIdentifier() ); + if (m_tokenizer.GetToken() == HLSLToken_Identifier) { + identifier = m_tree->AddString(m_tokenizer.GetIdentifier()); m_tokenizer.Next(); return true; } @@ -1956,8 +1897,7 @@ bool HLSLParser::AcceptIdentifier(const char*& identifier) bool HLSLParser::ExpectIdentifier(const char*& identifier) { - if (!AcceptIdentifier(identifier)) - { + if (!AcceptIdentifier(identifier)) { char near[HLSLTokenizer::s_maxIdentifier] = {}; m_tokenizer.GetTokenName(near); m_tokenizer.Error("Syntax error: expected identifier near '%s'", near); @@ -1969,8 +1909,7 @@ bool HLSLParser::ExpectIdentifier(const char*& identifier) bool HLSLParser::AcceptFloat(float& value) { - if (m_tokenizer.GetToken() == HLSLToken_FloatLiteral) - { + if (m_tokenizer.GetToken() == HLSLToken_FloatLiteral) { value = m_tokenizer.GetFloat(); m_tokenizer.Next(); return true; @@ -1980,19 +1919,17 @@ bool HLSLParser::AcceptFloat(float& value) bool HLSLParser::AcceptHalf(float& value) { - if(m_tokenizer.GetToken() == HLSLToken_HalfLiteral) - { - value = m_tokenizer.GetFloat(); - m_tokenizer.Next(); - return true; - } - return false; + if (m_tokenizer.GetToken() == HLSLToken_HalfLiteral) { + value = m_tokenizer.GetFloat(); + m_tokenizer.Next(); + return true; + } + return false; } bool HLSLParser::AcceptInt(int& value) { - if (m_tokenizer.GetToken() == HLSLToken_IntLiteral) - { + if (m_tokenizer.GetToken() == HLSLToken_IntLiteral) { value = m_tokenizer.GetInt(); m_tokenizer.Next(); return true; @@ -2002,12 +1939,12 @@ bool HLSLParser::AcceptInt(int& value) bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) { - HLSLAttribute * attributes = NULL; + HLSLAttribute* attributes = NULL; ParseAttributeBlock(attributes); - int line = GetLineNumber(); + int line = GetLineNumber(); const char* fileName = GetFileName(); - + HLSLType type; //HLSLBaseType type; //const char* typeName = NULL; @@ -2015,31 +1952,26 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) // TODO: this cast likely isn't safe HLSLToken token = (HLSLToken)m_tokenizer.GetToken(); - + bool doesNotExpectSemicolon = false; // Alec add comment - if (ParseComment(statement)) - { + if (ParseComment(statement)) { doesNotExpectSemicolon = true; } - else if (Accept(HLSLToken_Struct)) - { + else if (Accept(HLSLToken_Struct)) { // Struct declaration. const char* structName = NULL; - if (!ExpectIdentifier(structName)) - { + if (!ExpectIdentifier(structName)) { return false; } - if (FindUserDefinedType(structName) != NULL) - { + if (FindUserDefinedType(structName) != NULL) { m_tokenizer.Error("struct %s already defined", structName); return false; } - if (!Expect('{')) - { + if (!Expect('{')) { return false; } @@ -2047,30 +1979,25 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) structure->name = structName; m_userTypes.PushBack(structure); - + HLSLStructField* lastField = NULL; // Add the struct to our list of user defined types. - while (!Accept('}')) - { - if (CheckForUnexpectedEndOfStream('}')) - { + while (!Accept('}')) { + if (CheckForUnexpectedEndOfStream('}')) { return false; } - + // chain fields onto struct HLSLStructField* field = NULL; - if (!ParseFieldDeclaration(field)) - { + if (!ParseFieldDeclaration(field)) { return false; } ASSERT(field != NULL); - if (lastField == NULL) - { + if (lastField == NULL) { structure->field = field; } - else - { + else { lastField->nextField = field; } lastField = field; @@ -2082,71 +2009,62 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) Accept(HLSLToken_StructuredBuffer) || Accept(HLSLToken_RWStructuredBuffer) || Accept(HLSLToken_ByteAddressBuffer) || - Accept(HLSLToken_RWByteAddressBuffer)) - { + Accept(HLSLToken_RWByteAddressBuffer)) { HLSLBuffer* buffer = m_tree->AddNode(fileName, line); - + // these can appear on t or u slots for read vs. read/write // need to track what the user specified. Load vs. Store calls. buffer->bufferType = ConvertTokenToBufferType(token); - + // Is template struct type required? - if (Expect('<')) - { + if (Expect('<')) { const char* structName = nullptr; - + // Read the templated type, should reference a struct // don't need to support fields on this. - if (!ExpectIdentifier(structName) || !Expect('>')) - { + if (!ExpectIdentifier(structName) || !Expect('>')) { return false; } - + buffer->bufferStruct = const_cast(FindUserDefinedType(structName)); - if (!buffer->bufferStruct) - { + if (!buffer->bufferStruct) { return false; } } - + // get name of buffer AcceptIdentifier(buffer->name); - + // Parse ": register(t0/u0)" - if (Accept(':')) - { - if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(buffer->registerName) || !Expect(')')) - { + if (Accept(':')) { + if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(buffer->registerName) || !Expect(')')) { return false; } // TODO: Check that we aren't re-using a register. } - + // Buffer needs to show up to reference the fields // of the struct of the templated type. HLSLType bufferType(HLSLBaseType_UserDefined); bufferType.typeName = buffer->bufferStruct->name; // this is for userDefined name (f.e. struct) - - DeclareVariable( buffer->name, bufferType ); - + + DeclareVariable(buffer->name, bufferType); + // TODO: add fields as variables too? - + statement = buffer; } - else if (Accept(HLSLToken_CBuffer) || Accept(HLSLToken_TBuffer)) - { + else if (Accept(HLSLToken_CBuffer) || Accept(HLSLToken_TBuffer)) { // cbuffer/tbuffer declaration. HLSLBuffer* buffer = m_tree->AddNode(fileName, line); AcceptIdentifier(buffer->name); buffer->bufferType = ConvertTokenToBufferType(token); - + // Optional register assignment. - if (Accept(':')) - { - if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(buffer->registerName) || !Expect(')')) - { + if (Accept(':')) { + if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(buffer->registerName) || !Expect(')')) { return false; } // TODO: Check that we aren't re-using a register. @@ -2155,90 +2073,76 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) // Fields are defined inside the c/tbuffer. // These represent globals to the rest of the codebase which // is simply evil. - - if (!Expect('{')) - { + + if (!Expect('{')) { return false; } HLSLDeclaration* lastField = NULL; - while (!Accept('}')) - { - if (CheckForUnexpectedEndOfStream('}')) - { + while (!Accept('}')) { + if (CheckForUnexpectedEndOfStream('}')) { return false; } - + // TODO: can't convert statement to fields - if (ParseComment(statement)) - { + if (ParseComment(statement)) { continue; } - + HLSLDeclaration* field = NULL; - if (!ParseDeclaration(field)) - { + if (!ParseDeclaration(field)) { m_tokenizer.Error("Expected variable declaration"); return false; } - + // These show up as global variables of the fields - DeclareVariable( field->name, field->type ); - + DeclareVariable(field->name, field->type); + // chain fields onto buffer field->buffer = buffer; - if (buffer->field == NULL) - { + if (buffer->field == NULL) { buffer->field = field; } - else - { + else { lastField->nextStatement = field; } lastField = field; - + if (!Expect(';')) { return false; } - } statement = buffer; } - else if (AcceptType(true, type)) - { + else if (AcceptType(true, type)) { // Global declaration (uniform or function). const char* globalName = NULL; - if (!ExpectIdentifier(globalName)) - { + if (!ExpectIdentifier(globalName)) { return false; } - if (Accept('(')) - { + if (Accept('(')) { // Function declaration. HLSLFunction* function = m_tree->AddNode(fileName, line); - function->name = globalName; - function->returnType.baseType = type.baseType; - function->returnType.typeName = type.typeName; - function->attributes = attributes; + function->name = globalName; + function->returnType.baseType = type.baseType; + function->returnType.typeName = type.typeName; + function->attributes = attributes; BeginScope(); - if (!ParseArgumentList(function->argument, function->numArguments, function->numOutputArguments)) - { + if (!ParseArgumentList(function->argument, function->numArguments, function->numOutputArguments)) { return false; } const HLSLFunction* declaration = FindFunction(function); // Forward declaration - if (Accept(';')) - { + if (Accept(';')) { // Add a function entry so that calls can refer to it - if (!declaration) - { - m_functions.PushBack( function ); + if (!declaration) { + m_functions.PushBack(function); statement = function; } EndScope(); @@ -2246,28 +2150,23 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) } // Optional semantic. - if (Accept(':') && !ExpectIdentifier(function->semantic)) - { + if (Accept(':') && !ExpectIdentifier(function->semantic)) { return false; } - if (declaration) - { - if (declaration->forward || declaration->statement) - { + if (declaration) { + if (declaration->forward || declaration->statement) { m_tokenizer.Error("Duplicate function definition"); return false; } const_cast(declaration)->forward = function; } - else - { - m_functions.PushBack( function ); + else { + m_functions.PushBack(function); } - if (!Expect('{') || !ParseBlock(function->statement, function->returnType)) - { + if (!Expect('{') || !ParseBlock(function->statement, function->returnType)) { return false; } @@ -2275,23 +2174,19 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) // Note, no semi-colon at the end of a function declaration. statement = function; - + return true; } - else - { + else { // Uniform declaration. HLSLDeclaration* declaration = m_tree->AddNode(fileName, line); - declaration->name = globalName; - declaration->type = type; + declaration->name = globalName; + declaration->type = type; // Handle array syntax. - if (Accept('[')) - { - if (!Accept(']')) - { - if (!ParseExpression(declaration->type.arraySize) || !Expect(']')) - { + if (Accept('[')) { + if (!Accept(']')) { + if (!ParseExpression(declaration->type.arraySize) || !Expect(']')) { return false; } } @@ -2299,31 +2194,28 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) } // Handle optional register. - if (Accept(':')) - { + if (Accept(':')) { // @@ Currently we support either a semantic or a register, but not both. if (AcceptIdentifier(declaration->semantic)) { // int k = 1; } - else if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(declaration->registerName) || !Expect(')')) - { + else if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(declaration->registerName) || !Expect(')')) { return false; } } - DeclareVariable( globalName, declaration->type ); + DeclareVariable(globalName, declaration->type); - if (!ParseDeclarationAssignment(declaration)) - { + if (!ParseDeclarationAssignment(declaration)) { return false; } // TODO: Multiple variables declared on one line. - + statement = declaration; } } - + /* // These three are from .fx file syntax else if (ParseTechnique(statement)) { @@ -2336,7 +2228,7 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) doesNotExpectSemicolon = true; } */ - + if (statement != NULL) { statement->attributes = attributes; } @@ -2344,28 +2236,22 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) return doesNotExpectSemicolon || Expect(';'); } -bool HLSLParser::ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType, bool scoped/*=true*/) +bool HLSLParser::ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType, bool scoped /*=true*/) { - if (scoped) - { + if (scoped) { BeginScope(); } - if (Accept('{')) - { - if (!ParseBlock(firstStatement, returnType)) - { + if (Accept('{')) { + if (!ParseBlock(firstStatement, returnType)) { return false; } } - else - { - if (!ParseStatement(firstStatement, returnType)) - { + else { + if (!ParseStatement(firstStatement, returnType)) { return false; } } - if (scoped) - { + if (scoped) { EndScope(); } return true; @@ -2375,21 +2261,21 @@ bool HLSLParser::ParseComment(HLSLStatement*& statement) { if (m_tokenizer.GetToken() != HLSLToken_Comment) return false; - + const char* textName = m_tree->AddString(m_tokenizer.GetComment()); - + // This has already parsed the next comment before have had a chance to // grab the string from the previous comment, if they were sequenential comments. // So grabbing a copy of comment before this parses the next comment. if (!Accept(HLSLToken_Comment)) return false; - + const char* fileName = GetFileName(); - int line = GetLineNumber(); + int line = GetLineNumber(); HLSLComment* comment = m_tree->AddNode(fileName, line); comment->text = textName; - + // pass it back statement = comment; return true; @@ -2398,33 +2284,27 @@ bool HLSLParser::ParseComment(HLSLStatement*& statement) bool HLSLParser::ParseBlock(HLSLStatement*& firstStatement, const HLSLType& returnType) { HLSLStatement* lastStatement = NULL; - while (!Accept('}')) - { - if (CheckForUnexpectedEndOfStream('}')) - { + while (!Accept('}')) { + if (CheckForUnexpectedEndOfStream('}')) { return false; } - + HLSLStatement* statement = NULL; - - if (!ParseStatement(statement, returnType)) - { + + if (!ParseStatement(statement, returnType)) { return false; } - + // chain statements onto the list - if (statement != NULL) - { - if (firstStatement == NULL) - { + if (statement != NULL) { + if (firstStatement == NULL) { firstStatement = statement; } - else - { + else { lastStatement->nextStatement = statement; } lastStatement = statement; - + // some statement parsing can gen more than one statement, so find end while (lastStatement->nextStatement) lastStatement = lastStatement->nextStatement; @@ -2436,16 +2316,15 @@ bool HLSLParser::ParseBlock(HLSLStatement*& firstStatement, const HLSLType& retu bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& returnType) { const char* fileName = GetFileName(); - int line = GetLineNumber(); + int line = GetLineNumber(); // Empty statements. - if (Accept(';')) - { + if (Accept(';')) { return true; } - HLSLAttribute * attributes = NULL; - ParseAttributeBlock(attributes); // @@ Leak if not assigned to node? + HLSLAttribute* attributes = NULL; + ParseAttributeBlock(attributes); // @@ Leak if not assigned to node? #if 0 // @@ Work in progress. @@ -2518,78 +2397,64 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur } */ #endif - - if (ParseComment(statement)) - { + + if (ParseComment(statement)) { return true; } - + // If statement. - if (Accept(HLSLToken_If)) - { + if (Accept(HLSLToken_If)) { HLSLIfStatement* ifStatement = m_tree->AddNode(fileName, line); ifStatement->attributes = attributes; - if (!Expect('(') || !ParseExpression(ifStatement->condition) || !Expect(')')) - { + if (!Expect('(') || !ParseExpression(ifStatement->condition) || !Expect(')')) { return false; } statement = ifStatement; - if (!ParseStatementOrBlock(ifStatement->statement, returnType)) - { + if (!ParseStatementOrBlock(ifStatement->statement, returnType)) { return false; } - if (Accept(HLSLToken_Else)) - { + if (Accept(HLSLToken_Else)) { return ParseStatementOrBlock(ifStatement->elseStatement, returnType); } return true; } - + // For statement. - if (Accept(HLSLToken_For)) - { + if (Accept(HLSLToken_For)) { HLSLForStatement* forStatement = m_tree->AddNode(fileName, line); forStatement->attributes = attributes; - if (!Expect('(')) - { + if (!Expect('(')) { return false; } BeginScope(); - if (!ParseDeclaration(forStatement->initialization)) - { + if (!ParseDeclaration(forStatement->initialization)) { return false; } - if (!Expect(';')) - { + if (!Expect(';')) { return false; } ParseExpression(forStatement->condition); - if (!Expect(';')) - { + if (!Expect(';')) { return false; } ParseExpression(forStatement->increment); - if (!Expect(')')) - { + if (!Expect(')')) { return false; } statement = forStatement; - if (!ParseStatementOrBlock(forStatement->statement, returnType)) - { + if (!ParseStatementOrBlock(forStatement->statement, returnType)) { return false; } EndScope(); return true; } - if (attributes != NULL) - { + if (attributes != NULL) { // @@ Error. Unexpected attribute. We only support attributes associated to if and for statements. } // Block statement. - if (Accept('{')) - { + if (Accept('{')) { HLSLBlockStatement* blockStatement = m_tree->AddNode(fileName, line); statement = blockStatement; BeginScope(); @@ -2599,41 +2464,35 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur } // Discard statement. - if (Accept(HLSLToken_Discard)) - { + if (Accept(HLSLToken_Discard)) { HLSLDiscardStatement* discardStatement = m_tree->AddNode(fileName, line); statement = discardStatement; return Expect(';'); } // Break statement. - if (Accept(HLSLToken_Break)) - { + if (Accept(HLSLToken_Break)) { HLSLBreakStatement* breakStatement = m_tree->AddNode(fileName, line); statement = breakStatement; return Expect(';'); } // Continue statement. - if (Accept(HLSLToken_Continue)) - { + if (Accept(HLSLToken_Continue)) { HLSLContinueStatement* continueStatement = m_tree->AddNode(fileName, line); statement = continueStatement; return Expect(';'); } // Return statement - if (Accept(HLSLToken_Return)) - { + if (Accept(HLSLToken_Return)) { HLSLReturnStatement* returnStatement = m_tree->AddNode(fileName, line); - if (!Accept(';') && !ParseExpression(returnStatement->expression)) - { + if (!Accept(';') && !ParseExpression(returnStatement->expression)) { return false; } // Check that the return expression can be cast to the return type of the function. HLSLType voidType(HLSLBaseType_Void); - if (!CheckTypeCast(returnStatement->expression ? returnStatement->expression->expressionType : voidType, returnType)) - { + if (!CheckTypeCast(returnStatement->expression ? returnStatement->expression->expressionType : voidType, returnType)) { return false; } @@ -2642,14 +2501,12 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur } HLSLDeclaration* declaration = NULL; - HLSLExpression* expression = NULL; + HLSLExpression* expression = NULL; - if (ParseDeclaration(declaration)) - { + if (ParseDeclaration(declaration)) { statement = declaration; } - else if (ParseExpression(expression)) - { + else if (ParseExpression(expression)) { HLSLExpressionStatement* expressionStatement; expressionStatement = m_tree->AddNode(fileName, line); expressionStatement->expression = expression; @@ -2659,55 +2516,49 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur return Expect(';'); } - // IC: This is only used in block statements, or within control flow statements. So, it doesn't support semantics or layout modifiers. // @@ We should add suport for semantics for inline input/output declarations. bool HLSLParser::ParseDeclaration(HLSLDeclaration*& declaration) { - const char* fileName = GetFileName(); - int line = GetLineNumber(); + const char* fileName = GetFileName(); + int line = GetLineNumber(); HLSLType type; - if (!AcceptType(/*allowVoid=*/false, type)) - { + if (!AcceptType(/*allowVoid=*/false, type)) { return false; } - bool allowUnsizedArray = true; // This is needed for SSBO - - HLSLDeclaration * firstDeclaration = NULL; - HLSLDeclaration * lastDeclaration = NULL; + bool allowUnsizedArray = true; // This is needed for SSBO + + HLSLDeclaration* firstDeclaration = NULL; + HLSLDeclaration* lastDeclaration = NULL; do { const char* name; - if (!ExpectIdentifier(name)) - { + if (!ExpectIdentifier(name)) { // TODO: false means we didn't accept a declaration and we had an error! return false; } // Handle array syntax. - if (Accept('[')) - { + if (Accept('[')) { type.array = true; // Optionally allow no size to the specified for the array. - if (Accept(']') && allowUnsizedArray) - { + if (Accept(']') && allowUnsizedArray) { return true; } - if (!ParseExpression(type.arraySize) || !Expect(']')) - { + if (!ParseExpression(type.arraySize) || !Expect(']')) { return false; } } - HLSLDeclaration * parsedDeclaration = m_tree->AddNode(fileName, line); - parsedDeclaration->type = type; - parsedDeclaration->name = name; + HLSLDeclaration* parsedDeclaration = m_tree->AddNode(fileName, line); + parsedDeclaration->type = type; + parsedDeclaration->name = name; - DeclareVariable( parsedDeclaration->name, parsedDeclaration->type ); + DeclareVariable(parsedDeclaration->name, parsedDeclaration->type); // Handle option assignment of the declared variables(s). - if (!ParseDeclarationAssignment( parsedDeclaration )) { + if (!ParseDeclarationAssignment(parsedDeclaration)) { return false; } @@ -2715,7 +2566,7 @@ bool HLSLParser::ParseDeclaration(HLSLDeclaration*& declaration) if (lastDeclaration != NULL) lastDeclaration->nextDeclaration = parsedDeclaration; lastDeclaration = parsedDeclaration; - } while(Accept(',')); + } while (Accept(',')); declaration = firstDeclaration; @@ -2724,26 +2575,22 @@ bool HLSLParser::ParseDeclaration(HLSLDeclaration*& declaration) bool HLSLParser::ParseDeclarationAssignment(HLSLDeclaration* declaration) { - if (Accept('=')) - { + if (Accept('=')) { // Handle array initialization syntax. - if (declaration->type.array) - { + if (declaration->type.array) { int numValues = 0; - if (!Expect('{') || !ParseExpressionList('}', true, declaration->assignment, numValues)) - { + if (!Expect('{') || !ParseExpressionList('}', true, declaration->assignment, numValues)) { return false; } } -// else if (IsSamplerType(declaration->type.baseType)) // TODO: should be for SamplerStateBlock, not Sampler -// { -// if (!ParseSamplerState(declaration->assignment)) -// { -// return false; -// } -// } - else if (!ParseExpression(declaration->assignment)) - { + // else if (IsSamplerType(declaration->type.baseType)) // TODO: should be for SamplerStateBlock, not Sampler + // { + // if (!ParseSamplerState(declaration->assignment)) + // { + // return false; + // } + // } + else if (!ParseExpression(declaration->assignment)) { return false; } } @@ -2752,16 +2599,13 @@ bool HLSLParser::ParseDeclarationAssignment(HLSLDeclaration* declaration) bool HLSLParser::ParseFieldDeclaration(HLSLStructField*& field) { - field = m_tree->AddNode( GetFileName(), GetLineNumber() ); - if (!ExpectDeclaration(false, field->type, field->name)) - { + field = m_tree->AddNode(GetFileName(), GetLineNumber()); + if (!ExpectDeclaration(false, field->type, field->name)) { return false; } // Handle optional semantics. - if (Accept(':')) - { - if (!ExpectIdentifier(field->semantic)) - { + if (Accept(':')) { + if (!ExpectIdentifier(field->semantic)) { return false; } } @@ -2795,8 +2639,7 @@ bool HLSLParser::ParseFieldDeclaration(HLSLStructField*& field) bool HLSLParser::CheckTypeCast(const HLSLType& srcType, const HLSLType& dstType) { - if (GetTypeCastRank(m_tree, srcType, dstType) == -1) - { + if (GetTypeCastRank(m_tree, srcType, dstType) == -1) { const char* srcTypeName = GetTypeNameHLSL(srcType); const char* dstTypeName = GetTypeNameHLSL(dstType); m_tokenizer.Error("Cannot implicitly convert from '%s' to '%s'", srcTypeName, dstTypeName); @@ -2807,17 +2650,14 @@ bool HLSLParser::CheckTypeCast(const HLSLType& srcType, const HLSLType& dstType) bool HLSLParser::ParseExpression(HLSLExpression*& expression) { - if (!ParseBinaryExpression(0, expression)) - { + if (!ParseBinaryExpression(0, expression)) { return false; } HLSLBinaryOp assignOp; - if (AcceptAssign(assignOp)) - { + if (AcceptAssign(assignOp)) { HLSLExpression* expression2 = NULL; - if (!ParseExpression(expression2)) - { + if (!ParseExpression(expression2)) { return false; } HLSLBinaryExpression* binaryExpression = m_tree->AddNode(expression->fileName, expression->line); @@ -2828,8 +2668,7 @@ bool HLSLParser::ParseExpression(HLSLExpression*& expression) // However, for our usage of the types it should be sufficient. binaryExpression->expressionType = expression->expressionType; - if (!CheckTypeCast(expression2->expressionType, expression->expressionType)) - { + if (!CheckTypeCast(expression2->expressionType, expression->expressionType)) { const char* srcTypeName = GetTypeNameHLSL(expression2->expressionType); const char* dstTypeName = GetTypeNameHLSL(expression->expressionType); m_tokenizer.Error("Cannot implicitly convert from '%s' to '%s'", srcTypeName, dstTypeName); @@ -2845,28 +2684,56 @@ bool HLSLParser::ParseExpression(HLSLExpression*& expression) bool HLSLParser::AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp) { int token = m_tokenizer.GetToken(); - switch (token) - { - case HLSLToken_LogicalAnd: binaryOp = HLSLBinaryOp_And; break; - case HLSLToken_LogicalOr: binaryOp = HLSLBinaryOp_Or; break; - case '+': binaryOp = HLSLBinaryOp_Add; break; - case '-': binaryOp = HLSLBinaryOp_Sub; break; - case '*': binaryOp = HLSLBinaryOp_Mul; break; - case '/': binaryOp = HLSLBinaryOp_Div; break; - case '<': binaryOp = HLSLBinaryOp_Less; break; - case '>': binaryOp = HLSLBinaryOp_Greater; break; - case HLSLToken_LessEqual: binaryOp = HLSLBinaryOp_LessEqual; break; - case HLSLToken_GreaterEqual: binaryOp = HLSLBinaryOp_GreaterEqual; break; - case HLSLToken_EqualEqual: binaryOp = HLSLBinaryOp_Equal; break; - case HLSLToken_NotEqual: binaryOp = HLSLBinaryOp_NotEqual; break; - case '&': binaryOp = HLSLBinaryOp_BitAnd; break; - case '|': binaryOp = HLSLBinaryOp_BitOr; break; - case '^': binaryOp = HLSLBinaryOp_BitXor; break; - default: - return false; + switch (token) { + case HLSLToken_LogicalAnd: + binaryOp = HLSLBinaryOp_And; + break; + case HLSLToken_LogicalOr: + binaryOp = HLSLBinaryOp_Or; + break; + case '+': + binaryOp = HLSLBinaryOp_Add; + break; + case '-': + binaryOp = HLSLBinaryOp_Sub; + break; + case '*': + binaryOp = HLSLBinaryOp_Mul; + break; + case '/': + binaryOp = HLSLBinaryOp_Div; + break; + case '<': + binaryOp = HLSLBinaryOp_Less; + break; + case '>': + binaryOp = HLSLBinaryOp_Greater; + break; + case HLSLToken_LessEqual: + binaryOp = HLSLBinaryOp_LessEqual; + break; + case HLSLToken_GreaterEqual: + binaryOp = HLSLBinaryOp_GreaterEqual; + break; + case HLSLToken_EqualEqual: + binaryOp = HLSLBinaryOp_Equal; + break; + case HLSLToken_NotEqual: + binaryOp = HLSLBinaryOp_NotEqual; + break; + case '&': + binaryOp = HLSLBinaryOp_BitAnd; + break; + case '|': + binaryOp = HLSLBinaryOp_BitOr; + break; + case '^': + binaryOp = HLSLBinaryOp_BitXor; + break; + default: + return false; } - if (_binaryOpPriority[binaryOp] > priority) - { + if (_binaryOpPriority[binaryOp] > priority) { m_tokenizer.Next(); return true; } @@ -2876,32 +2743,25 @@ bool HLSLParser::AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp) bool HLSLParser::AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp) { int token = m_tokenizer.GetToken(); - if (token == HLSLToken_PlusPlus) - { + if (token == HLSLToken_PlusPlus) { unaryOp = pre ? HLSLUnaryOp_PreIncrement : HLSLUnaryOp_PostIncrement; } - else if (token == HLSLToken_MinusMinus) - { + else if (token == HLSLToken_MinusMinus) { unaryOp = pre ? HLSLUnaryOp_PreDecrement : HLSLUnaryOp_PostDecrement; } - else if (pre && token == '-') - { + else if (pre && token == '-') { unaryOp = HLSLUnaryOp_Negative; } - else if (pre && token == '+') - { + else if (pre && token == '+') { unaryOp = HLSLUnaryOp_Positive; } - else if (pre && token == '!') - { + else if (pre && token == '!') { unaryOp = HLSLUnaryOp_Not; } - else if (pre && token == '~') - { + else if (pre && token == '~') { unaryOp = HLSLUnaryOp_Not; } - else - { + else { return false; } m_tokenizer.Next(); @@ -2910,28 +2770,22 @@ bool HLSLParser::AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp) bool HLSLParser::AcceptAssign(HLSLBinaryOp& binaryOp) { - if (Accept('=')) - { + if (Accept('=')) { binaryOp = HLSLBinaryOp_Assign; } - else if (Accept(HLSLToken_PlusEqual)) - { + else if (Accept(HLSLToken_PlusEqual)) { binaryOp = HLSLBinaryOp_AddAssign; } - else if (Accept(HLSLToken_MinusEqual)) - { + else if (Accept(HLSLToken_MinusEqual)) { binaryOp = HLSLBinaryOp_SubAssign; - } - else if (Accept(HLSLToken_TimesEqual)) - { + } + else if (Accept(HLSLToken_TimesEqual)) { binaryOp = HLSLBinaryOp_MulAssign; - } - else if (Accept(HLSLToken_DivideEqual)) - { + } + else if (Accept(HLSLToken_DivideEqual)) { binaryOp = HLSLBinaryOp_DivAssign; - } - else - { + } + else { return false; } return true; @@ -2940,89 +2794,77 @@ bool HLSLParser::AcceptAssign(HLSLBinaryOp& binaryOp) bool HLSLParser::ParseBinaryExpression(int priority, HLSLExpression*& expression) { const char* fileName = GetFileName(); - int line = GetLineNumber(); + int line = GetLineNumber(); bool needsEndParen; - if (!ParseTerminalExpression(expression, needsEndParen)) - { + if (!ParseTerminalExpression(expression, needsEndParen)) { return false; } - // reset priority cause openned parenthesis - if( needsEndParen ) - priority = 0; + // reset priority cause openned parenthesis + if (needsEndParen) + priority = 0; - while (1) - { + while (1) { HLSLBinaryOp binaryOp; - if (AcceptBinaryOperator(priority, binaryOp)) - { - + if (AcceptBinaryOperator(priority, binaryOp)) { HLSLExpression* expression2 = NULL; - ASSERT( binaryOp < sizeof(_binaryOpPriority) / sizeof(int) ); - if (!ParseBinaryExpression(_binaryOpPriority[binaryOp], expression2)) - { + ASSERT(binaryOp < sizeof(_binaryOpPriority) / sizeof(int)); + if (!ParseBinaryExpression(_binaryOpPriority[binaryOp], expression2)) { return false; } HLSLBinaryExpression* binaryExpression = m_tree->AddNode(fileName, line); - binaryExpression->binaryOp = binaryOp; + binaryExpression->binaryOp = binaryOp; binaryExpression->expression1 = expression; binaryExpression->expression2 = expression2; - if (!GetBinaryOpResultType( binaryOp, expression->expressionType, expression2->expressionType, binaryExpression->expressionType )) - { - const char* typeName1 = GetTypeNameHLSL( binaryExpression->expression1->expressionType ); - const char* typeName2 = GetTypeNameHLSL( binaryExpression->expression2->expressionType ); + if (!GetBinaryOpResultType(binaryOp, expression->expressionType, expression2->expressionType, binaryExpression->expressionType)) { + const char* typeName1 = GetTypeNameHLSL(binaryExpression->expression1->expressionType); + const char* typeName2 = GetTypeNameHLSL(binaryExpression->expression2->expressionType); m_tokenizer.Error("binary '%s' : no global operator found which takes types '%s' and '%s' (or there is no acceptable conversion)", - GetBinaryOpName(binaryOp), typeName1, typeName2); + GetBinaryOpName(binaryOp), typeName1, typeName2); return false; } - + // Propagate constness. binaryExpression->expressionType.flags = (expression->expressionType.flags | expression2->expressionType.flags) & HLSLTypeFlag_Const; - + expression = binaryExpression; } - else if (_conditionalOpPriority > priority && Accept('?')) - { - + else if (_conditionalOpPriority > priority && Accept('?')) { HLSLConditionalExpression* conditionalExpression = m_tree->AddNode(fileName, line); conditionalExpression->condition = expression; - + HLSLExpression* expression1 = NULL; HLSLExpression* expression2 = NULL; - if (!ParseBinaryExpression(_conditionalOpPriority, expression1) || !Expect(':') || !ParseBinaryExpression(_conditionalOpPriority, expression2)) - { + if (!ParseBinaryExpression(_conditionalOpPriority, expression1) || !Expect(':') || !ParseBinaryExpression(_conditionalOpPriority, expression2)) { return false; } // Make sure both cases have compatible types. - if (GetTypeCastRank(m_tree, expression1->expressionType, expression2->expressionType) == -1) - { + if (GetTypeCastRank(m_tree, expression1->expressionType, expression2->expressionType) == -1) { const char* srcTypeName = GetTypeNameHLSL(expression2->expressionType); const char* dstTypeName = GetTypeNameHLSL(expression1->expressionType); m_tokenizer.Error("':' no possible conversion from from '%s' to '%s'", srcTypeName, dstTypeName); return false; } - conditionalExpression->trueExpression = expression1; + conditionalExpression->trueExpression = expression1; conditionalExpression->falseExpression = expression2; - conditionalExpression->expressionType = expression1->expressionType; + conditionalExpression->expressionType = expression1->expressionType; expression = conditionalExpression; } - else - { + else { break; } - if( needsEndParen ) - { - if( !Expect( ')' ) ) - return false; - needsEndParen = false; - } + if (needsEndParen) { + if (!Expect(')')) + return false; + needsEndParen = false; + } } return !needsEndParen || Expect(')'); @@ -3031,16 +2873,15 @@ bool HLSLParser::ParseBinaryExpression(int priority, HLSLExpression*& expression bool HLSLParser::ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseType type, const char* typeName) { const char* fileName = GetFileName(); - int line = GetLineNumber(); + int line = GetLineNumber(); HLSLConstructorExpression* constructorExpression = m_tree->AddNode(fileName, line); constructorExpression->type.baseType = type; constructorExpression->type.typeName = typeName; int numArguments = 0; - if (!ParseExpressionList(')', false, constructorExpression->argument, numArguments)) - { + if (!ParseExpressionList(')', false, constructorExpression->argument, numArguments)) { return false; - } + } constructorExpression->expressionType = constructorExpression->type; constructorExpression->expressionType.flags = HLSLTypeFlag_Const; expression = constructorExpression; @@ -3050,53 +2891,44 @@ bool HLSLParser::ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseTy bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& needsEndParen) { const char* fileName = GetFileName(); - int line = GetLineNumber(); + int line = GetLineNumber(); needsEndParen = false; HLSLUnaryOp unaryOp; - if (AcceptUnaryOperator(true, unaryOp)) - { + if (AcceptUnaryOperator(true, unaryOp)) { HLSLUnaryExpression* unaryExpression = m_tree->AddNode(fileName, line); unaryExpression->unaryOp = unaryOp; - if (!ParseTerminalExpression(unaryExpression->expression, needsEndParen)) - { + if (!ParseTerminalExpression(unaryExpression->expression, needsEndParen)) { return false; } - if (unaryOp == HLSLUnaryOp_BitNot) - { - if (!IsIntegerType(unaryExpression->expression->expressionType.baseType)) - { - const char * typeName = GetTypeNameHLSL(unaryExpression->expression->expressionType); + if (unaryOp == HLSLUnaryOp_BitNot) { + if (!IsIntegerType(unaryExpression->expression->expressionType.baseType)) { + const char* typeName = GetTypeNameHLSL(unaryExpression->expression->expressionType); m_tokenizer.Error("unary '~' : no global operator found which takes type '%s' (or there is no acceptable conversion)", typeName); return false; } } - if (unaryOp == HLSLUnaryOp_Not) - { + if (unaryOp == HLSLUnaryOp_Not) { unaryExpression->expressionType = HLSLType(HLSLBaseType_Bool); - + // Propagate constness. unaryExpression->expressionType.flags = unaryExpression->expression->expressionType.flags & HLSLTypeFlag_Const; } - else - { + else { unaryExpression->expressionType = unaryExpression->expression->expressionType; } expression = unaryExpression; return true; } - + // Expressions inside parenthesis or casts. - if (Accept('(')) - { + if (Accept('(')) { // Check for a casting operator. HLSLType type; - if (AcceptType(false, type)) - { + if (AcceptType(false, type)) { // This is actually a type constructor like (float2(... - if (Accept('(')) - { + if (Accept('(')) { needsEndParen = true; return ParsePartialConstructor(expression, type.baseType, type.typeName); } @@ -3106,43 +2938,38 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need castingExpression->expressionType = type; return Expect(')') && ParseExpression(castingExpression->expression); } - - if (!ParseExpression(expression) || !Expect(')')) - { + + if (!ParseExpression(expression) || !Expect(')')) { return false; } } - else - { + else { // Terminal values. float fValue = 0.0f; - int iValue = 0; - + int iValue = 0; + // literals - if (AcceptFloat(fValue)) - { + if (AcceptFloat(fValue)) { HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); - literalExpression->type = HLSLBaseType_Float; + literalExpression->type = HLSLBaseType_Float; literalExpression->fValue = fValue; literalExpression->expressionType.baseType = literalExpression->type; literalExpression->expressionType.flags = HLSLTypeFlag_Const; expression = literalExpression; return true; } - if(AcceptHalf(fValue)) - { - HLSLLiteralExpression* literalExpression = m_tree->AddNode( fileName, line ); - literalExpression->type = HLSLBaseType_Half; - literalExpression->fValue = fValue; - literalExpression->expressionType.baseType = literalExpression->type; - literalExpression->expressionType.flags = HLSLTypeFlag_Const; - expression = literalExpression; - return true; - } - if (AcceptInt(iValue)) - { + if (AcceptHalf(fValue)) { + HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); + literalExpression->type = HLSLBaseType_Half; + literalExpression->fValue = fValue; + literalExpression->expressionType.baseType = literalExpression->type; + literalExpression->expressionType.flags = HLSLTypeFlag_Const; + expression = literalExpression; + return true; + } + if (AcceptInt(iValue)) { HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); - literalExpression->type = HLSLBaseType_Int; + literalExpression->type = HLSLBaseType_Int; literalExpression->iValue = iValue; literalExpression->expressionType.baseType = literalExpression->type; literalExpression->expressionType.flags = HLSLTypeFlag_Const; @@ -3150,22 +2977,20 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need return true; } // TODO: need uint, u/short, double - + // boolean - if (Accept(HLSLToken_True)) - { + if (Accept(HLSLToken_True)) { HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); - literalExpression->type = HLSLBaseType_Bool; + literalExpression->type = HLSLBaseType_Bool; literalExpression->bValue = true; literalExpression->expressionType.baseType = literalExpression->type; literalExpression->expressionType.flags = HLSLTypeFlag_Const; expression = literalExpression; return true; } - if (Accept(HLSLToken_False)) - { + if (Accept(HLSLToken_False)) { HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); - literalExpression->type = HLSLBaseType_Bool; + literalExpression->type = HLSLBaseType_Bool; literalExpression->bValue = false; literalExpression->expressionType.baseType = literalExpression->type; literalExpression->expressionType.flags = HLSLTypeFlag_Const; @@ -3175,47 +3000,37 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need // Type constructor. HLSLType type; - if (AcceptType(/*allowVoid=*/false, type)) - { + if (AcceptType(/*allowVoid=*/false, type)) { Expect('('); - if (!ParsePartialConstructor(expression, type.baseType, type.typeName)) - { + if (!ParsePartialConstructor(expression, type.baseType, type.typeName)) { return false; } } - else - { + else { HLSLIdentifierExpression* identifierExpression = m_tree->AddNode(fileName, line); - if (!ExpectIdentifier(identifierExpression->name)) - { + if (!ExpectIdentifier(identifierExpression->name)) { return false; } bool undeclaredIdentifier = false; - + const HLSLType* identifierType = FindVariable(identifierExpression->name, identifierExpression->global); - if (identifierType != NULL) - { + if (identifierType != NULL) { identifierExpression->expressionType = *identifierType; } - else - { - if (GetIsFunction(identifierExpression->name)) - { + else { + if (GetIsFunction(identifierExpression->name)) { // Functions are always global scope. // TODO: what about member functions? identifierExpression->global = true; } - else - { + else { undeclaredIdentifier = true; } } - if (undeclaredIdentifier) - { - if (m_allowUndeclaredIdentifiers) - { + if (undeclaredIdentifier) { + if (m_allowUndeclaredIdentifiers) { HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); literalExpression->bValue = false; literalExpression->type = HLSLBaseType_Bool; @@ -3223,8 +3038,7 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need literalExpression->expressionType.flags = HLSLTypeFlag_Const; expression = literalExpression; } - else - { + else { m_tokenizer.Error("Undeclared identifier '%s'", identifierExpression->name); return false; } @@ -3236,14 +3050,12 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need } bool done = false; - while (!done) - { + while (!done) { done = true; // Post fix unary operator HLSLUnaryOp unaryOp2; - while (AcceptUnaryOperator(false, unaryOp2)) - { + while (AcceptUnaryOperator(false, unaryOp2)) { HLSLUnaryExpression* unaryExpression = m_tree->AddNode(fileName, line); unaryExpression->unaryOp = unaryOp2; unaryExpression->expression = expression; @@ -3253,204 +3065,188 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need } // Member access operator. - while (Accept('.')) - { + while (Accept('.')) { // member or member function const char* text = NULL; - if (!ExpectIdentifier(text)) - { + if (!ExpectIdentifier(text)) { return false; } - + //const HLSLMemberFuction* memberFunction = FindMemberFunction(text); //if (function != NULL) { // check parent type, and args to see if it's a match - + // copied from intrinsic lookup at end - if (Accept('(')) - { + if (Accept('(')) { HLSLMemberFunctionCall* functionCall = m_tree->AddNode(fileName, line); - + done = false; - + // parse the args - if (!ParseExpressionList(')', false, functionCall->argument, functionCall->numArguments)) - { + if (!ParseExpressionList(')', false, functionCall->argument, functionCall->numArguments)) { return false; } - - if (expression->nodeType != HLSLNodeType_IdentifierExpression) - { + + if (expression->nodeType != HLSLNodeType_IdentifierExpression) { m_tokenizer.Error("Expected function identifier"); return false; } - + // This is "tex" of tex.Sample(...) const HLSLIdentifierExpression* identifierExpression = static_cast(expression); - + // TODO: what if it's a chain of member functions? functionCall->memberIdentifier = identifierExpression; - + // TODO: lookup texture, buffer, struct for identiferExpression // TODO: prob need formatType to match half/float return type. - + // TODO: could lookup only float memberFunctions if spirv // which can't handle fp16 samplers. - + // This is matching to a member function (mostly intrinsics) - const HLSLFunction* function = MatchFunctionCall( functionCall, text, &identifierExpression->expressionType ); - if (function == NULL) - { + const HLSLFunction* function = MatchFunctionCall(functionCall, text, &identifierExpression->expressionType); + if (function == NULL) { return false; } - + functionCall->function = function; functionCall->expressionType = function->returnType; - + // or is it the identiferExpression? expression = functionCall; - + // for now don't allow chained member functions return true; } - - } - //else - { - // member variable - HLSLMemberAccess* memberAccess = m_tree->AddNode(fileName, line); - memberAccess->object = expression; - memberAccess->field = text; - - if (!GetMemberType(expression->expressionType, memberAccess)) - { - m_tokenizer.Error("Couldn't access '%s'", memberAccess->field); - - // this leaks memberAccess allocated above, but - // all allocated from single allocator, so just free/reset that - return false; - } - expression = memberAccess; - done = false; - } + } + //else + { + // member variable + HLSLMemberAccess* memberAccess = m_tree->AddNode(fileName, line); + memberAccess->object = expression; + memberAccess->field = text; + + if (!GetMemberType(expression->expressionType, memberAccess)) { + m_tokenizer.Error("Couldn't access '%s'", memberAccess->field); + + // this leaks memberAccess allocated above, but + // all allocated from single allocator, so just free/reset that + return false; + } + expression = memberAccess; + done = false; + } } // Handle array access. - while (Accept('[')) - { + while (Accept('[')) { HLSLArrayAccess* arrayAccess = m_tree->AddNode(fileName, line); arrayAccess->array = expression; - if (!ParseExpression(arrayAccess->index) || !Expect(']')) - { + if (!ParseExpression(arrayAccess->index) || !Expect(']')) { return false; } - if (expression->expressionType.baseType == HLSLBaseType_UserDefined) - { + if (expression->expressionType.baseType == HLSLBaseType_UserDefined) { // some buffer types (!IsGlobalFields) have array notation arrayAccess->expressionType.baseType = HLSLBaseType_UserDefined; arrayAccess->expressionType.typeName = expression->expressionType.typeName; - arrayAccess->expressionType.array = true; + arrayAccess->expressionType.array = true; arrayAccess->expressionType.arraySize = NULL; - } - else if (expression->expressionType.array) - { + else if (expression->expressionType.array) { arrayAccess->expressionType = expression->expressionType; - arrayAccess->expressionType.array = false; + arrayAccess->expressionType.array = false; arrayAccess->expressionType.arraySize = NULL; } - else - { - switch (expression->expressionType.baseType) - { - case HLSLBaseType_Float2: - case HLSLBaseType_Float3: - case HLSLBaseType_Float4: - arrayAccess->expressionType.baseType = HLSLBaseType_Float; - break; - case HLSLBaseType_Float2x2: - arrayAccess->expressionType.baseType = HLSLBaseType_Float2; - break; - case HLSLBaseType_Float3x3: - arrayAccess->expressionType.baseType = HLSLBaseType_Float3; - break; - case HLSLBaseType_Float4x4: - arrayAccess->expressionType.baseType = HLSLBaseType_Float4; - break; - - case HLSLBaseType_Half2: - case HLSLBaseType_Half3: - case HLSLBaseType_Half4: - arrayAccess->expressionType.baseType = HLSLBaseType_Half; - break; - case HLSLBaseType_Half2x2: - arrayAccess->expressionType.baseType = HLSLBaseType_Half2; - break; - case HLSLBaseType_Half3x3: - arrayAccess->expressionType.baseType = HLSLBaseType_Half3; - break; - case HLSLBaseType_Half4x4: - arrayAccess->expressionType.baseType = HLSLBaseType_Half4; - break; - - case HLSLBaseType_Double2: - case HLSLBaseType_Double3: - case HLSLBaseType_Double4: - arrayAccess->expressionType.baseType = HLSLBaseType_Double; - break; - case HLSLBaseType_Double2x2: - arrayAccess->expressionType.baseType = HLSLBaseType_Double2; - break; - case HLSLBaseType_Double3x3: - arrayAccess->expressionType.baseType = HLSLBaseType_Double3; - break; - case HLSLBaseType_Double4x4: - arrayAccess->expressionType.baseType = HLSLBaseType_Double4; - break; - - - case HLSLBaseType_Int2: - case HLSLBaseType_Int3: - case HLSLBaseType_Int4: - arrayAccess->expressionType.baseType = HLSLBaseType_Int; - break; - case HLSLBaseType_Uint2: - case HLSLBaseType_Uint3: - case HLSLBaseType_Uint4: - arrayAccess->expressionType.baseType = HLSLBaseType_Uint; - break; - case HLSLBaseType_Bool2: - case HLSLBaseType_Bool3: - case HLSLBaseType_Bool4: - arrayAccess->expressionType.baseType = HLSLBaseType_Bool; - break; - case HLSLBaseType_Ushort2: - case HLSLBaseType_Ushort3: - case HLSLBaseType_Ushort4: - arrayAccess->expressionType.baseType = HLSLBaseType_Ushort; - break; - case HLSLBaseType_Short2: - case HLSLBaseType_Short3: - case HLSLBaseType_Short4: - arrayAccess->expressionType.baseType = HLSLBaseType_Short; - break; - case HLSLBaseType_Ulong2: - case HLSLBaseType_Ulong3: - case HLSLBaseType_Ulong4: - arrayAccess->expressionType.baseType = HLSLBaseType_Ulong; - break; - case HLSLBaseType_Long2: - case HLSLBaseType_Long3: - case HLSLBaseType_Long4: - arrayAccess->expressionType.baseType = HLSLBaseType_Long; - break; - - // TODO: u/char - default: - m_tokenizer.Error("array, matrix, vector, or indexable object type expected in index expression"); - return false; + else { + switch (expression->expressionType.baseType) { + case HLSLBaseType_Float2: + case HLSLBaseType_Float3: + case HLSLBaseType_Float4: + arrayAccess->expressionType.baseType = HLSLBaseType_Float; + break; + case HLSLBaseType_Float2x2: + arrayAccess->expressionType.baseType = HLSLBaseType_Float2; + break; + case HLSLBaseType_Float3x3: + arrayAccess->expressionType.baseType = HLSLBaseType_Float3; + break; + case HLSLBaseType_Float4x4: + arrayAccess->expressionType.baseType = HLSLBaseType_Float4; + break; + + case HLSLBaseType_Half2: + case HLSLBaseType_Half3: + case HLSLBaseType_Half4: + arrayAccess->expressionType.baseType = HLSLBaseType_Half; + break; + case HLSLBaseType_Half2x2: + arrayAccess->expressionType.baseType = HLSLBaseType_Half2; + break; + case HLSLBaseType_Half3x3: + arrayAccess->expressionType.baseType = HLSLBaseType_Half3; + break; + case HLSLBaseType_Half4x4: + arrayAccess->expressionType.baseType = HLSLBaseType_Half4; + break; + + case HLSLBaseType_Double2: + case HLSLBaseType_Double3: + case HLSLBaseType_Double4: + arrayAccess->expressionType.baseType = HLSLBaseType_Double; + break; + case HLSLBaseType_Double2x2: + arrayAccess->expressionType.baseType = HLSLBaseType_Double2; + break; + case HLSLBaseType_Double3x3: + arrayAccess->expressionType.baseType = HLSLBaseType_Double3; + break; + case HLSLBaseType_Double4x4: + arrayAccess->expressionType.baseType = HLSLBaseType_Double4; + break; + + case HLSLBaseType_Int2: + case HLSLBaseType_Int3: + case HLSLBaseType_Int4: + arrayAccess->expressionType.baseType = HLSLBaseType_Int; + break; + case HLSLBaseType_Uint2: + case HLSLBaseType_Uint3: + case HLSLBaseType_Uint4: + arrayAccess->expressionType.baseType = HLSLBaseType_Uint; + break; + case HLSLBaseType_Bool2: + case HLSLBaseType_Bool3: + case HLSLBaseType_Bool4: + arrayAccess->expressionType.baseType = HLSLBaseType_Bool; + break; + case HLSLBaseType_Ushort2: + case HLSLBaseType_Ushort3: + case HLSLBaseType_Ushort4: + arrayAccess->expressionType.baseType = HLSLBaseType_Ushort; + break; + case HLSLBaseType_Short2: + case HLSLBaseType_Short3: + case HLSLBaseType_Short4: + arrayAccess->expressionType.baseType = HLSLBaseType_Short; + break; + case HLSLBaseType_Ulong2: + case HLSLBaseType_Ulong3: + case HLSLBaseType_Ulong4: + arrayAccess->expressionType.baseType = HLSLBaseType_Ulong; + break; + case HLSLBaseType_Long2: + case HLSLBaseType_Long3: + case HLSLBaseType_Long4: + arrayAccess->expressionType.baseType = HLSLBaseType_Long; + break; + + // TODO: u/char + default: + m_tokenizer.Error("array, matrix, vector, or indexable object type expected in index expression"); + return false; } } @@ -3461,69 +3257,56 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need // Handle function calls. Note, HLSL functions aren't like C function // pointers -- we can only directly call on an identifier, not on an // expression. - if (Accept('(')) - { + if (Accept('(')) { HLSLFunctionCall* functionCall = m_tree->AddNode(fileName, line); done = false; - if (!ParseExpressionList(')', false, functionCall->argument, functionCall->numArguments)) - { + if (!ParseExpressionList(')', false, functionCall->argument, functionCall->numArguments)) { return false; } - - if (expression->nodeType != HLSLNodeType_IdentifierExpression) - { + + if (expression->nodeType != HLSLNodeType_IdentifierExpression) { m_tokenizer.Error("Expected function identifier"); return false; } - + const HLSLIdentifierExpression* identifierExpression = static_cast(expression); - const HLSLFunction* function = MatchFunctionCall( functionCall, identifierExpression->name ); - if (function == NULL) - { + const HLSLFunction* function = MatchFunctionCall(functionCall, identifierExpression->name); + if (function == NULL) { return false; } - + functionCall->function = function; functionCall->expressionType = function->returnType; expression = functionCall; } - } return true; - } bool HLSLParser::ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpression*& firstExpression, int& numExpressions) { numExpressions = 0; HLSLExpression* lastExpression = NULL; - while (!Accept(endToken)) - { - if (CheckForUnexpectedEndOfStream(endToken)) - { + while (!Accept(endToken)) { + if (CheckForUnexpectedEndOfStream(endToken)) { return false; } - if (numExpressions > 0 && !Expect(',')) - { + if (numExpressions > 0 && !Expect(',')) { return false; } // It is acceptable for the final element in the initialization list to // have a trailing comma in some cases, like array initialization such as {1, 2, 3,} - if (allowEmptyEnd && Accept(endToken)) - { + if (allowEmptyEnd && Accept(endToken)) { break; } HLSLExpression* expression = NULL; - if (!ParseExpression(expression)) - { + if (!ParseExpression(expression)) { return false; } - if (firstExpression == NULL) - { + if (firstExpression == NULL) { firstExpression = expression; } - else - { + else { lastExpression->nextExpression = expression; } lastExpression = expression; @@ -3535,64 +3318,65 @@ bool HLSLParser::ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpre bool HLSLParser::ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments, int& numOutputArguments) { const char* fileName = GetFileName(); - int line = GetLineNumber(); - + int line = GetLineNumber(); + HLSLArgument* lastArgument = NULL; numArguments = 0; - while (!Accept(')')) - { - if (CheckForUnexpectedEndOfStream(')')) - { + while (!Accept(')')) { + if (CheckForUnexpectedEndOfStream(')')) { return false; } - if (numArguments > 0 && !Expect(',')) - { + if (numArguments > 0 && !Expect(',')) { return false; } - HLSLArgument* argument = m_tree->AddNode(fileName, line); - - // what is unifor modifier ? - if (Accept(HLSLToken_Uniform)) { argument->modifier = HLSLArgumentModifier_Uniform; } - - else if (Accept(HLSLToken_In)) { argument->modifier = HLSLArgumentModifier_In; } - else if (Accept(HLSLToken_Out)) { argument->modifier = HLSLArgumentModifier_Out; } - else if (Accept(HLSLToken_InOut)) { argument->modifier = HLSLArgumentModifier_Inout; } - else if (Accept(HLSLToken_Const)) { argument->modifier = HLSLArgumentModifier_Const; } - - if (!ExpectDeclaration(/*allowUnsizedArray=*/true, argument->type, argument->name)) - { + HLSLArgument* argument = m_tree->AddNode(fileName, line); + + // what is unifor modifier ? + if (Accept(HLSLToken_Uniform)) { + argument->modifier = HLSLArgumentModifier_Uniform; + } + + else if (Accept(HLSLToken_In)) { + argument->modifier = HLSLArgumentModifier_In; + } + else if (Accept(HLSLToken_Out)) { + argument->modifier = HLSLArgumentModifier_Out; + } + else if (Accept(HLSLToken_InOut)) { + argument->modifier = HLSLArgumentModifier_Inout; + } + else if (Accept(HLSLToken_Const)) { + argument->modifier = HLSLArgumentModifier_Const; + } + + if (!ExpectDeclaration(/*allowUnsizedArray=*/true, argument->type, argument->name)) { return false; } - DeclareVariable( argument->name, argument->type ); + DeclareVariable(argument->name, argument->type); // Optional semantic. - if (Accept(':') && !ExpectIdentifier(argument->semantic)) - { + if (Accept(':') && !ExpectIdentifier(argument->semantic)) { return false; } - if (Accept('=') && !ParseExpression(argument->defaultValue)) - { + if (Accept('=') && !ParseExpression(argument->defaultValue)) { // @@ Print error! return false; } - if (lastArgument != NULL) - { + if (lastArgument != NULL) { lastArgument->nextArgument = argument; } - else - { + else { firstArgument = argument; } lastArgument = argument; ++numArguments; - if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) - { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) { ++numOutputArguments; } } @@ -3810,7 +3594,7 @@ const EffectState* GetEffectState(const char* name, bool isSamplerState, bool is { const EffectState* validStates = effectStates; int count = sizeof(effectStates)/sizeof(effectStates[0]); - + if (isPipeline) { validStates = pipelineStates; @@ -3826,7 +3610,7 @@ const EffectState* GetEffectState(const char* name, bool isSamplerState, bool is // Case insensitive comparison. for (int i = 0; i < count; i++) { - if (String_EqualNoCase(name, validStates[i].name)) + if (String_EqualNoCase(name, validStates[i].name)) { return &validStates[i]; } @@ -3838,12 +3622,12 @@ const EffectState* GetEffectState(const char* name, bool isSamplerState, bool is static const EffectStateValue* GetStateValue(const char* name, const EffectState* state) { // Case insensitive comparison. - for (int i = 0; ; i++) + for (int i = 0; ; i++) { const EffectStateValue & value = state->values[i]; if (value.name == NULL) break; - if (String_EqualNoCase(name, value.name)) + if (String_EqualNoCase(name, value.name)) { return &value; } @@ -3909,7 +3693,7 @@ bool HLSLParser::ParseStateValue(const EffectState * state, HLSLStateAssignment* const bool expectsFloat = state->values == floatValues; const bool expectsBoolean = state->values == booleanValues; - if (!expectsExpression && !expectsInteger && !expectsFloat && !expectsBoolean) + if (!expectsExpression && !expectsInteger && !expectsFloat && !expectsBoolean) { if (m_tokenizer.GetToken() != HLSLToken_Identifier) { @@ -3986,7 +3770,7 @@ bool HLSLParser::ParseStateValue(const EffectState * state, HLSLStateAssignment* return false; } } - else + else { // Expect one of the allowed values. const EffectStateValue * stateValue = GetStateValue(m_tokenizer.GetIdentifier(), state); @@ -4042,17 +3826,17 @@ bool HLSLParser::ParseStateAssignment(HLSLStateAssignment*& stateAssignment, boo bool HLSLParser::ParseAttributeList(HLSLAttribute*& firstAttribute) { const char* fileName = GetFileName(); - int line = GetLineNumber(); - - HLSLAttribute * lastAttribute = firstAttribute; + int line = GetLineNumber(); + + HLSLAttribute* lastAttribute = firstAttribute; do { - const char * identifier = NULL; + const char* identifier = NULL; if (!ExpectIdentifier(identifier)) { return false; } - HLSLAttribute * attribute = m_tree->AddNode(fileName, line); - + HLSLAttribute* attribute = m_tree->AddNode(fileName, line); + if (String_Equal(identifier, "unroll")) attribute->attributeType = HLSLAttributeType_Unroll; else if (String_Equal(identifier, "flatten")) @@ -4061,20 +3845,18 @@ bool HLSLParser::ParseAttributeList(HLSLAttribute*& firstAttribute) attribute->attributeType = HLSLAttributeType_Branch; else if (String_Equal(identifier, "nofastmath")) attribute->attributeType = HLSLAttributeType_NoFastMath; - + // @@ parse arguments, () not required if attribute constructor has no arguments. - if (firstAttribute == NULL) - { + if (firstAttribute == NULL) { firstAttribute = attribute; } - else - { + else { lastAttribute->nextAttribute = attribute; } lastAttribute = attribute; - - } while(Accept(',')); + + } while (Accept(',')); return true; } @@ -4089,19 +3871,19 @@ bool HLSLParser::ParseAttributeList(HLSLAttribute*& firstAttribute) // [A(a)] statement; bool HLSLParser::ParseAttributeBlock(HLSLAttribute*& attribute) { - HLSLAttribute ** lastAttribute = &attribute; - while (*lastAttribute != NULL) { lastAttribute = &(*lastAttribute)->nextAttribute; } + HLSLAttribute** lastAttribute = &attribute; + while (*lastAttribute != NULL) { + lastAttribute = &(*lastAttribute)->nextAttribute; + } - if (!Accept('[')) - { + if (!Accept('[')) { return false; } // Parse list of attribute constructors. ParseAttributeList(*lastAttribute); - if (!Expect(']')) - { + if (!Expect(']')) { return false; } @@ -4151,31 +3933,24 @@ bool HLSLParser::ParseStage(HLSLStatement*& statement) } */ - - bool HLSLParser::Parse(HLSLTree* tree, const HLSLParserOptions& options) { m_tree = tree; m_options = options; - + HLSLRoot* root = m_tree->GetRoot(); HLSLStatement* lastStatement = NULL; - while (!Accept(HLSLToken_EndOfStream)) - { + while (!Accept(HLSLToken_EndOfStream)) { HLSLStatement* statement = NULL; - if (!ParseTopLevel(statement)) - { + if (!ParseTopLevel(statement)) { return false; } - if (statement != NULL) - { - if (lastStatement == NULL) - { + if (statement != NULL) { + if (lastStatement == NULL) { root->statement = statement; } - else - { + else { lastStatement->nextStatement = statement; } lastStatement = statement; @@ -4187,23 +3962,19 @@ bool HLSLParser::Parse(HLSLTree* tree, const HLSLParserOptions& options) bool HLSLParser::AcceptTypeModifier(int& flags) { - if (Accept(HLSLToken_Const)) - { + if (Accept(HLSLToken_Const)) { flags |= HLSLTypeFlag_Const; return true; } - else if (Accept(HLSLToken_Static)) - { + else if (Accept(HLSLToken_Static)) { flags |= HLSLTypeFlag_Static; return true; } - else if (Accept(HLSLToken_Uniform)) - { + else if (Accept(HLSLToken_Uniform)) { //flags |= HLSLTypeFlag_Uniform; // @@ Ignored. return true; } - else if (Accept(HLSLToken_Inline)) - { + else if (Accept(HLSLToken_Inline)) { //flags |= HLSLTypeFlag_Uniform; // @@ Ignored. In HLSL all functions are inline. return true; } @@ -4224,28 +3995,23 @@ bool HLSLParser::AcceptTypeModifier(int& flags) bool HLSLParser::AcceptInterpolationModifier(int& flags) { - if (Accept("linear")) - { - flags |= HLSLTypeFlag_Linear; + if (Accept("linear")) { + flags |= HLSLTypeFlag_Linear; return true; } - else if (Accept("centroid")) - { + else if (Accept("centroid")) { flags |= HLSLTypeFlag_Centroid; return true; } - else if (Accept("nointerpolation")) - { + else if (Accept("nointerpolation")) { flags |= HLSLTypeFlag_NoInterpolation; return true; } - else if (Accept("noperspective")) - { + else if (Accept("noperspective")) { flags |= HLSLTypeFlag_NoPerspective; return true; } - else if (Accept("sample")) - { + else if (Accept("sample")) { flags |= HLSLTypeFlag_Sample; return true; } @@ -4253,263 +4019,254 @@ bool HLSLParser::AcceptInterpolationModifier(int& flags) return false; } - -bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type/*, bool acceptFlags*/) +bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type /*, bool acceptFlags*/) { //if (type.flags != NULL) { type.flags = 0; - while(AcceptTypeModifier(type.flags) || AcceptInterpolationModifier(type.flags)) {} + while (AcceptTypeModifier(type.flags) || AcceptInterpolationModifier(type.flags)) { + } } int token = m_tokenizer.GetToken(); - if (token == HLSLToken_Comment) - { + if (token == HLSLToken_Comment) { // TODO: should this advance the tokenizer? // m_tokenizer.Next(); - + type.baseType = HLSLBaseType_Comment; return true; } - + // Check built-in types. type.baseType = HLSLBaseType_Void; - switch (token) - { - case HLSLToken_Float: - type.baseType = HLSLBaseType_Float; - break; - case HLSLToken_Float2: - type.baseType = HLSLBaseType_Float2; - break; - case HLSLToken_Float3: - type.baseType = HLSLBaseType_Float3; - break; - case HLSLToken_Float4: - type.baseType = HLSLBaseType_Float4; - break; - - case HLSLToken_Float2x2: - type.baseType = HLSLBaseType_Float2x2; - break; - case HLSLToken_Float3x3: - type.baseType = HLSLBaseType_Float3x3; - break; - case HLSLToken_Float4x4: - type.baseType = HLSLBaseType_Float4x4; - break; - - // The parser is remapping the type here - case HLSLToken_Halfio: - type.baseType = m_options.isHalfio ? HLSLBaseType_Half : HLSLBaseType_Float; - break; - case HLSLToken_Half2io: - type.baseType = m_options.isHalfio ? HLSLBaseType_Half2 : HLSLBaseType_Float2; - break; - case HLSLToken_Half3io: - type.baseType = m_options.isHalfio ? HLSLBaseType_Half3 : HLSLBaseType_Float3; - break; - case HLSLToken_Half4io: - type.baseType = m_options.isHalfio ? HLSLBaseType_Half4 : HLSLBaseType_Float4; - break; - - // The parser is remapping the type here - case HLSLToken_Halfst: - type.baseType = m_options.isHalfst ? HLSLBaseType_Half : HLSLBaseType_Float; - break; - case HLSLToken_Half2st: - type.baseType = m_options.isHalfst ? HLSLBaseType_Half2 : HLSLBaseType_Float2; - break; - case HLSLToken_Half3st: - type.baseType = m_options.isHalfst ? HLSLBaseType_Half3 : HLSLBaseType_Float3; - break; - case HLSLToken_Half4st: - type.baseType = m_options.isHalfst ? HLSLBaseType_Half4 : HLSLBaseType_Float4; - break; - - case HLSLToken_Half: - type.baseType = HLSLBaseType_Half; - break; - case HLSLToken_Half2: - type.baseType = HLSLBaseType_Half2; - break; - case HLSLToken_Half3: - type.baseType = HLSLBaseType_Half3; - break; - case HLSLToken_Half4: - type.baseType = HLSLBaseType_Half4; - break; - - case HLSLToken_Half2x2: - type.baseType = HLSLBaseType_Half2x2; - break; - case HLSLToken_Half3x3: - type.baseType = HLSLBaseType_Half3x3; - break; - case HLSLToken_Half4x4: - type.baseType = HLSLBaseType_Half4x4; - break; - - case HLSLToken_Bool: - type.baseType = HLSLBaseType_Bool; - break; - case HLSLToken_Bool2: - type.baseType = HLSLBaseType_Bool2; - break; - case HLSLToken_Bool3: - type.baseType = HLSLBaseType_Bool3; - break; - case HLSLToken_Bool4: - type.baseType = HLSLBaseType_Bool4; - break; - - case HLSLToken_Int: - type.baseType = HLSLBaseType_Int; - break; - case HLSLToken_Int2: - type.baseType = HLSLBaseType_Int2; - break; - case HLSLToken_Int3: - type.baseType = HLSLBaseType_Int3; - break; - case HLSLToken_Int4: - type.baseType = HLSLBaseType_Int4; - break; - - case HLSLToken_Uint: - type.baseType = HLSLBaseType_Uint; - break; - case HLSLToken_Uint2: - type.baseType = HLSLBaseType_Uint2; - break; - case HLSLToken_Uint3: - type.baseType = HLSLBaseType_Uint3; - break; - case HLSLToken_Uint4: - type.baseType = HLSLBaseType_Uint4; - break; - - case HLSLToken_Ushort: - type.baseType = HLSLBaseType_Ushort; - break; - case HLSLToken_Ushort2: - type.baseType = HLSLBaseType_Ushort2; - break; - case HLSLToken_Ushort3: - type.baseType = HLSLBaseType_Ushort3; - break; - case HLSLToken_Ushort4: - type.baseType = HLSLBaseType_Ushort4; - break; - - case HLSLToken_Short: - type.baseType = HLSLBaseType_Short; - break; - case HLSLToken_Short2: - type.baseType = HLSLBaseType_Short2; - break; - case HLSLToken_Short3: - type.baseType = HLSLBaseType_Short3; - break; - case HLSLToken_Short4: - type.baseType = HLSLBaseType_Short4; - break; - - // Textures (TODO: could have baseType be texture, with subtype like buffer) - case HLSLToken_Texture2D: - type.baseType = HLSLBaseType_Texture2D; - break; - case HLSLToken_Texture2DArray: - type.baseType = HLSLBaseType_Texture2DArray; - break; - case HLSLToken_Texture3D: - type.baseType = HLSLBaseType_Texture3D; - break; - case HLSLToken_TextureCube: - type.baseType = HLSLBaseType_TextureCube; - break; - case HLSLToken_Texture2DMS: - type.baseType = HLSLBaseType_Texture2DMS; - break; - case HLSLToken_TextureCubeArray: - type.baseType = HLSLBaseType_TextureCubeArray; - break; - - case HLSLToken_Depth2D: - type.baseType = HLSLBaseType_Depth2D; - break; - case HLSLToken_Depth2DArray: - type.baseType = HLSLBaseType_Depth2DArray; - break; - case HLSLToken_DepthCube: - type.baseType = HLSLBaseType_DepthCube; - break; - - case HLSLToken_RWTexture2D: - type.baseType = HLSLBaseType_RWTexture2D; - break; - - // samplers - case HLSLToken_SamplerState: - type.baseType = HLSLBaseType_SamplerState; - break; - case HLSLToken_SamplerComparisonState: - type.baseType = HLSLBaseType_SamplerComparisonState; - break; - - // older constants - case HLSLToken_CBuffer: - case HLSLToken_TBuffer: - // might make these BufferGlobals? - type.baseType = HLSLBaseType_Buffer; - break; - - // SSBO - case HLSLToken_StructuredBuffer: - case HLSLToken_RWStructuredBuffer: - case HLSLToken_ByteAddressBuffer: - case HLSLToken_RWByteAddressBuffer: - case HLSLToken_ConstantBuffer: - type.baseType = HLSLBaseType_Buffer; - break; - } - if (type.baseType != HLSLBaseType_Void) - { + switch (token) { + case HLSLToken_Float: + type.baseType = HLSLBaseType_Float; + break; + case HLSLToken_Float2: + type.baseType = HLSLBaseType_Float2; + break; + case HLSLToken_Float3: + type.baseType = HLSLBaseType_Float3; + break; + case HLSLToken_Float4: + type.baseType = HLSLBaseType_Float4; + break; + + case HLSLToken_Float2x2: + type.baseType = HLSLBaseType_Float2x2; + break; + case HLSLToken_Float3x3: + type.baseType = HLSLBaseType_Float3x3; + break; + case HLSLToken_Float4x4: + type.baseType = HLSLBaseType_Float4x4; + break; + + // The parser is remapping the type here + case HLSLToken_Halfio: + type.baseType = m_options.isHalfio ? HLSLBaseType_Half : HLSLBaseType_Float; + break; + case HLSLToken_Half2io: + type.baseType = m_options.isHalfio ? HLSLBaseType_Half2 : HLSLBaseType_Float2; + break; + case HLSLToken_Half3io: + type.baseType = m_options.isHalfio ? HLSLBaseType_Half3 : HLSLBaseType_Float3; + break; + case HLSLToken_Half4io: + type.baseType = m_options.isHalfio ? HLSLBaseType_Half4 : HLSLBaseType_Float4; + break; + + // The parser is remapping the type here + case HLSLToken_Halfst: + type.baseType = m_options.isHalfst ? HLSLBaseType_Half : HLSLBaseType_Float; + break; + case HLSLToken_Half2st: + type.baseType = m_options.isHalfst ? HLSLBaseType_Half2 : HLSLBaseType_Float2; + break; + case HLSLToken_Half3st: + type.baseType = m_options.isHalfst ? HLSLBaseType_Half3 : HLSLBaseType_Float3; + break; + case HLSLToken_Half4st: + type.baseType = m_options.isHalfst ? HLSLBaseType_Half4 : HLSLBaseType_Float4; + break; + + case HLSLToken_Half: + type.baseType = HLSLBaseType_Half; + break; + case HLSLToken_Half2: + type.baseType = HLSLBaseType_Half2; + break; + case HLSLToken_Half3: + type.baseType = HLSLBaseType_Half3; + break; + case HLSLToken_Half4: + type.baseType = HLSLBaseType_Half4; + break; + + case HLSLToken_Half2x2: + type.baseType = HLSLBaseType_Half2x2; + break; + case HLSLToken_Half3x3: + type.baseType = HLSLBaseType_Half3x3; + break; + case HLSLToken_Half4x4: + type.baseType = HLSLBaseType_Half4x4; + break; + + case HLSLToken_Bool: + type.baseType = HLSLBaseType_Bool; + break; + case HLSLToken_Bool2: + type.baseType = HLSLBaseType_Bool2; + break; + case HLSLToken_Bool3: + type.baseType = HLSLBaseType_Bool3; + break; + case HLSLToken_Bool4: + type.baseType = HLSLBaseType_Bool4; + break; + + case HLSLToken_Int: + type.baseType = HLSLBaseType_Int; + break; + case HLSLToken_Int2: + type.baseType = HLSLBaseType_Int2; + break; + case HLSLToken_Int3: + type.baseType = HLSLBaseType_Int3; + break; + case HLSLToken_Int4: + type.baseType = HLSLBaseType_Int4; + break; + + case HLSLToken_Uint: + type.baseType = HLSLBaseType_Uint; + break; + case HLSLToken_Uint2: + type.baseType = HLSLBaseType_Uint2; + break; + case HLSLToken_Uint3: + type.baseType = HLSLBaseType_Uint3; + break; + case HLSLToken_Uint4: + type.baseType = HLSLBaseType_Uint4; + break; + + case HLSLToken_Ushort: + type.baseType = HLSLBaseType_Ushort; + break; + case HLSLToken_Ushort2: + type.baseType = HLSLBaseType_Ushort2; + break; + case HLSLToken_Ushort3: + type.baseType = HLSLBaseType_Ushort3; + break; + case HLSLToken_Ushort4: + type.baseType = HLSLBaseType_Ushort4; + break; + + case HLSLToken_Short: + type.baseType = HLSLBaseType_Short; + break; + case HLSLToken_Short2: + type.baseType = HLSLBaseType_Short2; + break; + case HLSLToken_Short3: + type.baseType = HLSLBaseType_Short3; + break; + case HLSLToken_Short4: + type.baseType = HLSLBaseType_Short4; + break; + + // Textures (TODO: could have baseType be texture, with subtype like buffer) + case HLSLToken_Texture2D: + type.baseType = HLSLBaseType_Texture2D; + break; + case HLSLToken_Texture2DArray: + type.baseType = HLSLBaseType_Texture2DArray; + break; + case HLSLToken_Texture3D: + type.baseType = HLSLBaseType_Texture3D; + break; + case HLSLToken_TextureCube: + type.baseType = HLSLBaseType_TextureCube; + break; + case HLSLToken_Texture2DMS: + type.baseType = HLSLBaseType_Texture2DMS; + break; + case HLSLToken_TextureCubeArray: + type.baseType = HLSLBaseType_TextureCubeArray; + break; + + case HLSLToken_Depth2D: + type.baseType = HLSLBaseType_Depth2D; + break; + case HLSLToken_Depth2DArray: + type.baseType = HLSLBaseType_Depth2DArray; + break; + case HLSLToken_DepthCube: + type.baseType = HLSLBaseType_DepthCube; + break; + + case HLSLToken_RWTexture2D: + type.baseType = HLSLBaseType_RWTexture2D; + break; + + // samplers + case HLSLToken_SamplerState: + type.baseType = HLSLBaseType_SamplerState; + break; + case HLSLToken_SamplerComparisonState: + type.baseType = HLSLBaseType_SamplerComparisonState; + break; + + // older constants + case HLSLToken_CBuffer: + case HLSLToken_TBuffer: + // might make these BufferGlobals? + type.baseType = HLSLBaseType_Buffer; + break; + + // SSBO + case HLSLToken_StructuredBuffer: + case HLSLToken_RWStructuredBuffer: + case HLSLToken_ByteAddressBuffer: + case HLSLToken_RWByteAddressBuffer: + case HLSLToken_ConstantBuffer: + type.baseType = HLSLBaseType_Buffer; + break; + } + if (type.baseType != HLSLBaseType_Void) { m_tokenizer.Next(); - - if (IsTextureType(type.baseType)) - { + + if (IsTextureType(type.baseType)) { // Parse optional sampler type. - if (Accept('<')) - { + if (Accept('<')) { token = m_tokenizer.GetToken(); - + // TODO: need more format types // TODO: double, u/long, and other types - if (token >= HLSLToken_Float && token <= HLSLToken_Float4) - { + if (token >= HLSLToken_Float && token <= HLSLToken_Float4) { // TODO: code only tests if texture formatType exactly matches // when looking for Intrinsics, need to fix that before changing // this. - + type.formatType = HLSLBaseType_Float; // (HLSLBaseType)(HLSLBaseType_Float + (token - HLSLToken_Float)); } - else if (token >= HLSLToken_Half && token <= HLSLToken_Half4) - { - type.formatType = HLSLBaseType_Half; + else if (token >= HLSLToken_Half && token <= HLSLToken_Half4) { + type.formatType = HLSLBaseType_Half; // (HLSLBaseType)(HLSLBaseType_Half + (token - HLSLToken_Half)); } - else - { + else { m_tokenizer.Error("Expected half or float format type on texture."); return false; } m_tokenizer.Next(); - - if (!Expect('>')) - { + + if (!Expect('>')) { return false; } } @@ -4517,18 +4274,15 @@ bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type/*, bool acceptFlags*/ return true; } - if (allowVoid && Accept(HLSLToken_Void)) - { + if (allowVoid && Accept(HLSLToken_Void)) { type.baseType = HLSLBaseType_Void; return true; } - if (token == HLSLToken_Identifier) - { - const char* identifier = m_tree->AddString( m_tokenizer.GetIdentifier() ); - if (FindUserDefinedType(identifier) != NULL) - { + if (token == HLSLToken_Identifier) { + const char* identifier = m_tree->AddString(m_tokenizer.GetIdentifier()); + if (FindUserDefinedType(identifier) != NULL) { m_tokenizer.Next(); - + type.baseType = HLSLBaseType_UserDefined; type.typeName = identifier; return true; @@ -4539,8 +4293,7 @@ bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type/*, bool acceptFlags*/ bool HLSLParser::ExpectType(bool allowVoid, HLSLType& type) { - if (!AcceptType(allowVoid, type)) - { + if (!AcceptType(allowVoid, type)) { m_tokenizer.Error("Expected type"); return false; } @@ -4549,27 +4302,22 @@ bool HLSLParser::ExpectType(bool allowVoid, HLSLType& type) bool HLSLParser::AcceptDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name) { - if (!AcceptType(/*allowVoid=*/false, type)) - { + if (!AcceptType(/*allowVoid=*/false, type)) { return false; } - if (!ExpectIdentifier(name)) - { + if (!ExpectIdentifier(name)) { // TODO: false means we didn't accept a declaration and we had an error! return false; } // Handle array syntax. - if (Accept('[')) - { + if (Accept('[')) { type.array = true; // Optionally allow no size to the specified for the array. - if (Accept(']') && allowUnsizedArray) - { + if (Accept(']') && allowUnsizedArray) { return true; } - if (!ParseExpression(type.arraySize) || !Expect(']')) - { + if (!ParseExpression(type.arraySize) || !Expect(']')) { return false; } } @@ -4578,8 +4326,7 @@ bool HLSLParser::AcceptDeclaration(bool allowUnsizedArray, HLSLType& type, const bool HLSLParser::ExpectDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name) { - if (!AcceptDeclaration(allowUnsizedArray, type, name)) - { + if (!AcceptDeclaration(allowUnsizedArray, type, name)) { m_tokenizer.Error("Expected declaration"); return false; } @@ -4590,10 +4337,8 @@ const HLSLStruct* HLSLParser::FindUserDefinedType(const char* name) const { // Pointer comparison is sufficient for strings since they exist in the // string pool. - for (int i = 0; i < m_userTypes.GetSize(); ++i) - { - if (m_userTypes[i]->name == name) - { + for (int i = 0; i < m_userTypes.GetSize(); ++i) { + if (m_userTypes[i]->name == name) { return m_userTypes[i]; } } @@ -4602,8 +4347,7 @@ const HLSLStruct* HLSLParser::FindUserDefinedType(const char* name) const bool HLSLParser::CheckForUnexpectedEndOfStream(int endToken) { - if (Accept(HLSLToken_EndOfStream)) - { + if (Accept(HLSLToken_EndOfStream)) { char what[HLSLTokenizer::s_maxIdentifier]; m_tokenizer.GetTokenName(endToken, what); m_tokenizer.Error("Unexpected end of file while looking for '%s'", what); @@ -4619,7 +4363,7 @@ int HLSLParser::GetLineNumber() const const char* HLSLParser::GetFileName() { - return m_tree->AddString( m_tokenizer.GetFileName() ); + return m_tree->AddString(m_tokenizer.GetFileName()); } void HLSLParser::BeginScope() @@ -4632,8 +4376,7 @@ void HLSLParser::BeginScope() void HLSLParser::EndScope() { int numVariables = m_variables.GetSize() - 1; - while (m_variables[numVariables].name != NULL) - { + while (m_variables[numVariables].name != NULL) { --numVariables; ASSERT(numVariables >= 0); } @@ -4642,10 +4385,8 @@ void HLSLParser::EndScope() const HLSLType* HLSLParser::FindVariable(const char* name, bool& global) const { - for (int i = m_variables.GetSize() - 1; i >= 0; --i) - { - if (m_variables[i].name == name) - { + for (int i = m_variables.GetSize() - 1; i >= 0; --i) { + if (m_variables[i].name == name) { global = (i < m_numGlobals); return &m_variables[i].type; } @@ -4656,10 +4397,8 @@ const HLSLType* HLSLParser::FindVariable(const char* name, bool& global) const // This only search user-defined c-style functions. Intrinsics are not in this. const HLSLFunction* HLSLParser::FindFunction(const char* name) const { - for (int i = 0; i < m_functions.GetSize(); ++i) - { - if (m_functions[i]->name == name) - { + for (int i = 0; i < m_functions.GetSize(); ++i) { + if (m_functions[i]->name == name) { return m_functions[i]; } } @@ -4673,8 +4412,7 @@ static bool AreTypesEqual(HLSLTree* tree, const HLSLType& lhs, const HLSLType& r static bool AreArgumentListsEqual(HLSLTree* tree, HLSLArgument* lhs, HLSLArgument* rhs) { - while (lhs && rhs) - { + while (lhs && rhs) { if (!AreTypesEqual(tree, lhs->type, rhs->type)) return false; @@ -4693,12 +4431,10 @@ static bool AreArgumentListsEqual(HLSLTree* tree, HLSLArgument* lhs, HLSLArgumen const HLSLFunction* HLSLParser::FindFunction(const HLSLFunction* fun) const { - for (int i = 0; i < m_functions.GetSize(); ++i) - { + for (int i = 0; i < m_functions.GetSize(); ++i) { if (m_functions[i]->name == fun->name && AreTypesEqual(m_tree, m_functions[i]->returnType, fun->returnType) && - AreArgumentListsEqual(m_tree, m_functions[i]->argument, fun->argument)) - { + AreArgumentListsEqual(m_tree, m_functions[i]->argument, fun->argument)) { return m_functions[i]; } } @@ -4707,8 +4443,7 @@ const HLSLFunction* HLSLParser::FindFunction(const HLSLFunction* fun) const void HLSLParser::DeclareVariable(const char* name, const HLSLType& type) { - if (m_variables.GetSize() == m_numGlobals) - { + if (m_variables.GetSize() == m_numGlobals) { ++m_numGlobals; } Variable& variable = m_variables.PushBackNew(); @@ -4719,15 +4454,13 @@ void HLSLParser::DeclareVariable(const char* name, const HLSLType& type) bool HLSLParser::GetIsFunction(const char* name) const { // check user defined functions - for (int i = 0; i < m_functions.GetSize(); ++i) - { + for (int i = 0; i < m_functions.GetSize(); ++i) { // == is ok here because we're passed the strings through the string pool. - if (m_functions[i]->name == name) - { + if (m_functions[i]->name == name) { return true; } } - + // see if it's an intrinsic const auto& it = _intrinsicRangeMap.find(name); return it != _intrinsicRangeMap.end(); @@ -4735,49 +4468,43 @@ bool HLSLParser::GetIsFunction(const char* name) const const HLSLFunction* HLSLParser::MatchFunctionCall(const HLSLFunctionCall* functionCall, const char* name, const HLSLType* memberType) { - const HLSLFunction* matchedFunction = NULL; + const HLSLFunction* matchedFunction = NULL; //int numArguments = functionCall->numArguments; - int numMatchedOverloads = 0; - bool nameMatches = false; + int numMatchedOverloads = 0; + bool nameMatches = false; // Get the user defined c functions with the specified name. // There may be more than one, and these are not ordered. - for (int i = 0; i < m_functions.GetSize(); ++i) - { + for (int i = 0; i < m_functions.GetSize(); ++i) { const HLSLFunction* function = m_functions[i]; - if (function->name == name) - { + if (function->name == name) { nameMatches = true; - + // if caller requests member function, then memberType must match bool isMemberFunc = function->IsMemberFunction(); - - if (memberType) - { + + if (memberType) { if (!isMemberFunc) continue; - + if (memberType->baseType != function->memberType) continue; - + if (memberType->formatType != GetScalarType(function->returnType.baseType)) continue; } - else - { + else { if (isMemberFunc) continue; } - - CompareFunctionsResult result = CompareFunctions( m_tree, functionCall, function, matchedFunction ); - if (result == Function1Better) - { + + CompareFunctionsResult result = CompareFunctions(m_tree, functionCall, function, matchedFunction); + if (result == Function1Better) { matchedFunction = function; numMatchedOverloads = 1; } - else if (result == FunctionsEqual) - { + else if (result == FunctionsEqual) { ++numMatchedOverloads; } } @@ -4785,63 +4512,53 @@ const HLSLFunction* HLSLParser::MatchFunctionCall(const HLSLFunctionCall* functi // Get the intrinsic functions with the specified name. const auto& iter = _intrinsicRangeMap.find(name); - if (iter != _intrinsicRangeMap.end()) - { + if (iter != _intrinsicRangeMap.end()) { Range range = iter->second; - for (int i = 0; i < range.count; ++i) - { + for (int i = 0; i < range.count; ++i) { uint32_t idx = range.start + i; const HLSLFunction* function = &_intrinsics[idx].function; - + // if caller requests member function, then memberType must match bool isMemberFunc = function->IsMemberFunction(); - if (memberType) - { + if (memberType) { if (!isMemberFunc) break; - + if (memberType->baseType != function->memberType) continue; - + if (memberType->formatType != GetScalarType(function->returnType.baseType)) continue; } - else - { + else { if (isMemberFunc) break; } ASSERT(String_Equal(function->name, name)); - + nameMatches = true; - - CompareFunctionsResult result = CompareFunctions( m_tree, functionCall, function, matchedFunction ); - if (result == Function1Better) - { + + CompareFunctionsResult result = CompareFunctions(m_tree, functionCall, function, matchedFunction); + if (result == Function1Better) { matchedFunction = function; numMatchedOverloads = 1; } - else if (result == FunctionsEqual) - { + else if (result == FunctionsEqual) { ++numMatchedOverloads; } } } - - if (matchedFunction != NULL && numMatchedOverloads > 1) - { + + if (matchedFunction != NULL && numMatchedOverloads > 1) { // Multiple overloads match. m_tokenizer.Error("'%s' %d overloads have similar conversions", name, numMatchedOverloads); return NULL; } - else if (matchedFunction == NULL) - { - if (nameMatches) - { + else if (matchedFunction == NULL) { + if (nameMatches) { m_tokenizer.Error("'%s' no overloaded function matched all of the arguments", name); } - else - { + else { m_tokenizer.Error("Undeclared identifier '%s'", name); } } @@ -4851,29 +4568,26 @@ const HLSLFunction* HLSLParser::MatchFunctionCall(const HLSLFunctionCall* functi inline bool IsSwizzle(char c) { - return c == 'x' || c == 'y' || c == 'z' || c == 'w' || - c == 'r' || c == 'g' || c == 'b' || c == 'a'; + return c == 'x' || c == 'y' || c == 'z' || c == 'w' || + c == 'r' || c == 'g' || c == 'b' || c == 'a'; } -bool HLSLParser::GetMemberType(const HLSLType& objectType, HLSLMemberAccess * memberAccess) +bool HLSLParser::GetMemberType(const HLSLType& objectType, HLSLMemberAccess* memberAccess) { const char* fieldName = memberAccess->field; HLSLBaseType baseType = objectType.baseType; // pull field from struct - if (baseType == HLSLBaseType_UserDefined) - { - const HLSLStruct* structure = FindUserDefinedType( objectType.typeName ); + if (baseType == HLSLBaseType_UserDefined) { + const HLSLStruct* structure = FindUserDefinedType(objectType.typeName); ASSERT(structure != NULL); if (structure == NULL) return false; - + const HLSLStructField* field = structure->field; - while (field != NULL) - { - if (field->name == fieldName) - { + while (field != NULL) { + if (field->name == fieldName) { memberAccess->expressionType = field->type; return true; } @@ -4883,21 +4597,17 @@ bool HLSLParser::GetMemberType(const HLSLType& objectType, HLSLMemberAccess * me return false; } - if (baseTypeDescriptions[objectType.baseType].numericType == NumericType_NaN) - { + if (baseTypeDescriptions[objectType.baseType].numericType == NumericType_NaN) { // Currently we don't have an non-numeric types that allow member access. return false; } int swizzleLength = 0; - if (IsScalarType(baseType) || IsVectorType(baseType)) - { + if (IsScalarType(baseType) || IsVectorType(baseType)) { // Check for a swizzle on the scalar/vector types. - for (int i = 0; fieldName[i] != 0; ++i) - { - if (!IsSwizzle(fieldName[i])) - { + for (int i = 0; fieldName[i] != 0; ++i) { + if (!IsSwizzle(fieldName[i])) { m_tokenizer.Error("Invalid swizzle '%s'", fieldName); return false; } @@ -4907,102 +4617,89 @@ bool HLSLParser::GetMemberType(const HLSLType& objectType, HLSLMemberAccess * me if (swizzleLength == 0) return false; } - else if (IsMatrixType(baseType)) - { - + else if (IsMatrixType(baseType)) { // Check for a matrix element access (e.g. _m00 or _11) const char* n = fieldName; - while (n[0] == '_') - { + while (n[0] == '_') { ++n; int base = 1; - if (n[0] == 'm') - { + if (n[0] == 'm') { base = 0; ++n; } - if (!isdigit(n[0]) || !isdigit(n[1])) - { + if (!isdigit(n[0]) || !isdigit(n[1])) { m_tokenizer.Error("Invalid matrix digit"); return false; } int r = (n[0] - '0') - base; int c = (n[1] - '0') - base; - if (r >= baseTypeDescriptions[objectType.baseType].height) - { + if (r >= baseTypeDescriptions[objectType.baseType].height) { m_tokenizer.Error("Invalid matrix dimension %d", r); return false; } - if (c >= baseTypeDescriptions[objectType.baseType].numComponents) - { + if (c >= baseTypeDescriptions[objectType.baseType].numComponents) { m_tokenizer.Error("Invalid matrix dimension %d", c); return false; } ++swizzleLength; n += 2; - } - if (n[0] != 0) - { + if (n[0] != 0) { return false; } - } - else - { + else { return false; } - if (swizzleLength > 4) - { + if (swizzleLength > 4) { m_tokenizer.Error("Invalid swizzle '%s'", fieldName); return false; } - - switch (baseTypeDescriptions[objectType.baseType].numericType) - { - case NumericType_Float: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Float + swizzleLength - 1); - break; - case NumericType_Half: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Half + swizzleLength - 1); - break; - case NumericType_Double: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Double + swizzleLength - 1); - break; - - case NumericType_Int: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Int + swizzleLength - 1); - break; - case NumericType_Uint: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Uint + swizzleLength - 1); + + switch (baseTypeDescriptions[objectType.baseType].numericType) { + case NumericType_Float: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Float + swizzleLength - 1); + break; + case NumericType_Half: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Half + swizzleLength - 1); break; - case NumericType_Bool: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Bool + swizzleLength - 1); + case NumericType_Double: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Double + swizzleLength - 1); break; - case NumericType_Short: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Short + swizzleLength - 1); + + case NumericType_Int: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Int + swizzleLength - 1); + break; + case NumericType_Uint: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Uint + swizzleLength - 1); + break; + case NumericType_Bool: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Bool + swizzleLength - 1); + break; + case NumericType_Short: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Short + swizzleLength - 1); break; - case NumericType_Ushort: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Ushort + swizzleLength - 1); + case NumericType_Ushort: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Ushort + swizzleLength - 1); break; - case NumericType_Long: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Long + swizzleLength - 1); + case NumericType_Long: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Long + swizzleLength - 1); break; - case NumericType_Ulong: - memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Ulong + swizzleLength - 1); + case NumericType_Ulong: + memberAccess->expressionType.baseType = (HLSLBaseType)(HLSLBaseType_Ulong + swizzleLength - 1); break; - // TODO: u/char - default: - ASSERT(false); + // TODO: u/char + default: + ASSERT(false); } memberAccess->swizzle = true; - + return true; } -} +} //namespace M4 diff --git a/hlslparser/src/HLSLParser.h b/hlslparser/src/HLSLParser.h index 1a09da60..f963babf 100644 --- a/hlslparser/src/HLSLParser.h +++ b/hlslparser/src/HLSLParser.h @@ -10,35 +10,28 @@ #pragma once #include "Engine.h" - #include "HLSLTokenizer.h" #include "HLSLTree.h" -namespace M4 -{ +namespace M4 { struct EffectState; // This wouldn't be needed if could preprocess prior to calling parser. -struct HLSLParserOptions -{ +struct HLSLParserOptions { bool isHalfst = false; - + bool isHalfio = false; }; -class HLSLParser -{ - +class HLSLParser { public: - HLSLParser(Allocator* allocator, const char* fileName, const char* buffer, size_t length); void SetKeepComments(bool enable) { m_tokenizer.SetKeepComments(enable); } - + bool Parse(HLSLTree* tree, const HLSLParserOptions& options = HLSLParserOptions()); private: - bool Accept(int token); bool Expect(int token); @@ -53,14 +46,14 @@ class HLSLParser bool AcceptIdentifier(const char*& identifier); bool ExpectIdentifier(const char*& identifier); bool AcceptFloat(float& value); - bool AcceptHalf( float& value ); + bool AcceptHalf(float& value); bool AcceptInt(int& value); bool AcceptType(bool allowVoid, HLSLType& type); bool ExpectType(bool allowVoid, HLSLType& type); bool AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp); bool AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp); bool AcceptAssign(HLSLBinaryOp& binaryOp); - bool AcceptTypeModifier(int & typeFlags); + bool AcceptTypeModifier(int& typeFlags); bool AcceptInterpolationModifier(int& flags); /** @@ -85,18 +78,18 @@ class HLSLParser bool ParseDeclarationAssignment(HLSLDeclaration* declaration); bool ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseType type, const char* typeName); - bool ParseStateName(bool isSamplerState, bool isPipelineState, const char*& name, const EffectState *& state); + bool ParseStateName(bool isSamplerState, bool isPipelineState, const char*& name, const EffectState*& state); bool ParseColorMask(int& mask); - -// FX file -// bool ParseStateValue(const EffectState * state, HLSLStateAssignment* stateAssignment); -// bool ParseStateAssignment(HLSLStateAssignment*& stateAssignment, bool isSamplerState, bool isPipelineState); -// bool ParseSamplerState(HLSLExpression*& expression); -// bool ParseTechnique(HLSLStatement*& statement); -// bool ParsePass(HLSLPass*& pass); -// bool ParsePipeline(HLSLStatement*& pipeline); -// bool ParseStage(HLSLStatement*& stage); - + + // FX file + // bool ParseStateValue(const EffectState * state, HLSLStateAssignment* stateAssignment); + // bool ParseStateAssignment(HLSLStateAssignment*& stateAssignment, bool isSamplerState, bool isPipelineState); + // bool ParseSamplerState(HLSLExpression*& expression); + // bool ParseTechnique(HLSLStatement*& statement); + // bool ParsePass(HLSLPass*& pass); + // bool ParsePipeline(HLSLStatement*& pipeline); + // bool ParseStage(HLSLStatement*& stage); + bool ParseComment(HLSLStatement*& statement); bool ParseAttributeList(HLSLAttribute*& attribute); @@ -111,20 +104,20 @@ class HLSLParser void DeclareVariable(const char* name, const HLSLType& type); - /// Returned pointer is only valid until Declare or Begin/EndScope is called. + /// Returned pointer is only valid until Declare or Begin/EndScope is called. const HLSLType* FindVariable(const char* name, bool& global) const; const HLSLFunction* FindFunction(const char* name) const; const HLSLFunction* FindFunction(const HLSLFunction* fun) const; bool GetIsFunction(const char* name) const; - + /// Finds the overloaded function that matches the specified call. /// Pass memberType to match member functions. const HLSLFunction* MatchFunctionCall(const HLSLFunctionCall* functionCall, const char* name, const HLSLType* memberType = NULL); /// Gets the type of the named field on the specified object type (fieldName can also specify a swizzle. ) - bool GetMemberType(const HLSLType& objectType, HLSLMemberAccess * memberAccess); + bool GetMemberType(const HLSLType& objectType, HLSLMemberAccess* memberAccess); bool CheckTypeCast(const HLSLType& srcType, const HLSLType& dstType); @@ -132,33 +125,30 @@ class HLSLParser int GetLineNumber() const; private: - - struct Variable - { - const char* name; - HLSLType type; + struct Variable { + const char* name; + HLSLType type; }; - HLSLTokenizer m_tokenizer; - Array m_userTypes; - Array m_variables; - Array m_functions; - int m_numGlobals; - - HLSLTree* m_tree; - - bool m_allowUndeclaredIdentifiers = false; - bool m_disableSemanticValidation = false; - - HLSLParserOptions m_options; + HLSLTokenizer m_tokenizer; + Array m_userTypes; + Array m_variables; + Array m_functions; + int m_numGlobals; + + HLSLTree* m_tree; + + bool m_allowUndeclaredIdentifiers = false; + bool m_disableSemanticValidation = false; + + HLSLParserOptions m_options; }; -enum NumericType -{ +enum NumericType { NumericType_Float, NumericType_Half, NumericType_Double, // not in MSL - + NumericType_Bool, NumericType_Int, NumericType_Uint, @@ -166,13 +156,13 @@ enum NumericType NumericType_Ushort, NumericType_Ulong, NumericType_Long, - + // TODO: HLSL doesn't have byte/ubyte, MSL does // NumericType_UByte, // NumericType_Byte, - + NumericType_Count, - + NumericType_NaN, // not in count? }; @@ -226,4 +216,4 @@ HLSLBaseType GetScalarType(HLSLBaseType type); // returns 1 for scalar or 2/3/4 for vector types. int32_t GetVectorDimension(HLSLBaseType type); -} +} //namespace M4 diff --git a/hlslparser/src/HLSLTokenizer.cpp b/hlslparser/src/HLSLTokenizer.cpp index 965fb6ea..c8d89983 100644 --- a/hlslparser/src/HLSLTokenizer.cpp +++ b/hlslparser/src/HLSLTokenizer.cpp @@ -1,170 +1,177 @@ #include "HLSLTokenizer.h" -#include "Engine.h" - #include +#include #include #include #include -#include -namespace M4 -{ +#include "Engine.h" + +namespace M4 { // The order here must match the order in the Token enum. static const char* _reservedWords[] = -{ - "float", - "float2", - "float3", - "float4", - "float2x2", - "float3x3", - "float4x4", - - // for Nvidia/Adreno - "halfio", - "half2io", - "half3io", - "half4io", - - // for Android - "halfst", - "half2st", - "half3st", - "half4st", - - "half", - "half2", - "half3", - "half4", - "half2x2", - "half3x3", - "half4x4", - - "double", - "double2", - "double3", - "double4", - "double2x2", - "double3x3", - "double4x4", - - "bool", - "bool2", - "bool3", - "bool4", - - "int", - "int2", - "int3", - "int4", - - "uint", - "uint2", - "uint3", - "uint4", - - "short", - "short2", - "short3", - "short4", - - "ushort", - "ushort2", - "ushort3", - "ushort4", - - "long", - "long2", - "long3", - "long4", - - "ulong", - "ulong2", - "ulong3", - "ulong4", - - // TODO: u/char - - "Texture2D", - "Texture3D", - "TextureCube", - "Texture2DArray", - "TextureCubeArray", - "Texture2DMS", - - "Depth2D", - "Depth2DArray", // cascades - "DepthCube", - - "RWTexture2D", - - "SamplerState", - "SamplerComparisonState", - - "if", - "else", - "for", - "while", - "break", - "true", - "false", - "void", - "struct", - - // DX9 buffer types (tons of globals) - "cbuffer", - "tbuffer", - - // DX10 buffer templated types - "ConstantBuffer", // indexable cbuffer - "StructuredBuffer", - "RWStructuredBuffer", - "ByteAddressBuffer", - "RWByteAddressBuffer", - - "register", - "return", - "continue", - "discard", - - "const", - "static", - "inline", - - "uniform", - "in", - "out", - "inout", - - "#include", - - // these are from fx file - //"sampler_state", - //"technique", - //"pass", + { + "float", + "float2", + "float3", + "float4", + "float2x2", + "float3x3", + "float4x4", + + // for Nvidia/Adreno + "halfio", + "half2io", + "half3io", + "half4io", + + // for Android + "halfst", + "half2st", + "half3st", + "half4st", + + "half", + "half2", + "half3", + "half4", + "half2x2", + "half3x3", + "half4x4", + + "double", + "double2", + "double3", + "double4", + "double2x2", + "double3x3", + "double4x4", + + "bool", + "bool2", + "bool3", + "bool4", + + "int", + "int2", + "int3", + "int4", + + "uint", + "uint2", + "uint3", + "uint4", + + "short", + "short2", + "short3", + "short4", + + "ushort", + "ushort2", + "ushort3", + "ushort4", + + "long", + "long2", + "long3", + "long4", + + "ulong", + "ulong2", + "ulong3", + "ulong4", + + // TODO: u/char + + "Texture2D", + "Texture3D", + "TextureCube", + "Texture2DArray", + "TextureCubeArray", + "Texture2DMS", + + "Depth2D", + "Depth2DArray", // cascades + "DepthCube", + + "RWTexture2D", + + "SamplerState", + "SamplerComparisonState", + + "if", + "else", + "for", + "while", + "break", + "true", + "false", + "void", + "struct", + + // DX9 buffer types (tons of globals) + "cbuffer", + "tbuffer", + + // DX10 buffer templated types + "ConstantBuffer", // indexable cbuffer + "StructuredBuffer", + "RWStructuredBuffer", + "ByteAddressBuffer", + "RWByteAddressBuffer", + + "register", + "return", + "continue", + "discard", + + "const", + "static", + "inline", + + "uniform", + "in", + "out", + "inout", + + "#include", + + // these are from fx file + //"sampler_state", + //"technique", + //"pass", }; static bool GetIsSymbol(char c) { - switch (c) - { - case ';': - case ':': - case '(': case ')': - case '[': case ']': - case '{': case '}': - case '-': case '+': - case '*': case '/': - case '?': - case '!': - case ',': - case '=': - case '.': - case '<': case '>': - case '|': case '&': case '^': case '~': - case '@': - return true; + switch (c) { + case ';': + case ':': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '-': + case '+': + case '*': + case '/': + case '?': + case '!': + case ',': + case '=': + case '.': + case '<': + case '>': + case '|': + case '&': + case '^': + case '~': + case '@': + return true; } return false; } @@ -177,31 +184,28 @@ static bool GetIsNumberSeparator(char c) HLSLTokenizer::HLSLTokenizer(const char* fileName, const char* buffer, size_t length) { - m_buffer = buffer; - m_bufferEnd = buffer + length; - m_fileName = fileName; - m_lineNumber = 1; - m_tokenLineNumber = 1; - m_error = false; + m_buffer = buffer; + m_bufferEnd = buffer + length; + m_fileName = fileName; + m_lineNumber = 1; + m_tokenLineNumber = 1; + m_error = false; Next(); } void HLSLTokenizer::Next() { - while(SkipWhitespace() || SkipComment() || ScanLineDirective() || SkipPragmaDirective() || SkipInclude()) - { + while (SkipWhitespace() || SkipComment() || ScanLineDirective() || SkipPragmaDirective() || SkipInclude()) { } - if (m_error) - { + if (m_error) { m_token = HLSLToken_EndOfStream; return; } m_tokenLineNumber = m_lineNumber; - if (m_buffer >= m_bufferEnd || *m_buffer == '\0') - { + if (m_buffer >= m_bufferEnd || *m_buffer == '\0') { m_token = HLSLToken_EndOfStream; return; } @@ -209,168 +213,144 @@ void HLSLTokenizer::Next() const char* start = m_buffer; // single line comments - if (m_keepComments && (m_buffer[0] == '/' && m_buffer[1] == '/')) - { + if (m_keepComments && (m_buffer[0] == '/' && m_buffer[1] == '/')) { m_token = HLSLToken_Comment; m_buffer += 2; - + m_comment[0] = 0; - + // How to count the remaining string as tokens of the comment // typically expecting a single string, not a sequence of strings. - + // skip the newline too, but would need to increment lineNumber uint32_t commentLen = 0; - while (m_buffer < m_bufferEnd) - { - if (*(m_buffer) == '\n') - { + while (m_buffer < m_bufferEnd) { + if (*(m_buffer) == '\n') { m_buffer++; m_lineNumber++; break; } - + // store comment to temporary string if (commentLen < (s_maxComment - 1)) m_comment[commentLen++] = *m_buffer; - + m_buffer++; } - + m_comment[commentLen] = 0; - + return; } - + // +=, -=, *=, /=, ==, <=, >= - if (m_buffer[0] == '+' && m_buffer[1] == '=') - { + if (m_buffer[0] == '+' && m_buffer[1] == '=') { m_token = HLSLToken_PlusEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '-' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '-' && m_buffer[1] == '=') { m_token = HLSLToken_MinusEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '*' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '*' && m_buffer[1] == '=') { m_token = HLSLToken_TimesEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '/' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '/' && m_buffer[1] == '=') { m_token = HLSLToken_DivideEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '=' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '=' && m_buffer[1] == '=') { m_token = HLSLToken_EqualEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '!' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '!' && m_buffer[1] == '=') { m_token = HLSLToken_NotEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '<' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '<' && m_buffer[1] == '=') { m_token = HLSLToken_LessEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '>' && m_buffer[1] == '=') - { + else if (m_buffer[0] == '>' && m_buffer[1] == '=') { m_token = HLSLToken_GreaterEqual; m_buffer += 2; return; } - else if (m_buffer[0] == '&' && m_buffer[1] == '&') - { + else if (m_buffer[0] == '&' && m_buffer[1] == '&') { m_token = HLSLToken_LogicalAnd; m_buffer += 2; return; } - else if (m_buffer[0] == '|' && m_buffer[1] == '|') - { + else if (m_buffer[0] == '|' && m_buffer[1] == '|') { m_token = HLSLToken_LogicalOr; m_buffer += 2; return; } // ++, -- - if ((m_buffer[0] == '-' && m_buffer[1] == '-')) - { + if ((m_buffer[0] == '-' && m_buffer[1] == '-')) { m_token = HLSLToken_MinusMinus; m_buffer += 2; return; } - if ((m_buffer[0] == '+' && m_buffer[1] == '+')) - { + if ((m_buffer[0] == '+' && m_buffer[1] == '+')) { m_token = HLSLToken_PlusPlus; m_buffer += 2; return; } - + // Check for the start of a number. - if (ScanNumber()) - { + if (ScanNumber()) { return; } - - if (GetIsSymbol(m_buffer[0])) - { + + if (GetIsSymbol(m_buffer[0])) { m_token = static_cast(m_buffer[0]); ++m_buffer; return; } // Must be an identifier or a reserved word. - while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0])) - { + while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0])) { ++m_buffer; } size_t length = m_buffer - start; memcpy(m_identifier, start, length); m_identifier[length] = 0; - + const int numReservedWords = sizeof(_reservedWords) / sizeof(const char*); - for (int i = 0; i < numReservedWords; ++i) - { + for (int i = 0; i < numReservedWords; ++i) { // TODO: remove O(N) search of strings, need unordered_map - if (String_Equal(_reservedWords[i], m_identifier)) - { + if (String_Equal(_reservedWords[i], m_identifier)) { m_token = 256 + i; return; } } m_token = HLSLToken_Identifier; - } bool HLSLTokenizer::SkipInclude() { bool result = false; - + static const char* keyword = "#include"; static uint32_t keywordLen = (uint32_t)strlen(keyword); - - if( strncmp( m_buffer, keyword, keywordLen ) == 0 && isspace( m_buffer[ keywordLen ] ) ) - { + + if (strncmp(m_buffer, keyword, keywordLen) == 0 && isspace(m_buffer[keywordLen])) { m_buffer += keywordLen; result = true; - while( m_buffer < m_bufferEnd ) - { - if( *( m_buffer++ ) == '\n' ) - { + while (m_buffer < m_bufferEnd) { + if (*(m_buffer++) == '\n') { ++m_lineNumber; break; } @@ -379,15 +359,12 @@ bool HLSLTokenizer::SkipInclude() return result; } - bool HLSLTokenizer::SkipWhitespace() { bool result = false; - while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) - { + while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) { result = true; - if (m_buffer[0] == '\n') - { + if (m_buffer[0] == '\n') { ++m_lineNumber; } ++m_buffer; @@ -398,41 +375,32 @@ bool HLSLTokenizer::SkipWhitespace() bool HLSLTokenizer::SkipComment() { bool result = false; - if (m_buffer[0] == '/') - { - if ((!m_keepComments) && m_buffer[1] == '/') - { + if (m_buffer[0] == '/') { + if ((!m_keepComments) && m_buffer[1] == '/') { // Single line comment. result = true; m_buffer += 2; - while (m_buffer < m_bufferEnd) - { - if (*(m_buffer++) == '\n') - { + while (m_buffer < m_bufferEnd) { + if (*(m_buffer++) == '\n') { ++m_lineNumber; break; } } } - else if (m_buffer[1] == '*') - { + else if (m_buffer[1] == '*') { // Multi-line comment. result = true; m_buffer += 2; - while (m_buffer < m_bufferEnd) - { - if (m_buffer[0] == '\n') - { + while (m_buffer < m_bufferEnd) { + if (m_buffer[0] == '\n') { ++m_lineNumber; } - if (m_buffer[0] == '*' && m_buffer[1] == '/') - { + if (m_buffer[0] == '*' && m_buffer[1] == '/') { break; } ++m_buffer; } - if (m_buffer < m_bufferEnd) - { + if (m_buffer < m_bufferEnd) { m_buffer += 2; } } @@ -442,46 +410,39 @@ bool HLSLTokenizer::SkipComment() bool HLSLTokenizer::SkipPragmaDirective() { - bool result = false; - + bool result = false; + static const char* keyword = "#include"; static uint32_t keywordLen = (uint32_t)strlen(keyword); - if( strncmp( m_buffer, keyword, keywordLen ) == 0 && isspace( m_buffer[ keywordLen ] ) ) - { + if (strncmp(m_buffer, keyword, keywordLen) == 0 && isspace(m_buffer[keywordLen])) { m_buffer += keywordLen; result = true; - while( m_buffer < m_bufferEnd ) - { - if( *( m_buffer++ ) == '\n' ) - { + while (m_buffer < m_bufferEnd) { + if (*(m_buffer++) == '\n') { ++m_lineNumber; break; } } } - return result; + return result; } bool HLSLTokenizer::ScanNumber() { - // Don't treat the + or - as part of the number. - if (m_buffer[0] == '+' || m_buffer[0] == '-') - { + if (m_buffer[0] == '+' || m_buffer[0] == '-') { return false; } // Parse hex literals. - if (m_bufferEnd - m_buffer > 2 && m_buffer[0] == '0' && m_buffer[1] == 'x') - { - char* hEnd = NULL; - int iValue = (int)String_ToIntHex(m_buffer+2, &hEnd); - if (GetIsNumberSeparator(hEnd[0])) - { + if (m_bufferEnd - m_buffer > 2 && m_buffer[0] == '0' && m_buffer[1] == 'x') { + char* hEnd = NULL; + int iValue = (int)String_ToIntHex(m_buffer + 2, &hEnd); + if (GetIsNumberSeparator(hEnd[0])) { m_buffer = hEnd; - m_token = HLSLToken_IntLiteral; // TODO: handle uint, etc. + m_token = HLSLToken_IntLiteral; // TODO: handle uint, etc. m_iValue = iValue; return true; } @@ -490,37 +451,33 @@ bool HLSLTokenizer::ScanNumber() char* fEnd = NULL; double fValue = String_ToDouble(m_buffer, &fEnd); - if (fEnd == m_buffer) - { + if (fEnd == m_buffer) { return false; } - char* iEnd = NULL; - int iValue = String_ToInt(m_buffer, &iEnd); + char* iEnd = NULL; + int iValue = String_ToInt(m_buffer, &iEnd); // TODO: handle lf, etc. Double not really worth adding, since it's // so hobbled. - + // If the character after the number is an f then the f is treated as part // of the number (to handle 1.0f syntax). bool isHalf = false; - if( ( fEnd[ 0 ] == 'f' || fEnd[ 0 ] == 'h' ) && fEnd < m_bufferEnd ) - { - isHalf = fEnd[ 0 ] == 'h'; + if ((fEnd[0] == 'f' || fEnd[0] == 'h') && fEnd < m_bufferEnd) { + isHalf = fEnd[0] == 'h'; ++fEnd; - } + } - if( fEnd > iEnd && GetIsNumberSeparator( fEnd[ 0 ] ) ) - { - m_buffer = fEnd; - m_token = ( isHalf || fEnd[ 0 ] == 'h' ) ? HLSLToken_HalfLiteral : HLSLToken_FloatLiteral; + if (fEnd > iEnd && GetIsNumberSeparator(fEnd[0])) { + m_buffer = fEnd; + m_token = (isHalf || fEnd[0] == 'h') ? HLSLToken_HalfLiteral : HLSLToken_FloatLiteral; m_fValue = static_cast(fValue); return true; } - else if (iEnd > m_buffer && GetIsNumberSeparator(iEnd[0])) - { + else if (iEnd > m_buffer && GetIsNumberSeparator(iEnd[0])) { m_buffer = iEnd; - m_token = HLSLToken_IntLiteral; // TODO: uint/short/ushort + m_token = HLSLToken_IntLiteral; // TODO: uint/short/ushort m_iValue = iValue; return true; } @@ -532,15 +489,12 @@ bool HLSLTokenizer::ScanLineDirective() { static const char* keyword = "#line"; static uint32_t keywordLen = (uint32_t)strlen(keyword); - - if (strncmp(m_buffer, keyword, keywordLen) == 0 && isspace(m_buffer[keywordLen])) - { + + if (strncmp(m_buffer, keyword, keywordLen) == 0 && isspace(m_buffer[keywordLen])) { m_buffer += keywordLen; - - while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) - { - if (m_buffer[0] == '\n') - { + + while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) { + if (m_buffer[0] == '\n') { Error("Syntax error: expected line number after #line"); return false; } @@ -550,43 +504,36 @@ bool HLSLTokenizer::ScanLineDirective() char* iEnd = NULL; int lineNumber = String_ToInt(m_buffer, &iEnd); - if (!isspace(*iEnd)) - { + if (!isspace(*iEnd)) { Error("Syntax error: expected line number after #line"); return false; } m_buffer = iEnd; - while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) - { + while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) { char c = m_buffer[0]; ++m_buffer; - if (c == '\n') - { + if (c == '\n') { m_lineNumber = lineNumber; return true; } } - if (m_buffer >= m_bufferEnd) - { + if (m_buffer >= m_bufferEnd) { m_lineNumber = lineNumber; return true; } - if (m_buffer[0] != '"') - { + if (m_buffer[0] != '"') { Error("Syntax error: expected '\"' after line number near #line"); return false; } - + ++m_buffer; - + int i = 0; - while (i + 1 < s_maxIdentifier && m_buffer < m_bufferEnd && m_buffer[0] != '"') - { - if (m_buffer[0] == '\n') - { + while (i + 1 < s_maxIdentifier && m_buffer < m_bufferEnd && m_buffer[0] != '"') { + if (m_buffer[0] == '\n') { Error("Syntax error: expected '\"' before end of line near #line"); return false; } @@ -595,28 +542,24 @@ bool HLSLTokenizer::ScanLineDirective() ++m_buffer; ++i; } - + m_lineDirectiveFileName[i] = 0; - - if (m_buffer >= m_bufferEnd) - { + + if (m_buffer >= m_bufferEnd) { Error("Syntax error: expected '\"' before end of file near #line"); return false; } - if (i + 1 >= s_maxIdentifier) - { + if (i + 1 >= s_maxIdentifier) { Error("Syntax error: file name too long near #line"); return false; } // Skip the closing quote ++m_buffer; - - while (m_buffer < m_bufferEnd && m_buffer[0] != '\n') - { - if (!isspace(m_buffer[0])) - { + + while (m_buffer < m_bufferEnd && m_buffer[0] != '\n') { + if (!isspace(m_buffer[0])) { Error("Syntax error: unexpected input after file name near #line"); return false; } @@ -630,11 +573,9 @@ bool HLSLTokenizer::ScanLineDirective() m_fileName = m_lineDirectiveFileName; return true; - } return false; - } int HLSLTokenizer::GetToken() const @@ -677,12 +618,11 @@ void HLSLTokenizer::Error(const char* format, ...) // It's not always convenient to stop executing when an error occurs, // so just track once we've hit an error and stop reporting them until // we successfully bail out of execution. - if (m_error) - { + if (m_error) { return; } m_error = true; - + va_list args; va_start(args, format); Log_ErrorArgList(format, args, m_fileName, m_lineNumber); @@ -694,27 +634,23 @@ void HLSLTokenizer::Error(const char* format, ...) // Gcc/lcang convention (must be absolute filename for clickthrough) // Visual Stuidio can pick up on this formatting too //Log_Error("%s:%d: %s: %s\n", m_fileName, m_lineNumber, isError ? "error" : "warning", buffer); -} +} void HLSLTokenizer::GetTokenName(char buffer[s_maxIdentifier]) const { - if (m_token == HLSLToken_FloatLiteral || m_token == HLSLToken_HalfLiteral ) - { + if (m_token == HLSLToken_FloatLiteral || m_token == HLSLToken_HalfLiteral) { snprintf(buffer, s_maxIdentifier, "%f", m_fValue); - + String_StripTrailingFloatZeroes(buffer); } - else if (m_token == HLSLToken_IntLiteral) - { + else if (m_token == HLSLToken_IntLiteral) { snprintf(buffer, s_maxIdentifier, "%d", m_iValue); } // TODO: short/ushort/uint - else if (m_token == HLSLToken_Identifier) - { + else if (m_token == HLSLToken_Identifier) { String_Copy(buffer, m_identifier, s_maxIdentifier); } - else - { + else { GetTokenName(m_token, buffer); } } @@ -722,89 +658,84 @@ void HLSLTokenizer::GetTokenName(char buffer[s_maxIdentifier]) const void HLSLTokenizer::GetTokenName(int token, char buffer[s_maxIdentifier]) { // ascii - if (token < 256) - { + if (token < 256) { buffer[0] = (char)token; buffer[1] = 0; } - else if (token < HLSLToken_LessEqual) - { + else if (token < HLSLToken_LessEqual) { strcpy(buffer, _reservedWords[token - 256]); } - else - { - switch (token) - { - case HLSLToken_PlusPlus: - strcpy(buffer, "++"); - break; - case HLSLToken_MinusMinus: - strcpy(buffer, "--"); - break; - - case HLSLToken_PlusEqual: - strcpy(buffer, "+="); - break; - case HLSLToken_MinusEqual: - strcpy(buffer, "-="); - break; - case HLSLToken_TimesEqual: - strcpy(buffer, "*="); - break; - case HLSLToken_DivideEqual: - strcpy(buffer, "/="); - break; - - // DONE: Missing several token types - case HLSLToken_LessEqual: - strcpy(buffer, "<="); - break; - case HLSLToken_GreaterEqual: - strcpy(buffer, ">="); - break; - case HLSLToken_EqualEqual: - strcpy(buffer, "=="); - break; - case HLSLToken_NotEqual: - strcpy(buffer, "!="); - break; - - case HLSLToken_LogicalAnd: - strcpy(buffer, "&&"); - break; - case HLSLToken_LogicalOr: - strcpy(buffer, "||"); - break; - - // literals - case HLSLToken_HalfLiteral: - strcpy( buffer, "half" ); - break; - case HLSLToken_FloatLiteral: - strcpy(buffer, "float"); - break; - case HLSLToken_IntLiteral: - strcpy(buffer, "int"); - break; - // TODO: need uint, short, ushort - - case HLSLToken_Identifier: - strcpy(buffer, "identifier"); - break; - case HLSLToken_EndOfStream: - strcpy(buffer, ""); - break; - - case HLSLToken_Comment: - strcpy(buffer, "comment"); - break; - - default: - strcpy(buffer, "unknown"); - break; + else { + switch (token) { + case HLSLToken_PlusPlus: + strcpy(buffer, "++"); + break; + case HLSLToken_MinusMinus: + strcpy(buffer, "--"); + break; + + case HLSLToken_PlusEqual: + strcpy(buffer, "+="); + break; + case HLSLToken_MinusEqual: + strcpy(buffer, "-="); + break; + case HLSLToken_TimesEqual: + strcpy(buffer, "*="); + break; + case HLSLToken_DivideEqual: + strcpy(buffer, "/="); + break; + + // DONE: Missing several token types + case HLSLToken_LessEqual: + strcpy(buffer, "<="); + break; + case HLSLToken_GreaterEqual: + strcpy(buffer, ">="); + break; + case HLSLToken_EqualEqual: + strcpy(buffer, "=="); + break; + case HLSLToken_NotEqual: + strcpy(buffer, "!="); + break; + + case HLSLToken_LogicalAnd: + strcpy(buffer, "&&"); + break; + case HLSLToken_LogicalOr: + strcpy(buffer, "||"); + break; + + // literals + case HLSLToken_HalfLiteral: + strcpy(buffer, "half"); + break; + case HLSLToken_FloatLiteral: + strcpy(buffer, "float"); + break; + case HLSLToken_IntLiteral: + strcpy(buffer, "int"); + break; + // TODO: need uint, short, ushort + + case HLSLToken_Identifier: + strcpy(buffer, "identifier"); + break; + case HLSLToken_EndOfStream: + strcpy(buffer, ""); + break; + + case HLSLToken_Comment: + strcpy(buffer, "comment"); + break; + + default: + strcpy(buffer, "unknown"); + break; } } - } -} +} //namespace M4 diff --git a/hlslparser/src/HLSLTokenizer.h b/hlslparser/src/HLSLTokenizer.h index 166309a4..b48d451a 100644 --- a/hlslparser/src/HLSLTokenizer.h +++ b/hlslparser/src/HLSLTokenizer.h @@ -2,44 +2,42 @@ #include "Engine.h" -namespace M4 -{ +namespace M4 { /** In addition to the values in this enum, all of the ASCII characters are valid tokens. */ -enum HLSLToken -{ +enum HLSLToken { // The order here must match the order in the _reservedWords - + // Built-in types. - HLSLToken_Float = 256, + HLSLToken_Float = 256, HLSLToken_Float2, HLSLToken_Float3, HLSLToken_Float4, - HLSLToken_Float2x2, + HLSLToken_Float2x2, HLSLToken_Float3x3, HLSLToken_Float4x4, - + // for Nvidia/Adreno HLSLToken_Halfio, HLSLToken_Half2io, HLSLToken_Half3io, HLSLToken_Half4io, - + // for Android w/o fp16 storage HLSLToken_Halfst, HLSLToken_Half2st, HLSLToken_Half3st, HLSLToken_Half4st, - + HLSLToken_Half, HLSLToken_Half2, HLSLToken_Half3, HLSLToken_Half4, - HLSLToken_Half2x2, + HLSLToken_Half2x2, HLSLToken_Half3x3, HLSLToken_Half4x4, - + HLSLToken_Double, HLSLToken_Double2, HLSLToken_Double3, @@ -47,17 +45,17 @@ enum HLSLToken HLSLToken_Double2x2, HLSLToken_Double3x3, HLSLToken_Double4x4, - + HLSLToken_Bool, - HLSLToken_Bool2, - HLSLToken_Bool3, - HLSLToken_Bool4, - + HLSLToken_Bool2, + HLSLToken_Bool3, + HLSLToken_Bool4, + HLSLToken_Int, HLSLToken_Int2, HLSLToken_Int3, HLSLToken_Int4, - + HLSLToken_Uint, HLSLToken_Uint2, HLSLToken_Uint3, @@ -67,22 +65,22 @@ enum HLSLToken HLSLToken_Short2, HLSLToken_Short3, HLSLToken_Short4, - + HLSLToken_Ushort, HLSLToken_Ushort2, HLSLToken_Ushort3, HLSLToken_Ushort4, - + HLSLToken_Long, HLSLToken_Long2, HLSLToken_Long3, HLSLToken_Long4, - + HLSLToken_Ulong, HLSLToken_Ulong2, HLSLToken_Ulong3, HLSLToken_Ulong4, - + // TODO: u/char HLSLToken_Texture2D, HLSLToken_Texture3D, @@ -90,17 +88,17 @@ enum HLSLToken HLSLToken_Texture2DArray, HLSLToken_TextureCubeArray, HLSLToken_Texture2DMS, - + HLSLToken_Depth2D, HLSLToken_Depth2DArray, HLSLToken_DepthCube, // TODO: other depth types - + HLSLToken_RWTexture2D, - + HLSLToken_SamplerState, HLSLToken_SamplerComparisonState, - + // Reserved words. HLSLToken_If, HLSLToken_Else, @@ -111,11 +109,11 @@ enum HLSLToken HLSLToken_False, HLSLToken_Void, HLSLToken_Struct, - + // dx9 HLSLToken_CBuffer, HLSLToken_TBuffer, - + // dx10 templated types (TODO: hook to parser and generator) HLSLToken_ConstantBuffer, HLSLToken_StructuredBuffer, @@ -125,12 +123,12 @@ enum HLSLToken HLSLToken_ByteAddressBuffer, HLSLToken_RWByteAddressBuffer, // RWTexture, and other types - + HLSLToken_Register, HLSLToken_Return, HLSLToken_Continue, HLSLToken_Discard, - + HLSLToken_Const, HLSLToken_Static, HLSLToken_Inline, @@ -150,10 +148,10 @@ enum HLSLToken HLSLToken_Include, // HLSLToken_Pragma // HLSLToken_Line - + //=================== // End of strings that have to match in _reservedWords in .cpp - + // Multi-character symbols. HLSLToken_LessEqual, HLSLToken_GreaterEqual, @@ -165,29 +163,26 @@ enum HLSLToken HLSLToken_MinusEqual, HLSLToken_TimesEqual, HLSLToken_DivideEqual, - HLSLToken_LogicalAnd, // && - HLSLToken_LogicalOr, // || - + HLSLToken_LogicalAnd, // && + HLSLToken_LogicalOr, // || + // Other token types. HLSLToken_FloatLiteral, - HLSLToken_HalfLiteral, + HLSLToken_HalfLiteral, HLSLToken_IntLiteral, - + HLSLToken_Identifier, - HLSLToken_Comment, // Alec added this - + HLSLToken_Comment, // Alec added this + HLSLToken_EndOfStream, }; -class HLSLTokenizer -{ - +class HLSLTokenizer { public: - /// Maximum string length of an identifier. constexpr static int s_maxIdentifier = 255 + 1; constexpr static int s_maxComment = 4096; - + /// The file name is only used for error reporting. HLSLTokenizer(const char* fileName, const char* buffer, size_t length); @@ -199,7 +194,7 @@ class HLSLTokenizer /// Returns the number of the current token. float GetFloat() const; - int GetInt() const; + int GetInt() const; /// Returns the identifier for the current token. const char* GetIdentifier() const; @@ -225,35 +220,31 @@ class HLSLTokenizer /// Tokenizer will default to strip double-slash comments, but this tries to preserve them if true void SetKeepComments(bool enable) { m_keepComments = enable; } - -private: +private: bool SkipWhitespace(); bool SkipComment(); - bool SkipPragmaDirective(); + bool SkipPragmaDirective(); bool SkipInclude(); - + bool ScanNumber(); bool ScanLineDirective(); private: - - const char* m_fileName = nullptr; - const char* m_buffer = nullptr; - const char* m_bufferEnd = nullptr; - int m_lineNumber = 0; - bool m_error = false; - - int m_token = 0; - float m_fValue = 0.0f; - int m_iValue = 0; - char m_identifier[s_maxIdentifier] = {}; - char m_comment[s_maxComment] = {}; - char m_lineDirectiveFileName[s_maxIdentifier] = {}; - int m_tokenLineNumber = 0; - bool m_keepComments = false; - + const char* m_fileName = nullptr; + const char* m_buffer = nullptr; + const char* m_bufferEnd = nullptr; + int m_lineNumber = 0; + bool m_error = false; + + int m_token = 0; + float m_fValue = 0.0f; + int m_iValue = 0; + char m_identifier[s_maxIdentifier] = {}; + char m_comment[s_maxComment] = {}; + char m_lineDirectiveFileName[s_maxIdentifier] = {}; + int m_tokenLineNumber = 0; + bool m_keepComments = false; }; -} - +} //namespace M4 diff --git a/hlslparser/src/HLSLTree.cpp b/hlslparser/src/HLSLTree.cpp index 6a0392aa..4332b6b5 100644 --- a/hlslparser/src/HLSLTree.cpp +++ b/hlslparser/src/HLSLTree.cpp @@ -2,12 +2,11 @@ #include "Engine.h" -namespace M4 -{ +namespace M4 { // TODO: split helper calls out to new .h, so can include that // over to HLSLParser.cpp -extern bool IsSamplerType(const HLSLType & type); +extern bool IsSamplerType(const HLSLType &type); extern bool IsScalarType(HLSLBaseType type); extern bool IsIntegerType(HLSLBaseType type); @@ -15,26 +14,22 @@ extern bool IsFloatingType(HLSLBaseType type); extern int32_t GetVectorDimension(HLSLBaseType type); - - -HLSLTree::HLSLTree(Allocator* allocator) : - m_allocator(allocator), m_stringPool(allocator) +HLSLTree::HLSLTree(Allocator *allocator) : m_allocator(allocator), m_stringPool(allocator) { - m_firstPage = m_allocator->New(); - m_firstPage->next = NULL; + m_firstPage = m_allocator->New(); + m_firstPage->next = NULL; - m_currentPage = m_firstPage; + m_currentPage = m_firstPage; m_currentPageOffset = 0; - m_root = AddNode(NULL, 1); + m_root = AddNode(NULL, 1); } HLSLTree::~HLSLTree() { - NodePage* page = m_firstPage; - while (page != NULL) - { - NodePage* next = page->next; + NodePage *page = m_firstPage; + while (page != NULL) { + NodePage *next = page->next; m_allocator->Delete(page); page = next; } @@ -42,59 +37,55 @@ HLSLTree::~HLSLTree() void HLSLTree::AllocatePage() { - NodePage* newPage = m_allocator->New(); - newPage->next = NULL; - m_currentPage->next = newPage; - m_currentPageOffset = 0; - m_currentPage = newPage; + NodePage *newPage = m_allocator->New(); + newPage->next = NULL; + m_currentPage->next = newPage; + m_currentPageOffset = 0; + m_currentPage = newPage; } -const char* HLSLTree::AddString(const char* string) -{ +const char *HLSLTree::AddString(const char *string) +{ return m_stringPool.AddString(string); } -const char* HLSLTree::AddStringFormat(const char* format, ...) +const char *HLSLTree::AddStringFormat(const char *format, ...) { va_list args; va_start(args, format); - const char * string = m_stringPool.AddStringFormatList(format, args); + const char *string = m_stringPool.AddStringFormatList(format, args); va_end(args); return string; } -bool HLSLTree::GetContainsString(const char* string) const +bool HLSLTree::GetContainsString(const char *string) const { return m_stringPool.GetContainsString(string); } -HLSLRoot* HLSLTree::GetRoot() const +HLSLRoot *HLSLTree::GetRoot() const { return m_root; } -void* HLSLTree::AllocateMemory(size_t size) +void *HLSLTree::AllocateMemory(size_t size) { - if (m_currentPageOffset + size > s_nodePageSize) - { + if (m_currentPageOffset + size > s_nodePageSize) { AllocatePage(); } - void* buffer = m_currentPage->buffer + m_currentPageOffset; + void *buffer = m_currentPage->buffer + m_currentPageOffset; m_currentPageOffset += size; return buffer; } // @@ This doesn't do any parameter matching. Simply returns the first function with that name. -HLSLFunction * HLSLTree::FindFunction(const char * name) +HLSLFunction *HLSLTree::FindFunction(const char *name) { - HLSLStatement * statement = m_root->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Function) - { - HLSLFunction * function = (HLSLFunction *)statement; - if (String_Equal(name, function->name)) - { + HLSLStatement *statement = m_root->statement; + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Function) { + HLSLFunction *function = (HLSLFunction *)statement; + if (String_Equal(name, function->name)) { return function; } } @@ -105,56 +96,47 @@ HLSLFunction * HLSLTree::FindFunction(const char * name) return NULL; } -HLSLDeclaration * HLSLTree::FindGlobalDeclaration(const char * name, HLSLBuffer ** buffer_out/*=NULL*/) +HLSLDeclaration *HLSLTree::FindGlobalDeclaration(const char *name, HLSLBuffer **buffer_out /*=NULL*/) { - HLSLStatement * statement = m_root->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Declaration) - { - HLSLDeclaration * declaration = (HLSLDeclaration *)statement; - if (String_Equal(name, declaration->name)) - { + HLSLStatement *statement = m_root->statement; + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Declaration) { + HLSLDeclaration *declaration = (HLSLDeclaration *)statement; + if (String_Equal(name, declaration->name)) { if (buffer_out) *buffer_out = NULL; return declaration; } } - else if (statement->nodeType == HLSLNodeType_Buffer) - { - HLSLBuffer* buffer = (HLSLBuffer*)statement; - + else if (statement->nodeType == HLSLNodeType_Buffer) { + HLSLBuffer *buffer = (HLSLBuffer *)statement; + // This searches the fields to find the buffer, // since cbuffer/tbuffer represent globals. - if (buffer->IsGlobalFields()) - { - HLSLDeclaration* field = buffer->field; - while (field != NULL) - { + if (buffer->IsGlobalFields()) { + HLSLDeclaration *field = buffer->field; + while (field != NULL) { ASSERT(field->nodeType == HLSLNodeType_Declaration); - if (String_Equal(name, field->name)) - { + if (String_Equal(name, field->name)) { if (buffer_out) *buffer_out = buffer; return field; } - field = (HLSLDeclaration*)field->nextStatement; + field = (HLSLDeclaration *)field->nextStatement; } } - else - { - if (String_Equal(name, buffer->name)) - { + else { + if (String_Equal(name, buffer->name)) { if (buffer_out) *buffer_out = buffer; return NULL; } - + /* This isn't same type... - + // Note: should pass buffers, but buffer/texture // and cbuffer fields can be global to entire shader. - + // find struct first const HLSLStruct* bufferStruct = buffer->bufferStruct; - + // new search those for the fields HLSLStructField* field = bufferStruct->field; while (field != NULL) @@ -178,16 +160,13 @@ HLSLDeclaration * HLSLTree::FindGlobalDeclaration(const char * name, HLSLBuffer return NULL; } -HLSLStruct * HLSLTree::FindGlobalStruct(const char * name) +HLSLStruct *HLSLTree::FindGlobalStruct(const char *name) { - HLSLStatement * statement = m_root->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Struct) - { - HLSLStruct * declaration = (HLSLStruct *)statement; - if (String_Equal(name, declaration->name)) - { + HLSLStatement *statement = m_root->statement; + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Struct) { + HLSLStruct *declaration = (HLSLStruct *)statement; + if (String_Equal(name, declaration->name)) { return declaration; } } @@ -261,16 +240,13 @@ HLSLPipeline * HLSLTree::FindPipeline(const char * name) } */ -HLSLBuffer * HLSLTree::FindBuffer(const char * name) +HLSLBuffer *HLSLTree::FindBuffer(const char *name) { - HLSLStatement * statement = m_root->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Buffer) - { - HLSLBuffer * buffer = (HLSLBuffer *)statement; - if (String_Equal(name, buffer->name)) - { + HLSLStatement *statement = m_root->statement; + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Buffer) { + HLSLBuffer *buffer = (HLSLBuffer *)statement; + if (String_Equal(name, buffer->name)) { return buffer; } } @@ -281,15 +257,12 @@ HLSLBuffer * HLSLTree::FindBuffer(const char * name) return NULL; } - - -bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) +bool HLSLTree::GetExpressionValue(HLSLExpression *expression, int &value) { - ASSERT (expression != NULL); + ASSERT(expression != NULL); // Expression must be constant. - if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) - { + if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) { return false; } @@ -298,30 +271,25 @@ bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) if (expression->expressionType.baseType != HLSLBaseType_Long && expression->expressionType.baseType != HLSLBaseType_Short && expression->expressionType.baseType != HLSLBaseType_Int && - - expression->expressionType.baseType != HLSLBaseType_Bool) - { + + expression->expressionType.baseType != HLSLBaseType_Bool) { return false; } - if (expression->expressionType.array) - { + if (expression->expressionType.array) { return false; } - if (expression->nodeType == HLSLNodeType_BinaryExpression) - { - HLSLBinaryExpression * binaryExpression = (HLSLBinaryExpression *)expression; + if (expression->nodeType == HLSLNodeType_BinaryExpression) { + HLSLBinaryExpression *binaryExpression = (HLSLBinaryExpression *)expression; int value1, value2; if (!GetExpressionValue(binaryExpression->expression1, value1) || - !GetExpressionValue(binaryExpression->expression2, value2)) - { + !GetExpressionValue(binaryExpression->expression2, value2)) { return false; } - switch(binaryExpression->binaryOp) - { + switch (binaryExpression->binaryOp) { case HLSLBinaryOp_And: value = value1 && value2; return true; @@ -376,17 +344,14 @@ bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) return false; } } - else if (expression->nodeType == HLSLNodeType_UnaryExpression) - { - HLSLUnaryExpression * unaryExpression = (HLSLUnaryExpression *)expression; + else if (expression->nodeType == HLSLNodeType_UnaryExpression) { + HLSLUnaryExpression *unaryExpression = (HLSLUnaryExpression *)expression; - if (!GetExpressionValue(unaryExpression->expression, value)) - { + if (!GetExpressionValue(unaryExpression->expression, value)) { return false; } - switch(unaryExpression->unaryOp) - { + switch (unaryExpression->unaryOp) { case HLSLUnaryOp_Negative: value = -value; return true; @@ -407,38 +372,34 @@ bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) return false; } } - else if (expression->nodeType == HLSLNodeType_IdentifierExpression) - { - HLSLIdentifierExpression * identifier = (HLSLIdentifierExpression *)expression; + else if (expression->nodeType == HLSLNodeType_IdentifierExpression) { + HLSLIdentifierExpression *identifier = (HLSLIdentifierExpression *)expression; - HLSLDeclaration * declaration = FindGlobalDeclaration(identifier->name); - if (declaration == NULL) - { + HLSLDeclaration *declaration = FindGlobalDeclaration(identifier->name); + if (declaration == NULL) { return false; } - if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) - { + if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) { return false; } return GetExpressionValue(declaration->assignment, value); } - else if (expression->nodeType == HLSLNodeType_LiteralExpression) - { - HLSLLiteralExpression * literal = (HLSLLiteralExpression *)expression; - + else if (expression->nodeType == HLSLNodeType_LiteralExpression) { + HLSLLiteralExpression *literal = (HLSLLiteralExpression *)expression; + if (literal->expressionType.baseType == HLSLBaseType_Int) value = literal->iValue; else if (literal->expressionType.baseType == HLSLBaseType_Long) value = literal->iValue; // precision loss to Int else if (literal->expressionType.baseType == HLSLBaseType_Short) value = literal->iValue; - + else if (literal->expressionType.baseType == HLSLBaseType_Bool) value = (int)literal->bValue; else return false; - + return true; } @@ -446,26 +407,25 @@ bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) } // TODO: Nothing calling this? -bool HLSLTree::NeedsFunction(const char* name) +bool HLSLTree::NeedsFunction(const char *name) { // Early out if (!GetContainsString(name)) return false; - struct NeedsFunctionVisitor: HLSLTreeVisitor - { - const char* name; + struct NeedsFunctionVisitor : HLSLTreeVisitor { + const char *name; bool result; virtual ~NeedsFunctionVisitor() {} - - virtual void VisitTopLevelStatement(HLSLStatement * node) + + virtual void VisitTopLevelStatement(HLSLStatement *node) { if (!node->hidden) HLSLTreeVisitor::VisitTopLevelStatement(node); } - virtual void VisitFunctionCall(HLSLFunctionCall * node) + virtual void VisitFunctionCall(HLSLFunctionCall *node) { result = result || String_Equal(name, node->function->name); @@ -483,29 +443,26 @@ bool HLSLTree::NeedsFunction(const char* name) } // Returns dimension, 0 if invalid. -int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) +int HLSLTree::GetExpressionValue(HLSLExpression *expression, float values[4]) { - ASSERT (expression != NULL); + ASSERT(expression != NULL); // Expression must be constant. - if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) - { + if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) { return 0; } HLSLBaseType type = expression->expressionType.baseType; - - if (IsIntegerType(type)) - { - if (IsScalarType(type)) - { + + if (IsIntegerType(type)) { + if (IsScalarType(type)) { int intValue; if (GetExpressionValue(expression, intValue)) { - for (int i = 0; i < 4; i++) values[i] = (float)intValue; // @@ Warn if conversion is not exact. + for (int i = 0; i < 4; i++) values[i] = (float)intValue; // @@ Warn if conversion is not exact. return 1; } } - + return 0; } // this skips other int types not handled above @@ -513,48 +470,40 @@ int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) return 0; // @@ Not supported yet, but we may need it? - if (expression->expressionType.array) - { + if (expression->expressionType.array) { return false; } int dim = GetVectorDimension(type); - if (expression->nodeType == HLSLNodeType_BinaryExpression) - { - HLSLBinaryExpression * binaryExpression = (HLSLBinaryExpression *)expression; - + if (expression->nodeType == HLSLNodeType_BinaryExpression) { + HLSLBinaryExpression *binaryExpression = (HLSLBinaryExpression *)expression; + float values1[4], values2[4]; int dim1 = GetExpressionValue(binaryExpression->expression1, values1); int dim2 = GetExpressionValue(binaryExpression->expression2, values2); - if (dim1 == 0 || dim2 == 0) - { + if (dim1 == 0 || dim2 == 0) { return 0; } - if (dim1 != dim2) - { + if (dim1 != dim2) { // Broadcast scalar to vector size. - if (dim1 == 1) - { + if (dim1 == 1) { for (int i = 1; i < dim2; i++) values1[i] = values1[0]; dim1 = dim2; } - else if (dim2 == 1) - { + else if (dim2 == 1) { for (int i = 1; i < dim1; i++) values2[i] = values2[0]; dim2 = dim1; } - else - { + else { return 0; } } ASSERT(dim == dim1); - switch(binaryExpression->binaryOp) - { + switch (binaryExpression->binaryOp) { case HLSLBinaryOp_Add: for (int i = 0; i < dim; i++) values[i] = values1[i] + values2[i]; return dim; @@ -571,19 +520,16 @@ int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) return 0; } } - else if (expression->nodeType == HLSLNodeType_UnaryExpression) - { - HLSLUnaryExpression * unaryExpression = (HLSLUnaryExpression *)expression; - + else if (expression->nodeType == HLSLNodeType_UnaryExpression) { + HLSLUnaryExpression *unaryExpression = (HLSLUnaryExpression *)expression; + int dim1 = GetExpressionValue(unaryExpression->expression, values); - if (dim1 == 0) - { + if (dim1 == 0) { return 0; } ASSERT(dim == dim1); - switch(unaryExpression->unaryOp) - { + switch (unaryExpression->unaryOp) { case HLSLUnaryOp_Negative: for (int i = 0; i < dim; i++) values[i] = -values[i]; return dim; @@ -594,14 +540,12 @@ int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) return 0; } } - else if (expression->nodeType == HLSLNodeType_ConstructorExpression) - { - HLSLConstructorExpression * constructor = (HLSLConstructorExpression *)expression; + else if (expression->nodeType == HLSLNodeType_ConstructorExpression) { + HLSLConstructorExpression *constructor = (HLSLConstructorExpression *)expression; int idx = 0; - HLSLExpression * arg = constructor->argument; - while (arg != NULL) - { + HLSLExpression *arg = constructor->argument; + while (arg != NULL) { float tmp[4]; int n = GetExpressionValue(arg, tmp); for (int i = 0; i < n; i++) values[idx + i] = tmp[i]; @@ -613,25 +557,21 @@ int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) return dim; } - else if (expression->nodeType == HLSLNodeType_IdentifierExpression) - { - HLSLIdentifierExpression * identifier = (HLSLIdentifierExpression *)expression; + else if (expression->nodeType == HLSLNodeType_IdentifierExpression) { + HLSLIdentifierExpression *identifier = (HLSLIdentifierExpression *)expression; - HLSLDeclaration * declaration = FindGlobalDeclaration(identifier->name); - if (declaration == NULL) - { + HLSLDeclaration *declaration = FindGlobalDeclaration(identifier->name); + if (declaration == NULL) { return 0; } - if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) - { + if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) { return 0; } return GetExpressionValue(declaration->assignment, values); } - else if (expression->nodeType == HLSLNodeType_LiteralExpression) - { - HLSLLiteralExpression * literal = (HLSLLiteralExpression *)expression; + else if (expression->nodeType == HLSLNodeType_LiteralExpression) { + HLSLLiteralExpression *literal = (HLSLLiteralExpression *)expression; if (literal->expressionType.baseType == HLSLBaseType_Float) values[0] = literal->fValue; @@ -639,44 +579,41 @@ int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) values[0] = literal->fValue; else if (literal->expressionType.baseType == HLSLBaseType_Double) values[0] = literal->fValue; // TODO: need more precision - + else if (literal->expressionType.baseType == HLSLBaseType_Bool) values[0] = literal->bValue; - + // TODO: add uint types, fix precision of short/long/double/half // signed ints else if (literal->expressionType.baseType == HLSLBaseType_Int) - values[0] = (float)literal->iValue; // @@ Warn if conversion is not exact. + values[0] = (float)literal->iValue; // @@ Warn if conversion is not exact. else if (literal->expressionType.baseType == HLSLBaseType_Short) values[0] = (float)literal->iValue; else if (literal->expressionType.baseType == HLSLBaseType_Long) values[0] = (float)literal->iValue; else return 0; - + return 1; } return 0; } - - - -void HLSLTreeVisitor::VisitType(HLSLType & type) +void HLSLTreeVisitor::VisitType(HLSLType &type) { } -void HLSLTreeVisitor::VisitRoot(HLSLRoot * root) +void HLSLTreeVisitor::VisitRoot(HLSLRoot *root) { - HLSLStatement * statement = root->statement; + HLSLStatement *statement = root->statement; while (statement != NULL) { VisitTopLevelStatement(statement); statement = statement->nextStatement; } } -void HLSLTreeVisitor::VisitTopLevelStatement(HLSLStatement * node) +void HLSLTreeVisitor::VisitTopLevelStatement(HLSLStatement *node) { if (node->nodeType == HLSLNodeType_Declaration) { VisitDeclaration((HLSLDeclaration *)node); @@ -691,23 +628,23 @@ void HLSLTreeVisitor::VisitTopLevelStatement(HLSLStatement * node) VisitFunction((HLSLFunction *)node); } else if (node->nodeType == HLSLNodeType_Comment) { - VisitComment((HLSLComment*)node); + VisitComment((HLSLComment *)node); } - + // FX file stuff -// else if (node->nodeType == HLSLNodeType_Technique) { -// VisitTechnique((HLSLTechnique *)node); -// } -// else if (node->nodeType == HLSLNodeType_Pipeline) { -// VisitPipeline((HLSLPipeline *)node); -// } - + // else if (node->nodeType == HLSLNodeType_Technique) { + // VisitTechnique((HLSLTechnique *)node); + // } + // else if (node->nodeType == HLSLNodeType_Pipeline) { + // VisitPipeline((HLSLPipeline *)node); + // } + else { ASSERT(false); } } -void HLSLTreeVisitor::VisitStatements(HLSLStatement * statement) +void HLSLTreeVisitor::VisitStatements(HLSLStatement *statement) { while (statement != NULL) { VisitStatement(statement); @@ -715,7 +652,7 @@ void HLSLTreeVisitor::VisitStatements(HLSLStatement * statement) } } -void HLSLTreeVisitor::VisitStatement(HLSLStatement * node) +void HLSLTreeVisitor::VisitStatement(HLSLStatement *node) { // Function statements if (node->nodeType == HLSLNodeType_Declaration) { @@ -753,7 +690,7 @@ void HLSLTreeVisitor::VisitStatement(HLSLStatement * node) } } -void HLSLTreeVisitor::VisitDeclaration(HLSLDeclaration * node) +void HLSLTreeVisitor::VisitDeclaration(HLSLDeclaration *node) { VisitType(node->type); /*do { @@ -768,31 +705,29 @@ void HLSLTreeVisitor::VisitDeclaration(HLSLDeclaration * node) } } -void HLSLTreeVisitor::VisitStruct(HLSLStruct * node) +void HLSLTreeVisitor::VisitStruct(HLSLStruct *node) { - HLSLStructField * field = node->field; + HLSLStructField *field = node->field; while (field != NULL) { VisitStructField(field); field = field->nextField; } } -void HLSLTreeVisitor::VisitStructField(HLSLStructField * node) +void HLSLTreeVisitor::VisitStructField(HLSLStructField *node) { // This can use a constant in an array field that must be resolved - if (node->type.array) - { + if (node->type.array) { VisitExpression(node->type.arraySize); } - + VisitType(node->type); } -void HLSLTreeVisitor::VisitBuffer(HLSLBuffer * node) +void HLSLTreeVisitor::VisitBuffer(HLSLBuffer *node) { - if (node->IsGlobalFields()) - { - HLSLDeclaration* field = node->field; + if (node->IsGlobalFields()) { + HLSLDeclaration *field = node->field; while (field != NULL) { ASSERT(field->nodeType == HLSLNodeType_Declaration); VisitDeclaration(field); @@ -800,8 +735,7 @@ void HLSLTreeVisitor::VisitBuffer(HLSLBuffer * node) field = (HLSLDeclaration *)field->nextStatement; } } - else - { + else { VisitStruct(node->bufferStruct); } } @@ -811,11 +745,11 @@ void HLSLTreeVisitor::VisitBuffer(HLSLBuffer * node) VisitType(node->type); }*/ -void HLSLTreeVisitor::VisitFunction(HLSLFunction * node) +void HLSLTreeVisitor::VisitFunction(HLSLFunction *node) { VisitType(node->returnType); - HLSLArgument* argument = node->argument; + HLSLArgument *argument = node->argument; while (argument != NULL) { VisitArgument(argument); argument = argument->nextArgument; @@ -824,7 +758,7 @@ void HLSLTreeVisitor::VisitFunction(HLSLFunction * node) VisitStatements(node->statement); } -void HLSLTreeVisitor::VisitArgument(HLSLArgument * node) +void HLSLTreeVisitor::VisitArgument(HLSLArgument *node) { VisitType(node->type); if (node->defaultValue != NULL) { @@ -832,12 +766,12 @@ void HLSLTreeVisitor::VisitArgument(HLSLArgument * node) } } -void HLSLTreeVisitor::VisitExpressionStatement(HLSLExpressionStatement * node) +void HLSLTreeVisitor::VisitExpressionStatement(HLSLExpressionStatement *node) { VisitExpression(node->expression); } -void HLSLTreeVisitor::VisitExpression(HLSLExpression * node) +void HLSLTreeVisitor::VisitExpression(HLSLExpression *node) { VisitType(node->expressionType); @@ -872,29 +806,29 @@ void HLSLTreeVisitor::VisitExpression(HLSLExpression * node) VisitFunctionCall((HLSLFunctionCall *)node); } else if (node->nodeType == HLSLNodeType_MemberFunctionCall) { - HLSLMemberFunctionCall* memberFunctionCall = (HLSLMemberFunctionCall *)node; - VisitIdentifierExpression((HLSLIdentifierExpression*)memberFunctionCall->memberIdentifier); // const_cast + HLSLMemberFunctionCall *memberFunctionCall = (HLSLMemberFunctionCall *)node; + VisitIdentifierExpression((HLSLIdentifierExpression *)memberFunctionCall->memberIdentifier); // const_cast VisitFunctionCall(memberFunctionCall); } // Acoget-TODO: This was missing. Did adding it break anything? -// else if (node->nodeType == HLSLNodeType_SamplerState) { -// VisitSamplerState((HLSLSamplerState *)node); -// } + // else if (node->nodeType == HLSLNodeType_SamplerState) { + // VisitSamplerState((HLSLSamplerState *)node); + // } else { ASSERT(false); } } -void HLSLTreeVisitor::VisitReturnStatement(HLSLReturnStatement * node) +void HLSLTreeVisitor::VisitReturnStatement(HLSLReturnStatement *node) { VisitExpression(node->expression); } -void HLSLTreeVisitor::VisitDiscardStatement(HLSLDiscardStatement * node) {} -void HLSLTreeVisitor::VisitBreakStatement(HLSLBreakStatement * node) {} -void HLSLTreeVisitor::VisitContinueStatement(HLSLContinueStatement * node) {} +void HLSLTreeVisitor::VisitDiscardStatement(HLSLDiscardStatement *node) {} +void HLSLTreeVisitor::VisitBreakStatement(HLSLBreakStatement *node) {} +void HLSLTreeVisitor::VisitContinueStatement(HLSLContinueStatement *node) {} -void HLSLTreeVisitor::VisitIfStatement(HLSLIfStatement * node) +void HLSLTreeVisitor::VisitIfStatement(HLSLIfStatement *node) { VisitExpression(node->condition); VisitStatements(node->statement); @@ -903,7 +837,7 @@ void HLSLTreeVisitor::VisitIfStatement(HLSLIfStatement * node) } } -void HLSLTreeVisitor::VisitForStatement(HLSLForStatement * node) +void HLSLTreeVisitor::VisitForStatement(HLSLForStatement *node) { if (node->initialization) { VisitDeclaration(node->initialization); @@ -917,61 +851,61 @@ void HLSLTreeVisitor::VisitForStatement(HLSLForStatement * node) VisitStatements(node->statement); } -void HLSLTreeVisitor::VisitBlockStatement(HLSLBlockStatement * node) +void HLSLTreeVisitor::VisitBlockStatement(HLSLBlockStatement *node) { VisitStatements(node->statement); } -void HLSLTreeVisitor::VisitUnaryExpression(HLSLUnaryExpression * node) +void HLSLTreeVisitor::VisitUnaryExpression(HLSLUnaryExpression *node) { VisitExpression(node->expression); } -void HLSLTreeVisitor::VisitBinaryExpression(HLSLBinaryExpression * node) +void HLSLTreeVisitor::VisitBinaryExpression(HLSLBinaryExpression *node) { VisitExpression(node->expression1); VisitExpression(node->expression2); } -void HLSLTreeVisitor::VisitConditionalExpression(HLSLConditionalExpression * node) +void HLSLTreeVisitor::VisitConditionalExpression(HLSLConditionalExpression *node) { VisitExpression(node->condition); VisitExpression(node->falseExpression); VisitExpression(node->trueExpression); } -void HLSLTreeVisitor::VisitCastingExpression(HLSLCastingExpression * node) +void HLSLTreeVisitor::VisitCastingExpression(HLSLCastingExpression *node) { VisitType(node->type); VisitExpression(node->expression); } -void HLSLTreeVisitor::VisitLiteralExpression(HLSLLiteralExpression * node) {} -void HLSLTreeVisitor::VisitIdentifierExpression(HLSLIdentifierExpression * node) {} +void HLSLTreeVisitor::VisitLiteralExpression(HLSLLiteralExpression *node) {} +void HLSLTreeVisitor::VisitIdentifierExpression(HLSLIdentifierExpression *node) {} -void HLSLTreeVisitor::VisitConstructorExpression(HLSLConstructorExpression * node) +void HLSLTreeVisitor::VisitConstructorExpression(HLSLConstructorExpression *node) { - HLSLExpression * argument = node->argument; + HLSLExpression *argument = node->argument; while (argument != NULL) { VisitExpression(argument); argument = argument->nextExpression; } } -void HLSLTreeVisitor::VisitMemberAccess(HLSLMemberAccess * node) +void HLSLTreeVisitor::VisitMemberAccess(HLSLMemberAccess *node) { VisitExpression(node->object); } -void HLSLTreeVisitor::VisitArrayAccess(HLSLArrayAccess * node) +void HLSLTreeVisitor::VisitArrayAccess(HLSLArrayAccess *node) { VisitExpression(node->array); VisitExpression(node->index); } -void HLSLTreeVisitor::VisitFunctionCall(HLSLFunctionCall * node) +void HLSLTreeVisitor::VisitFunctionCall(HLSLFunctionCall *node) { - HLSLExpression * argument = node->argument; + HLSLExpression *argument = node->argument; while (argument != NULL) { VisitExpression(argument); argument = argument->nextExpression; @@ -1015,14 +949,13 @@ void HLSLTreeVisitor::VisitPipeline(HLSLPipeline * node) } */ -void HLSLTreeVisitor::VisitComment(HLSLComment * node) +void HLSLTreeVisitor::VisitComment(HLSLComment *node) { - } -void HLSLTreeVisitor::VisitFunctions(HLSLRoot * root) +void HLSLTreeVisitor::VisitFunctions(HLSLRoot *root) { - HLSLStatement * statement = root->statement; + HLSLStatement *statement = root->statement; while (statement != NULL) { if (statement->nodeType == HLSLNodeType_Function) { VisitFunction((HLSLFunction *)statement); @@ -1032,9 +965,9 @@ void HLSLTreeVisitor::VisitFunctions(HLSLRoot * root) } } -void HLSLTreeVisitor::VisitParameters(HLSLRoot * root) +void HLSLTreeVisitor::VisitParameters(HLSLRoot *root) { - HLSLStatement * statement = root->statement; + HLSLStatement *statement = root->statement; while (statement != NULL) { if (statement->nodeType == HLSLNodeType_Declaration) { VisitDeclaration((HLSLDeclaration *)statement); @@ -1044,54 +977,49 @@ void HLSLTreeVisitor::VisitParameters(HLSLRoot * root) } } - -class ResetHiddenFlagVisitor : public HLSLTreeVisitor -{ +class ResetHiddenFlagVisitor : public HLSLTreeVisitor { public: virtual ~ResetHiddenFlagVisitor() {} - - virtual void VisitTopLevelStatement(HLSLStatement * statement) override + + virtual void VisitTopLevelStatement(HLSLStatement *statement) override { statement->hidden = true; - if (statement->nodeType == HLSLNodeType_Buffer) - { - VisitBuffer((HLSLBuffer*)statement); + if (statement->nodeType == HLSLNodeType_Buffer) { + VisitBuffer((HLSLBuffer *)statement); } } // Hide buffer fields. - virtual void VisitDeclaration(HLSLDeclaration * node) override + virtual void VisitDeclaration(HLSLDeclaration *node) override { - // node->hidden = true; + // node->hidden = true; } - virtual void VisitComment(HLSLComment * node) override + virtual void VisitComment(HLSLComment *node) override { node->hidden = true; } - - virtual void VisitArgument(HLSLArgument * node) override + + virtual void VisitArgument(HLSLArgument *node) override { - node->hidden = false; // Arguments are visible by default. + node->hidden = false; // Arguments are visible by default. } }; -class MarkVisibleStatementsVisitor : public HLSLTreeVisitor -{ +class MarkVisibleStatementsVisitor : public HLSLTreeVisitor { public: - - HLSLTree * tree; - MarkVisibleStatementsVisitor(HLSLTree * tree) : tree(tree) {} + HLSLTree *tree; + MarkVisibleStatementsVisitor(HLSLTree *tree) : tree(tree) {} virtual ~MarkVisibleStatementsVisitor() {} - - virtual void VisitComment(HLSLComment * node) override + + virtual void VisitComment(HLSLComment *node) override { node->hidden = false; } - virtual void VisitFunction(HLSLFunction * node) override + virtual void VisitFunction(HLSLFunction *node) override { node->hidden = false; HLSLTreeVisitor::VisitFunction(node); @@ -1100,118 +1028,101 @@ class MarkVisibleStatementsVisitor : public HLSLTreeVisitor VisitFunction(node->forward); } - virtual void VisitFunctionCall(HLSLFunctionCall * node) override + virtual void VisitFunctionCall(HLSLFunctionCall *node) override { HLSLTreeVisitor::VisitFunctionCall(node); - if (node->function->hidden) - { - VisitFunction(const_cast(node->function)); + if (node->function->hidden) { + VisitFunction(const_cast(node->function)); } } - virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node) override + virtual void VisitIdentifierExpression(HLSLIdentifierExpression *node) override { HLSLTreeVisitor::VisitIdentifierExpression(node); - - if (node->global) - { - HLSLBuffer* buffer = NULL; - HLSLDeclaration * declaration = tree->FindGlobalDeclaration(node->name, &buffer); - if (declaration != NULL && declaration->hidden) - { + if (node->global) { + HLSLBuffer *buffer = NULL; + HLSLDeclaration *declaration = tree->FindGlobalDeclaration(node->name, &buffer); + + if (declaration != NULL && declaration->hidden) { declaration->hidden = false; VisitDeclaration(declaration); } - if (buffer != NULL && buffer->hidden) - { + if (buffer != NULL && buffer->hidden) { buffer->hidden = false; } } } - - virtual void VisitType(HLSLType & type) override + + virtual void VisitType(HLSLType &type) override { -// if (type.array) -// { -// // Alec added this to try to handle structs with array constants, but -// // it causes other issues. VisitStructField calls VisitType. -// -// // handle sized or unsized array, since sized may use constant -// // VisitExpression(type.arraySize); -// int bp = 0; -// bp = bp; -// } -// else - if (type.baseType == HLSLBaseType_UserDefined) - { - HLSLStruct * globalStruct = tree->FindGlobalStruct(type.typeName); - if (globalStruct != NULL) - { + // if (type.array) + // { + // // Alec added this to try to handle structs with array constants, but + // // it causes other issues. VisitStructField calls VisitType. + // + // // handle sized or unsized array, since sized may use constant + // // VisitExpression(type.arraySize); + // int bp = 0; + // bp = bp; + // } + // else + if (type.baseType == HLSLBaseType_UserDefined) { + HLSLStruct *globalStruct = tree->FindGlobalStruct(type.typeName); + if (globalStruct != NULL) { globalStruct->hidden = false; VisitStruct(globalStruct); } } } - }; - -void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1/*=NULL*/) +void PruneTree(HLSLTree *tree, const char *entryName0, const char *entryName1 /*=NULL*/) { - HLSLRoot* root = tree->GetRoot(); + HLSLRoot *root = tree->GetRoot(); // Reset all flags. ResetHiddenFlagVisitor reset; reset.VisitRoot(root); // Mark all the statements necessary for these entrypoints. - HLSLFunction* entry = tree->FindFunction(entryName0); - if (entry != NULL) - { + HLSLFunction *entry = tree->FindFunction(entryName0); + if (entry != NULL) { MarkVisibleStatementsVisitor mark(tree); mark.VisitFunction(entry); } - if (entryName1 != NULL) - { + if (entryName1 != NULL) { entry = tree->FindFunction(entryName1); - if (entry != NULL) - { + if (entry != NULL) { MarkVisibleStatementsVisitor mark(tree); mark.VisitFunction(entry); } } // Mark buffers visible, if any of their fields is visible. - HLSLStatement * statement = root->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Buffer) - { - HLSLBuffer* buffer = (HLSLBuffer*)statement; + HLSLStatement *statement = root->statement; + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Buffer) { + HLSLBuffer *buffer = (HLSLBuffer *)statement; - if (buffer->IsGlobalFields()) - { + if (buffer->IsGlobalFields()) { // mark buffer visible if any of its fields are used - HLSLDeclaration* field = buffer->field; - while (field != NULL) - { + HLSLDeclaration *field = buffer->field; + while (field != NULL) { ASSERT(field->nodeType == HLSLNodeType_Declaration); - if (!field->hidden) - { + if (!field->hidden) { buffer->hidden = false; break; } - field = (HLSLDeclaration*)field->nextStatement; + field = (HLSLDeclaration *)field->nextStatement; } } - else - { + else { // TODO: these load from a struct so may just need // to somehow mark this if present. - + /* all struct fields are hidden = false, so this doesn't work // mark buffer visible if any struct fields are used HLSLStructField* field = buffer->bufferStruct->field; @@ -1233,84 +1144,73 @@ void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1/*= } } - -void SortTree(HLSLTree * tree) +void SortTree(HLSLTree *tree) { // Stable sort so that statements are in this order: // const scalars for arrays, structs, declarations, functions, techniques. - // but their relative order is preserved. + // but their relative order is preserved. - HLSLRoot* root = tree->GetRoot(); + HLSLRoot *root = tree->GetRoot(); + + HLSLStatement *constScalarDeclarations = NULL; + HLSLStatement *lastConstScalarDeclaration = NULL; - HLSLStatement* constScalarDeclarations = NULL; - HLSLStatement* lastConstScalarDeclaration = NULL; - - HLSLStatement* structs = NULL; - HLSLStatement* lastStruct = NULL; - - HLSLStatement* constDeclarations = NULL; - HLSLStatement* lastConstDeclaration = NULL; - - HLSLStatement* declarations = NULL; - HLSLStatement* lastDeclaration = NULL; - - HLSLStatement* functions = NULL; - HLSLStatement* lastFunction = NULL; - - HLSLStatement* other = NULL; - HLSLStatement* lastOther = NULL; - - -#define AppendToList(statement, list, listLast) \ - if (list == NULL) list = statement; \ + HLSLStatement *structs = NULL; + HLSLStatement *lastStruct = NULL; + + HLSLStatement *constDeclarations = NULL; + HLSLStatement *lastConstDeclaration = NULL; + + HLSLStatement *declarations = NULL; + HLSLStatement *lastDeclaration = NULL; + + HLSLStatement *functions = NULL; + HLSLStatement *lastFunction = NULL; + + HLSLStatement *other = NULL; + HLSLStatement *lastOther = NULL; + +#define AppendToList(statement, list, listLast) \ + if (list == NULL) list = statement; \ if (listLast != NULL) listLast->nextStatement = statement; \ listLast = statement; - - HLSLStatement* statement = root->statement; + + HLSLStatement *statement = root->statement; while (statement != NULL) { - HLSLStatement* nextStatement = statement->nextStatement; + HLSLStatement *nextStatement = statement->nextStatement; statement->nextStatement = NULL; if (statement->nodeType == HLSLNodeType_Struct) { AppendToList(statement, structs, lastStruct); } else if (statement->nodeType == HLSLNodeType_Declaration || - statement->nodeType == HLSLNodeType_Buffer) - { + statement->nodeType == HLSLNodeType_Buffer) { // There are cases where a struct uses a const array size, // so those need to be ordered prior to the struct. - if (statement->nodeType == HLSLNodeType_Declaration) - { - HLSLDeclaration* decl = (HLSLDeclaration *)statement; - - if (decl->type.flags & HLSLTypeFlag_Const) - { + if (statement->nodeType == HLSLNodeType_Declaration) { + HLSLDeclaration *decl = (HLSLDeclaration *)statement; + + if (decl->type.flags & HLSLTypeFlag_Const) { // this is a global scalar, so best to order first - if (IsScalarType(decl->type.baseType)) - { + if (IsScalarType(decl->type.baseType)) { AppendToList(statement, constScalarDeclarations, lastConstScalarDeclaration); } - else - { + else { AppendToList(statement, constDeclarations, lastConstDeclaration); } } - else - { + else { AppendToList(statement, declarations, lastDeclaration); } } - else if (statement->nodeType == HLSLNodeType_Buffer) - { + else if (statement->nodeType == HLSLNodeType_Buffer) { AppendToList(statement, declarations, lastDeclaration); } } - else if (statement->nodeType == HLSLNodeType_Function) - { + else if (statement->nodeType == HLSLNodeType_Function) { AppendToList(statement, functions, lastFunction); } - else - { + else { AppendToList(statement, other, lastOther); } @@ -1318,48 +1218,54 @@ void SortTree(HLSLTree * tree) } // Chain all the statements in the order that we want. - HLSLStatement * firstStatement = constScalarDeclarations; - HLSLStatement * lastStatement = lastConstScalarDeclaration; + HLSLStatement *firstStatement = constScalarDeclarations; + HLSLStatement *lastStatement = lastConstScalarDeclaration; if (structs != NULL) { - if (firstStatement == NULL) firstStatement = structs; - else lastStatement->nextStatement = structs; + if (firstStatement == NULL) + firstStatement = structs; + else + lastStatement->nextStatement = structs; lastStatement = lastStruct; } - + if (constDeclarations != NULL) { - if (firstStatement == NULL) firstStatement = constDeclarations; - else lastStatement->nextStatement = constDeclarations; + if (firstStatement == NULL) + firstStatement = constDeclarations; + else + lastStatement->nextStatement = constDeclarations; lastStatement = lastConstDeclaration; } if (declarations != NULL) { - if (firstStatement == NULL) firstStatement = declarations; - else lastStatement->nextStatement = declarations; + if (firstStatement == NULL) + firstStatement = declarations; + else + lastStatement->nextStatement = declarations; lastStatement = lastDeclaration; } if (functions != NULL) { - if (firstStatement == NULL) firstStatement = functions; - else lastStatement->nextStatement = functions; + if (firstStatement == NULL) + firstStatement = functions; + else + lastStatement->nextStatement = functions; lastStatement = lastFunction; } if (other != NULL) { - if (firstStatement == NULL) firstStatement = other; - else lastStatement->nextStatement = other; + if (firstStatement == NULL) + firstStatement = other; + else + lastStatement->nextStatement = other; lastStatement = lastOther; } root->statement = firstStatement; } - - - - // First and last can be the same. -void AddStatements(HLSLRoot * root, HLSLStatement * before, HLSLStatement * first, HLSLStatement * last) +void AddStatements(HLSLRoot *root, HLSLStatement *before, HLSLStatement *first, HLSLStatement *last) { if (before == NULL) { last->nextStatement = root->statement; @@ -1371,12 +1277,11 @@ void AddStatements(HLSLRoot * root, HLSLStatement * before, HLSLStatement * firs } } -void AddSingleStatement(HLSLRoot * root, HLSLStatement * before, HLSLStatement * statement) +void AddSingleStatement(HLSLRoot *root, HLSLStatement *before, HLSLStatement *statement) { AddStatements(root, before, statement, statement); } - /* *X file releated // @@ This is very game-specific. Should be moved to pipeline_parser or somewhere else. void GroupParameters(HLSLTree * tree) @@ -1400,7 +1305,7 @@ void GroupParameters(HLSLTree * tree) HLSLDeclaration * lastPerPassSampler = NULL; HLSLStatement * statementBeforeBuffers = NULL; - + HLSLStatement* previousStatement = NULL; HLSLStatement* statement = root->statement; while (statement != NULL) @@ -1408,7 +1313,7 @@ void GroupParameters(HLSLTree * tree) HLSLStatement* nextStatement = statement->nextStatement; if (statement->nodeType == HLSLNodeType_Struct) // Do not remove this, or it will mess the else clause below. - { + { statementBeforeBuffers = statement; } else if (statement->nodeType == HLSLNodeType_Declaration) @@ -1529,7 +1434,7 @@ void GroupParameters(HLSLTree * tree) perItemBuffer->name = tree->AddString("per_item"); perItemBuffer->registerName = tree->AddString("b0"); perItemBuffer->field = firstPerItemDeclaration; - + // Set declaration buffer pointers. HLSLDeclaration * field = perItemBuffer->field; while (field != NULL) @@ -1558,64 +1463,58 @@ void GroupParameters(HLSLTree * tree) field->buffer = perPassBuffer; field = (HLSLDeclaration *)field->nextStatement; } - + // Add buffer to statements. AddSingleStatement(root, statementBeforeBuffers, perPassBuffer); } } */ -class FindArgumentVisitor : public HLSLTreeVisitor -{ +class FindArgumentVisitor : public HLSLTreeVisitor { public: bool found; - const char * name; + const char *name; virtual ~FindArgumentVisitor() {} - - FindArgumentVisitor() - { - found = false; - name = NULL; - } - - bool FindArgument(const char * _name, HLSLFunction * function) + + FindArgumentVisitor() + { + found = false; + name = NULL; + } + + bool FindArgument(const char *_name, HLSLFunction *function) { found = false; name = _name; VisitStatements(function->statement); return found; } - - virtual void VisitStatements(HLSLStatement * statement) override + + virtual void VisitStatements(HLSLStatement *statement) override { - while (statement != NULL && !found) - { + while (statement != NULL && !found) { VisitStatement(statement); statement = statement->nextStatement; } } - virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node) override + virtual void VisitIdentifierExpression(HLSLIdentifierExpression *node) override { - if (node->name == name) - { + if (node->name == name) { found = true; } } }; - -void HideUnusedArguments(HLSLFunction * function) +void HideUnusedArguments(HLSLFunction *function) { FindArgumentVisitor visitor; - + // For each argument. - HLSLArgument * arg = function->argument; - while (arg != NULL) - { - if (!visitor.FindArgument(arg->name, function)) - { + HLSLArgument *arg = function->argument; + while (arg != NULL) { + if (!visitor.FindArgument(arg->name, function)) { arg->hidden = true; } @@ -1623,30 +1522,31 @@ void HideUnusedArguments(HLSLFunction * function) } } -bool NeedsFlattening(HLSLExpression * expr, int level = 0) { +bool NeedsFlattening(HLSLExpression *expr, int level = 0) +{ if (expr == NULL) { return false; } if (expr->nodeType == HLSLNodeType_UnaryExpression) { - HLSLUnaryExpression * unaryExpr = (HLSLUnaryExpression *)expr; - return NeedsFlattening(unaryExpr->expression, level+1) || NeedsFlattening(expr->nextExpression, level); + HLSLUnaryExpression *unaryExpr = (HLSLUnaryExpression *)expr; + return NeedsFlattening(unaryExpr->expression, level + 1) || NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_BinaryExpression) { - HLSLBinaryExpression * binaryExpr = (HLSLBinaryExpression *)expr; + HLSLBinaryExpression *binaryExpr = (HLSLBinaryExpression *)expr; if (IsAssignOp(binaryExpr->binaryOp)) { - return NeedsFlattening(binaryExpr->expression2, level+1) || NeedsFlattening(expr->nextExpression, level); + return NeedsFlattening(binaryExpr->expression2, level + 1) || NeedsFlattening(expr->nextExpression, level); } else { - return NeedsFlattening(binaryExpr->expression1, level+1) || NeedsFlattening(binaryExpr->expression2, level+1) || NeedsFlattening(expr->nextExpression, level); + return NeedsFlattening(binaryExpr->expression1, level + 1) || NeedsFlattening(binaryExpr->expression2, level + 1) || NeedsFlattening(expr->nextExpression, level); } } else if (expr->nodeType == HLSLNodeType_ConditionalExpression) { - HLSLConditionalExpression * conditionalExpr = (HLSLConditionalExpression *)expr; - return NeedsFlattening(conditionalExpr->condition, level+1) || NeedsFlattening(conditionalExpr->trueExpression, level+1) || NeedsFlattening(conditionalExpr->falseExpression, level+1) || NeedsFlattening(expr->nextExpression, level); + HLSLConditionalExpression *conditionalExpr = (HLSLConditionalExpression *)expr; + return NeedsFlattening(conditionalExpr->condition, level + 1) || NeedsFlattening(conditionalExpr->trueExpression, level + 1) || NeedsFlattening(conditionalExpr->falseExpression, level + 1) || NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_CastingExpression) { - HLSLCastingExpression * castingExpr = (HLSLCastingExpression *)expr; - return NeedsFlattening(castingExpr->expression, level+1) || NeedsFlattening(expr->nextExpression, level); + HLSLCastingExpression *castingExpr = (HLSLCastingExpression *)expr; + return NeedsFlattening(castingExpr->expression, level + 1) || NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_LiteralExpression) { return NeedsFlattening(expr->nextExpression, level); @@ -1655,24 +1555,24 @@ bool NeedsFlattening(HLSLExpression * expr, int level = 0) { return NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_ConstructorExpression) { - HLSLConstructorExpression * constructorExpr = (HLSLConstructorExpression *)expr; - return NeedsFlattening(constructorExpr->argument, level+1) || NeedsFlattening(expr->nextExpression, level); + HLSLConstructorExpression *constructorExpr = (HLSLConstructorExpression *)expr; + return NeedsFlattening(constructorExpr->argument, level + 1) || NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_MemberAccess) { - return NeedsFlattening(expr->nextExpression, level+1); + return NeedsFlattening(expr->nextExpression, level + 1); } else if (expr->nodeType == HLSLNodeType_ArrayAccess) { - HLSLArrayAccess * arrayAccess = (HLSLArrayAccess *)expr; - return NeedsFlattening(arrayAccess->array, level+1) || NeedsFlattening(arrayAccess->index, level+1) || NeedsFlattening(expr->nextExpression, level); + HLSLArrayAccess *arrayAccess = (HLSLArrayAccess *)expr; + return NeedsFlattening(arrayAccess->array, level + 1) || NeedsFlattening(arrayAccess->index, level + 1) || NeedsFlattening(expr->nextExpression, level); } else if (expr->nodeType == HLSLNodeType_FunctionCall) { - HLSLFunctionCall * functionCall = (HLSLFunctionCall *)expr; + HLSLFunctionCall *functionCall = (HLSLFunctionCall *)expr; if (functionCall->function->numOutputArguments > 0) { if (level > 0) { return true; } } - return NeedsFlattening(functionCall->argument, level+1) || NeedsFlattening(expr->nextExpression, level); + return NeedsFlattening(functionCall->argument, level + 1) || NeedsFlattening(expr->nextExpression, level); } else { //assert(false); @@ -1680,11 +1580,11 @@ bool NeedsFlattening(HLSLExpression * expr, int level = 0) { } } - struct StatementList { - HLSLStatement * head = NULL; - HLSLStatement * tail = NULL; - void append(HLSLStatement * st) { + HLSLStatement *head = NULL; + HLSLStatement *tail = NULL; + void append(HLSLStatement *st) + { if (head == NULL) { tail = head = st; } @@ -1693,292 +1593,285 @@ struct StatementList { } }; +class ExpressionFlattener : public HLSLTreeVisitor { +public: + HLSLTree *m_tree; + int tmp_index; + HLSLStatement **statement_pointer; + HLSLFunction *current_function; - class ExpressionFlattener : public HLSLTreeVisitor + ExpressionFlattener() { - public: - HLSLTree * m_tree; - int tmp_index; - HLSLStatement ** statement_pointer; - HLSLFunction * current_function; - - ExpressionFlattener() - { - m_tree = NULL; - tmp_index = 0; - statement_pointer = NULL; - current_function = NULL; - } - virtual ~ExpressionFlattener() {} - - void FlattenExpressions(HLSLTree * tree) - { - m_tree = tree; - VisitRoot(tree->GetRoot()); + m_tree = NULL; + tmp_index = 0; + statement_pointer = NULL; + current_function = NULL; + } + virtual ~ExpressionFlattener() {} + + void FlattenExpressions(HLSLTree *tree) + { + m_tree = tree; + VisitRoot(tree->GetRoot()); + } + + // Visit all statements updating the statement_pointer so that we can insert and replace statements. @@ Add this to the default visitor? + virtual void VisitFunction(HLSLFunction *node) override + { + current_function = node; + statement_pointer = &node->statement; + VisitStatements(node->statement); + statement_pointer = NULL; + current_function = NULL; + } + + virtual void VisitComment(HLSLComment *node) override + { + // TODO: do nothing? + } + + virtual void VisitIfStatement(HLSLIfStatement *node) override + { + if (NeedsFlattening(node->condition, 1)) { + assert(false); // @@ Add statements before if statement. } - // Visit all statements updating the statement_pointer so that we can insert and replace statements. @@ Add this to the default visitor? - virtual void VisitFunction(HLSLFunction * node) override - { - current_function = node; - statement_pointer = &node->statement; - VisitStatements(node->statement); - statement_pointer = NULL; - current_function = NULL; + statement_pointer = &node->statement; + VisitStatements(node->statement); + if (node->elseStatement) { + statement_pointer = &node->elseStatement; + VisitStatements(node->elseStatement); } + } - virtual void VisitComment(HLSLComment * node) override - { - // TODO: do nothing? + virtual void VisitForStatement(HLSLForStatement *node) override + { + if (NeedsFlattening(node->initialization->assignment, 1)) { + assert(false); // @@ Add statements before for statement. } - - virtual void VisitIfStatement(HLSLIfStatement * node) override - { - if (NeedsFlattening(node->condition, 1)) { - assert(false); // @@ Add statements before if statement. - } - - statement_pointer = &node->statement; - VisitStatements(node->statement); - if (node->elseStatement) { - statement_pointer = &node->elseStatement; - VisitStatements(node->elseStatement); - } + if (NeedsFlattening(node->condition, 1) || NeedsFlattening(node->increment, 1)) { + assert(false); // @@ These are tricky to implement. Need to handle all loop exits. } - - virtual void VisitForStatement(HLSLForStatement * node) override - { - if (NeedsFlattening(node->initialization->assignment, 1)) { - assert(false); // @@ Add statements before for statement. - } - if (NeedsFlattening(node->condition, 1) || NeedsFlattening(node->increment, 1)) { - assert(false); // @@ These are tricky to implement. Need to handle all loop exits. - } - statement_pointer = &node->statement; - VisitStatements(node->statement); + statement_pointer = &node->statement; + VisitStatements(node->statement); + } + + virtual void VisitBlockStatement(HLSLBlockStatement *node) override + { + statement_pointer = &node->statement; + VisitStatements(node->statement); + } + + virtual void VisitStatements(HLSLStatement *statement) override + { + while (statement != NULL) { + VisitStatement(statement); + statement_pointer = &statement->nextStatement; + statement = statement->nextStatement; } - - virtual void VisitBlockStatement(HLSLBlockStatement * node) override - { - statement_pointer = &node->statement; - VisitStatements(node->statement); + } + + // This is usually a function call or assignment. + virtual void VisitExpressionStatement(HLSLExpressionStatement *node) override + { + if (NeedsFlattening(node->expression, 0)) { + StatementList statements; + Flatten(node->expression, statements, false); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement *tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; + + // @@ Delete node? } - - virtual void VisitStatements(HLSLStatement * statement) override - { - while (statement != NULL) { - VisitStatement(statement); - statement_pointer = &statement->nextStatement; - statement = statement->nextStatement; - } + } + + virtual void VisitDeclaration(HLSLDeclaration *node) override + { + // Skip global declarations. + if (statement_pointer == NULL) return; + + if (NeedsFlattening(node->assignment, 1)) { + StatementList statements; + HLSLIdentifierExpression *ident = Flatten(node->assignment, statements, true); + + // @@ Delete node->assignment? + + node->assignment = ident; + statements.append(node); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement *tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; } + } - // This is usually a function call or assignment. - virtual void VisitExpressionStatement(HLSLExpressionStatement * node) override - { - if (NeedsFlattening(node->expression, 0)) - { - StatementList statements; - Flatten(node->expression, statements, false); - - // Link beginning of statement list. - *statement_pointer = statements.head; - - // Link end of statement list. - HLSLStatement * tail = statements.tail; - tail->nextStatement = node->nextStatement; - - // Update statement pointer. - statement_pointer = &tail->nextStatement; - - // @@ Delete node? - } + virtual void VisitReturnStatement(HLSLReturnStatement *node) override + { + if (NeedsFlattening(node->expression, 1)) { + StatementList statements; + HLSLIdentifierExpression *ident = Flatten(node->expression, statements, true); + + // @@ Delete node->expression? + + node->expression = ident; + statements.append(node); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement *tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; } + } - virtual void VisitDeclaration(HLSLDeclaration * node) override - { - // Skip global declarations. - if (statement_pointer == NULL) return; - - if (NeedsFlattening(node->assignment, 1)) - { - StatementList statements; - HLSLIdentifierExpression * ident = Flatten(node->assignment, statements, true); - - // @@ Delete node->assignment? - - node->assignment = ident; - statements.append(node); - - // Link beginning of statement list. - *statement_pointer = statements.head; - - // Link end of statement list. - HLSLStatement * tail = statements.tail; - tail->nextStatement = node->nextStatement; - - // Update statement pointer. - statement_pointer = &tail->nextStatement; - } + HLSLDeclaration *BuildTemporaryDeclaration(HLSLExpression *expr) + { + assert(expr->expressionType.baseType != HLSLBaseType_Void); + + HLSLDeclaration *declaration = m_tree->AddNode(expr->fileName, expr->line); + declaration->name = m_tree->AddStringFormat("tmp%d", tmp_index++); + declaration->type = expr->expressionType; + declaration->assignment = expr; + + //HLSLIdentifierExpression * ident = (HLSLIdentifierExpression *)expr; + + return declaration; + } + + HLSLExpressionStatement *BuildExpressionStatement(HLSLExpression *expr) + { + HLSLExpressionStatement *statement = m_tree->AddNode(expr->fileName, expr->line); + statement->expression = expr; + return statement; + } + + HLSLIdentifierExpression *AddExpressionStatement(HLSLExpression *expr, StatementList &statements, bool wantIdent) + { + if (wantIdent) { + HLSLDeclaration *declaration = BuildTemporaryDeclaration(expr); + statements.append(declaration); + + HLSLIdentifierExpression *ident = m_tree->AddNode(expr->fileName, expr->line); + ident->name = declaration->name; + ident->expressionType = declaration->type; + return ident; + } + else { + HLSLExpressionStatement *statement = BuildExpressionStatement(expr); + statements.append(statement); + return NULL; } + } - virtual void VisitReturnStatement(HLSLReturnStatement * node) override - { - if (NeedsFlattening(node->expression, 1)) - { - StatementList statements; - HLSLIdentifierExpression * ident = Flatten(node->expression, statements, true); - - // @@ Delete node->expression? - - node->expression = ident; - statements.append(node); - - // Link beginning of statement list. - *statement_pointer = statements.head; - - // Link end of statement list. - HLSLStatement * tail = statements.tail; - tail->nextStatement = node->nextStatement; - - // Update statement pointer. - statement_pointer = &tail->nextStatement; - } + HLSLIdentifierExpression *Flatten(HLSLExpression *expr, StatementList &statements, bool wantIdent = true) + { + if (!NeedsFlattening(expr, wantIdent)) { + return AddExpressionStatement(expr, statements, wantIdent); } - - HLSLDeclaration * BuildTemporaryDeclaration(HLSLExpression * expr) - { - assert(expr->expressionType.baseType != HLSLBaseType_Void); - - HLSLDeclaration * declaration = m_tree->AddNode(expr->fileName, expr->line); - declaration->name = m_tree->AddStringFormat("tmp%d", tmp_index++); - declaration->type = expr->expressionType; - declaration->assignment = expr; - - //HLSLIdentifierExpression * ident = (HLSLIdentifierExpression *)expr; - - return declaration; - } - - HLSLExpressionStatement * BuildExpressionStatement(HLSLExpression * expr) - { - HLSLExpressionStatement * statement = m_tree->AddNode(expr->fileName, expr->line); - statement->expression = expr; - return statement; + if (expr->nodeType == HLSLNodeType_UnaryExpression) { + assert(expr->nextExpression == NULL); + + HLSLUnaryExpression *unaryExpr = (HLSLUnaryExpression *)expr; + + HLSLIdentifierExpression *tmp = Flatten(unaryExpr->expression, statements, true); + + HLSLUnaryExpression *newUnaryExpr = m_tree->AddNode(unaryExpr->fileName, unaryExpr->line); + newUnaryExpr->unaryOp = unaryExpr->unaryOp; + newUnaryExpr->expression = tmp; + newUnaryExpr->expressionType = unaryExpr->expressionType; + + return AddExpressionStatement(newUnaryExpr, statements, wantIdent); } + else if (expr->nodeType == HLSLNodeType_BinaryExpression) { + assert(expr->nextExpression == NULL); - HLSLIdentifierExpression * AddExpressionStatement(HLSLExpression * expr, StatementList & statements, bool wantIdent) - { - if (wantIdent) { - HLSLDeclaration * declaration = BuildTemporaryDeclaration(expr); - statements.append(declaration); - - HLSLIdentifierExpression * ident = m_tree->AddNode(expr->fileName, expr->line); - ident->name = declaration->name; - ident->expressionType = declaration->type; - return ident; + HLSLBinaryExpression *binaryExpr = (HLSLBinaryExpression *)expr; + + if (IsAssignOp(binaryExpr->binaryOp)) { + // Flatten right hand side only. + HLSLIdentifierExpression *tmp2 = Flatten(binaryExpr->expression2, statements, true); + + HLSLBinaryExpression *newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); + newBinaryExpr->binaryOp = binaryExpr->binaryOp; + newBinaryExpr->expression1 = binaryExpr->expression1; + newBinaryExpr->expression2 = tmp2; + newBinaryExpr->expressionType = binaryExpr->expressionType; + + return AddExpressionStatement(newBinaryExpr, statements, wantIdent); } else { - HLSLExpressionStatement * statement = BuildExpressionStatement(expr); - statements.append(statement); - return NULL; + HLSLIdentifierExpression *tmp1 = Flatten(binaryExpr->expression1, statements, true); + HLSLIdentifierExpression *tmp2 = Flatten(binaryExpr->expression2, statements, true); + + HLSLBinaryExpression *newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); + newBinaryExpr->binaryOp = binaryExpr->binaryOp; + newBinaryExpr->expression1 = tmp1; + newBinaryExpr->expression2 = tmp2; + newBinaryExpr->expressionType = binaryExpr->expressionType; + + return AddExpressionStatement(newBinaryExpr, statements, wantIdent); } } - - HLSLIdentifierExpression * Flatten(HLSLExpression * expr, StatementList & statements, bool wantIdent = true) - { - if (!NeedsFlattening(expr, wantIdent)) { - return AddExpressionStatement(expr, statements, wantIdent); - } - - if (expr->nodeType == HLSLNodeType_UnaryExpression) { - assert(expr->nextExpression == NULL); - - HLSLUnaryExpression * unaryExpr = (HLSLUnaryExpression *)expr; - - HLSLIdentifierExpression * tmp = Flatten(unaryExpr->expression, statements, true); - - HLSLUnaryExpression * newUnaryExpr = m_tree->AddNode(unaryExpr->fileName, unaryExpr->line); - newUnaryExpr->unaryOp = unaryExpr->unaryOp; - newUnaryExpr->expression = tmp; - newUnaryExpr->expressionType = unaryExpr->expressionType; - - return AddExpressionStatement(newUnaryExpr, statements, wantIdent); - } - else if (expr->nodeType == HLSLNodeType_BinaryExpression) { - assert(expr->nextExpression == NULL); - - HLSLBinaryExpression * binaryExpr = (HLSLBinaryExpression *)expr; - - if (IsAssignOp(binaryExpr->binaryOp)) { - // Flatten right hand side only. - HLSLIdentifierExpression * tmp2 = Flatten(binaryExpr->expression2, statements, true); - - HLSLBinaryExpression * newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); - newBinaryExpr->binaryOp = binaryExpr->binaryOp; - newBinaryExpr->expression1 = binaryExpr->expression1; - newBinaryExpr->expression2 = tmp2; - newBinaryExpr->expressionType = binaryExpr->expressionType; - - return AddExpressionStatement(newBinaryExpr, statements, wantIdent); - } - else { - HLSLIdentifierExpression * tmp1 = Flatten(binaryExpr->expression1, statements, true); - HLSLIdentifierExpression * tmp2 = Flatten(binaryExpr->expression2, statements, true); - - HLSLBinaryExpression * newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); - newBinaryExpr->binaryOp = binaryExpr->binaryOp; - newBinaryExpr->expression1 = tmp1; - newBinaryExpr->expression2 = tmp2; - newBinaryExpr->expressionType = binaryExpr->expressionType; - - return AddExpressionStatement(newBinaryExpr, statements, wantIdent); - } - } - else if (expr->nodeType == HLSLNodeType_ConditionalExpression) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_CastingExpression) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_LiteralExpression) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_IdentifierExpression) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_ConstructorExpression) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_MemberAccess) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_ArrayAccess) { - assert(false); - } - else if (expr->nodeType == HLSLNodeType_FunctionCall) { - HLSLFunctionCall * functionCall = (HLSLFunctionCall *)expr; - - // @@ Output function as is? - // @@ We have to flatten function arguments! This is tricky, need to handle input/output arguments. - assert(!NeedsFlattening(functionCall->argument)); - - return AddExpressionStatement(expr, statements, wantIdent); - } - else { - assert(false); - } - return NULL; + else if (expr->nodeType == HLSLNodeType_ConditionalExpression) { + assert(false); } - }; + else if (expr->nodeType == HLSLNodeType_CastingExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_LiteralExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_IdentifierExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_ConstructorExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_MemberAccess) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_ArrayAccess) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_FunctionCall) { + HLSLFunctionCall *functionCall = (HLSLFunctionCall *)expr; + + // @@ Output function as is? + // @@ We have to flatten function arguments! This is tricky, need to handle input/output arguments. + assert(!NeedsFlattening(functionCall->argument)); + + return AddExpressionStatement(expr, statements, wantIdent); + } + else { + assert(false); + } + return NULL; + } +}; - -void FlattenExpressions(HLSLTree* tree) { +void FlattenExpressions(HLSLTree *tree) +{ ExpressionFlattener flattener; flattener.FlattenExpressions(tree); } -} // M4 - +} //namespace M4 diff --git a/hlslparser/src/HLSLTree.h b/hlslparser/src/HLSLTree.h index 3ad0bd63..39956bac 100644 --- a/hlslparser/src/HLSLTree.h +++ b/hlslparser/src/HLSLTree.h @@ -1,41 +1,38 @@ #pragma once -#include "Engine.h" - #include -namespace M4 -{ +#include "Engine.h" -enum HLSLTarget -{ +namespace M4 { + +enum HLSLTarget { HLSLTarget_VertexShader, HLSLTarget_PixelShader, - + HLSLTarget_ComputeShader, - + // none of these are portable to Metal/Android, they have own triangulation // HLSLTarget_GeometryShader, // HLSLTarget_HullShader, // HLSLTarget_ControlShader, - + // This is compute prior to frag (combined vertex + geo state) // HLSLTarget_MeshShader, }; -enum HLSLNodeType -{ +enum HLSLNodeType { HLSLNodeType_Root, - + HLSLNodeType_Declaration, HLSLNodeType_Struct, HLSLNodeType_StructField, HLSLNodeType_Buffer, HLSLNodeType_BufferField, // TODO: or just ref structField - + HLSLNodeType_Function, HLSLNodeType_Argument, - + HLSLNodeType_ExpressionStatement, HLSLNodeType_Expression, HLSLNodeType_ReturnStatement, @@ -56,7 +53,7 @@ enum HLSLNodeType HLSLNodeType_ArrayAccess, HLSLNodeType_FunctionCall, HLSLNodeType_MemberFunctionCall, - + /* FX file stuff HLSLNodeType_StateAssignment, HLSLNodeType_SamplerState, @@ -65,33 +62,32 @@ enum HLSLNodeType HLSLNodeType_Pipeline, HLSLNodeType_Stage, */ - + HLSLNodeType_Attribute, HLSLNodeType_Comment }; -enum HLSLBaseType -{ +enum HLSLBaseType { HLSLBaseType_Unknown, HLSLBaseType_Void, - + // float HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4, - HLSLBaseType_Float2x2, + HLSLBaseType_Float2x2, HLSLBaseType_Float3x3, HLSLBaseType_Float4x4, - + HLSLBaseType_Half, HLSLBaseType_Half2, HLSLBaseType_Half3, HLSLBaseType_Half4, - HLSLBaseType_Half2x2, + HLSLBaseType_Half2x2, HLSLBaseType_Half3x3, HLSLBaseType_Half4x4, - + HLSLBaseType_Double, HLSLBaseType_Double2, HLSLBaseType_Double3, @@ -99,43 +95,43 @@ enum HLSLBaseType HLSLBaseType_Double2x2, HLSLBaseType_Double3x3, HLSLBaseType_Double4x4, - + // integer HLSLBaseType_Bool, HLSLBaseType_Bool2, - HLSLBaseType_Bool3, - HLSLBaseType_Bool4, - + HLSLBaseType_Bool3, + HLSLBaseType_Bool4, + HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4, - + HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4, - + HLSLBaseType_Short, HLSLBaseType_Short2, HLSLBaseType_Short3, HLSLBaseType_Short4, - + HLSLBaseType_Ushort, HLSLBaseType_Ushort2, HLSLBaseType_Ushort3, HLSLBaseType_Ushort4, - + HLSLBaseType_Long, HLSLBaseType_Long2, HLSLBaseType_Long3, HLSLBaseType_Long4, - + HLSLBaseType_Ulong, HLSLBaseType_Ulong2, HLSLBaseType_Ulong3, HLSLBaseType_Ulong4, - + // Seems like these should be subtype of HLSLTexture, but // many of the intrinsics require a specific type of texture. // MSL has many more types, included depth vs. regular textures. @@ -145,45 +141,44 @@ enum HLSLBaseType HLSLBaseType_Texture2DArray, HLSLBaseType_TextureCubeArray, HLSLBaseType_Texture2DMS, - + HLSLBaseType_Depth2D, HLSLBaseType_Depth2DArray, HLSLBaseType_DepthCube, // TODO: add more depth types as needed (pair with SamplerComparisonState) - + HLSLBaseType_RWTexture2D, - + // Only 2 sampler types. - type is for defining state inside them HLSLBaseType_SamplerState, HLSLBaseType_SamplerComparisonState, - - HLSLBaseType_UserDefined, // struct - HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). + + HLSLBaseType_UserDefined, // struct + HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). //HLSLBaseType_Auto, // this wasn't hooked up - HLSLBaseType_Comment, // single line comments optionally transferred to output - + HLSLBaseType_Comment, // single line comments optionally transferred to output + // Buffer subtypes below HLSLBaseType_Buffer, - + HLSLBaseType_Count, - + // counts //HLSLBaseType_FirstNumeric = HLSLBaseType_Float, //HLSLBaseType_LastNumeric = HLSLBaseType_Ulong4, - + //HLSLBaseType_FirstInteger = HLSLBaseType_Bool, //HLSLBaseType_LastInteger = HLSLBaseType_LastNumeric, - + HLSLBaseType_NumericCount = HLSLBaseType_Ulong4 - HLSLBaseType_Float + 1 }; - + // This a subtype to HLSLBaseType_Buffer -enum HLSLBufferType -{ +enum HLSLBufferType { // DX9 HLSLBufferType_CBuffer, HLSLBufferType_TBuffer, - + // DX10 templated types HLSLBufferType_ConstantBuffer, // indexable HLSLBufferType_StructuredBuffer, @@ -192,18 +187,17 @@ enum HLSLBufferType HLSLBufferType_RWByteAddressBuffer }; -enum HLSLBinaryOp -{ +enum HLSLBinaryOp { // bit ops HLSLBinaryOp_And, HLSLBinaryOp_Or, - + // math ops HLSLBinaryOp_Add, HLSLBinaryOp_Sub, HLSLBinaryOp_Mul, HLSLBinaryOp_Div, - + // comparison ops HLSLBinaryOp_Less, HLSLBinaryOp_Greater, @@ -211,12 +205,12 @@ enum HLSLBinaryOp HLSLBinaryOp_GreaterEqual, HLSLBinaryOp_Equal, HLSLBinaryOp_NotEqual, - + // bit ops HLSLBinaryOp_BitAnd, HLSLBinaryOp_BitOr, HLSLBinaryOp_BitXor, - + // assign ops HLSLBinaryOp_Assign, HLSLBinaryOp_AddAssign, @@ -225,60 +219,58 @@ enum HLSLBinaryOp HLSLBinaryOp_DivAssign, }; -inline bool IsCompareOp( HLSLBinaryOp op ) +inline bool IsCompareOp(HLSLBinaryOp op) { - return op == HLSLBinaryOp_Less || - op == HLSLBinaryOp_Greater || - op == HLSLBinaryOp_LessEqual || - op == HLSLBinaryOp_GreaterEqual || - op == HLSLBinaryOp_Equal || - op == HLSLBinaryOp_NotEqual; + return op == HLSLBinaryOp_Less || + op == HLSLBinaryOp_Greater || + op == HLSLBinaryOp_LessEqual || + op == HLSLBinaryOp_GreaterEqual || + op == HLSLBinaryOp_Equal || + op == HLSLBinaryOp_NotEqual; } -inline bool IsArithmeticOp( HLSLBinaryOp op ) +inline bool IsArithmeticOp(HLSLBinaryOp op) { return op == HLSLBinaryOp_Add || - op == HLSLBinaryOp_Sub || - op == HLSLBinaryOp_Mul || - op == HLSLBinaryOp_Div; + op == HLSLBinaryOp_Sub || + op == HLSLBinaryOp_Mul || + op == HLSLBinaryOp_Div; } -inline bool IsLogicOp( HLSLBinaryOp op ) +inline bool IsLogicOp(HLSLBinaryOp op) { return op == HLSLBinaryOp_And || - op == HLSLBinaryOp_Or; + op == HLSLBinaryOp_Or; } -inline bool IsAssignOp( HLSLBinaryOp op ) +inline bool IsAssignOp(HLSLBinaryOp op) { return op == HLSLBinaryOp_Assign || - op == HLSLBinaryOp_AddAssign || - op == HLSLBinaryOp_SubAssign || - op == HLSLBinaryOp_MulAssign || - op == HLSLBinaryOp_DivAssign; + op == HLSLBinaryOp_AddAssign || + op == HLSLBinaryOp_SubAssign || + op == HLSLBinaryOp_MulAssign || + op == HLSLBinaryOp_DivAssign; } -inline bool IsBitOp( HLSLBinaryOp op ) +inline bool IsBitOp(HLSLBinaryOp op) { return op == HLSLBinaryOp_BitAnd || - op == HLSLBinaryOp_BitOr || - op == HLSLBinaryOp_BitXor; + op == HLSLBinaryOp_BitOr || + op == HLSLBinaryOp_BitXor; } - -enum HLSLUnaryOp -{ - HLSLUnaryOp_Negative, // -x - HLSLUnaryOp_Positive, // +x - HLSLUnaryOp_Not, // !x - HLSLUnaryOp_PreIncrement, // ++x - HLSLUnaryOp_PreDecrement, // --x - HLSLUnaryOp_PostIncrement, // x++ - HLSLUnaryOp_PostDecrement, // x++ - HLSLUnaryOp_BitNot, // ~x + +enum HLSLUnaryOp { + HLSLUnaryOp_Negative, // -x + HLSLUnaryOp_Positive, // +x + HLSLUnaryOp_Not, // !x + HLSLUnaryOp_PreIncrement, // ++x + HLSLUnaryOp_PreDecrement, // --x + HLSLUnaryOp_PostIncrement, // x++ + HLSLUnaryOp_PostDecrement, // x++ + HLSLUnaryOp_BitNot, // ~x }; -enum HLSLArgumentModifier -{ +enum HLSLArgumentModifier { HLSLArgumentModifier_None, HLSLArgumentModifier_In, HLSLArgumentModifier_Out, @@ -287,8 +279,7 @@ enum HLSLArgumentModifier HLSLArgumentModifier_Const, }; -enum HLSLTypeFlags -{ +enum HLSLTypeFlags { HLSLTypeFlag_None = 0, HLSLTypeFlag_Const = 0x01, HLSLTypeFlag_Static = 0x02, @@ -312,23 +303,21 @@ enum HLSLTypeFlags HLSLTypeFlag_NoPromote = 0x200000, }; -enum HLSLAttributeType -{ +enum HLSLAttributeType { HLSLAttributeType_Unknown, - + // TODO: a lot more attributes, these are loop attributes // f.e. specialization constant and numthreads for HLSL HLSLAttributeType_Unroll, HLSLAttributeType_Branch, HLSLAttributeType_Flatten, HLSLAttributeType_NoFastMath, - + }; -enum HLSLAddressSpace -{ +enum HLSLAddressSpace { HLSLAddressSpace_Undefined, - + // These only apply to MSL HLSLAddressSpace_Constant, HLSLAddressSpace_Device, @@ -338,7 +327,6 @@ enum HLSLAddressSpace // TODO: ThreadgroupImageblock }; - struct HLSLNode; struct HLSLRoot; struct HLSLStatement; @@ -359,312 +347,278 @@ struct HLSLFunctionCall; struct HLSLArrayAccess; struct HLSLAttribute; -struct HLSLType -{ +struct HLSLType { explicit HLSLType(HLSLBaseType _baseType = HLSLBaseType_Unknown) - { - baseType = _baseType; + { + baseType = _baseType; } bool TestFlags(int flags_) const { return (flags & flags_) == flags_; } - - HLSLBaseType baseType = HLSLBaseType_Unknown; - HLSLBaseType formatType = HLSLBaseType_Float; // Half or Float (only applies to templated params like buffer/texture) - const char* typeName = NULL; // For user defined types. - bool array = false; - HLSLExpression* arraySize = NULL; // can ref constant like NUM_LIGHTS - int flags = 0; - HLSLAddressSpace addressSpace = HLSLAddressSpace_Undefined; // MSL mostly + + HLSLBaseType baseType = HLSLBaseType_Unknown; + HLSLBaseType formatType = HLSLBaseType_Float; // Half or Float (only applies to templated params like buffer/texture) + const char* typeName = NULL; // For user defined types. + bool array = false; + HLSLExpression* arraySize = NULL; // can ref constant like NUM_LIGHTS + int flags = 0; + HLSLAddressSpace addressSpace = HLSLAddressSpace_Undefined; // MSL mostly }; // Only Statment, Argument, StructField can be marked hidden. // But many elements like Buffer derive from Statement. /// Base class for all nodes in the HLSL AST -struct HLSLNode -{ - HLSLNodeType nodeType; // set to s_type - const char* fileName = NULL; - int line = 0; +struct HLSLNode { + HLSLNodeType nodeType; // set to s_type + const char* fileName = NULL; + int line = 0; }; -struct HLSLRoot : public HLSLNode -{ +struct HLSLRoot : public HLSLNode { static const HLSLNodeType s_type = HLSLNodeType_Root; - HLSLStatement* statement = NULL; // First statement. + HLSLStatement* statement = NULL; // First statement. }; -struct HLSLStatement : public HLSLNode -{ - HLSLStatement* nextStatement = NULL; // Next statement in the block. - HLSLAttribute* attributes = NULL; - +struct HLSLStatement : public HLSLNode { + HLSLStatement* nextStatement = NULL; // Next statement in the block. + HLSLAttribute* attributes = NULL; + // This allows tree pruning. Marked true after traversing use in - mutable bool hidden = false; - + mutable bool hidden = false; + // This is marked as false at start, and multi endpoint traversal marks // when a global is already written, and next write is skipped. - mutable bool written = false; + mutable bool written = false; }; // [unroll] -struct HLSLAttribute : public HLSLNode -{ +struct HLSLAttribute : public HLSLNode { static const HLSLNodeType s_type = HLSLNodeType_Attribute; - HLSLAttributeType attributeType = HLSLAttributeType_Unknown; - HLSLExpression* argument = NULL; - HLSLAttribute* nextAttribute = NULL; + HLSLAttributeType attributeType = HLSLAttributeType_Unknown; + HLSLExpression* argument = NULL; + HLSLAttribute* nextAttribute = NULL; }; -struct HLSLDeclaration : public HLSLStatement -{ +struct HLSLDeclaration : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_Declaration; - const char* name = NULL; - HLSLType type; - const char* registerName = NULL; // @@ Store register index? - const char* semantic = NULL; - HLSLDeclaration* nextDeclaration = NULL; // If multiple variables declared on a line. - HLSLExpression* assignment = NULL; - - HLSLBuffer* buffer = NULL; // reference cbuffer for decl + const char* name = NULL; + HLSLType type; + const char* registerName = NULL; // @@ Store register index? + const char* semantic = NULL; + HLSLDeclaration* nextDeclaration = NULL; // If multiple variables declared on a line. + HLSLExpression* assignment = NULL; + + HLSLBuffer* buffer = NULL; // reference cbuffer for decl }; -struct HLSLStruct : public HLSLStatement -{ +struct HLSLStruct : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_Struct; - const char* name = NULL; - HLSLStructField* field = NULL; // First field in the structure. + const char* name = NULL; + HLSLStructField* field = NULL; // First field in the structure. }; -struct HLSLStructField : public HLSLNode -{ +struct HLSLStructField : public HLSLNode { static const HLSLNodeType s_type = HLSLNodeType_StructField; - const char* name = NULL; - HLSLType type; - const char* semantic = NULL; - const char* sv_semantic = NULL; - HLSLStructField* nextField = NULL; // Next field in the structure. - bool hidden = false; + const char* name = NULL; + HLSLType type; + const char* semantic = NULL; + const char* sv_semantic = NULL; + HLSLStructField* nextField = NULL; // Next field in the structure. + bool hidden = false; }; /// Buffer declaration. -struct HLSLBuffer : public HLSLStatement -{ +struct HLSLBuffer : public HLSLStatement { // These spill a ton of globals throughout shader bool IsGlobalFields() const { - return bufferType == HLSLBufferType_CBuffer || - bufferType == HLSLBufferType_TBuffer; + return bufferType == HLSLBufferType_CBuffer || + bufferType == HLSLBufferType_TBuffer; } - + // DX changes registers for read-only vs. read-write buffers (SRV vs. UAV) // so constant/cbuffer use b, structured/byte use t (like textures), // and read-write use u. MSL only has u and bool IsReadOnly() const { - return bufferType == HLSLBufferType_CBuffer || - bufferType == HLSLBufferType_TBuffer || - bufferType == HLSLBufferType_ConstantBuffer || - bufferType == HLSLBufferType_StructuredBuffer || - bufferType == HLSLBufferType_ByteAddressBuffer; + return bufferType == HLSLBufferType_CBuffer || + bufferType == HLSLBufferType_TBuffer || + bufferType == HLSLBufferType_ConstantBuffer || + bufferType == HLSLBufferType_StructuredBuffer || + bufferType == HLSLBufferType_ByteAddressBuffer; } - + static const HLSLNodeType s_type = HLSLNodeType_Buffer; - const char* name = NULL; - const char* registerName = NULL; - HLSLDeclaration* field = NULL; - HLSLBufferType bufferType = HLSLBufferType_CBuffer; - HLSLStruct* bufferStruct = NULL; + const char* name = NULL; + const char* registerName = NULL; + HLSLDeclaration* field = NULL; + HLSLBufferType bufferType = HLSLBufferType_CBuffer; + HLSLStruct* bufferStruct = NULL; }; - /// Function declaration -struct HLSLFunction : public HLSLStatement -{ +struct HLSLFunction : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_Function; - const char* name = NULL; - HLSLType returnType; - HLSLBaseType memberType = HLSLBaseType_Unknown; // for sampler members, must also look at GetScalarType(returnType) - const char* semantic = NULL; - const char* sv_semantic = NULL; - int numArguments = 0; - int numOutputArguments = 0; // Includes out and inout arguments. - HLSLArgument* argument = NULL; - HLSLStatement* statement = NULL; - HLSLFunction* forward = NULL; // Which HLSLFunction this one forward-declares - + const char* name = NULL; + HLSLType returnType; + HLSLBaseType memberType = HLSLBaseType_Unknown; // for sampler members, must also look at GetScalarType(returnType) + const char* semantic = NULL; + const char* sv_semantic = NULL; + int numArguments = 0; + int numOutputArguments = 0; // Includes out and inout arguments. + HLSLArgument* argument = NULL; + HLSLStatement* statement = NULL; + HLSLFunction* forward = NULL; // Which HLSLFunction this one forward-declares + bool IsMemberFunction() const { return memberType != HLSLBaseType_Unknown; } }; /// Declaration of an argument to a function. -struct HLSLArgument : public HLSLNode -{ +struct HLSLArgument : public HLSLNode { static const HLSLNodeType s_type = HLSLNodeType_Argument; - const char* name = NULL; - HLSLArgumentModifier modifier = HLSLArgumentModifier_None; - HLSLType type; - const char* semantic = NULL; - const char* sv_semantic = NULL; - HLSLExpression* defaultValue = NULL; - HLSLArgument* nextArgument = NULL; - bool hidden = false; + const char* name = NULL; + HLSLArgumentModifier modifier = HLSLArgumentModifier_None; + HLSLType type; + const char* semantic = NULL; + const char* sv_semantic = NULL; + HLSLExpression* defaultValue = NULL; + HLSLArgument* nextArgument = NULL; + bool hidden = false; }; /// A expression which forms a complete statement. -struct HLSLExpressionStatement : public HLSLStatement -{ +struct HLSLExpressionStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_ExpressionStatement; - HLSLExpression* expression = NULL; + HLSLExpression* expression = NULL; }; -struct HLSLReturnStatement : public HLSLStatement -{ +struct HLSLReturnStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_ReturnStatement; - HLSLExpression* expression = NULL; + HLSLExpression* expression = NULL; }; -struct HLSLDiscardStatement : public HLSLStatement -{ +struct HLSLDiscardStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_DiscardStatement; }; -struct HLSLBreakStatement : public HLSLStatement -{ +struct HLSLBreakStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_BreakStatement; }; -struct HLSLContinueStatement : public HLSLStatement -{ +struct HLSLContinueStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_ContinueStatement; }; -struct HLSLIfStatement : public HLSLStatement -{ +struct HLSLIfStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_IfStatement; - HLSLExpression* condition = NULL; - HLSLStatement* statement = NULL; - HLSLStatement* elseStatement = NULL; - bool isStatic = false; + HLSLExpression* condition = NULL; + HLSLStatement* statement = NULL; + HLSLStatement* elseStatement = NULL; + bool isStatic = false; }; -struct HLSLForStatement : public HLSLStatement -{ +struct HLSLForStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_ForStatement; - HLSLDeclaration* initialization = NULL; - HLSLExpression* condition = NULL; - HLSLExpression* increment = NULL; - HLSLStatement* statement = NULL; + HLSLDeclaration* initialization = NULL; + HLSLExpression* condition = NULL; + HLSLExpression* increment = NULL; + HLSLStatement* statement = NULL; }; -struct HLSLBlockStatement : public HLSLStatement -{ +struct HLSLBlockStatement : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_BlockStatement; - HLSLStatement* statement = NULL; + HLSLStatement* statement = NULL; }; - /// Base type for all types of expressions. -struct HLSLExpression : public HLSLNode -{ +struct HLSLExpression : public HLSLNode { static const HLSLNodeType s_type = HLSLNodeType_Expression; - HLSLType expressionType; - HLSLExpression* nextExpression = NULL; // Used when the expression is part of a list, like in a function call. + HLSLType expressionType; + HLSLExpression* nextExpression = NULL; // Used when the expression is part of a list, like in a function call. }; // -a -struct HLSLUnaryExpression : public HLSLExpression -{ +struct HLSLUnaryExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_UnaryExpression; - HLSLUnaryOp unaryOp = {}; - HLSLExpression* expression = NULL; + HLSLUnaryOp unaryOp = {}; + HLSLExpression* expression = NULL; }; /// a + b -struct HLSLBinaryExpression : public HLSLExpression -{ +struct HLSLBinaryExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_BinaryExpression; - HLSLBinaryOp binaryOp = {}; - HLSLExpression* expression1 = NULL; - HLSLExpression* expression2 = NULL; + HLSLBinaryOp binaryOp = {}; + HLSLExpression* expression1 = NULL; + HLSLExpression* expression2 = NULL; }; /// ? : construct -struct HLSLConditionalExpression : public HLSLExpression -{ +struct HLSLConditionalExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_ConditionalExpression; - HLSLExpression* condition = NULL; - HLSLExpression* trueExpression = NULL; - HLSLExpression* falseExpression = NULL; + HLSLExpression* condition = NULL; + HLSLExpression* trueExpression = NULL; + HLSLExpression* falseExpression = NULL; }; /// v = (half4)v2 -struct HLSLCastingExpression : public HLSLExpression -{ +struct HLSLCastingExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_CastingExpression; - HLSLType type; - HLSLExpression* expression = NULL; + HLSLType type; + HLSLExpression* expression = NULL; }; /// Float, integer, boolean, etc. literal constant. -struct HLSLLiteralExpression : public HLSLExpression -{ +struct HLSLLiteralExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_LiteralExpression; - HLSLBaseType type = HLSLBaseType_Unknown; // Note, not all types can be literals. - union - { - bool bValue; - float fValue; - int32_t iValue; + HLSLBaseType type = HLSLBaseType_Unknown; // Note, not all types can be literals. + union { + bool bValue; + float fValue; + int32_t iValue; }; }; /// An identifier, typically a variable name or structure field name. -struct HLSLIdentifierExpression : public HLSLExpression -{ +struct HLSLIdentifierExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_IdentifierExpression; - const char* name = NULL; - bool global = false; // This is a global variable. + const char* name = NULL; + bool global = false; // This is a global variable. }; /// float2(1, 2) -struct HLSLConstructorExpression : public HLSLExpression -{ +struct HLSLConstructorExpression : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_ConstructorExpression; - HLSLType type; - HLSLExpression* argument = NULL; + HLSLType type; + HLSLExpression* argument = NULL; }; /// object.member input.member or input[10].member -struct HLSLMemberAccess : public HLSLExpression -{ +struct HLSLMemberAccess : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_MemberAccess; - HLSLExpression* object = NULL; - const char* field = NULL; - bool swizzle = false; + HLSLExpression* object = NULL; + const char* field = NULL; + bool swizzle = false; }; /// array[index] -struct HLSLArrayAccess : public HLSLExpression -{ +struct HLSLArrayAccess : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_ArrayAccess; - HLSLExpression* array = NULL; - HLSLExpression* index = NULL; + HLSLExpression* array = NULL; + HLSLExpression* index = NULL; }; /// c-style foo(arg1, arg2) - args can have defaults that are parsed -struct HLSLFunctionCall : public HLSLExpression -{ +struct HLSLFunctionCall : public HLSLExpression { static const HLSLNodeType s_type = HLSLNodeType_FunctionCall; const HLSLFunction* function = NULL; - HLSLExpression* argument = NULL; - int numArguments = 0; + HLSLExpression* argument = NULL; + int numArguments = 0; }; // TODO: finish adding this for texture and buffer ops /// c++ style member.foo(arg1, arg2) -struct HLSLMemberFunctionCall : public HLSLFunctionCall -{ +struct HLSLMemberFunctionCall : public HLSLFunctionCall { static const HLSLNodeType s_type = HLSLNodeType_MemberFunctionCall; - + // could be buffer, texture, raytrace const HLSLIdentifierExpression* memberIdentifier = NULL; }; @@ -737,18 +691,14 @@ struct HLSLStage : public HLSLStatement */ #endif -struct HLSLComment : public HLSLStatement -{ +struct HLSLComment : public HLSLStatement { static const HLSLNodeType s_type = HLSLNodeType_Comment; - const char* text = NULL; + const char* text = NULL; }; /// Abstract syntax tree for parsed HLSL code. -class HLSLTree -{ - +class HLSLTree { public: - explicit HLSLTree(Allocator* allocator); ~HLSLTree(); @@ -767,116 +717,108 @@ class HLSLTree T* AddNode(const char* fileName, int line) { HLSLNode* node = new (AllocateMemory(sizeof(T))) T(); - node->nodeType = T::s_type; - node->fileName = fileName; - node->line = line; + node->nodeType = T::s_type; + node->fileName = fileName; + node->line = line; return static_cast(node); } - HLSLFunction * FindFunction(const char * name); - HLSLDeclaration * FindGlobalDeclaration(const char * name, HLSLBuffer ** buffer_out = NULL); - - HLSLStruct * FindGlobalStruct(const char * name); - HLSLBuffer * FindBuffer(const char * name); + HLSLFunction* FindFunction(const char* name); + HLSLDeclaration* FindGlobalDeclaration(const char* name, HLSLBuffer** buffer_out = NULL); -// FX files -// HLSLTechnique * FindTechnique(const char * name); -// HLSLPipeline * FindFirstPipeline(); -// HLSLPipeline * FindNextPipeline(HLSLPipeline * current); -// HLSLPipeline * FindPipeline(const char * name); - - bool GetExpressionValue(HLSLExpression * expression, int & value); - int GetExpressionValue(HLSLExpression * expression, float values[4]); + HLSLStruct* FindGlobalStruct(const char* name); + HLSLBuffer* FindBuffer(const char* name); - bool NeedsFunction(const char * name); + // FX files + // HLSLTechnique * FindTechnique(const char * name); + // HLSLPipeline * FindFirstPipeline(); + // HLSLPipeline * FindNextPipeline(HLSLPipeline * current); + // HLSLPipeline * FindPipeline(const char * name); -private: + bool GetExpressionValue(HLSLExpression* expression, int& value); + int GetExpressionValue(HLSLExpression* expression, float values[4]); - void* AllocateMemory(size_t size); - void AllocatePage(); + bool NeedsFunction(const char* name); private: + void* AllocateMemory(size_t size); + void AllocatePage(); +private: static const size_t s_nodePageSize = 1024 * 4; - struct NodePage - { - NodePage* next; - char buffer[s_nodePageSize]; + struct NodePage { + NodePage* next; + char buffer[s_nodePageSize]; }; - Allocator* m_allocator; - StringPool m_stringPool; - HLSLRoot* m_root; - - NodePage* m_firstPage; - NodePage* m_currentPage; - size_t m_currentPageOffset; + Allocator* m_allocator; + StringPool m_stringPool; + HLSLRoot* m_root; + NodePage* m_firstPage; + NodePage* m_currentPage; + size_t m_currentPageOffset; }; - - -class HLSLTreeVisitor -{ +class HLSLTreeVisitor { public: virtual ~HLSLTreeVisitor() {} - virtual void VisitType(HLSLType & type); - - virtual void VisitRoot(HLSLRoot * node); - virtual void VisitTopLevelStatement(HLSLStatement * node); - virtual void VisitStatements(HLSLStatement * statement); - virtual void VisitStatement(HLSLStatement * node); - virtual void VisitDeclaration(HLSLDeclaration * node); - virtual void VisitStruct(HLSLStruct * node); - virtual void VisitStructField(HLSLStructField * node); - virtual void VisitBuffer(HLSLBuffer * node); + virtual void VisitType(HLSLType& type); + + virtual void VisitRoot(HLSLRoot* node); + virtual void VisitTopLevelStatement(HLSLStatement* node); + virtual void VisitStatements(HLSLStatement* statement); + virtual void VisitStatement(HLSLStatement* node); + virtual void VisitDeclaration(HLSLDeclaration* node); + virtual void VisitStruct(HLSLStruct* node); + virtual void VisitStructField(HLSLStructField* node); + virtual void VisitBuffer(HLSLBuffer* node); //virtual void VisitBufferField(HLSLBufferField * node); // TODO: - virtual void VisitFunction(HLSLFunction * node); - virtual void VisitArgument(HLSLArgument * node); - virtual void VisitExpressionStatement(HLSLExpressionStatement * node); - virtual void VisitExpression(HLSLExpression * node); - virtual void VisitReturnStatement(HLSLReturnStatement * node); - virtual void VisitDiscardStatement(HLSLDiscardStatement * node); - virtual void VisitBreakStatement(HLSLBreakStatement * node); - virtual void VisitContinueStatement(HLSLContinueStatement * node); - virtual void VisitIfStatement(HLSLIfStatement * node); - virtual void VisitForStatement(HLSLForStatement * node); - virtual void VisitBlockStatement(HLSLBlockStatement * node); - virtual void VisitUnaryExpression(HLSLUnaryExpression * node); - virtual void VisitBinaryExpression(HLSLBinaryExpression * node); - virtual void VisitConditionalExpression(HLSLConditionalExpression * node); - virtual void VisitCastingExpression(HLSLCastingExpression * node); - virtual void VisitLiteralExpression(HLSLLiteralExpression * node); - virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node); - virtual void VisitConstructorExpression(HLSLConstructorExpression * node); - virtual void VisitMemberAccess(HLSLMemberAccess * node); - virtual void VisitArrayAccess(HLSLArrayAccess * node); - virtual void VisitFunctionCall(HLSLFunctionCall * node); - - virtual void VisitComment(HLSLComment * node); - - virtual void VisitFunctions(HLSLRoot * root); - virtual void VisitParameters(HLSLRoot * root); - - HLSLFunction * FindFunction(HLSLRoot * root, const char * name); - HLSLDeclaration * FindGlobalDeclaration(HLSLRoot * root, const char * name); - HLSLStruct * FindGlobalStruct(HLSLRoot * root, const char * name); - + virtual void VisitFunction(HLSLFunction* node); + virtual void VisitArgument(HLSLArgument* node); + virtual void VisitExpressionStatement(HLSLExpressionStatement* node); + virtual void VisitExpression(HLSLExpression* node); + virtual void VisitReturnStatement(HLSLReturnStatement* node); + virtual void VisitDiscardStatement(HLSLDiscardStatement* node); + virtual void VisitBreakStatement(HLSLBreakStatement* node); + virtual void VisitContinueStatement(HLSLContinueStatement* node); + virtual void VisitIfStatement(HLSLIfStatement* node); + virtual void VisitForStatement(HLSLForStatement* node); + virtual void VisitBlockStatement(HLSLBlockStatement* node); + virtual void VisitUnaryExpression(HLSLUnaryExpression* node); + virtual void VisitBinaryExpression(HLSLBinaryExpression* node); + virtual void VisitConditionalExpression(HLSLConditionalExpression* node); + virtual void VisitCastingExpression(HLSLCastingExpression* node); + virtual void VisitLiteralExpression(HLSLLiteralExpression* node); + virtual void VisitIdentifierExpression(HLSLIdentifierExpression* node); + virtual void VisitConstructorExpression(HLSLConstructorExpression* node); + virtual void VisitMemberAccess(HLSLMemberAccess* node); + virtual void VisitArrayAccess(HLSLArrayAccess* node); + virtual void VisitFunctionCall(HLSLFunctionCall* node); + + virtual void VisitComment(HLSLComment* node); + + virtual void VisitFunctions(HLSLRoot* root); + virtual void VisitParameters(HLSLRoot* root); + + HLSLFunction* FindFunction(HLSLRoot* root, const char* name); + HLSLDeclaration* FindGlobalDeclaration(HLSLRoot* root, const char* name); + HLSLStruct* FindGlobalStruct(HLSLRoot* root, const char* name); + // These are fx file constructs -// virtual void VisitStateAssignment(HLSLStateAssignment * node); -// virtual void VisitSamplerState(HLSLSamplerState * node); -// virtual void VisitPass(HLSLPass * node); -// virtual void VisitTechnique(HLSLTechnique * node); -// virtual void VisitPipeline(HLSLPipeline * node); + // virtual void VisitStateAssignment(HLSLStateAssignment * node); + // virtual void VisitSamplerState(HLSLSamplerState * node); + // virtual void VisitPass(HLSLPass * node); + // virtual void VisitTechnique(HLSLTechnique * node); + // virtual void VisitPipeline(HLSLPipeline * node); }; - // Tree transformations: extern void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1 = NULL); extern void SortTree(HLSLTree* tree); //extern void GroupParameters(HLSLTree* tree); -extern void HideUnusedArguments(HLSLFunction * function); +extern void HideUnusedArguments(HLSLFunction* function); extern void FlattenExpressions(HLSLTree* tree); - -} // M4 + +} //namespace M4 diff --git a/hlslparser/src/MSLGenerator.cpp b/hlslparser/src/MSLGenerator.cpp index 9d1dc56d..faffb254 100644 --- a/hlslparser/src/MSLGenerator.cpp +++ b/hlslparser/src/MSLGenerator.cpp @@ -9,12 +9,12 @@ #include "MSLGenerator.h" +#include + #include "Engine.h" #include "HLSLParser.h" #include "HLSLTree.h" -#include - // MSL limitations: // - Some type conversions and constructors don't work exactly the same way. For example, casts to smaller size vectors are not alloweed in C++. @@ Add more details... // - Swizzles on scalar types, whether or not it expands them. a_float.x, a_float.xxxx both cause compile errors. @@ -25,14 +25,12 @@ // - No support for boolean vectors and logical operators involving vectors. This is not just in metal. // - No support for non-float texture types -namespace M4 -{ +namespace M4 { static void ParseSemantic(const char* semantic, uint32_t* outputLength, uint32_t* outputIndex) { const char* semanticIndex = semantic; - while (*semanticIndex && !isdigit(*semanticIndex)) - { + while (*semanticIndex && !isdigit(*semanticIndex)) { semanticIndex++; } @@ -43,36 +41,29 @@ static void ParseSemantic(const char* semantic, uint32_t* outputLength, uint32_t // Parse register name and advance next register index. static int ParseRegister(const char* registerName, int& nextRegister) { - if (!registerName) - { + if (!registerName) { return nextRegister++; } // skip over the u/b/t register prefix - while (*registerName && !isdigit(*registerName)) - { + while (*registerName && !isdigit(*registerName)) { registerName++; } - if (!*registerName) - { + if (!*registerName) { return nextRegister++; } // parse the number int result = atoi(registerName); - if (nextRegister <= result) - { + if (nextRegister <= result) { nextRegister = result + 1; } return result; } - - - MSLGenerator::MSLGenerator() { m_tree = NULL; @@ -92,8 +83,7 @@ void MSLGenerator::Error(const char* format, ...) const // It's not always convenient to stop executing when an error occurs, // so just track once we've hit an error and stop reporting them until // we successfully bail out of execution. - if (m_error) - { + if (m_error) { return; } m_error = true; @@ -106,36 +96,33 @@ void MSLGenerator::Error(const char* format, ...) const inline void MSLGenerator::AddClassArgument(ClassArgument* arg) { - if (m_firstClassArgument == NULL) - { + if (m_firstClassArgument == NULL) { m_firstClassArgument = arg; } - else - { + else { m_lastClassArgument->nextArg = arg; } m_lastClassArgument = arg; } - void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entryFunction) { // Hide unused arguments. @@ It would be good to do this in the other generators too. - + // PruneTree resets hidden flags to true, then marks visible elements // based on whether entry point visits them. PruneTree(tree, entryFunction->name); // Note: takes second entry - + // This sorts tree by type, but keeps ordering SortTree(tree); - + // This strips any unused inputs to the entry point function HideUnusedArguments(entryFunction); - + // Note sure if/where to add these calls. Just wanted to point // out that nothing is calling them, but could be useful. FlattenExpressions(tree); - + HLSLRoot* root = tree->GetRoot(); HLSLStatement* statement = root->statement; ASSERT(m_firstClassArgument == NULL); @@ -146,56 +133,50 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr int nextSamplerRegister = 0; int nextBufferRegister = 0; - while (statement != NULL) - { - if (statement->hidden) - { + while (statement != NULL) { + if (statement->hidden) { statement = statement->nextStatement; continue; } - - if (statement->nodeType == HLSLNodeType_Declaration) - { + + if (statement->nodeType == HLSLNodeType_Declaration) { HLSLDeclaration* declaration = (HLSLDeclaration*)statement; - if (IsTextureType(declaration->type)) - { - const char * textureName = declaration->name; - + if (IsTextureType(declaration->type)) { + const char* textureName = declaration->name; + int textureRegister = ParseRegister(declaration->registerName, nextTextureRegister); - const char * textureRegisterName = m_tree->AddStringFormat("texture(%d)", textureRegister); + const char* textureRegisterName = m_tree->AddStringFormat("texture(%d)", textureRegister); if (declaration->type.addressSpace == HLSLAddressSpace_Undefined) declaration->type.addressSpace = HLSLAddressSpace_Device; - + AddClassArgument(new ClassArgument(textureName, declaration->type, textureRegisterName, true)); } - else if (IsSamplerType(declaration->type)) - { - const char * samplerName = declaration->name; - + else if (IsSamplerType(declaration->type)) { + const char* samplerName = declaration->name; + int samplerRegister = ParseRegister(declaration->registerName, nextSamplerRegister); - const char * samplerRegisterName = m_tree->AddStringFormat("sampler(%d)", samplerRegister); - + const char* samplerRegisterName = m_tree->AddStringFormat("sampler(%d)", samplerRegister); + if (declaration->type.addressSpace == HLSLAddressSpace_Undefined) declaration->type.addressSpace = HLSLAddressSpace_Device; - + AddClassArgument(new ClassArgument(samplerName, declaration->type, samplerRegisterName, true)); } } - else if (statement->nodeType == HLSLNodeType_Buffer) - { - HLSLBuffer * buffer = (HLSLBuffer *)statement; - + else if (statement->nodeType == HLSLNodeType_Buffer) { + HLSLBuffer* buffer = (HLSLBuffer*)statement; + HLSLType type(HLSLBaseType_UserDefined); - + // TODO: on cbuffer is a ubo, not tbuffer, or others // TODO: this is having to rename due to globals if (buffer->IsGlobalFields()) type.typeName = m_tree->AddStringFormat("%s_ubo", buffer->name); else type.typeName = m_tree->AddStringFormat("%s", buffer->bufferStruct->name); - + // TODO: ConstantBuffer can use ptr notation, detect array decl bool isRef = buffer->bufferType == HLSLBufferType_ConstantBuffer || buffer->IsGlobalFields(); @@ -204,10 +185,10 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr type.addressSpace = HLSLAddressSpace_Constant; else type.addressSpace = HLSLAddressSpace_Device; - + int bufferRegister = ParseRegister(buffer->registerName, nextBufferRegister) + m_options.bufferRegisterOffset; - const char * bufferRegisterName = m_tree->AddStringFormat("buffer(%d)", bufferRegister); + const char* bufferRegisterName = m_tree->AddStringFormat("buffer(%d)", bufferRegister); AddClassArgument(new ClassArgument(buffer->name, type, bufferRegisterName, isRef)); } @@ -220,58 +201,45 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr // Translate semantics. HLSLArgument* argument = entryFunction->argument; - while (argument != NULL) - { - if (argument->hidden) - { + while (argument != NULL) { + if (argument->hidden) { argument = argument->nextArgument; continue; } - if (argument->modifier == HLSLArgumentModifier_Out) - { + if (argument->modifier == HLSLArgumentModifier_Out) { // Translate output arguments semantics. - if (argument->type.baseType == HLSLBaseType_UserDefined) - { + if (argument->type.baseType == HLSLBaseType_UserDefined) { // Our vertex input is a struct and its fields need to be tagged when we generate that HLSLStruct* structure = tree->FindGlobalStruct(argument->type.typeName); - if (structure == NULL) - { + if (structure == NULL) { Error("Vertex shader output struct '%s' not found in shader\n", argument->type.typeName); } HLSLStructField* field = structure->field; - while (field != NULL) - { - if (!field->hidden) - { + while (field != NULL) { + if (!field->hidden) { field->sv_semantic = TranslateOutputSemantic(field->semantic); } field = field->nextField; } } - else - { + else { argument->sv_semantic = TranslateOutputSemantic(argument->semantic); } } - else - { + else { // Translate input arguments semantics. - if (argument->type.baseType == HLSLBaseType_UserDefined) - { + if (argument->type.baseType == HLSLBaseType_UserDefined) { // Our vertex input is a struct and its fields need to be tagged when we generate that HLSLStruct* structure = tree->FindGlobalStruct(argument->type.typeName); - if (structure == NULL) - { + if (structure == NULL) { Error("Vertex shader input struct '%s' not found in shader\n", argument->type.typeName); } HLSLStructField* field = structure->field; - while (field != NULL) - { - if (!field->hidden) - { + while (field != NULL) { + if (!field->hidden) { field->sv_semantic = TranslateInputSemantic(field->semantic); // Force type to uint. @@ -288,8 +256,7 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr field = field->nextField; } } - else - { + else { argument->sv_semantic = TranslateInputSemantic(argument->semantic); // Force type to uint. @@ -304,29 +271,23 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr } // Translate return value semantic. - if (entryFunction->returnType.baseType != HLSLBaseType_Void) - { - if (entryFunction->returnType.baseType == HLSLBaseType_UserDefined) - { + if (entryFunction->returnType.baseType != HLSLBaseType_Void) { + if (entryFunction->returnType.baseType == HLSLBaseType_UserDefined) { // Our vertex input is a struct and its fields need to be tagged when we generate that HLSLStruct* structure = tree->FindGlobalStruct(entryFunction->returnType.typeName); - if (structure == NULL) - { + if (structure == NULL) { Error("Vertex shader output struct '%s' not found in shader\n", entryFunction->returnType.typeName); } HLSLStructField* field = structure->field; - while (field != NULL) - { - if (!field->hidden) - { + while (field != NULL) { + if (!field->hidden) { field->sv_semantic = TranslateOutputSemantic(field->semantic); } field = field->nextField; } } - else - { + else { entryFunction->sv_semantic = TranslateOutputSemantic(entryFunction->semantic); //Error("MSL only supports COLOR semantic in return \n", entryFunction->returnType.typeName); @@ -337,8 +298,7 @@ void MSLGenerator::Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entr void MSLGenerator::CleanPrepass() { ClassArgument* currentArg = m_firstClassArgument; - while (currentArg != NULL) - { + while (currentArg != NULL) { ClassArgument* nextArg = currentArg->nextArg; delete currentArg; currentArg = nextArg; @@ -352,7 +312,7 @@ void MSLGenerator::PrependDeclarations() { // Any special function stubs we need go here // That includes special constructors to emulate HLSL not being strict - + //Branch internally to HLSL vs. MSL verision m_writer.WriteLine(0, "#include \"ShaderMSL.h\""); } @@ -360,30 +320,32 @@ void MSLGenerator::PrependDeclarations() // Any reference or pointer must be qualified with address space in MSL const char* MSLGenerator::GetAddressSpaceName(HLSLBaseType baseType, HLSLAddressSpace addressSpace) const { - if (IsSamplerType(baseType)) - { + if (IsSamplerType(baseType)) { return "thread"; } - if (IsTextureType(baseType)) - { + if (IsTextureType(baseType)) { return "thread"; } // buffers also need to handle readonly (constant and const device) vs. // readwrite (device). - - switch(addressSpace) - { - case HLSLAddressSpace_Constant: return "constant"; - case HLSLAddressSpace_Device: return "device"; - case HLSLAddressSpace_Thread: return "thread"; - case HLSLAddressSpace_Shared: return "shared"; - //case HLSLAddressSpace_Threadgroup: return "threadgroup_local"; - //case HLSLAddressSpace_ThreadgroupImageblock: return "threadgroup_imageblock"); - - case HLSLAddressSpace_Undefined: break; - } - + + switch (addressSpace) { + case HLSLAddressSpace_Constant: + return "constant"; + case HLSLAddressSpace_Device: + return "device"; + case HLSLAddressSpace_Thread: + return "thread"; + case HLSLAddressSpace_Shared: + return "shared"; + //case HLSLAddressSpace_Threadgroup: return "threadgroup_local"; + //case HLSLAddressSpace_ThreadgroupImageblock: return "threadgroup_imageblock"); + + case HLSLAddressSpace_Undefined: + break; + } + Error("Unknown address space"); return ""; } @@ -396,7 +358,7 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_tree = tree; m_target = target; m_entryName = entryName; - + m_options = options; m_writer.SetWriteFileLine(options.writeFileLine); @@ -404,8 +366,7 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry // Find entry point function HLSLFunction* entryFunction = tree->FindFunction(entryName); - if (entryFunction == NULL) - { + if (entryFunction == NULL) { Error("Entry point '%s' doesn't exist\n", entryName); return false; } @@ -423,7 +384,7 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry // Uniforms are then passed to the constructor and copied to member variables. std::string shaderClassNameStr = entryName; shaderClassNameStr += "NS"; // to distinguish from function - + const char* shaderClassName = shaderClassNameStr.c_str(); m_writer.WriteLine(0, "struct %s {", shaderClassName); @@ -434,50 +395,45 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_writer.BeginLine(1); m_writer.Write("%s(", shaderClassName); - + // mod int indent = m_writer.EndLine(); - m_writer.BeginLine(indent+1); // 1 more level for params - + m_writer.BeginLine(indent + 1); // 1 more level for params + const ClassArgument* currentArg = m_firstClassArgument; - while (currentArg != NULL) - { + while (currentArg != NULL) { m_writer.Write("%s ", GetAddressSpaceName(currentArg->type.baseType, currentArg->type.addressSpace)); - + // ref vs. ptr bool isRef = currentArg->isRef; - + m_writer.Write("%s %s %s", GetTypeName(currentArg->type, /*exactType=*/true), isRef ? "&" : "*", currentArg->name); currentArg = currentArg->nextArg; - if (currentArg) - { + if (currentArg) { m_writer.Write(", "); - + // mod indent = m_writer.EndLine(); m_writer.BeginLine(indent); } } m_writer.Write(")"); - + // mod indent = m_writer.EndLine(); m_writer.BeginLine(indent); - + currentArg = m_firstClassArgument; - if (currentArg) - { + if (currentArg) { m_writer.Write(" : "); } - while (currentArg != NULL) - { + while (currentArg != NULL) { m_writer.Write("%s(%s)", currentArg->name, currentArg->name); currentArg = currentArg->nextArg; - if (currentArg) - { + if (currentArg) { m_writer.Write(", "); - + // mod indent = m_writer.EndLine(); m_writer.BeginLine(indent); @@ -487,14 +443,12 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_writer.WriteLine(0, "};"); // Class - // Generate real entry point, the one called by Metal m_writer.WriteLine(0, ""); // If function return value has a non-color output semantic, declare a temporary struct for the output. bool wrapReturnType = false; - if (entryFunction->sv_semantic != NULL && !String_Equal(entryFunction->sv_semantic, "color(0)")) - { + if (entryFunction->sv_semantic != NULL && !String_Equal(entryFunction->sv_semantic, "color(0)")) { wrapReturnType = true; m_writer.WriteLine(0, "struct %s_output { %s tmp [[%s]]; };", entryName, GetTypeName(entryFunction->returnType, /*exactType=*/true), entryFunction->sv_semantic); @@ -502,7 +456,6 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_writer.WriteLine(0, ""); } - m_writer.BeginLine(0); // @@ Add/Translate function attributes. @@ -512,115 +465,103 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry // MSL doesn't seem to have this, set from code? // if (m_target == HLSLTarget_ComputeShader) // m_writer.WriteLine(indent, "[numthreads(1,1,1)]"); - - switch(m_target) - { - case HLSLTarget_VertexShader: m_writer.Write("vertex "); break; - case HLSLTarget_PixelShader: m_writer.Write("fragment "); break; - case HLSLTarget_ComputeShader: m_writer.Write("kernel "); break; + + switch (m_target) { + case HLSLTarget_VertexShader: + m_writer.Write("vertex "); + break; + case HLSLTarget_PixelShader: + m_writer.Write("fragment "); + break; + case HLSLTarget_ComputeShader: + m_writer.Write("kernel "); + break; } // Return type. - if (wrapReturnType) - { + if (wrapReturnType) { m_writer.Write("%s_output", entryName); } - else - { - if (entryFunction->returnType.baseType == HLSLBaseType_UserDefined) - { + else { + if (entryFunction->returnType.baseType == HLSLBaseType_UserDefined) { // Alec removing namespaced structs // m_writer.Write("%s::", shaderClassName); } m_writer.Write("%s", GetTypeName(entryFunction->returnType, /*exactType=*/true)); } - + m_writer.Write(" %s(", entryName); // Alec added for readability indent = m_writer.EndLine(); - - m_writer.BeginLine(indent+1); // indent more - + + m_writer.BeginLine(indent + 1); // indent more + //-------------------- // This is the class taking in arguments - + int argumentCount = 0; HLSLArgument* argument = entryFunction->argument; - while (argument != NULL) - { - if (argument->hidden) - { + while (argument != NULL) { + if (argument->hidden) { argument = argument->nextArgument; continue; } - - if (argument->type.baseType == HLSLBaseType_UserDefined) - { + + if (argument->type.baseType == HLSLBaseType_UserDefined) { //TODO: aled removing namespaced structs //m_writer.Write("%s::", shaderClassName); } m_writer.Write("%s %s", GetTypeName(argument->type, /*exactType=*/true), argument->name); // @@ IC: We are assuming that the first argument is the 'stage_in'. - if (argument->type.baseType == HLSLBaseType_UserDefined && argument == entryFunction->argument) - { + if (argument->type.baseType == HLSLBaseType_UserDefined && argument == entryFunction->argument) { m_writer.Write(" [[stage_in]]"); } - else if (argument->sv_semantic) - { + else if (argument->sv_semantic) { m_writer.Write(" [[%s]]", argument->sv_semantic); } - + argumentCount++; - + argument = argument->nextArgument; - if (argument && !argument->hidden) - { + if (argument && !argument->hidden) { m_writer.Write(", "); - + // Alec added for readability indent = m_writer.EndLine(); m_writer.BeginLine(indent); } - - } // These are additional inputs/outputs not [[stage_in]] - + currentArg = m_firstClassArgument; - if (argumentCount && currentArg != NULL) - { + if (argumentCount && currentArg != NULL) { m_writer.Write(","); - + // Alec added for readability indent = m_writer.EndLine(); m_writer.BeginLine(indent); - } - while (currentArg != NULL) - { - if (currentArg->type.baseType == HLSLBaseType_UserDefined) - { + while (currentArg != NULL) { + if (currentArg->type.baseType == HLSLBaseType_UserDefined) { bool isRef = currentArg->isRef; - + m_writer.Write("%s %s %s %s [[%s]]", GetAddressSpaceName(currentArg->type.baseType, currentArg->type.addressSpace), - // shaderClassName, - currentArg->type.typeName, isRef ? "&" : "*", currentArg->name, + // shaderClassName, + currentArg->type.typeName, isRef ? "&" : "*", currentArg->name, currentArg->registerName); } - else - { + else { m_writer.Write("%s %s [[%s]]", GetTypeName(currentArg->type, /*exactType=*/true), currentArg->name, currentArg->registerName); } currentArg = currentArg->nextArg; - if (currentArg) - { + if (currentArg) { m_writer.Write(", "); } - + // Alec added for readability indent = m_writer.EndLine(); m_writer.BeginLine(indent); @@ -633,18 +574,15 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_writer.Write("%s %s", shaderClassName, entryName); currentArg = m_firstClassArgument; - if (currentArg) - { + if (currentArg) { m_writer.Write("("); - while (currentArg != NULL) - { + while (currentArg != NULL) { m_writer.Write("%s", currentArg->name); currentArg = currentArg->nextArg; - if (currentArg) - { + if (currentArg) { m_writer.Write(", "); - + // indent = m_writer.EndLine(); // m_writer.BeginLine(indent); } @@ -656,33 +594,27 @@ bool MSLGenerator::Generate(HLSLTree* tree, HLSLTarget target, const char* entry m_writer.BeginLine(1); - if (wrapReturnType) - { + if (wrapReturnType) { m_writer.Write("%s_output output; output.tmp = %s.%s(", entryName, entryName, entryName); } - else - { + else { m_writer.Write("return %s.%s(", entryName, entryName); } argument = entryFunction->argument; - while (argument != NULL) - { - if (!argument->hidden) - { + while (argument != NULL) { + if (!argument->hidden) { m_writer.Write("%s", argument->name); } argument = argument->nextArgument; - if (argument && !argument->hidden) - { + if (argument && !argument->hidden) { m_writer.Write(", "); } } m_writer.EndLine(");"); - if (wrapReturnType) - { + if (wrapReturnType) { m_writer.WriteLine(1, "return output;"); } @@ -703,22 +635,18 @@ const char* MSLGenerator::GetResult() const void MSLGenerator::OutputStaticDeclarations(int indent, HLSLStatement* statement) { - while (statement != NULL) - { - if (statement->hidden) - { + while (statement != NULL) { + if (statement->hidden) { statement = statement->nextStatement; continue; } // write struct/buffer outside of the namespace struct - if (statement->nodeType == HLSLNodeType_Struct) - { - if (!statement->written) - { + if (statement->nodeType == HLSLNodeType_Struct) { + if (!statement->written) { HLSLStruct* structure = static_cast(statement); OutputStruct(indent, structure); - + // skipped for multi-entrypoint statement->written = true; } @@ -730,44 +658,39 @@ void MSLGenerator::OutputStaticDeclarations(int indent, HLSLStatement* statement { HLSLBuffer* buffer = static_cast(statement); OutputBuffer(indent, buffer); - + // skipped for multi-entrypoint statement->written = true; } } */ - - else if (statement->nodeType == HLSLNodeType_Declaration) - { + + else if (statement->nodeType == HLSLNodeType_Declaration) { HLSLDeclaration* declaration = static_cast(statement); const HLSLType& type = declaration->type; - if (type.TestFlags(HLSLTypeFlag_Const | HLSLTypeFlag_Static)) - { - if (!declaration->written) - { + if (type.TestFlags(HLSLTypeFlag_Const | HLSLTypeFlag_Static)) { + if (!declaration->written) { m_writer.BeginLine(indent, declaration->fileName, declaration->line); OutputDeclaration(declaration); m_writer.EndLine(";"); - + // skipped for multi-entrypoint declaration->written = true; } - + // TODO: sure this is needed, or does written handle it // hide declaration from subsequent passes declaration->hidden = true; } } - else if (statement->nodeType == HLSLNodeType_Function) - { + else if (statement->nodeType == HLSLNodeType_Function) { HLSLFunction* function = static_cast(statement); - - if (!function->forward) - { + + if (!function->forward) { OutputStaticDeclarations(indent, function->statement); - + // skipped for multi-entrypoint //function->written = true; } @@ -783,29 +706,27 @@ bool MSLGenerator::CanSkipWrittenStatement(const HLSLStatement* statement) const // only write these once for multi-entrypoint if (statement->nodeType == HLSLNodeType_Comment || - // statement->nodeType == HLSLNodeType_Buffer || - statement->nodeType == HLSLNodeType_Struct) + // statement->nodeType == HLSLNodeType_Buffer || + statement->nodeType == HLSLNodeType_Struct) return true; // only write const scalars out once, so they don't conflict - if (statement->nodeType == HLSLNodeType_Declaration) - { + if (statement->nodeType == HLSLNodeType_Declaration) { const HLSLDeclaration* decl = (const HLSLDeclaration*)statement; - if (IsScalarType(decl->type.baseType) && decl->type.flags & HLSLTypeFlag_Const) - { + if (IsScalarType(decl->type.baseType) && decl->type.flags & HLSLTypeFlag_Const) { return true; } } // TODO: all functions are currently thrown into the namespace class // so can't yet strip them. - + // Helper functions should be skipped once written out -// if (statement->nodeType == HLSLNodeType_Function) -// { -// return true; -// } - + // if (statement->nodeType == HLSLNodeType_Function) + // { + // return true; + // } + return false; } @@ -813,101 +734,82 @@ bool MSLGenerator::CanSkipWrittenStatement(const HLSLStatement* statement) const void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) { // Main generator loop: called recursively - while (statement != NULL) - { + while (statement != NULL) { // skip pruned statements - if (statement->hidden) - { + if (statement->hidden) { statement = statement->nextStatement; continue; } - + // skip writing across multiple entry points // skip writing some types across multiple entry points - if (CanSkipWrittenStatement(statement)) - { + if (CanSkipWrittenStatement(statement)) { statement = statement->nextStatement; continue; } statement->written = true; - + OutputAttributes(indent, statement->attributes); - - if (statement->nodeType == HLSLNodeType_Comment) - { + + if (statement->nodeType == HLSLNodeType_Comment) { HLSLComment* comment = static_cast(statement); m_writer.WriteLine(indent, "//%s", comment->text); } - else if (statement->nodeType == HLSLNodeType_Declaration) - { + else if (statement->nodeType == HLSLNodeType_Declaration) { HLSLDeclaration* declaration = static_cast(statement); - if (declaration->assignment && declaration->assignment->nodeType == HLSLNodeType_FunctionCall) - { + if (declaration->assignment && declaration->assignment->nodeType == HLSLNodeType_FunctionCall) { OutputFunctionCallStatement(indent, (HLSLFunctionCall*)declaration->assignment, declaration); } - else - { + else { m_writer.BeginLine(indent, declaration->fileName, declaration->line); OutputDeclaration(declaration); m_writer.EndLine(";"); } } - else if (statement->nodeType == HLSLNodeType_Struct) - { + else if (statement->nodeType == HLSLNodeType_Struct) { HLSLStruct* structure = static_cast(statement); OutputStruct(indent, structure); } - else if (statement->nodeType == HLSLNodeType_Buffer) - { + else if (statement->nodeType == HLSLNodeType_Buffer) { HLSLBuffer* buffer = static_cast(statement); OutputBuffer(indent, buffer); } - else if (statement->nodeType == HLSLNodeType_Function) - { + else if (statement->nodeType == HLSLNodeType_Function) { HLSLFunction* function = static_cast(statement); - if (!function->forward) - { + if (!function->forward) { OutputFunction(indent, function); } } - else if (statement->nodeType == HLSLNodeType_ExpressionStatement) - { + else if (statement->nodeType == HLSLNodeType_ExpressionStatement) { HLSLExpressionStatement* expressionStatement = static_cast(statement); HLSLExpression* expression = expressionStatement->expression; - if (expression->nodeType == HLSLNodeType_FunctionCall) - { + if (expression->nodeType == HLSLNodeType_FunctionCall) { OutputFunctionCallStatement(indent, (HLSLFunctionCall*)expression, NULL); } - else - { + else { m_writer.BeginLine(indent, statement->fileName, statement->line); OutputExpression(expressionStatement->expression, NULL); m_writer.EndLine(";"); } } - else if (statement->nodeType == HLSLNodeType_ReturnStatement) - { + else if (statement->nodeType == HLSLNodeType_ReturnStatement) { HLSLReturnStatement* returnStatement = static_cast(statement); - if (m_currentFunction->numOutputArguments > 0) - { + if (m_currentFunction->numOutputArguments > 0) { m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); m_writer.Write("return { "); int numArguments = 0; - if (returnStatement->expression != NULL) - { + if (returnStatement->expression != NULL) { OutputTypedExpression(m_currentFunction->returnType, returnStatement->expression, NULL); numArguments++; } - HLSLArgument * argument = m_currentFunction->argument; - while (argument != NULL) - { - if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) - { + HLSLArgument* argument = m_currentFunction->argument; + while (argument != NULL) { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) { if (numArguments) m_writer.Write(", "); m_writer.Write("%s", argument->name); numArguments++; @@ -917,35 +819,29 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) m_writer.EndLine(" };"); } - else if (returnStatement->expression != NULL) - { + else if (returnStatement->expression != NULL) { m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); m_writer.Write("return "); OutputTypedExpression(m_currentFunction->returnType, returnStatement->expression, NULL); m_writer.EndLine(";"); } - else - { + else { m_writer.WriteLineTagged(indent, returnStatement->fileName, returnStatement->line, "return;"); } } - else if (statement->nodeType == HLSLNodeType_DiscardStatement) - { + else if (statement->nodeType == HLSLNodeType_DiscardStatement) { HLSLDiscardStatement* discardStatement = static_cast(statement); m_writer.WriteLineTagged(indent, discardStatement->fileName, discardStatement->line, "discard_fragment();"); } - else if (statement->nodeType == HLSLNodeType_BreakStatement) - { + else if (statement->nodeType == HLSLNodeType_BreakStatement) { HLSLBreakStatement* breakStatement = static_cast(statement); m_writer.WriteLineTagged(indent, breakStatement->fileName, breakStatement->line, "break;"); } - else if (statement->nodeType == HLSLNodeType_ContinueStatement) - { + else if (statement->nodeType == HLSLNodeType_ContinueStatement) { HLSLContinueStatement* continueStatement = static_cast(statement); m_writer.WriteLineTagged(indent, continueStatement->fileName, continueStatement->line, "continue;"); } - else if (statement->nodeType == HLSLNodeType_IfStatement) - { + else if (statement->nodeType == HLSLNodeType_IfStatement) { HLSLIfStatement* ifStatement = static_cast(statement); if (ifStatement->isStatic) { @@ -968,16 +864,14 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) m_writer.EndLine(); OutputStatements(indent + 1, ifStatement->statement); m_writer.WriteLine(indent, "}"); - if (ifStatement->elseStatement != NULL) - { + if (ifStatement->elseStatement != NULL) { m_writer.WriteLine(indent, "else {"); OutputStatements(indent + 1, ifStatement->elseStatement); m_writer.WriteLine(indent, "}"); } } } - else if (statement->nodeType == HLSLNodeType_ForStatement) - { + else if (statement->nodeType == HLSLNodeType_ForStatement) { HLSLForStatement* forStatement = static_cast(statement); m_writer.BeginLine(indent, forStatement->fileName, forStatement->line); m_writer.Write("for ("); @@ -991,25 +885,23 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) OutputStatements(indent + 1, forStatement->statement); m_writer.WriteLine(indent, "}"); } - else if (statement->nodeType == HLSLNodeType_BlockStatement) - { + else if (statement->nodeType == HLSLNodeType_BlockStatement) { HLSLBlockStatement* blockStatement = static_cast(statement); m_writer.WriteLineTagged(indent, blockStatement->fileName, blockStatement->line, "{"); OutputStatements(indent + 1, blockStatement->statement); m_writer.WriteLine(indent, "}"); } - + // fx file support for Technique/Pipeline -// else if (statement->nodeType == HLSLNodeType_Technique) -// { -// // Techniques are ignored. -// } -// else if (statement->nodeType == HLSLNodeType_Pipeline) -// { -// // Pipelines are ignored. -// } - else - { + // else if (statement->nodeType == HLSLNodeType_Technique) + // { + // // Techniques are ignored. + // } + // else if (statement->nodeType == HLSLNodeType_Pipeline) + // { + // // Pipelines are ignored. + // } + else { // Unhandled statement type. Error("Unknown statement"); } @@ -1023,18 +915,15 @@ void MSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) { // IC: These do not appear to exist in MSL. while (attribute != NULL) { - if (attribute->attributeType == HLSLAttributeType_Unroll) - { + if (attribute->attributeType == HLSLAttributeType_Unroll) { // @@ Do any of these work? //m_writer.WriteLine(indent, attribute->fileName, attribute->line, "#pragma unroll"); //m_writer.WriteLine(indent, attribute->fileName, attribute->line, "[[unroll]]"); } - else if (attribute->attributeType == HLSLAttributeType_Flatten) - { + else if (attribute->attributeType == HLSLAttributeType_Flatten) { // @@ } - else if (attribute->attributeType == HLSLAttributeType_Branch) - { + else if (attribute->attributeType == HLSLAttributeType_Branch) { // @@, [[likely]]? } @@ -1044,25 +933,21 @@ void MSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) void MSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) { - if (IsSamplerType(declaration->type)) - { + if (IsSamplerType(declaration->type)) { m_writer.Write("%s sampler& %s", GetAddressSpaceName(declaration->type.baseType, declaration->type.addressSpace), declaration->name); } - else if (IsTextureType(declaration->type)) - { + else if (IsTextureType(declaration->type)) { const char* textureName = GetTypeName(declaration->type, true); if (textureName) m_writer.Write("%s %s& %s", GetAddressSpaceName(declaration->type.baseType, declaration->type.addressSpace), textureName, declaration->name); else Error("Unknown texture"); } - else - { + else { OutputDeclaration(declaration->type, declaration->name, declaration->assignment); declaration = declaration->nextDeclaration; - while (declaration != NULL) - { + while (declaration != NULL) { m_writer.Write(","); OutputDeclarationBody(declaration->type, declaration->name, declaration->assignment); declaration = declaration->nextDeclaration; @@ -1074,18 +959,15 @@ void MSLGenerator::OutputStruct(int indent, HLSLStruct* structure) { m_writer.WriteLineTagged(indent, structure->fileName, structure->line, "struct %s {", structure->name); HLSLStructField* field = structure->field; - while (field != NULL) - { - if (!field->hidden) - { + while (field != NULL) { + if (!field->hidden) { m_writer.BeginLine(indent + 1, field->fileName, field->line); OutputDeclaration(field->type, field->name, NULL); - + // DONE: would need a semantic remap for all possible semantics // just use the name the caller specified if sv_semantic // is not set. The header can handle translating - if (field->sv_semantic) - { + if (field->sv_semantic) { m_writer.Write(" [[%s]]", field->sv_semantic); } @@ -1098,45 +980,39 @@ void MSLGenerator::OutputStruct(int indent, HLSLStruct* structure) void MSLGenerator::OutputBuffer(int indent, HLSLBuffer* buffer) { - if (!buffer->IsGlobalFields()) - { + if (!buffer->IsGlobalFields()) { m_writer.BeginLine(indent, buffer->fileName, buffer->line); - + // TODO: handle array count for indexing into constant buffer // some are unbounded array like BAB and SBO // TODO: may need to use t/u registers for those too and a thread? - + // TODO: fix this, ConstantBuffer can index into a constant buffer too // detect use of array notation on decl bool isRef = buffer->bufferType == HLSLBufferType_ConstantBuffer || buffer->IsGlobalFields(); - + if (buffer->bufferType == HLSLBufferType_ConstantBuffer || buffer->bufferType == HLSLBufferType_ByteAddressBuffer || - buffer->bufferType == HLSLBufferType_StructuredBuffer) - { + buffer->bufferType == HLSLBufferType_StructuredBuffer) { m_writer.Write("constant %s %s %s", buffer->bufferStruct->name, isRef ? "&" : "*", buffer->name); } - else - { - m_writer.Write("device %s %s %s", buffer->bufferStruct->name, isRef ? "&" : "*", buffer->name); + else { + m_writer.Write("device %s %s %s", buffer->bufferStruct->name, isRef ? "&" : "*", buffer->name); } - + m_writer.EndLine(";"); } - else - { + else { // converted cbuffer that spill tons of globals for every field HLSLDeclaration* field = buffer->field; - + m_writer.BeginLine(indent, buffer->fileName, buffer->line); m_writer.Write("struct %s_ubo", buffer->name); m_writer.EndLine(" {"); - - while (field != NULL) - { - if (!field->hidden) - { + + while (field != NULL) { + if (!field->hidden) { m_writer.BeginLine(indent + 1, field->fileName, field->line); OutputDeclaration(field->type, field->name, field->assignment, false, false, 0); // /*alignment=*/16); m_writer.EndLine(";"); @@ -1144,7 +1020,7 @@ void MSLGenerator::OutputBuffer(int indent, HLSLBuffer* buffer) field = (HLSLDeclaration*)field->nextStatement; } m_writer.WriteLine(indent, "};"); - + m_writer.WriteLine(indent, "constant %s_ubo & %s;", buffer->name, buffer->name); } } @@ -1155,26 +1031,22 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) const char* returnTypeName = GetTypeName(function->returnType, /*exactType=*/false); // Declare output tuple. - if (function->numOutputArguments > 0) - { + if (function->numOutputArguments > 0) { returnTypeName = m_tree->AddStringFormat("%s_out%d", functionName, function->line); // @@ Find a better way to generate unique name. m_writer.BeginLine(indent, function->fileName, function->line); m_writer.Write("struct %s { ", returnTypeName); m_writer.EndLine(); - if (function->returnType.baseType != HLSLBaseType_Void) - { + if (function->returnType.baseType != HLSLBaseType_Void) { m_writer.BeginLine(indent + 1, function->fileName, function->line); OutputDeclaration(function->returnType, "__result", /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); m_writer.EndLine(";"); } - HLSLArgument * argument = function->argument; - while (argument != NULL) - { - if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) - { + HLSLArgument* argument = function->argument; + while (argument != NULL) { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) { m_writer.BeginLine(indent + 1, function->fileName, function->line); OutputDeclaration(argument->type, argument->name, /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); m_writer.EndLine(";"); @@ -1188,8 +1060,7 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) m_writer.BeginLine(indent, function->fileName, function->line); m_writer.Write("%s %s_%d(", returnTypeName, functionName, function->line); } - else - { + else { m_writer.BeginLine(indent, function->fileName, function->line); m_writer.Write("%s %s(", returnTypeName, functionName); } @@ -1200,11 +1071,9 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) m_currentFunction = function; // Local declarations for output arguments. - HLSLArgument * argument = function->argument; - while (argument != NULL) - { - if (argument->modifier == HLSLArgumentModifier_Out) - { + HLSLArgument* argument = function->argument; + while (argument != NULL) { + if (argument->modifier == HLSLArgumentModifier_Out) { m_writer.BeginLine(indent + 1, function->fileName, function->line); OutputDeclaration(argument->type, argument->name, /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); m_writer.EndLine(";"); @@ -1215,31 +1084,25 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) OutputStatements(indent + 1, function->statement); // @@ Modify return statements if function has multiple output arguments! // Output implicit return. - if (function->numOutputArguments > 0) - { + if (function->numOutputArguments > 0) { bool needsImplicitReturn = true; - HLSLStatement * statement = function->statement; - if (statement != NULL) - { - while (statement->nextStatement != NULL) - { + HLSLStatement* statement = function->statement; + if (statement != NULL) { + while (statement->nextStatement != NULL) { statement = statement->nextStatement; } needsImplicitReturn = (statement->nodeType != HLSLNodeType_ReturnStatement) && function->returnType.baseType == HLSLBaseType_Void; } - if (needsImplicitReturn) - { + if (needsImplicitReturn) { m_writer.BeginLine(indent + 1); m_writer.Write("return { "); int numArguments = 0; - HLSLArgument * argument2 = m_currentFunction->argument; - while (argument2 != NULL) - { + HLSLArgument* argument2 = m_currentFunction->argument; + while (argument2 != NULL) { if (argument2->modifier == HLSLArgumentModifier_Out || - argument2->modifier == HLSLArgumentModifier_Inout) - { + argument2->modifier == HLSLArgumentModifier_Inout) { if (numArguments) m_writer.Write(", "); m_writer.Write("%s ", argument2->name); numArguments++; @@ -1255,23 +1118,19 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) m_currentFunction = NULL; } - // @@ We could be a lot smarter removing parenthesis based on the operator precedence of the parent expression. -static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentExpression) { - +static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentExpression) +{ // For now we just omit the parenthesis if there's no parent expression. - if (parentExpression == NULL) - { + if (parentExpression == NULL) { return false; } // One more special case that's pretty common. - if (parentExpression->nodeType == HLSLNodeType_MemberAccess) - { + if (parentExpression->nodeType == HLSLNodeType_MemberAccess) { if (expression->nodeType == HLSLNodeType_IdentifierExpression || expression->nodeType == HLSLNodeType_ArrayAccess || - expression->nodeType == HLSLNodeType_MemberAccess) - { + expression->nodeType == HLSLNodeType_MemberAccess) { return false; } } @@ -1279,7 +1138,7 @@ static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentE return true; } -bool MSLGenerator::NeedsCast(const HLSLType & target, const HLSLType & source) +bool MSLGenerator::NeedsCast(const HLSLType& target, const HLSLType& source) { HLSLBaseType targetType = target.baseType; HLSLBaseType sourceType = source.baseType; @@ -1294,23 +1153,20 @@ bool MSLGenerator::NeedsCast(const HLSLType & target, const HLSLType & source) return false; }*/ - if (m_options.treatHalfAsFloat) - { + if (m_options.treatHalfAsFloat) { // use call to convert half back to float type if (IsHalf(targetType)) targetType = HalfToFloatBaseType(targetType); - if (IsHalf(sourceType)) sourceType = HalfToFloatBaseType(sourceType ); + if (IsHalf(sourceType)) sourceType = HalfToFloatBaseType(sourceType); } return targetType != sourceType && (IsCoreTypeEqual(targetType, sourceType) || IsScalarType(sourceType)); } - void MSLGenerator::OutputTypedExpression(const HLSLType& type, HLSLExpression* expression, HLSLExpression* parentExpression) { // If base types are not exactly the same, do explicit cast. bool closeCastExpression = false; - if (NeedsCast(type, expression->expressionType)) - { + if (NeedsCast(type, expression->expressionType)) { OutputCast(type); m_writer.Write("("); closeCastExpression = true; @@ -1318,28 +1174,24 @@ void MSLGenerator::OutputTypedExpression(const HLSLType& type, HLSLExpression* e OutputExpression(expression, parentExpression); - if (closeCastExpression) - { + if (closeCastExpression) { m_writer.Write(")"); } } void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression) { - if (expression->nodeType == HLSLNodeType_IdentifierExpression) - { + if (expression->nodeType == HLSLNodeType_IdentifierExpression) { HLSLIdentifierExpression* identifierExpression = static_cast(expression); const char* name = identifierExpression->name; - + { - if (identifierExpression->global) - { + if (identifierExpression->global) { // prepend cbuffer name - HLSLBuffer * buffer; - HLSLDeclaration * declaration = m_tree->FindGlobalDeclaration(identifierExpression->name, &buffer); + HLSLBuffer* buffer; + HLSLDeclaration* declaration = m_tree->FindGlobalDeclaration(identifierExpression->name, &buffer); - if (declaration && declaration->buffer) - { + if (declaration && declaration->buffer) { ASSERT(buffer == declaration->buffer); m_writer.Write("%s.", declaration->buffer->name); } @@ -1369,177 +1221,214 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* }*/ } } - else if (expression->nodeType == HLSLNodeType_CastingExpression) - { + else if (expression->nodeType == HLSLNodeType_CastingExpression) { HLSLCastingExpression* castingExpression = static_cast(expression); OutputCast(castingExpression->type); m_writer.Write("("); OutputExpression(castingExpression->expression, castingExpression); m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_ConstructorExpression) - { + else if (expression->nodeType == HLSLNodeType_ConstructorExpression) { HLSLConstructorExpression* constructorExpression = static_cast(expression); - + m_writer.Write("%s(", GetTypeName(constructorExpression->type, /*exactType=*/false)); //OutputExpressionList(constructorExpression->type, constructorExpression->argument); // @@ Get element type. OutputExpressionList(constructorExpression->argument); m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_LiteralExpression) - { + else if (expression->nodeType == HLSLNodeType_LiteralExpression) { HLSLLiteralExpression* literalExpression = static_cast(expression); - + HLSLBaseType type = literalExpression->type; if (m_options.treatHalfAsFloat && IsHalf(type)) type = HLSLBaseType_Float; - - switch (type) - { - - case HLSLBaseType_Half: - case HLSLBaseType_Double: - case HLSLBaseType_Float: - { - char floatBuffer[64]; - - String_FormatFloat(floatBuffer, sizeof(floatBuffer), literalExpression->fValue); - String_StripTrailingFloatZeroes(floatBuffer); - m_writer.Write("%s%s", floatBuffer, type == HLSLBaseType_Half ? "h" : ""); - break; - } - // TODO: missing uint types (trailing character u, ul, ..) - - case HLSLBaseType_Short: - case HLSLBaseType_Long: - case HLSLBaseType_Int: - m_writer.Write("%d", literalExpression->iValue); - break; - - case HLSLBaseType_Bool: - m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); - break; - default: - Error("Unhandled literal"); - //ASSERT(0); + + switch (type) { + case HLSLBaseType_Half: + case HLSLBaseType_Double: + case HLSLBaseType_Float: { + char floatBuffer[64]; + + String_FormatFloat(floatBuffer, sizeof(floatBuffer), literalExpression->fValue); + String_StripTrailingFloatZeroes(floatBuffer); + m_writer.Write("%s%s", floatBuffer, type == HLSLBaseType_Half ? "h" : ""); + break; + } + // TODO: missing uint types (trailing character u, ul, ..) + + case HLSLBaseType_Short: + case HLSLBaseType_Long: + case HLSLBaseType_Int: + m_writer.Write("%d", literalExpression->iValue); + break; + + case HLSLBaseType_Bool: + m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); + break; + default: + Error("Unhandled literal"); + //ASSERT(0); } } - else if (expression->nodeType == HLSLNodeType_UnaryExpression) - { + else if (expression->nodeType == HLSLNodeType_UnaryExpression) { HLSLUnaryExpression* unaryExpression = static_cast(expression); const char* op = "?"; bool pre = true; - switch (unaryExpression->unaryOp) - { - case HLSLUnaryOp_Negative: op = "-"; break; - case HLSLUnaryOp_Positive: op = "+"; break; - case HLSLUnaryOp_Not: op = "!"; break; - case HLSLUnaryOp_BitNot: op = "~"; break; - case HLSLUnaryOp_PreIncrement: op = "++"; break; - case HLSLUnaryOp_PreDecrement: op = "--"; break; - case HLSLUnaryOp_PostIncrement: op = "++"; pre = false; break; - case HLSLUnaryOp_PostDecrement: op = "--"; pre = false; break; + switch (unaryExpression->unaryOp) { + case HLSLUnaryOp_Negative: + op = "-"; + break; + case HLSLUnaryOp_Positive: + op = "+"; + break; + case HLSLUnaryOp_Not: + op = "!"; + break; + case HLSLUnaryOp_BitNot: + op = "~"; + break; + case HLSLUnaryOp_PreIncrement: + op = "++"; + break; + case HLSLUnaryOp_PreDecrement: + op = "--"; + break; + case HLSLUnaryOp_PostIncrement: + op = "++"; + pre = false; + break; + case HLSLUnaryOp_PostDecrement: + op = "--"; + pre = false; + break; } bool addParenthesis = NeedsParenthesis(unaryExpression->expression, expression); if (addParenthesis) m_writer.Write("("); - if (pre) - { + if (pre) { m_writer.Write("%s", op); OutputExpression(unaryExpression->expression, unaryExpression); } - else - { + else { OutputExpression(unaryExpression->expression, unaryExpression); m_writer.Write("%s", op); } if (addParenthesis) m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_BinaryExpression) - { + else if (expression->nodeType == HLSLNodeType_BinaryExpression) { HLSLBinaryExpression* binaryExpression = static_cast(expression); bool addParenthesis = NeedsParenthesis(expression, parentExpression); if (addParenthesis) m_writer.Write("("); - + { - if (IsArithmeticOp(binaryExpression->binaryOp) || IsLogicOp(binaryExpression->binaryOp)) - { + if (IsArithmeticOp(binaryExpression->binaryOp) || IsLogicOp(binaryExpression->binaryOp)) { // Do intermediate type promotion, without changing dimension: HLSLType promotedType = binaryExpression->expression1->expressionType; - if (!IsNumericTypeEqual(binaryExpression->expressionType.baseType, promotedType.baseType)) - { + if (!IsNumericTypeEqual(binaryExpression->expressionType.baseType, promotedType.baseType)) { promotedType.baseType = PromoteType(binaryExpression->expressionType.baseType, promotedType.baseType); } OutputTypedExpression(promotedType, binaryExpression->expression1, binaryExpression); } - else - { + else { OutputExpression(binaryExpression->expression1, binaryExpression); } const char* op = "?"; - switch (binaryExpression->binaryOp) - { - case HLSLBinaryOp_Add: op = " + "; break; - case HLSLBinaryOp_Sub: op = " - "; break; - case HLSLBinaryOp_Mul: op = " * "; break; - case HLSLBinaryOp_Div: op = " / "; break; - case HLSLBinaryOp_Less: op = " < "; break; - case HLSLBinaryOp_Greater: op = " > "; break; - case HLSLBinaryOp_LessEqual: op = " <= "; break; - case HLSLBinaryOp_GreaterEqual: op = " >= "; break; - case HLSLBinaryOp_Equal: op = " == "; break; - case HLSLBinaryOp_NotEqual: op = " != "; break; - case HLSLBinaryOp_Assign: op = " = "; break; - case HLSLBinaryOp_AddAssign: op = " += "; break; - case HLSLBinaryOp_SubAssign: op = " -= "; break; - case HLSLBinaryOp_MulAssign: op = " *= "; break; - case HLSLBinaryOp_DivAssign: op = " /= "; break; - case HLSLBinaryOp_And: op = " && "; break; - case HLSLBinaryOp_Or: op = " || "; break; - case HLSLBinaryOp_BitAnd: op = " & "; break; - case HLSLBinaryOp_BitOr: op = " | "; break; - case HLSLBinaryOp_BitXor: op = " ^ "; break; - default: - Error("unhandled literal"); - //ASSERT(0); + switch (binaryExpression->binaryOp) { + case HLSLBinaryOp_Add: + op = " + "; + break; + case HLSLBinaryOp_Sub: + op = " - "; + break; + case HLSLBinaryOp_Mul: + op = " * "; + break; + case HLSLBinaryOp_Div: + op = " / "; + break; + case HLSLBinaryOp_Less: + op = " < "; + break; + case HLSLBinaryOp_Greater: + op = " > "; + break; + case HLSLBinaryOp_LessEqual: + op = " <= "; + break; + case HLSLBinaryOp_GreaterEqual: + op = " >= "; + break; + case HLSLBinaryOp_Equal: + op = " == "; + break; + case HLSLBinaryOp_NotEqual: + op = " != "; + break; + case HLSLBinaryOp_Assign: + op = " = "; + break; + case HLSLBinaryOp_AddAssign: + op = " += "; + break; + case HLSLBinaryOp_SubAssign: + op = " -= "; + break; + case HLSLBinaryOp_MulAssign: + op = " *= "; + break; + case HLSLBinaryOp_DivAssign: + op = " /= "; + break; + case HLSLBinaryOp_And: + op = " && "; + break; + case HLSLBinaryOp_Or: + op = " || "; + break; + case HLSLBinaryOp_BitAnd: + op = " & "; + break; + case HLSLBinaryOp_BitOr: + op = " | "; + break; + case HLSLBinaryOp_BitXor: + op = " ^ "; + break; + default: + Error("unhandled literal"); + //ASSERT(0); } m_writer.Write("%s", op); - if (binaryExpression->binaryOp == HLSLBinaryOp_MulAssign || binaryExpression->binaryOp == HLSLBinaryOp_DivAssign || IsArithmeticOp(binaryExpression->binaryOp) || - IsLogicOp(binaryExpression->binaryOp)) - { + IsLogicOp(binaryExpression->binaryOp)) { // Do intermediate type promotion, without changing dimension: HLSLType promotedType = binaryExpression->expression2->expressionType; - if (!IsNumericTypeEqual(binaryExpression->expressionType.baseType, promotedType.baseType)) - { + if (!IsNumericTypeEqual(binaryExpression->expressionType.baseType, promotedType.baseType)) { // This should only promote up (half->float, etc) promotedType.baseType = PromoteType(binaryExpression->expressionType.baseType, promotedType.baseType); } OutputTypedExpression(promotedType, binaryExpression->expression2, binaryExpression); } - else if (IsAssignOp(binaryExpression->binaryOp)) - { + else if (IsAssignOp(binaryExpression->binaryOp)) { OutputTypedExpression(binaryExpression->expressionType, binaryExpression->expression2, binaryExpression); } - else - { + else { OutputExpression(binaryExpression->expression2, binaryExpression); } } if (addParenthesis) m_writer.Write(")"); } - else if (expression->nodeType == HLSLNodeType_ConditionalExpression) - { + else if (expression->nodeType == HLSLNodeType_ConditionalExpression) { HLSLConditionalExpression* conditionalExpression = static_cast(expression); - + // TODO: @@ Remove parenthesis. m_writer.Write("(("); OutputExpression(conditionalExpression->condition, NULL); @@ -1549,27 +1438,23 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* OutputExpression(conditionalExpression->falseExpression, NULL); m_writer.Write("))"); } - else if (expression->nodeType == HLSLNodeType_MemberAccess) - { + else if (expression->nodeType == HLSLNodeType_MemberAccess) { HLSLMemberAccess* memberAccess = static_cast(expression); bool addParenthesis = NeedsParenthesis(memberAccess->object, expression); - if (addParenthesis) - { + if (addParenthesis) { m_writer.Write("("); } OutputExpression(memberAccess->object, NULL); - if (addParenthesis) - { + if (addParenthesis) { m_writer.Write(")"); } m_writer.Write(".%s", memberAccess->field); } - else if (expression->nodeType == HLSLNodeType_ArrayAccess) - { + else if (expression->nodeType == HLSLNodeType_ArrayAccess) { HLSLArrayAccess* arrayAccess = static_cast(expression); - + // Just use the matrix notation, using column_order instead of row_order //if (arrayAccess->array->expressionType.array) // || !IsMatrixType(arrayAccess->array->expressionType.baseType)) { @@ -1578,32 +1463,29 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* OutputExpression(arrayAccess->index, NULL); m_writer.Write("]"); } -// else -// { -// // @@ This doesn't work for l-values! -// m_writer.Write("column("); -// OutputExpression(arrayAccess->array, NULL); -// m_writer.Write(", "); -// OutputExpression(arrayAccess->index, NULL); -// m_writer.Write(")"); -// } - } - else if (expression->nodeType == HLSLNodeType_FunctionCall) - { + // else + // { + // // @@ This doesn't work for l-values! + // m_writer.Write("column("); + // OutputExpression(arrayAccess->array, NULL); + // m_writer.Write(", "); + // OutputExpression(arrayAccess->index, NULL); + // m_writer.Write(")"); + // } + } + else if (expression->nodeType == HLSLNodeType_FunctionCall) { HLSLFunctionCall* functionCall = static_cast(expression); OutputFunctionCall(functionCall, parentExpression); } - else if (expression->nodeType == HLSLNodeType_MemberFunctionCall) - { + else if (expression->nodeType == HLSLNodeType_MemberFunctionCall) { HLSLMemberFunctionCall* functionCall = static_cast(expression); - + // Write out the member identifier m_writer.Write("%s.", functionCall->memberIdentifier->name); OutputFunctionCall(functionCall, parentExpression); } - else - { + else { Error("unknown expression"); } } @@ -1611,16 +1493,13 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* void MSLGenerator::OutputCast(const HLSLType& type) { // Note: msl fails on float4x4 to float3x3 casting - if (type.baseType == HLSLBaseType_Float3x3) - { + if (type.baseType == HLSLBaseType_Float3x3) { m_writer.Write("tofloat3x3"); } - else if (type.baseType == HLSLBaseType_Half3x3) - { + else if (type.baseType == HLSLBaseType_Half3x3) { m_writer.Write("tohalft3x3"); } - else - { + else { m_writer.Write("("); OutputDeclarationType(type, /*isConst=*/false, /*isRef=*/false, /*alignment=*/0, /*isTypeCast=*/true); m_writer.Write(")"); @@ -1631,17 +1510,14 @@ void MSLGenerator::OutputCast(const HLSLType& type) void MSLGenerator::OutputArguments(HLSLArgument* argument) { int numArgs = 0; - while (argument != NULL) - { + while (argument != NULL) { // Skip hidden and output arguments. - if (argument->hidden || argument->modifier == HLSLArgumentModifier_Out) - { + if (argument->hidden || argument->modifier == HLSLArgumentModifier_Out) { argument = argument->nextArgument; continue; } - if (numArgs > 0) - { + if (numArgs > 0) { m_writer.Write(", "); } @@ -1651,8 +1527,7 @@ void MSLGenerator::OutputArguments(HLSLArgument* argument) { isRef = true; }*/ - if (argument->modifier == HLSLArgumentModifier_In || argument->modifier == HLSLArgumentModifier_Const) - { + if (argument->modifier == HLSLArgumentModifier_In || argument->modifier == HLSLArgumentModifier_Const) { isConst = true; } @@ -1670,76 +1545,62 @@ void MSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, HLS void MSLGenerator::OutputDeclarationType(const HLSLType& type, bool isRef, bool isConst, int alignment, bool isTypeCast) { - const char* typeName = GetTypeName(type, /*exactType=*/isTypeCast); // @@ Don't allow type changes in uniform/globals or casts! + const char* typeName = GetTypeName(type, /*exactType=*/isTypeCast); // @@ Don't allow type changes in uniform/globals or casts! /*if (!isTypeCast)*/ { - if (isRef && !isTypeCast) - { + if (isRef && !isTypeCast) { m_writer.Write("%s ", GetAddressSpaceName(type.baseType, type.addressSpace)); } - if (isConst || type.TestFlags(HLSLTypeFlag_Const)) - { + if (isConst || type.TestFlags(HLSLTypeFlag_Const)) { m_writer.Write("constant "); - -// m_writer.Write("const "); -// -// if ((type.flags & HLSLTypeFlag_Static) != 0 && !isTypeCast) -// { -// // TODO: use GetAddressSpaceName? -// m_writer.Write("static constant constexpr "); -// } + + // m_writer.Write("const "); + // + // if ((type.flags & HLSLTypeFlag_Static) != 0 && !isTypeCast) + // { + // // TODO: use GetAddressSpaceName? + // m_writer.Write("static constant constexpr "); + // } } } - - if (alignment != 0 && !isTypeCast) - { + + if (alignment != 0 && !isTypeCast) { // caller can request alignment, but default is 0 m_writer.Write("alignas(%d) ", alignment); } m_writer.Write("%s", typeName); - if (isTypeCast) - { + if (isTypeCast) { // Do not output modifiers inside type cast expressions. return; } // Interpolation modifiers. - if (type.TestFlags(HLSLTypeFlag_NoInterpolation)) - { + if (type.TestFlags(HLSLTypeFlag_NoInterpolation)) { m_writer.Write(" [[flat]]"); } - else - { - if (type.TestFlags(HLSLTypeFlag_NoPerspective)) - { - if (type.TestFlags(HLSLTypeFlag_Centroid)) - { + else { + if (type.TestFlags(HLSLTypeFlag_NoPerspective)) { + if (type.TestFlags(HLSLTypeFlag_Centroid)) { m_writer.Write(" [[centroid_no_perspective]]"); } - else if (type.TestFlags(HLSLTypeFlag_Sample)) - { + else if (type.TestFlags(HLSLTypeFlag_Sample)) { m_writer.Write(" [[sample_no_perspective]]"); } - else - { + else { m_writer.Write(" [[center_no_perspective]]"); } } - else - { - if (type.TestFlags(HLSLTypeFlag_Centroid)) - { + else { + if (type.TestFlags(HLSLTypeFlag_Centroid)) { m_writer.Write(" [[centroid_perspective]]"); } - else if (type.TestFlags(HLSLTypeFlag_Sample)) - { + else if (type.TestFlags(HLSLTypeFlag_Sample)) { m_writer.Write(" [[sample_perspective]]"); } - else - { + else { // Default. //m_writer.Write(" [[center_perspective]]"); } @@ -1749,8 +1610,7 @@ void MSLGenerator::OutputDeclarationType(const HLSLType& type, bool isRef, bool void MSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef) { - if (isRef) - { + if (isRef) { // Arrays of refs are illegal in C++ and hence MSL, need to "link" the & to the var name m_writer.Write("(&"); } @@ -1758,17 +1618,14 @@ void MSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, // Then name m_writer.Write(" %s", name); - if (isRef) - { + if (isRef) { m_writer.Write(")"); } // Add brackets for arrays - if (type.array) - { + if (type.array) { m_writer.Write("["); - if (type.arraySize != NULL) - { + if (type.arraySize != NULL) { OutputExpression(type.arraySize, NULL); } m_writer.Write("]"); @@ -1777,17 +1634,14 @@ void MSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, // Semantics and registers unhandled for now // Assignment handling - if (assignment != NULL) - { + if (assignment != NULL) { m_writer.Write(" = "); - if (type.array) - { + if (type.array) { m_writer.Write("{ "); OutputExpressionList(assignment); m_writer.Write(" }"); } - else - { + else { OutputTypedExpression(type, assignment, NULL); } } @@ -1796,10 +1650,8 @@ void MSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, void MSLGenerator::OutputExpressionList(HLSLExpression* expression) { int numExpressions = 0; - while (expression != NULL) - { - if (numExpressions > 0) - { + while (expression != NULL) { + if (numExpressions > 0) { m_writer.Write(", "); } OutputExpression(expression, NULL); @@ -1809,13 +1661,11 @@ void MSLGenerator::OutputExpressionList(HLSLExpression* expression) } // Cast all expressions to given type. -void MSLGenerator::OutputExpressionList(const HLSLType & type, HLSLExpression* expression) +void MSLGenerator::OutputExpressionList(const HLSLType& type, HLSLExpression* expression) { int numExpressions = 0; - while (expression != NULL) - { - if (numExpressions > 0) - { + while (expression != NULL) { + if (numExpressions > 0) { m_writer.Write(", "); } @@ -1829,13 +1679,10 @@ void MSLGenerator::OutputExpressionList(const HLSLType & type, HLSLExpression* e void MSLGenerator::OutputExpressionList(HLSLArgument* argument, HLSLExpression* expression) { int numExpressions = 0; - while (expression != NULL) - { + while (expression != NULL) { ASSERT(argument != NULL); - if (argument->modifier != HLSLArgumentModifier_Out) - { - if (numExpressions > 0) - { + if (argument->modifier != HLSLArgumentModifier_Out) { + if (numExpressions > 0) { m_writer.Write(", "); } @@ -1848,46 +1695,36 @@ void MSLGenerator::OutputExpressionList(HLSLArgument* argument, HLSLExpression* } } - - inline bool isAddressable(HLSLExpression* expression) { - if (expression->nodeType == HLSLNodeType_IdentifierExpression) - { + if (expression->nodeType == HLSLNodeType_IdentifierExpression) { return true; } - if (expression->nodeType == HLSLNodeType_ArrayAccess) - { + if (expression->nodeType == HLSLNodeType_ArrayAccess) { return true; } - if (expression->nodeType == HLSLNodeType_MemberAccess) - { + if (expression->nodeType == HLSLNodeType_MemberAccess) { HLSLMemberAccess* memberAccess = (HLSLMemberAccess*)expression; return !memberAccess->swizzle; } return false; } - void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall, HLSLDeclaration* declaration) { // Nothing special about these cases: - if (functionCall->function->numOutputArguments == 0) - { + if (functionCall->function->numOutputArguments == 0) { m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); - if (declaration) - { + if (declaration) { OutputDeclaration(declaration); } - else - { + else { OutputExpression(functionCall, NULL); } m_writer.EndLine(";"); return; } - // Transform this: // float foo = functionCall(bah, poo); @@ -1904,12 +1741,10 @@ void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* fun OutputExpressionList(functionCall->function->argument, functionCall->argument); m_writer.EndLine(");"); - HLSLExpression * expression = functionCall->argument; - HLSLArgument * argument = functionCall->function->argument; - while (argument != NULL) - { - if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) - { + HLSLExpression* expression = functionCall->argument; + HLSLArgument* argument = functionCall->function->argument; + while (argument != NULL) { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) { m_writer.BeginLine(indent); OutputExpression(expression, NULL); // @@ This assignment may need a cast. @@ -1925,99 +1760,96 @@ void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* fun argument = argument->nextArgument; } - if (declaration) - { + if (declaration) { m_writer.BeginLine(indent); OutputDeclarationType(declaration->type); m_writer.Write(" %s = out%d.__result;", declaration->name, functionCall->line); m_writer.EndLine(); } + /* TODO: Alec, why is all this chopped out? -/* TODO: Alec, why is all this chopped out? + int argumentIndex = 0; + HLSLArgument* argument = functionCall->function->argument; + HLSLExpression* expression = functionCall->argument; + while (argument != NULL) + { + if (!isAddressable(expression)) + { + if (argument->modifier == HLSLArgumentModifier_Out) + { + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + OutputDeclarationType(argument->type); + m_writer.Write("tmp%d;", argumentIndex); + m_writer.EndLine(); + } + else if (argument->modifier == HLSLArgumentModifier_Inout) + { + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + OutputDeclarationType(argument->type); + m_writer.Write("tmp%d = ", argumentIndex); + OutputExpression(expression, NULL); + m_writer.EndLine(";"); + } + } + argument = argument->nextArgument; + expression = expression->nextExpression; + argumentIndex++; + } - int argumentIndex = 0; - HLSLArgument* argument = functionCall->function->argument; - HLSLExpression* expression = functionCall->argument; - while (argument != NULL) - { - if (!isAddressable(expression)) + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + const char* name = functionCall->function->name; + m_writer.Write("%s(", name); + //OutputExpressionList(functionCall->argument); + + // Output expression list with temporary substitution. + argumentIndex = 0; + argument = functionCall->function->argument; + expression = functionCall->argument; + while (expression != NULL) { - if (argument->modifier == HLSLArgumentModifier_Out) + if (!isAddressable(expression) && (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout)) { - m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); - OutputDeclarationType(argument->type); - m_writer.Write("tmp%d;", argumentIndex); - m_writer.EndLine(); + m_writer.Write("tmp%d", argumentIndex); } - else if (argument->modifier == HLSLArgumentModifier_Inout) + else { - m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); - OutputDeclarationType(argument->type); - m_writer.Write("tmp%d = ", argumentIndex); OutputExpression(expression, NULL); - m_writer.EndLine(";"); } - } - argument = argument->nextArgument; - expression = expression->nextExpression; - argumentIndex++; - } - m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); - const char* name = functionCall->function->name; - m_writer.Write("%s(", name); - //OutputExpressionList(functionCall->argument); - - // Output expression list with temporary substitution. - argumentIndex = 0; - argument = functionCall->function->argument; - expression = functionCall->argument; - while (expression != NULL) - { - if (!isAddressable(expression) && (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout)) - { - m_writer.Write("tmp%d", argumentIndex); - } - else - { - OutputExpression(expression, NULL); + argument = argument->nextArgument; + expression = expression->nextExpression; + argumentIndex++; + if (expression) + { + m_writer.Write(", "); + } } + m_writer.EndLine(");"); - argument = argument->nextArgument; - expression = expression->nextExpression; - argumentIndex++; - if (expression) + argumentIndex = 0; + argument = functionCall->function->argument; + expression = functionCall->argument; + while (expression != NULL) { - m_writer.Write(", "); - } - } - m_writer.EndLine(");"); + if (!isAddressable(expression) && (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout)) + { + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + OutputExpression(expression, NULL); + m_writer.Write(" = tmp%d", argumentIndex); + m_writer.EndLine(";"); + } - argumentIndex = 0; - argument = functionCall->function->argument; - expression = functionCall->argument; - while (expression != NULL) - { - if (!isAddressable(expression) && (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout)) - { - m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); - OutputExpression(expression, NULL); - m_writer.Write(" = tmp%d", argumentIndex); - m_writer.EndLine(";"); + argument = argument->nextArgument; + expression = expression->nextExpression; + argumentIndex++; } - - argument = argument->nextArgument; - expression = expression->nextExpression; - argumentIndex++; - } -*/ + */ } -void MSLGenerator::OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression * parentExpression) +void MSLGenerator::OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression* parentExpression) { - if (functionCall->function->numOutputArguments > 0) - { + if (functionCall->function->numOutputArguments > 0) { ASSERT(false); } @@ -2043,7 +1875,7 @@ void MSLGenerator::OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpres } } -const char* MSLGenerator::TranslateInputSemantic(const char * semantic) +const char* MSLGenerator::TranslateInputSemantic(const char* semantic) { if (semantic == NULL) return NULL; @@ -2051,8 +1883,7 @@ const char* MSLGenerator::TranslateInputSemantic(const char * semantic) uint32_t length, index; ParseSemantic(semantic, &length, &index); - if (m_target == HLSLTarget_VertexShader) - { + if (m_target == HLSLTarget_VertexShader) { // These are DX10 convention if (String_Equal(semantic, "SV_InstanceID")) return "instance_id"; @@ -2067,14 +1898,13 @@ const char* MSLGenerator::TranslateInputSemantic(const char * semantic) return "base_instance"; //if (String_Equal(semantic, "DRAW_INDEX")) // return "draw_index"; - + // TODO: primitive_id, barycentric - + // Handle attributes - + // Can set custom attributes via a callback - if (m_options.attributeCallback) - { + if (m_options.attributeCallback) { char name[64]; ASSERT(length < sizeof(name)); @@ -2083,45 +1913,42 @@ const char* MSLGenerator::TranslateInputSemantic(const char * semantic) int attribute = m_options.attributeCallback(name, index); - if (attribute >= 0) - { + if (attribute >= 0) { return m_tree->AddStringFormat("attribute(%d)", attribute); } } - + if (String_Equal(semantic, "SV_Position")) return "attribute(POSITION)"; return m_tree->AddStringFormat("attribute(%s)", semantic); } - else if (m_target == HLSLTarget_PixelShader) - { + else if (m_target == HLSLTarget_PixelShader) { // PS inputs - + if (String_Equal(semantic, "SV_Position")) return "position"; - - // if (String_Equal(semantic, "POSITION")) - // return "position"; + + // if (String_Equal(semantic, "POSITION")) + // return "position"; if (String_Equal(semantic, "SV_IsFrontFace")) return "front_facing"; - + // VS sets what layer to render into, ps can look at it. // Gpu Family 5. if (String_Equal(semantic, "SV_RenderTargetArrayIndex")) return "render_target_array_index"; - + // dual source? passes in underlying color if (String_Equal(semantic, "DST_COLOR")) return "color(0)"; - + if (String_Equal(semantic, "SV_SampleIndex")) return "sample_id"; //if (String_Equal(semantic, "SV_Coverage")) return "sample_mask"; //if (String_Equal(semantic, "SV_Coverage")) return "sample_mask,post_depth_coverage"; } - else if (m_target == HLSLTarget_ComputeShader) - { + else if (m_target == HLSLTarget_ComputeShader) { // compute inputs if (String_Equal(semantic, "SV_DispatchThreadID")) return "thread_position_in_grid"; @@ -2129,7 +1956,7 @@ const char* MSLGenerator::TranslateInputSemantic(const char * semantic) return NULL; } -const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) +const char* MSLGenerator::TranslateOutputSemantic(const char* semantic) { if (semantic == NULL) return NULL; @@ -2137,11 +1964,10 @@ const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) uint32_t length, index; ParseSemantic(semantic, &length, &index); - if (m_target == HLSLTarget_VertexShader) - { + if (m_target == HLSLTarget_VertexShader) { if (String_Equal(semantic, "SV_Position")) return "position"; - + // PSIZE is non-square in DX9, and square in DX10 (and MSL) // https://github.com/KhronosGroup/glslang/issues/1154 if (String_Equal(semantic, "PSIZE")) @@ -2150,24 +1976,23 @@ const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) // control layer in Gpu Family 5 if (String_Equal(semantic, "SV_RenderTargetArrayIndex")) return "render_target_array_index"; - + // TODO: add // SV_ViewportArrayIndex // SV_ClipDistance0..n, SV_CullDistance0..n } - else if (m_target == HLSLTarget_PixelShader) - { -// Not supporting flags, add as bool to options if needed -// if (m_options.flags & MSLGenerator::Flag_NoIndexAttribute) -// { -// // No dual-source blending on iOS, and no index() attribute -// if (String_Equal(semantic, "COLOR0_1")) return NULL; -// } -// else + else if (m_target == HLSLTarget_PixelShader) { + // Not supporting flags, add as bool to options if needed + // if (m_options.flags & MSLGenerator::Flag_NoIndexAttribute) + // { + // // No dual-source blending on iOS, and no index() attribute + // if (String_Equal(semantic, "COLOR0_1")) return NULL; + // } + // else { // See these settings // MTLBlendFactorSource1Color, OneMinusSource1Color, Source1Alpha, OneMinuSource1Alpha. - + // @@ IC: Hardcoded for this specific case, extend ParseSemantic? if (String_Equal(semantic, "COLOR0_1")) return "color(0), index(1)"; @@ -2176,25 +2001,24 @@ const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) // This is only in A14 and higher if (String_Equal(semantic, "SV_Berycentrics")) return "barycentric_coord"; - + // Is there an HLSL euivalent. Have vulkan ext for PointSize // "point_coord" - + // "primitive_id" - - if (strncmp(semantic, "SV_Target", length) == 0) - { + + if (strncmp(semantic, "SV_Target", length) == 0) { return m_tree->AddStringFormat("color(%d)", index); } -// if (strncmp(semantic, "COLOR", length) == 0) -// { -// return m_tree->AddStringFormat("color(%d)", index); -// } + // if (strncmp(semantic, "COLOR", length) == 0) + // { + // return m_tree->AddStringFormat("color(%d)", index); + // } // depth variants to preserve earlyz, use greater on reverseZ if (String_Equal(semantic, "SV_Depth")) return "depth(any)"; - + // These don't quite line up, since comparison is not == // Metal can only use any/less/greater. Preserve early z when outputting depth. // reverseZ would use greater. @@ -2202,19 +2026,16 @@ const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) return "depth(greater)"; if (String_Equal(semantic, "SV_DepthLessEqual")) return "depth(less)"; - + if (String_Equal(semantic, "SV_Coverage")) return "sample_mask"; } - else if (m_target == HLSLTarget_ComputeShader) - { + else if (m_target == HLSLTarget_ComputeShader) { // compute outputs - } return NULL; } - const char* MSLGenerator::GetTypeName(const HLSLType& type, bool exactType) { bool promote = ((type.flags & HLSLTypeFlag_NoPromote) == 0); @@ -2222,59 +2043,57 @@ const char* MSLGenerator::GetTypeName(const HLSLType& type, bool exactType) // number bool isHalfNumerics = promote && !m_options.treatHalfAsFloat; HLSLBaseType baseType = type.baseType; - + // Note: these conversions should really be done during parsing // so that casting gets applied. if (!isHalfNumerics) baseType = HalfToFloatBaseType(baseType); - + // MSL doesn't support double if (IsDouble(baseType)) baseType = DoubleToFloatBaseType(baseType); - + HLSLType remappedType(baseType); remappedType.typeName = type.typeName; // in case it's a struct - + if (IsSamplerType(baseType) || IsNumericType(baseType) || baseType == HLSLBaseType_Void || baseType == HLSLBaseType_UserDefined) return GetTypeNameMetal(remappedType); - + // texture - if (IsTextureType(baseType)) - { + if (IsTextureType(baseType)) { // unclear if depth supports half, may have to be float always - - bool isHalfTexture = promote && IsHalf(type.formatType) && !m_options.treatHalfAsFloat; - + + bool isHalfTexture = promote && IsHalf(type.formatType) && !m_options.treatHalfAsFloat; + // MSL docs state must be float type, but what about D16f texture? if (IsDepthTextureType(baseType)) isHalfTexture = false; - + // TODO: could use GetTypeNameMetal() but it doesn't include <> portion // so would have to pool and then return the result. - + // This would allow more formats // const char* textureTypeName = GetTypeNameMetal(baseType); // const char* formatTypeName = GetFormatTypeName(baseType, formatType); // snprintf(buf, sizeof(buf), "%s<%s>", textureTypeName, formatTypeName); - - switch (baseType) - { + + switch (baseType) { case HLSLBaseType_Depth2D: return isHalfTexture ? "depth2d" : "depth2d"; case HLSLBaseType_Depth2DArray: return isHalfTexture ? "depth2d_array" : "depth2d_array"; case HLSLBaseType_DepthCube: return isHalfTexture ? "depthcube" : "depthcube"; - + /* TODO: also depth_ms_array, but HLSL6.6 equivalent case HLSLBaseType_Depth2DMS: return isHalfTexture ? "depth2d_ms" : "depth2d_ms"; */ - + // More types than just half/float for this case HLSLBaseType_RWTexture2D: return isHalfTexture ? "texture2d" : "texture2d"; - + case HLSLBaseType_Texture2D: return isHalfTexture ? "texture2d" : "texture2d"; case HLSLBaseType_Texture2DArray: @@ -2287,14 +2106,14 @@ const char* MSLGenerator::GetTypeName(const HLSLType& type, bool exactType) return isHalfTexture ? "texturecube_array" : "texturecube_array"; case HLSLBaseType_Texture2DMS: return isHalfTexture ? "texture2d_ms" : "texture2d_ms"; - + default: break; } } - + Error("Unknown Type"); return NULL; } -} // M4 +} //namespace M4 diff --git a/hlslparser/src/MSLGenerator.h b/hlslparser/src/MSLGenerator.h index 25cd4d34..1b69b028 100644 --- a/hlslparser/src/MSLGenerator.h +++ b/hlslparser/src/MSLGenerator.h @@ -3,20 +3,18 @@ #include "CodeWriter.h" #include "HLSLTree.h" -namespace M4 -{ +namespace M4 { -class HLSLTree; +class HLSLTree; struct HLSLFunction; struct HLSLStruct; - -struct MSLOptions -{ + +struct MSLOptions { int (*attributeCallback)(const char* name, uint32_t index) = NULL; - + // no CLI to set offset uint32_t bufferRegisterOffset = 0; - + bool writeFileLine = false; bool treatHalfAsFloat = false; }; @@ -24,8 +22,7 @@ struct MSLOptions /** * This class is used to generate MSL shaders. */ -class MSLGenerator -{ +class MSLGenerator { public: MSLGenerator(); @@ -33,32 +30,29 @@ class MSLGenerator const char* GetResult() const; private: - // @@ Rename class argument. Add buffers & textures. - struct ClassArgument - { + struct ClassArgument { const char* name; HLSLType type; //const char* typeName; // @@ Do we need more than the type name? const char* registerName; bool isRef; - - ClassArgument * nextArg; - - ClassArgument(const char* name, HLSLType type, const char * registerName, bool isRef) : - name(name), type(type), registerName(registerName), isRef(isRef) - { - nextArg = NULL; - } + + ClassArgument* nextArg; + + ClassArgument(const char* name, HLSLType type, const char* registerName, bool isRef) : name(name), type(type), registerName(registerName), isRef(isRef) + { + nextArg = NULL; + } }; - void AddClassArgument(ClassArgument * arg); + void AddClassArgument(ClassArgument* arg); void Prepass(HLSLTree* tree, HLSLTarget target, HLSLFunction* entryFunction); void CleanPrepass(); - + void PrependDeclarations(); - + void OutputStaticDeclarations(int indent, HLSLStatement* statement); void OutputStatements(int indent, HLSLStatement* statement); void OutputAttributes(int indent, HLSLAttribute* attribute); @@ -68,9 +62,9 @@ class MSLGenerator void OutputFunction(int indent, HLSLFunction* function); void OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression); void OutputTypedExpression(const HLSLType& type, HLSLExpression* expression, HLSLExpression* parentExpression); - bool NeedsCast(const HLSLType & target, const HLSLType & source); + bool NeedsCast(const HLSLType& target, const HLSLType& source); void OutputCast(const HLSLType& type); - + void OutputArguments(HLSLArgument* argument); void OutputDeclaration(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false, bool isConst = false, int alignment = 0); void OutputDeclarationType(const HLSLType& type, bool isConst = false, bool isRef = false, int alignment = 0, bool isTypeCast = false); @@ -78,36 +72,34 @@ class MSLGenerator void OutputExpressionList(HLSLExpression* expression); void OutputExpressionList(const HLSLType& type, HLSLExpression* expression); void OutputExpressionList(HLSLArgument* argument, HLSLExpression* expression); - + void OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall, HLSLDeclaration* assingmentExpression); - void OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression * parentExpression); + void OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression* parentExpression); const char* TranslateInputSemantic(const char* semantic); const char* TranslateOutputSemantic(const char* semantic); const char* GetTypeName(const HLSLType& type, bool exactType); const char* GetAddressSpaceName(HLSLBaseType baseType, HLSLAddressSpace addressSpace) const; - + bool CanSkipWrittenStatement(const HLSLStatement* statement) const; - + void Error(const char* format, ...) const M4_PRINTF_ATTR(2, 3); private: + CodeWriter m_writer; - CodeWriter m_writer; + HLSLTree* m_tree; + const char* m_entryName; + HLSLTarget m_target; + MSLOptions m_options; - HLSLTree* m_tree; - const char* m_entryName; - HLSLTarget m_target; - MSLOptions m_options; + mutable bool m_error; - mutable bool m_error; + ClassArgument* m_firstClassArgument; + ClassArgument* m_lastClassArgument; - ClassArgument * m_firstClassArgument; - ClassArgument * m_lastClassArgument; - - HLSLFunction * m_currentFunction; + HLSLFunction* m_currentFunction; }; -} // M4 - +} //namespace M4 diff --git a/hlslparser/src/Main.cpp b/hlslparser/src/Main.cpp index addaa5d8..b471f26f 100644 --- a/hlslparser/src/Main.cpp +++ b/hlslparser/src/Main.cpp @@ -1,23 +1,22 @@ #include "HLSLParser.h" //#include "GLSLGenerator.h" -#include "HLSLGenerator.h" -#include "MSLGenerator.h" - #include #include #include +#include "HLSLGenerator.h" +#include "MSLGenerator.h" + using namespace std; -enum Language -{ +enum Language { Language_MSL, - Language_HLSL, + Language_HLSL, }; -bool ReadFile( const char* fileName, string& str ) +bool ReadFile(const char* fileName, string& str) { struct stat stats = {}; if (stat(fileName, &stats) < 0) { @@ -37,17 +36,16 @@ bool ReadFile( const char* fileName, string& str ) void PrintUsage() { - fprintf(stderr, - "usage: hlslparser [-h|-g] -i shader.hlsl -o [shader.hlsl | shader.metal]\n" - "Translate DX9-style HLSL shader to HLSL/MSL shader.\n" - " -i input HLSL\n" - " -o output HLSL or MSL\n" - "optional arguments:\n" - " -g debug mode, preserve comments\n" - " -h, --help show this help message and exit\n" - " -line write #file/line directive\n" - " -nohalf turn half into float" - ); + fprintf(stderr, + "usage: hlslparser [-h|-g] -i shader.hlsl -o [shader.hlsl | shader.metal]\n" + "Translate DX9-style HLSL shader to HLSL/MSL shader.\n" + " -i input HLSL\n" + " -o output HLSL or MSL\n" + "optional arguments:\n" + " -g debug mode, preserve comments\n" + " -h, --help show this help message and exit\n" + " -line write #file/line directive\n" + " -nohalf turn half into float"); } // Taken from KrmaLog.cpp @@ -61,12 +59,12 @@ static bool endsWith(const string& value, const string& ending) if (value.size() < ending.size()) return false; uint32_t start = (uint32_t)(value.size() - ending.size()); - + for (uint32_t i = 0; i < ending.size(); ++i) { if (value[start + i] != ending[i]) return false; } - + return true; } @@ -77,221 +75,193 @@ static string filenameNoExtension(const char* filename) if (dotPosStr == nullptr) return filename; auto dotPos = dotPosStr - filename; - + // now chop off the extension string filenameNoExt = filename; return filenameNoExt.substr(0, dotPos); } -int main( int argc, char* argv[] ) +int main(int argc, char* argv[]) { - using namespace M4; + using namespace M4; - // Parse arguments - string fileName; - const char* entryName = NULL; + // Parse arguments + string fileName; + const char* entryName = NULL; - // TODO: could we take modern DX12 HLSL and translate to MSL only - // That would simplify all this. What spirv-cross already does though. - // Could drop HLSLGenerator then, and just use this to gen MSL. - // Much of the glue code can just be in a header, but having it - // in parser, lets this only splice code that is needed. + // TODO: could we take modern DX12 HLSL and translate to MSL only + // That would simplify all this. What spirv-cross already does though. + // Could drop HLSLGenerator then, and just use this to gen MSL. + // Much of the glue code can just be in a header, but having it + // in parser, lets this only splice code that is needed. - Language language = Language_MSL; - HLSLTarget target = HLSLTarget_PixelShader; + Language language = Language_MSL; + HLSLTarget target = HLSLTarget_PixelShader; string outputFileName; bool isDebug = false; bool isTreatHalfAsFloat = false; bool isWriteFileLine = false; - - for( int argn = 1; argn < argc; ++argn ) - { - const char* const arg = argv[ argn ]; - - if( String_Equal( arg, "-h" ) || String_Equal( arg, "--help" ) ) - { - PrintUsage(); - return 0; - } - - else if( String_Equal( arg, "-o" ) || String_Equal( arg, "-output" ) ) - { - if ( ++argn < argc ) - outputFileName = argv[ argn ]; + + for (int argn = 1; argn < argc; ++argn) { + const char* const arg = argv[argn]; + + if (String_Equal(arg, "-h") || String_Equal(arg, "--help")) { + PrintUsage(); + return 0; } - else if( String_Equal( arg, "-i" ) || String_Equal( arg, "-input" ) ) - { - if ( ++argn < argc ) - fileName = argv[ argn ]; - } - else if ( String_Equal( arg, "-g" )) - { + + else if (String_Equal(arg, "-o") || String_Equal(arg, "-output")) { + if (++argn < argc) + outputFileName = argv[argn]; + } + else if (String_Equal(arg, "-i") || String_Equal(arg, "-input")) { + if (++argn < argc) + fileName = argv[argn]; + } + else if (String_Equal(arg, "-g")) { // will preserve double-slash comments where possible isDebug = true; } - else if ( String_Equal( arg, "-nohalf" )) - { + else if (String_Equal(arg, "-nohalf")) { // will preserve double-slash comments where possible isTreatHalfAsFloat = true; } - else if ( String_Equal( arg, "-line" )) - { + else if (String_Equal(arg, "-line")) { // will preserve double-slash comments where possible isWriteFileLine = true; } - -// This is derived from end characters of entry point -// else if( String_Equal( arg, "-vs" ) ) -// { -// target = HLSLTarget_VertexShader; -// } -// else if( String_Equal( arg, "-fs" ) ) -// { -// target = HLSLTarget_PixelShader; -// } - // TODO: require a arg to set entryName -// else if( entryName == NULL ) -// { -// entryName = arg; -// } - else - { - Log_Error( "Too many arguments\n" ); - PrintUsage(); - return 1; - } - } - - if( fileName.empty() ) - { - Log_Error( "Missing source filename\n" ); - PrintUsage(); - return 1; - } - if( !endsWith( fileName, "hlsl" ) ) - { - Log_Error( "Input filename must end with .hlsl\n" ); + + // This is derived from end characters of entry point + // else if( String_Equal( arg, "-vs" ) ) + // { + // target = HLSLTarget_VertexShader; + // } + // else if( String_Equal( arg, "-fs" ) ) + // { + // target = HLSLTarget_PixelShader; + // } + // TODO: require a arg to set entryName + // else if( entryName == NULL ) + // { + // entryName = arg; + // } + else { + Log_Error("Too many arguments\n"); + PrintUsage(); + return 1; + } + } + + if (fileName.empty()) { + Log_Error("Missing source filename\n"); + PrintUsage(); + return 1; + } + if (!endsWith(fileName, "hlsl")) { + Log_Error("Input filename must end with .hlsl\n"); PrintUsage(); return 1; } - - if( outputFileName.empty() ) - { - Log_Error( "Missing dest filename\n" ); + + if (outputFileName.empty()) { + Log_Error("Missing dest filename\n"); PrintUsage(); return 1; } - if( endsWith( outputFileName, "hlsl" ) ) - { + if (endsWith(outputFileName, "hlsl")) { language = Language_HLSL; } - else if( endsWith( outputFileName, "metal" ) ) - { + else if (endsWith(outputFileName, "metal")) { language = Language_MSL; } - else - { - Log_Error( "Output file must end with .hlsl or msls\n" ); + else { + Log_Error("Output file must end with .hlsl or msls\n"); PrintUsage(); return 1; } - + // replace the extension on the output file - outputFileName = filenameNoExtension( outputFileName.c_str() ); - + outputFileName = filenameNoExtension(outputFileName.c_str()); + // Allow a mix of shaders in file. // Code now finds entry points. // outputFileName += (target == HLSLTarget_PixelShader) ? "PS" : "VS"; - - if ( language == Language_MSL ) - { + + if (language == Language_MSL) { outputFileName += ".metal"; } - else if ( language == Language_HLSL ) - { + else if (language == Language_HLSL) { outputFileName += ".hlsl"; } - + // Win build on github is failing on this, so skip for now // find full pathname of the fileName, so that errors are logged // in way that can be clicked to. absolute includes .. in it, canonical does not. std::error_code errorCode; // To shutup exceptions auto path = filesystem::path(fileName); fileName = filesystem::canonical(path, errorCode).generic_string(); - + // if this file doesn't exist, then canonical throws exception path = filesystem::path(outputFileName); - if (filesystem::exists(path)) - { + if (filesystem::exists(path)) { outputFileName = filesystem::canonical(path, errorCode).generic_string(); - - if ( outputFileName == fileName ) - { - Log_Error( "Src and Dst filenames match. Exiting.\n" ); + + if (outputFileName == fileName) { + Log_Error("Src and Dst filenames match. Exiting.\n"); return 1; } } - + //------------------------------------ // Now start the work - - // Read input file + + // Read input file string source; - if (!ReadFile( fileName.c_str(), source )) - { - Log_Error( "Input file not found\n" ); + if (!ReadFile(fileName.c_str(), source)) { + Log_Error("Input file not found\n"); return 1; } - // Parse input file - Allocator allocator; - HLSLParser parser( &allocator, fileName.c_str(), source.data(), source.size() ); - if (isDebug) - { + // Parse input file + Allocator allocator; + HLSLParser parser(&allocator, fileName.c_str(), source.data(), source.size()); + if (isDebug) { parser.SetKeepComments(true); } - HLSLTree tree( &allocator ); - + HLSLTree tree(&allocator); + // TODO: tie this to CLI, MSL should set both to true HLSLParserOptions parserOptions; parserOptions.isHalfst = true; parserOptions.isHalfio = true; - - if( !parser.Parse( &tree, parserOptions ) ) - { - Log_Error( "Parsing failed\n" ); - return 1; - } - + + if (!parser.Parse(&tree, parserOptions)) { + Log_Error("Parsing failed\n"); + return 1; + } + int status = 0; - + // build a list of entryPoints Array entryPoints(&allocator); - if (entryName != nullptr) - { + if (entryName != nullptr) { entryPoints.PushBack(entryName); } - else - { + else { // search all functions with designated endings HLSLStatement* statement = tree.GetRoot()->statement; - while (statement != NULL) - { - if (statement->nodeType == HLSLNodeType_Function) - { + while (statement != NULL) { + if (statement->nodeType == HLSLNodeType_Function) { HLSLFunction* function = (HLSLFunction*)statement; const char* name = function->name; - - if (endsWith(name, "VS")) - { + + if (endsWith(name, "VS")) { entryPoints.PushBack(name); } - else if (endsWith(name, "PS")) - { + else if (endsWith(name, "PS")) { entryPoints.PushBack(name); } - else if (endsWith(name, "CS")) - { + else if (endsWith(name, "CS")) { entryPoints.PushBack(name); } } @@ -299,11 +269,10 @@ int main( int argc, char* argv[] ) statement = statement->nextStatement; } } - + string output; - - for (uint32_t i = 0; i < (uint32_t)entryPoints.GetSize(); ++i) - { + + for (uint32_t i = 0; i < (uint32_t)entryPoints.GetSize(); ++i) { const char* entryPoint = entryPoints[i]; entryName = entryPoint; if (endsWith(entryPoint, "VS")) @@ -312,67 +281,59 @@ int main( int argc, char* argv[] ) target = HLSLTarget_PixelShader; else if (endsWith(entryPoint, "CS")) target = HLSLTarget_ComputeShader; - + // Generate output - if (language == Language_HLSL) - { + if (language == Language_HLSL) { HLSLOptions options; options.writeFileLine = isWriteFileLine; options.treatHalfAsFloat = isTreatHalfAsFloat; options.writeVulkan = true; // TODO: tie to CLI - + HLSLGenerator generator; - if (generator.Generate( &tree, target, entryName, options)) - { + if (generator.Generate(&tree, target, entryName, options)) { // write the buffer out output += generator.GetResult(); } - else - { - Log_Error( "Translation failed, aborting\n" ); + else { + Log_Error("Translation failed, aborting\n"); status = 1; } } - else if (language == Language_MSL) - { + else if (language == Language_MSL) { MSLOptions options; options.writeFileLine = isWriteFileLine; options.treatHalfAsFloat = isTreatHalfAsFloat; - + MSLGenerator generator; - if (generator.Generate(&tree, target, entryName, options)) - { + if (generator.Generate(&tree, target, entryName, options)) { // write the buffer out output += generator.GetResult(); } - else - { - Log_Error( "Translation failed, aborting\n" ); + else { + Log_Error("Translation failed, aborting\n"); status = 1; } } - + if (status != 0) break; } - - if (status == 0) - { + + if (status == 0) { // using wb to avoid having Win convert \n to \r\n - FILE* fp = fopen( outputFileName.c_str(), "wb" ); - if ( !fp ) - { - Log_Error( "Could not open output file %s\n", outputFileName.c_str() ); + FILE* fp = fopen(outputFileName.c_str(), "wb"); + if (!fp) { + Log_Error("Could not open output file %s\n", outputFileName.c_str()); return 1; } - + fprintf(fp, "%s", output.c_str()); - fclose( fp ); + fclose(fp); } - + // It's not enough to return 1 from main, but set exit code. if (status) exit(status); - + return status; } diff --git a/kram-preview/KramPreviewViewController.mm b/kram-preview/KramPreviewViewController.mm index 9cdc071f..4fe3f82b 100644 --- a/kram-preview/KramPreviewViewController.mm +++ b/kram-preview/KramPreviewViewController.mm @@ -3,35 +3,36 @@ // in all copies or substantial portions of the Software. #import "KramPreviewViewController.h" -#import -#include #import +#include +#import #include "KramLib.h" using namespace kram; // Same code in Preview and Thumbnail -inline NSError* KLOGF(uint32_t code, const char* format, ...) { +inline NSError* KLOGF(uint32_t code, const char* format, ...) +{ string str; - + va_list args; va_start(args, format); /* int32_t len = */ append_vsprintf(str, format, args); va_end(args); - + // log here, so it can see it in Console. But this never appears. // How are you supposed to debug failures? Resorted to passing a unique code into this call. // It wasn't originally supposed to generate an NSError //NSLog(@"%s", str.c_str()); - + // Console prints this as , so what's the point of producing a localizedString ? // This doesn't seem to work to Console app, but maybe if logs are to terminal // sudo log config --mode "level:debug" --subsystem com.hialec.kramv - + NSString* errorText = [NSString stringWithUTF8String:str.c_str()]; - return [NSError errorWithDomain:@"com.hialec.kramv" code:code userInfo:@{NSLocalizedDescriptionKey: errorText}]; + return [NSError errorWithDomain:@"com.hialec.kramv" code:code userInfo:@{NSLocalizedDescriptionKey : errorText}]; } @interface KramPreviewViewController () @@ -41,38 +42,45 @@ @implementation KramPreviewViewController { NSImageView* _imageView; } -- (NSString *)nibName { +- (NSString*)nibName +{ return @"KramPreviewViewController"; } -- (void)loadView { +- (void)loadView +{ [super loadView]; // Do any additional setup after loading the view. - + _imageView = [[NSImageView alloc] initWithFrame:self.view.frame]; [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; //Required to opt-in to autolayout // no frame, already the default // _imageView.imageFrameStyle = NSImageFrameNone; - + _imageView.imageScaling = NSImageScaleProportionallyUpOrDown; - - [self.view addSubview: _imageView]; - - NSDictionary* views = @{@"myview": _imageView}; + + [self.view addSubview:_imageView]; + + NSDictionary* views = @{@"myview" : _imageView}; [self.view addConstraints:[NSLayoutConstraint - constraintsWithVisualFormat:@"H:|[myview]|" options:0 metrics:nil - views:views]]; + constraintsWithVisualFormat:@"H:|[myview]|" + options:0 + metrics:nil + views:views]]; [self.view addConstraints:[NSLayoutConstraint - constraintsWithVisualFormat:@"V:|[myview]|" options:0 metrics:nil - views:views]]; + constraintsWithVisualFormat:@"V:|[myview]|" + options:0 + metrics:nil + views:views]]; //[NSLayoutConstraint activateConstraints: self.view.constraints]; } // This isn't a view, but hoping this is called -- (void)viewDidAppear { +- (void)viewDidAppear +{ [super viewDidAppear]; - + // this must be called after layer is ready //self.view.layer.backgroundColor = [NSColor blackColor].CGColor; _imageView.layer.backgroundColor = [NSColor blackColor].CGColor; @@ -82,9 +90,9 @@ - (void)viewDidAppear { * Implement this method and set QLSupportsSearchableItems to YES in the Info.plist of the extension if you support CoreSpotlight. * - (void)preparePreviewOfSearchableItemWithIdentifier:(NSString *)identifier queryString:(NSString *)queryString completionHandler:(void (^)(NSError * _Nullable))handler { - + // Perform any setup necessary in order to prepare the view. - + // Call the completion handler so Quick Look knows that the preview is fully loaded. // Quick Look will display a loading spinner while the completion handler is not called. @@ -92,43 +100,43 @@ - (void)preparePreviewOfSearchableItemWithIdentifier:(NSString *)identifier quer } */ -- (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSError * _Nullable))handler { - +- (void)preparePreviewOfFileAtURL:(NSURL*)url completionHandler:(void (^)(NSError* _Nullable))handler +{ NSError* error = nil; const char* filename = [url fileSystemRepresentation]; -// if (![_imageView isKindOfClass:[NSImageView class]]) { -// error = KLOGF(9, "kramv %s expected NSImageView \n", filename); -// handler(error); -// return; -// } - + // if (![_imageView isKindOfClass:[NSImageView class]]) { + // error = KLOGF(9, "kramv %s expected NSImageView \n", filename); + // handler(error); + // return; + // } + // Add the supported content types to the QLSupportedContentTypes array in the Info.plist of the extension. // Perform any setup necessary in order to prepare the view. - + // The following is adapted out of Thumbnailer - + // No request here, may need to use view size uint32_t maxWidth = _imageView.frame.size.width; uint32_t maxHeight = _imageView.frame.size.height; - + // ignore upper case extensions if (!isSupportedFilename(filename)) { error = KLOGF(1, "kramv %s only supports ktx, ktx2, dds files\n", filename); handler(error); return; } - + KTXImage image; KTXImageData imageData; TexEncoder decoderType = kTexEncoderUnknown; - + if (!imageData.open(filename, image)) { error = KLOGF(2, "kramv %s coould not open file\n", filename); handler(error); return; } - + // This will set decoder auto textureType = MyMTLTextureType2D; // image.textureType if (!validateFormatAndDecoder(textureType, image.pixelFormat, decoderType)) { @@ -136,13 +144,13 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr handler(error); return; } - + bool isPremul = image.isPremul(); bool isSrgb = isSrgbFormat(image.pixelFormat); - + // unpack a level to get the blocks uint32_t mipNumber = 0; - + uint32_t mipCount = image.mipCount(); uint32_t w, h, d; for (uint32_t i = 0; i < mipCount; ++i) { @@ -151,25 +159,24 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr mipNumber++; } } - + // clamp to smallest mipNumber = std::min(mipNumber, mipCount - 1); image.mipDimensions(mipNumber, w, h, d); - + uint32_t chunkNum = 0; // TODO: could embed chunk(s) to gen thumbnail from, cube/array? uint32_t numChunks = image.totalChunks(); - + vector mipData; // new decode the blocks in that chunk if (isBlockFormat(image.pixelFormat)) { - uint64_t mipLength = image.mipLevels[mipNumber].length; - - // then decode any blocks to rgba8u, not dealing with HDR formats yet + + // then decode any blocks to rgba8u, not dealing with HDR formats yet if (image.isSupercompressed()) { const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; - + mipData.resize(mipLength * numChunks); uint8_t* dstData = mipData.data(); if (!image.unpackLevel(mipNumber, srcData, dstData)) { @@ -177,7 +184,7 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr handler(error); return; } - + // now extract the chunk for the thumbnail out of that level if (numChunks > 1) { macroUnusedVar(chunkNum); @@ -187,66 +194,63 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr mipData.resize(mipLength); } } - else - { + else { // this just truncate to chunk 0 instead of copying chunkNum first mipData.resize(mipLength); - + const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; - + memcpy(mipData.data(), srcData, mipLength); } - + KramDecoder decoder; KramDecoderParams params; - + // TODO: should honor swizzle in the ktx image // TODO: probaby need an snorm rgba format to convert the snorm versions, so they're not all red // if sdf, will be signed format and that will stay red - - switch(image.pixelFormat) - { + + switch (image.pixelFormat) { // To avoid showing single channel content in red, replicate to rgb case MyMTLPixelFormatBC4_RUnorm: case MyMTLPixelFormatEAC_R11Unorm: params.swizzleText = "rrr1"; break; - + default: break; } - + vector dstMipData; - + // only space for one chunk for now dstMipData.resize(numChunks * h * w * sizeof(Color)); - + // want to just decode one chunk of the level that was unpacked abovve if (!decoder.decodeBlocks(w, h, mipData.data(), (int32_t)mipData.size(), image.pixelFormat, dstMipData, params)) { error = KLOGF(6, "kramv %s failed to decode blocks\n", filename); handler(error); return; } - + mipData = dstMipData; } - else if (isExplicitFormat(image.pixelFormat)) - { + else if (isExplicitFormat(image.pixelFormat)) { Image image2D; if (!image2D.loadThumbnailFromKTX(image, mipNumber)) { error = KLOGF(7, "kramv %s failed to convert image to 4 channels\n", filename); handler(error); return; } - + // TODO: could swizzle height (single channel) textures to rrr1 - + // copy from Color back to uint8_t uint32_t mipSize = h * w * sizeof(Color); mipData.resize(mipSize); memcpy(mipData.data(), image2D.pixels().data(), mipSize); } - + // https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html#//apple_ref/doc/uid/TP30001066-CH212-TPXREF101 uint32_t rowBytes = w * sizeof(Color); @@ -254,25 +258,25 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr // use vimage in the Accelerate.framework // https://developer.apple.com/library/archive/releasenotes/Performance/RN-vecLib/index.html#//apple_ref/doc/uid/TP40001049 - vImage_Buffer buf = { mipData.data(), h, w, rowBytes }; + vImage_Buffer buf = {mipData.data(), h, w, rowBytes}; // Declare the pixel format for the vImage_Buffer vImage_CGImageFormat format = { - .bitsPerComponent = 8, - .bitsPerPixel = 32, + .bitsPerComponent = 8, + .bitsPerPixel = 32, }; - + format.bitmapInfo = kCGBitmapByteOrderDefault | (CGBitmapInfo)(isPremul ? kCGImageAlphaPremultipliedLast : kCGImageAlphaLast); format.colorSpace = isSrgb ? CGColorSpaceCreateWithName(kCGColorSpaceSRGB) : CGColorSpaceCreateDeviceRGB(); - + // don't need to allocate, can requse memory from mip // TODO: might want to convert to PNG, but maybe thumbnail system does that automatically? // see how big thumbs.db is after running this - + // This doesn't allocate, but in an imageView that must outlast the handle call, does that work? bool skipPixelCopy = false; - + vImage_Error err = 0; CGImageRef cgImage = vImageCreateCGImageFromBuffer(&buf, &format, NULL, NULL, skipPixelCopy ? kvImageNoAllocate : kvImageNoFlags, &err); if (err) { @@ -283,30 +287,29 @@ - (void)preparePreviewOfFileAtURL:(NSURL *)url completionHandler:(void (^)(NSErr CGRect rect = CGRectMake(0, 0, w, h); NSImage* nsImage = [[NSImage alloc] initWithCGImage:cgImage size:rect.size]; - + NSImageView* nsImageView = _imageView; // (NSImageView*)self.view; - + // Copositing is like it's using NSCompositeCopy instead of SourceOver // The default is NSCompositeSourceOver. NSRectFill() ignores // -[NSGraphicsContext compositingOperation] and continues to use NSCompositeCopy. // So may have to use NSFillRect which uses SourceOver // https://cocoadev.github.io/NSCompositingOperation/ - + nsImageView.image = nsImage; // This seems to cause plugin to fail with NoAllocate set // This leaks a CGImageRef, but the CGImage doesn't hold any memory w/NoAllocate. if (!skipPixelCopy) CGImageRelease(cgImage); - + // TODO: could add description with info from texture (format, etc) // self.textView.text = ... - + // Call the completion handler so Quick Look knows that the preview is fully loaded. // Quick Look will display a loading spinner while the completion handler is not called. - + handler(nil); } @end - diff --git a/kram-profile/Source/KramZipHelper.cpp b/kram-profile/Source/KramZipHelper.cpp index acb9af00..ddf9b889 100644 --- a/kram-profile/Source/KramZipHelper.cpp +++ b/kram-profile/Source/KramZipHelper.cpp @@ -2,10 +2,10 @@ #include //#include // for copy_if on Win -#include +#include #include #include -#include +#include #include "miniz.h" @@ -75,19 +75,20 @@ int32_t append_sprintf(string& str, const char* format, ...) } // This is extracted from CBA Analysis.cpp -extern "C" const char* _Nullable collapseFunctionName(const char* _Nonnull name_) { +extern "C" const char* _Nullable collapseFunctionName(const char* _Nonnull name_) +{ // Adapted from code in Analysis. Really the only call needed from CBA. // serialize to multiple threads static mutex sMutex; static unordered_map sMap; lock_guard lock(sMutex); - + string elt(name_); auto it = sMap.find(elt); if (it != sMap.end()) { return it->second.c_str(); } - + // Parsing op<, op<<, op>, and op>> seems hard. Just skip'm all if (strstr(name_, "operator") != nullptr) return nullptr; @@ -96,9 +97,8 @@ extern "C" const char* _Nullable collapseFunctionName(const char* _Nonnull name_ retval.reserve(elt.size()); auto b_range = elt.begin(); auto e_range = elt.begin(); - while (b_range != elt.end()) - { - e_range = std::find(b_range, elt.end(), '<'); + while (b_range != elt.end()) { + e_range = std::find(b_range, elt.end(), '<'); if (e_range == elt.end()) break; ++e_range; @@ -107,17 +107,13 @@ extern "C" const char* _Nullable collapseFunctionName(const char* _Nonnull name_ b_range = e_range; int open_count = 1; // find the matching close angle bracket - for (; b_range != elt.end(); ++b_range) - { - if (*b_range == '<') - { + for (; b_range != elt.end(); ++b_range) { + if (*b_range == '<') { ++open_count; continue; } - if (*b_range == '>') - { - if (--open_count == 0) - { + if (*b_range == '>') { + if (--open_count == 0) { break; } continue; @@ -125,41 +121,40 @@ extern "C" const char* _Nullable collapseFunctionName(const char* _Nonnull name_ } // b_range is now pointing at a close angle, or it is at the end of the string } - if (b_range > e_range) - { - // we are in a wacky case where something like op> showed up in a mangled name. - // just bail. - // TODO: this still isn't correct, but it avoids crashes. - return nullptr; + if (b_range > e_range) { + // we are in a wacky case where something like op> showed up in a mangled name. + // just bail. + // TODO: this still isn't correct, but it avoids crashes. + return nullptr; } // append the footer retval.append(b_range, e_range); - + // add it to the map sMap[elt] = std::move(retval); - + return sMap[elt].c_str(); } -extern "C" const char* _Nullable demangleSymbolName(const char* _Nonnull symbolName_) { +extern "C" const char* _Nullable demangleSymbolName(const char* _Nonnull symbolName_) +{ // serialize to multiple threads static mutex sMutex; static unordered_map sSymbolToDemangleName; lock_guard lock(sMutex); - + string symbolName(symbolName_); auto it = sSymbolToDemangleName.find(symbolName); if (it != sSymbolToDemangleName.end()) { return it->second; } - + // see CBA if want a generalized demangle for Win/Linux size_t size = 0; int status = 0; char* symbol = abi::__cxa_demangle(symbolName.c_str(), nullptr, &size, &status); const char* result = nullptr; if (status == 0) { - sSymbolToDemangleName[symbolName] = symbol; result = symbol; // not freeing the symbols here @@ -172,10 +167,10 @@ extern "C" const char* _Nullable demangleSymbolName(const char* _Nonnull symbolN // status = -2 on most of the mangled Win clang-cli symbols. Nice one // Microsoft. //result = symbolName_; - + result = nullptr; } - + return result; } @@ -286,13 +281,13 @@ void ZipHelper::initZipEntryTables() ZipEntry& zipEntry = _zipEntrys[index]; zipEntry.fileIndex = stat.m_file_index; - zipEntry.filename = filename; // can alias + zipEntry.filename = filename; // can alias zipEntry.uncompressedSize = stat.m_uncomp_size; zipEntry.compressedSize = stat.m_comp_size; - zipEntry.modificationDate = (int32_t)stat.m_time; // really a time_t - #undef crc32 + zipEntry.modificationDate = (int32_t)stat.m_time; // really a time_t +#undef crc32 zipEntry.crc32 = stat.m_crc32; - + // TODO: stat.m_time, state.m_crc32 index++; @@ -356,7 +351,7 @@ bool ZipHelper::extract(const char* filename, uint8_t* bufferData, uint64_t buff if (bufferDataSize < entry->uncompressedSize) { return false; } - + if (!extract(*entry, bufferData, bufferDataSize)) { return false; } @@ -364,7 +359,6 @@ bool ZipHelper::extract(const char* filename, uint8_t* bufferData, uint64_t buff return true; } - bool ZipHelper::extractPartial(const char* filename, vector& buffer) const { if (buffer.empty()) { @@ -399,9 +393,9 @@ bool ZipHelper::extract(const ZipEntry& entry, void* buffer, uint64_t bufferSize // https://dougallj.wordpress.com/2022/08/20/faster-zlib-deflate-decompression-on-the-apple-m1-and-x86/ // https://developer.apple.com/documentation/compression/1481000-compression_decode_buffer?language=objc - + // This call is internal, so caller has already tested failure cases. - + #if USE_LIBCOMPRESSION const uint8_t* data = mz_zip_reader_get_raw_data(zip.get(), entry.fileIndex); if (!data) { @@ -409,20 +403,19 @@ bool ZipHelper::extract(const ZipEntry& entry, void* buffer, uint64_t bufferSize } // need to extra data and header char scratchBuffer[compression_decode_scratch_buffer_size(COMPRESSION_ZLIB)]; - + uint64_t bytesDecoded = compression_decode_buffer( (uint8_t*)buffer, entry.uncompressedSize, (const uint8_t*)data, entry.compressedSize, scratchBuffer, COMPRESSION_ZLIB); - + bool success = false; - if (bytesDecoded == entry.uncompressedSize) - { + if (bytesDecoded == entry.uncompressedSize) { success = true; } #else - + // this pulls pages from mmap, no allocations mz_bool success = mz_zip_reader_extract_to_mem( zip.get(), entry.fileIndex, buffer, bufferSize, 0); @@ -452,7 +445,7 @@ bool ZipHelper::extractRaw(const char* filename, const uint8_t** bufferData, uin } *bufferData = data; - + // This isn't correct, need to return comp_size. // Caller may need the uncompressed size though to decompress fully into. //bufferDataSize = stat.m_uncomp_size; @@ -461,4 +454,4 @@ bool ZipHelper::extractRaw(const char* filename, const uint8_t** bufferData, uin return true; } -} // namespace kram +} // namespace kram diff --git a/kram-profile/Source/KramZipHelper.h b/kram-profile/Source/KramZipHelper.h index c19e08d5..0dd7d13c 100644 --- a/kram-profile/Source/KramZipHelper.h +++ b/kram-profile/Source/KramZipHelper.h @@ -8,8 +8,8 @@ #include #include -#include #include +#include // from miniz // had to change miniz from anonymous struct typedef, or can't fwd declare @@ -21,7 +21,7 @@ namespace kram { using namespace STL_NAMESPACE; struct ZipEntry { - const char* filename; // max 512, aliased + const char* filename; // max 512, aliased int32_t fileIndex; // attributes @@ -75,8 +75,8 @@ struct ZipHelper { std::unique_ptr zip; vector _zipEntrys; - const uint8_t* zipData; // aliased + const uint8_t* zipData; // aliased vector allFilenames; }; -} // namespace kram +} // namespace kram diff --git a/kram-profile/Source/KramZipHelperW.h b/kram-profile/Source/KramZipHelperW.h index dd260734..72cfe2c2 100644 --- a/kram-profile/Source/KramZipHelperW.h +++ b/kram-profile/Source/KramZipHelperW.h @@ -3,7 +3,7 @@ #import typedef struct ZipEntryW { - const char* _Nonnull filename; // max 512, aliased + const char* _Nonnull filename; // max 512, aliased int32_t fileIndex; // attributes @@ -13,25 +13,24 @@ typedef struct ZipEntryW { uint32_t crc32; } ZipEntryW; - // Use this to bridge the C++ over to Swift for now // TODO: form a clang module and reference C++ directly @interface ZipHelperW : NSObject - - (nonnull instancetype)initWithData:(nonnull NSData*)data; - - // extract the data. Can alias into the file. - - (nullable NSData*)extract:(nonnull const char*)filename; - - // pass back vector this way for now, should be property - - (nonnull const ZipEntryW*)zipEntrys; +- (nonnull instancetype)initWithData:(nonnull NSData*)data; + +// extract the data. Can alias into the file. +- (nullable NSData*)extract:(nonnull const char*)filename; - - (NSInteger)zipEntrysCount; +// pass back vector this way for now, should be property +- (nonnull const ZipEntryW*)zipEntrys; - // This isn't the fileIndex, but uses count above to avoid needing to do unsafe - - (ZipEntryW)zipEntry:(NSInteger)index; +- (NSInteger)zipEntrysCount; - // retrieve an entry by filename - - (ZipEntryW)zipEntryByName:(nonnull const char*)name; +// This isn't the fileIndex, but uses count above to avoid needing to do unsafe +- (ZipEntryW)zipEntry:(NSInteger)index; + +// retrieve an entry by filename +- (ZipEntryW)zipEntryByName:(nonnull const char*)name; @end @@ -41,4 +40,3 @@ const char* _Nullable demangleSymbolName(const char* _Nonnull symbolName_); // This is really the only call needed out of CBA // Convert templated code to collapsed name so get more correspondence in map. const char* _Nullable collapseFunctionName(const char* _Nonnull name_); - diff --git a/kram-profile/Source/KramZipHelperW.mm b/kram-profile/Source/KramZipHelperW.mm index 2ad4da7d..fa232d5e 100644 --- a/kram-profile/Source/KramZipHelperW.mm +++ b/kram-profile/Source/KramZipHelperW.mm @@ -1,4 +1,5 @@ #include "KramZipHelperW.h" + #include "KramZipHelper.h" using namespace kram; @@ -7,20 +8,21 @@ @implementation ZipHelperW { ZipHelper _helper; } -- (nonnull instancetype)initWithData:(nonnull NSData*)data { +- (nonnull instancetype)initWithData:(nonnull NSData*)data +{ _helper.openForRead((const uint8_t*)data.bytes, data.length); return self; } -- (nullable NSData*)extract:(nonnull const char*)filename { - +- (nullable NSData*)extract:(nonnull const char*)filename +{ NSData* data = nil; - + auto entry = _helper.zipEntry(filename); if (!entry) { return nil; } - + bool isCompressed = entry->uncompressedSize != entry->compressedSize; if (isCompressed) { // this allocates memory @@ -30,31 +32,35 @@ - (nullable NSData*)extract:(nonnull const char*)filename { else { const uint8_t* bytes = nullptr; uint64_t bytesLength = 0; - + // this aliases the archive _helper.extractRaw(filename, &bytes, bytesLength); data = [NSData dataWithBytesNoCopy:(void*)bytes length:bytesLength freeWhenDone:NO]; } - + return data; } // Need this for the list data -- (nonnull const ZipEntryW*)zipEntrys { +- (nonnull const ZipEntryW*)zipEntrys +{ return (const ZipEntryW*)_helper.zipEntrys().data(); } -- (NSInteger)zipEntrysCount { +- (NSInteger)zipEntrysCount +{ return _helper.zipEntrys().size(); } -- (ZipEntryW)zipEntry:(NSInteger)index { +- (ZipEntryW)zipEntry:(NSInteger)index +{ return *(const ZipEntryW*)&_helper.zipEntrys()[index]; } -- (ZipEntryW)zipEntryByName:(nonnull const char*)name { +- (ZipEntryW)zipEntryByName:(nonnull const char*)name +{ // DONE: fix to return a dummy type, since zips can be missing files // from one iteration to the next. - static ZipEntryW nilEntry = { "" }; + static ZipEntryW nilEntry = {""}; const ZipEntry* entry = _helper.zipEntry(name); if (entry) { return *(const ZipEntryW*)entry; @@ -64,6 +70,4 @@ - (ZipEntryW)zipEntryByName:(nonnull const char*)name { } } - @end - diff --git a/kram-profile/Source/kram-profile-Bridging-Header.h b/kram-profile/Source/kram-profile-Bridging-Header.h index 81a9554e..b99d6e26 100644 --- a/kram-profile/Source/kram-profile-Bridging-Header.h +++ b/kram-profile/Source/kram-profile-Bridging-Header.h @@ -2,5 +2,5 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // -#include "KramZipHelperW.h" #include "CBA.h" +#include "KramZipHelperW.h" diff --git a/kram-profile/Source/track_event_parser.cpp b/kram-profile/Source/track_event_parser.cpp index d1291c86..1da63ca1 100644 --- a/kram-profile/Source/track_event_parser.cpp +++ b/kram-profile/Source/track_event_parser.cpp @@ -25,22 +25,6 @@ #include "perfetto/ext/base/base64.h" #include "perfetto/ext/base/string_writer.h" #include "perfetto/trace_processor/status.h" -#include "src/trace_processor/importers/common/args_tracker.h" -#include "src/trace_processor/importers/common/args_translation_table.h" -#include "src/trace_processor/importers/common/event_tracker.h" -#include "src/trace_processor/importers/common/flow_tracker.h" -#include "src/trace_processor/importers/common/process_tracker.h" -#include "src/trace_processor/importers/common/track_tracker.h" -#include "src/trace_processor/importers/json/json_utils.h" -#include "src/trace_processor/importers/proto/packet_analyzer.h" -#include "src/trace_processor/importers/proto/packet_sequence_state.h" -#include "src/trace_processor/importers/proto/profile_packet_utils.h" -#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h" -#include "src/trace_processor/importers/proto/track_event_tracker.h" -#include "src/trace_processor/util/debug_annotation_parser.h" -#include "src/trace_processor/util/proto_to_args_parser.h" -#include "src/trace_processor/util/status_macros.h" - #include "protos/perfetto/common/android_log_constants.pbzero.h" #include "protos/perfetto/trace/extension_descriptor.pbzero.h" #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h" @@ -59,6 +43,21 @@ #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h" #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h" #include "protos/perfetto/trace/track_event/track_event.pbzero.h" +#include "src/trace_processor/importers/common/args_tracker.h" +#include "src/trace_processor/importers/common/args_translation_table.h" +#include "src/trace_processor/importers/common/event_tracker.h" +#include "src/trace_processor/importers/common/flow_tracker.h" +#include "src/trace_processor/importers/common/process_tracker.h" +#include "src/trace_processor/importers/common/track_tracker.h" +#include "src/trace_processor/importers/json/json_utils.h" +#include "src/trace_processor/importers/proto/packet_analyzer.h" +#include "src/trace_processor/importers/proto/packet_sequence_state.h" +#include "src/trace_processor/importers/proto/profile_packet_utils.h" +#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h" +#include "src/trace_processor/importers/proto/track_event_tracker.h" +#include "src/trace_processor/util/debug_annotation_parser.h" +#include "src/trace_processor/util/proto_to_args_parser.h" +#include "src/trace_processor/util/status_macros.h" namespace perfetto { namespace trace_processor { diff --git a/kram-thumb-win/Dll.cpp b/kram-thumb-win/Dll.cpp index 7d13f5ac..267e3c5e 100644 --- a/kram-thumb-win/Dll.cpp +++ b/kram-thumb-win/Dll.cpp @@ -1,19 +1,20 @@ // based on QOI Thumbnail Provider for Windows Explorer // Written by iOrange in 2021 -// +// // Based on Microsoft's example // https://github.com/microsoft/windows-classic-samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/RecipeThumbnailProvider -// +// // Also more info here: // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/cc144118(v=vs.85) #include +#include // For SHChangeNotify #include #include // For IThumbnailProvider. -#include // For SHChangeNotify -#include + #include -#include // For std::size +#include +#include // For std::size // from KramThumbProvider.cpp extern HRESULT KramThumbProvider_CreateInstance(REFIID riid, void** ppv); @@ -27,49 +28,53 @@ extern HRESULT KramThumbProvider_CreateInstance(REFIID riid, void** ppv); #define SZ_CLSID_KramTHUMBHANDLER L"{a9a47ef5-c238-42a9-a4e6-a85558811dac}" constexpr CLSID kCLSID_KramThumbHandler = {0xa9a47ef5, 0xc238, 0x42a9, {0xa4, 0xe6, 0xa8, 0x55, 0x58, 0x81, 0x1d, 0xac}}; - -typedef HRESULT(*PFNCREATEINSTANCE)(REFIID riid, void** ppvObject); +typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void** ppvObject); struct CLASS_OBJECT_INIT { - const CLSID* pClsid; - PFNCREATEINSTANCE pfnCreate; + const CLSID* pClsid; + PFNCREATEINSTANCE pfnCreate; }; // add classes supported by this module here constexpr CLASS_OBJECT_INIT kClassObjectInit[] = { - { &kCLSID_KramThumbHandler, KramThumbProvider_CreateInstance } -}; + {&kCLSID_KramThumbHandler, KramThumbProvider_CreateInstance}}; - -std::atomic_long gModuleReferences(0); -HINSTANCE gModuleInstance = nullptr; +std::atomic_long gModuleReferences(0); +HINSTANCE gModuleInstance = nullptr; // Standard DLL functions -STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void*) { +STDAPI_(BOOL) +DllMain(HINSTANCE hInstance, DWORD dwReason, void*) +{ if (DLL_PROCESS_ATTACH == dwReason) { gModuleInstance = hInstance; ::DisableThreadLibraryCalls(hInstance); - } else if (DLL_PROCESS_DETACH == dwReason) { + } + else if (DLL_PROCESS_DETACH == dwReason) { gModuleInstance = nullptr; } return TRUE; } -STDAPI DllCanUnloadNow() { +STDAPI DllCanUnloadNow() +{ // Only allow the DLL to be unloaded after all outstanding references have been released return (gModuleReferences > 0) ? S_FALSE : S_OK; } -void DllAddRef() { +void DllAddRef() +{ ++gModuleReferences; } -void DllRelease() { +void DllRelease() +{ --gModuleReferences; } class CClassFactory : public IClassFactory { public: - static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT* pClassObjectInits, size_t cClassObjectInits, REFIID riid, void** ppv) { + static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT* pClassObjectInits, size_t cClassObjectInits, REFIID riid, void** ppv) + { *ppv = NULL; HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; for (size_t i = 0; i < cClassObjectInits; ++i) { @@ -87,29 +92,34 @@ class CClassFactory : public IClassFactory { } CClassFactory(PFNCREATEINSTANCE pfnCreate) - : mReferences(1) - , mCreateFunc(pfnCreate) { + : mReferences(1), mCreateFunc(pfnCreate) + { DllAddRef(); } - virtual ~CClassFactory() { + virtual ~CClassFactory() + { DllRelease(); } // IUnknown - IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) { + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) + { static const QITAB qit[] = { QITABENT(CClassFactory, IClassFactory), - { 0 } - }; + {0}}; return QISearch(this, qit, riid, ppv); } - IFACEMETHODIMP_(ULONG) AddRef() { + IFACEMETHODIMP_(ULONG) + AddRef() + { return ++mReferences; } - IFACEMETHODIMP_(ULONG) Release() { + IFACEMETHODIMP_(ULONG) + Release() + { const long refs = --mReferences; if (!refs) { delete this; @@ -118,38 +128,43 @@ class CClassFactory : public IClassFactory { } // IClassFactory - IFACEMETHODIMP CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv) { + IFACEMETHODIMP CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv) + { return punkOuter ? CLASS_E_NOAGGREGATION : mCreateFunc(riid, ppv); } - IFACEMETHODIMP LockServer(BOOL fLock) { + IFACEMETHODIMP LockServer(BOOL fLock) + { if (fLock) { DllAddRef(); - } else { + } + else { DllRelease(); } return S_OK; } private: - std::atomic_long mReferences; - PFNCREATEINSTANCE mCreateFunc; + std::atomic_long mReferences; + PFNCREATEINSTANCE mCreateFunc; }; -STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv) { +STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv) +{ return CClassFactory::CreateInstance(clsid, kClassObjectInit, std::size(kClassObjectInit), riid, ppv); } // A struct to hold the information required for a registry entry struct REGISTRY_ENTRY { - HKEY hkeyRoot; + HKEY hkeyRoot; PCWSTR pszKeyName; PCWSTR pszValueName; PCWSTR pszData; }; // Creates a registry key (if needed) and sets the default value of the key -HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY* pRegistryEntry) { +HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY* pRegistryEntry) +{ HKEY hKey; HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName, @@ -166,28 +181,30 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY* pRegistryEntry) { } // Registers this COM server -STDAPI DllRegisterServer() { +STDAPI DllRegisterServer() +{ HRESULT hr; - WCHAR szModuleName[MAX_PATH] = { 0 }; + WCHAR szModuleName[MAX_PATH] = {0}; if (!GetModuleFileNameW(gModuleInstance, szModuleName, ARRAYSIZE(szModuleName))) { hr = HRESULT_FROM_WIN32(GetLastError()); - } else { + } + else { // List of registry entries we want to create const REGISTRY_ENTRY registryEntries[] = { // RootKey KeyName ValueName Data - {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER, nullptr, SZ_KramTHUMBHANDLER}, - {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER L"\\InProcServer32", nullptr, szModuleName}, - {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", L"Apartment"}, + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER, nullptr, SZ_KramTHUMBHANDLER}, + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER L"\\InProcServer32", nullptr, szModuleName}, + {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_KramTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", L"Apartment"}, // libkram can decode any of these and create a thumbnail // The Vista GUID for the thumbnail handler Shell extension is E357FCCD-A995-4576-B01F-234630154E96. - {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx", L"PerceivedType", L"image"}, - {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, - {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx2", L"PerceivedType", L"image"}, - {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx2\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, - {HKEY_CURRENT_USER, L"Software\\Classes\\.dds", L"PerceivedType", L"image"}, - {HKEY_CURRENT_USER, L"Software\\Classes\\.dds\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx", L"PerceivedType", L"image"}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx2", L"PerceivedType", L"image"}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.ktx2\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.dds", L"PerceivedType", L"image"}, + {HKEY_CURRENT_USER, L"Software\\Classes\\.dds\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, //{HKEY_CURRENT_USER, L"Software\\Classes\\.png", L"PerceivedType", L"image"}, //{HKEY_CURRENT_USER, L"Software\\Classes\\.png\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", nullptr, SZ_CLSID_KramTHUMBHANDLER}, }; @@ -208,7 +225,8 @@ STDAPI DllRegisterServer() { } // Unregisters this COM server -STDAPI DllUnregisterServer() { +STDAPI DllUnregisterServer() +{ HRESULT hr = S_OK; const PCWSTR regKeys[] = { @@ -216,7 +234,7 @@ STDAPI DllUnregisterServer() { L"Software\\Classes\\.ktx", L"Software\\Classes\\.ktx2", L"Software\\Classes\\.dds", - // L"Software\\Classes\\.png", // only need this if Win png bg is bad + // L"Software\\Classes\\.png", // only need this if Win png bg is bad }; // Delete the registry entries diff --git a/kram-thumb-win/KramThumbProvider.cpp b/kram-thumb-win/KramThumbProvider.cpp index a32a7563..e49ccfd5 100644 --- a/kram-thumb-win/KramThumbProvider.cpp +++ b/kram-thumb-win/KramThumbProvider.cpp @@ -1,12 +1,13 @@ -#include "KramLib.h" - #include #include // For IThumbnailProvider. #include // For ComPtr -#include + #include +#include #include +#include "KramLib.h" + using namespace kram; using namespace std; // or STL_NAMESPACE @@ -48,32 +49,37 @@ struct ImageToPass { KTXImageData imageData; }; -class KramThumbProvider final : public IInitializeWithStream, public IThumbnailProvider -{ +class KramThumbProvider final : public IInitializeWithStream, public IThumbnailProvider { public: KramThumbProvider() - : mReferences(1) - , mStream{} { + : mReferences(1), mStream{} + { } - virtual ~KramThumbProvider() { + virtual ~KramThumbProvider() + { } // IUnknown - IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) { + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) + { static const QITAB qit[] = { QITABENT(KramThumbProvider, IInitializeWithStream), QITABENT(KramThumbProvider, IThumbnailProvider), - { 0 }, + {0}, }; return QISearch(this, qit, riid, ppv); } - IFACEMETHODIMP_(ULONG) AddRef() { + IFACEMETHODIMP_(ULONG) + AddRef() + { return ++mReferences; } - IFACEMETHODIMP_(ULONG) Release() { + IFACEMETHODIMP_(ULONG) + Release() + { long refs = --mReferences; if (!refs) { delete this; @@ -82,8 +88,9 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP } // IInitializeWithStream - IFACEMETHODIMP Initialize(IStream* pStream, DWORD /*grfMode*/) { - HRESULT hr = E_UNEXPECTED; // can only be inited once + IFACEMETHODIMP Initialize(IStream* pStream, DWORD /*grfMode*/) + { + HRESULT hr = E_UNEXPECTED; // can only be inited once if (!mStream) { // take a reference to the stream if we have not been inited yet hr = pStream->QueryInterface(mStream.ReleaseAndGetAddressOf()); @@ -92,8 +99,8 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP } // IThumbnailProvider - IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha) { - + IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha) + { // read from stream and create a thumbnail if (!ImageToHBITMAP(cx, phbmp)) { return E_OUTOFMEMORY; @@ -101,7 +108,7 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP // always 4 channels *pdwAlpha = WTSAT_ARGB; - + return S_OK; } @@ -122,11 +129,10 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP vector streamData; streamData.resize(streamSize); ULONG bytesRead = 0; - HRESULT hr = mStream->Read(streamData.data(), streamSize, &bytesRead); // can only read ULONG + HRESULT hr = mStream->Read(streamData.data(), streamSize, &bytesRead); // can only read ULONG if (FAILED(hr) || streamSize != bytesRead) return false; - // https://learn.microsoft.com/en-us/windows/win32/api/thumbcache/nf-thumbcache-ithumbnailprovider-getthumbnail std::shared_ptr imageToPass = std::make_shared(); @@ -143,7 +149,7 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP } // This will set decoder - auto textureType = MyMTLTextureType2D; // image.textureType + auto textureType = MyMTLTextureType2D; // image.textureType if (!validateFormatAndDecoder(textureType, image.pixelFormat, decoderType)) { KLOGF(3, "format decode only supports ktx and ktx2 output"); return false; @@ -162,7 +168,7 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP float width; float height; }; - NSSize contextSize = { (float)maxSize, (float)maxSize }; + NSSize contextSize = {(float)maxSize, (float)maxSize}; // compute w/h from aspect ratio of image float requestWidth, requestHeight; @@ -206,7 +212,7 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP //----------------- - uint32_t chunkNum = 0; // TODO: could embed chunk(s) to gen thumbnail from, cube/array? + uint32_t chunkNum = 0; // TODO: could embed chunk(s) to gen thumbnail from, cube/array? uint32_t numChunks = image.totalChunks(); vector mipData; @@ -294,19 +300,17 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP mipData.resize(mipSize); memcpy(mipData.data(), image2D.pixels().data(), mipSize); } - - //--------------------- - + // create a bitmap, and allocate memory for the pixels BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = static_cast(w); - bmi.bmiHeader.biHeight = -static_cast(h); // -h to be top-down + bmi.bmiHeader.biHeight = -static_cast(h); // -h to be top-down bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; // TODO: use BI_PNG to shrink thumbnails + bmi.bmiHeader.biCompression = BI_RGB; // TODO: use BI_PNG to shrink thumbnails Color* dstPixels = nullptr; HBITMAP hbmp = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, reinterpret_cast(&dstPixels), nullptr, 0); @@ -329,7 +333,7 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP // setting to 1 for premul is equivalent of blend to opaque black dstPixels[i].a = 255; - + if (!isPremul) { uint32_t alpha = srcPixels[i].a; if (alpha < 255) { @@ -345,11 +349,12 @@ class KramThumbProvider final : public IInitializeWithStream, public IThumbnailP } private: - std::atomic_long mReferences; - ComPtr mStream; // provided during initialization. + std::atomic_long mReferences; + ComPtr mStream; // provided during initialization. }; -HRESULT KramThumbProvider_CreateInstance(REFIID riid, void** ppv) { +HRESULT KramThumbProvider_CreateInstance(REFIID riid, void** ppv) +{ KramThumbProvider* provider = new (std::nothrow) KramThumbProvider(); HRESULT hr = provider ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { diff --git a/kram-thumb-win/resource.h b/kram-thumb-win/resource.h index 4494a87d..1fb651e3 100644 --- a/kram-thumb-win/resource.h +++ b/kram-thumb-win/resource.h @@ -2,17 +2,17 @@ // Microsoft Visual C++ generated include file. // Used by Dll.rc // -#define VER_DEBUG 0 -#define VS_VERSION_INFO 1 -#define IDC_STATIC -1 +#define VER_DEBUG 0 +#define VS_VERSION_INFO 1 +#define IDC_STATIC -1 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/kram-thumb/KramThumbnailProvider.mm b/kram-thumb/KramThumbnailProvider.mm index aa00187c..49138cf3 100644 --- a/kram-thumb/KramThumbnailProvider.mm +++ b/kram-thumb/KramThumbnailProvider.mm @@ -3,75 +3,76 @@ // in all copies or substantial portions of the Software. #import "KramThumbnailProvider.h" -#include "KramLib.h" +#import // for vImage #import #import -#import // for vImage + +#include "KramLib.h" using namespace kram; using namespace STL_NAMESPACE; @implementation KramThumbnailProvider -inline NSError* KLOGF(uint32_t code, const char* format, ...) { +inline NSError* KLOGF(uint32_t code, const char* format, ...) +{ string str; - + va_list args; va_start(args, format); /* int32_t len = */ append_vsprintf(str, format, args); va_end(args); - + // log here, so it can see it in Console. But this never appears. // How are you supposed to debug failures? Resorted to passing a unique code into this call. // It wasn't originally supposed to generate an NSError //NSLog(@"%s", str.c_str()); - + // Console prints this as , so what's the point of producing a localizedString ? // This doesn't seem to work to Console app, but maybe if logs are to terminal // sudo log config --mode "level:debug" --subsystem com.hialec.kramv - + NSString* errorText = [NSString stringWithUTF8String:str.c_str()]; - return [NSError errorWithDomain:@"com.hialec.kramv" code:code userInfo:@{NSLocalizedDescriptionKey:errorText}]; + return [NSError errorWithDomain:@"com.hialec.kramv" code:code userInfo:@{NSLocalizedDescriptionKey : errorText}]; } -struct ImageToPass -{ +struct ImageToPass { KTXImage image; KTXImageData imageData; }; -- (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request completionHandler:(void (^)(QLThumbnailReply * _Nullable, NSError * _Nullable))handler { +- (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest*)request completionHandler:(void (^)(QLThumbnailReply* _Nullable, NSError* _Nullable))handler +{ + // Draw the thumbnail into a context passed to your block, set up with Core Graphics's coordinate system. - // Draw the thumbnail into a context passed to your block, set up with Core Graphics's coordinate system. - const char* filename = [request.fileURL fileSystemRepresentation]; // DONE: could return NSError to caller if non-null NSError* error = nil; string errorText; - + // TODO: use first x-many bytes also to validate, open will do that if (!isSupportedFilename(filename)) { error = KLOGF(1, "kramv %s only supports ktx,ktx2,dds,png files\n", filename); handler(nil, error); return; } - + std::shared_ptr imageToPass = std::make_shared(); TexEncoder decoderType = kTexEncoderUnknown; uint32_t imageWidth, imageHeight; - + { KTXImage& image = imageToPass->image; KTXImageData& imageData = imageToPass->imageData; - + if (!imageData.open(filename, image)) { error = KLOGF(2, "kramv %s could not open file\n", filename); handler(nil, error); return; } - + // This will set decoder auto textureType = MyMTLTextureType2D; // image.textureType if (!validateFormatAndDecoder(textureType, image.pixelFormat, decoderType)) { @@ -79,210 +80,206 @@ - (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request complet handler(nil, error); return; } - + imageWidth = STL_NAMESPACE::max(1U, image.width); imageHeight = STL_NAMESPACE::max(1U, image.height); } // This is retina factor float requestScale = request.scale; - + // One of the sides must match maximumSize, but can have // different aspect ratios below that on a given sides. NSSize contextSize = request.maximumSize; - + // compute w/h from aspect ratio of image float requestWidth, requestHeight; - + float imageAspect = imageWidth / (float)imageHeight; - if (imageAspect >= 1.0f) - { + if (imageAspect >= 1.0f) { requestWidth = contextSize.width; requestHeight = std::clamp((contextSize.width / imageAspect), 1.0, contextSize.height); } - else - { + else { requestWidth = std::clamp((contextSize.height * imageAspect), 1.0, contextSize.width); requestHeight = contextSize.height; } - + // will be further scaled by requestScale contextSize = CGSizeMake(requestWidth, requestHeight); - - handler([QLThumbnailReply replyWithContextSize:contextSize drawingBlock:^BOOL(CGContextRef _Nonnull context) - { - KTXImage& image = imageToPass->image; - - bool isPremul = image.isPremul(); - bool isSrgb = isSrgbFormat(image.pixelFormat); - - //----------------- - - // unpack a level to get the blocks - uint32_t mipNumber = 0; - uint32_t mipCount = image.mipCount(); - - uint32_t w, h, d; - for (uint32_t i = 0; i < mipCount; ++i) { - image.mipDimensions(i, w, h, d); - if (w > request.maximumSize.width || h > request.maximumSize.height) { - mipNumber++; - } - } - - // clamp to smallest - mipNumber = std::min(mipNumber, mipCount - 1); - image.mipDimensions(mipNumber, w, h, d); - - //----------------- - - uint32_t chunkNum = 0; // TODO: could embed chunk(s) to gen thumbnail from, cube/array? - uint32_t numChunks = image.totalChunks(); - - vector mipData; - - // now decode the blocks in that chunk to Color - if (isBlockFormat(image.pixelFormat)) { - - // then decode any blocks to rgba8u, not dealing with HDR formats yet - uint64_t mipLength = image.mipLevels[mipNumber].length; - - if (image.isSupercompressed()) { - const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; - - mipData.resize(mipLength * numChunks); - uint8_t* dstData = mipData.data(); - if (!image.unpackLevel(mipNumber, srcData, dstData)) { - //KLOGF("kramv %s failed to unpack mip\n", filename); - return NO; - } - - // now extract the chunk for the thumbnail out of that level - if (numChunks > 1) { - macroUnusedVar(chunkNum); - assert(chunkNum == 0); - - // this just truncate to chunk 0 instead of copying chunkNum first - mipData.resize(mipLength); - } - } - else - { - // this just truncate to chunk 0 instead of copying chunkNum first - mipData.resize(mipLength); - - const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; - - memcpy(mipData.data(), srcData, mipLength); - } - - KramDecoder decoder; - KramDecoderParams params; - params.decoder = decoderType; - - // TODO: should honor swizzle in the ktx image - // TODO: probaby need an snorm rgba format to convert the snorm versions, so they're not all red - // if sdf, will be signed format and that will stay red - - switch(image.pixelFormat) - { - // To avoid showing single channel content in red, replicate to rgb - case MyMTLPixelFormatBC4_RUnorm: - case MyMTLPixelFormatEAC_R11Unorm: - params.swizzleText = "rrr1"; - break; - - default: - break; - } - - vector dstMipData; - - // only space for one chunk for now - dstMipData.resize(h * w * sizeof(Color)); - - // want to just decode one chunk of the level that was unpacked abovve - if (!decoder.decodeBlocks(w, h, mipData.data(), (int32_t)mipData.size(), image.pixelFormat, dstMipData, params)) { - // Can't return NSError - //error = KLOGF("kramv %s failed to decode blocks\n", filename); - return NO; - } - - // copy over original encoded data - mipData = dstMipData; - } - else if (isExplicitFormat(image.pixelFormat)) { - // explicit formats like r/rg/rgb and 16f/32F need to be converted to rgba8 here - // this should currently clamp, but could do range tonemap, see Image::convertToFourChannel() - // but this needs to be slightly different. This will decompress mip again - - Image image2D; - if (!image2D.loadThumbnailFromKTX(image, mipNumber)) { - //KLOGF("kramv %s failed to convert image to 4 channels\n", filename); - return NO; - } - - // copy from Color back to uint8_t - uint32_t mipSize = h * w * sizeof(Color); - mipData.resize(mipSize); - memcpy(mipData.data(), image2D.pixels().data(), mipSize); - } - - // https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html#//apple_ref/doc/uid/TP30001066-CH212-TPXREF101 - - uint32_t rowBytes = w * sizeof(Color); - - // use vimage in the Accelerate.framework - // https://developer.apple.com/library/archive/releasenotes/Performance/RN-vecLib/index.html#//apple_ref/doc/uid/TP40001049 - - vImage_Buffer buf = { mipData.data(), h, w, rowBytes }; - - // Declare the pixel format for the vImage_Buffer - vImage_CGImageFormat format = { - .bitsPerComponent = 8, - .bitsPerPixel = 32, - }; - - format.bitmapInfo = kCGBitmapByteOrderDefault | (CGBitmapInfo)(isPremul ? kCGImageAlphaPremultipliedLast : kCGImageAlphaLast); - format.colorSpace = isSrgb ? CGColorSpaceCreateWithName(kCGColorSpaceSRGB) : CGColorSpaceCreateDeviceRGB(); - - // don't need to allocate, can reuse memory from mip - bool skipPixelCopy = true; - - vImage_Error err = 0; - CGImageRef cgImage = vImageCreateCGImageFromBuffer(&buf, &format, NULL, NULL, skipPixelCopy ? kvImageNoAllocate : kvImageNoFlags, &err); - if (err) { - // Can't return NSError - //error = KLOGF("kramv %s failed create cgimage\n", filename); - return NO; - } - - CGRect rect = CGRectMake(0, 0, - (uint32_t)roundf(contextSize.width * requestScale), - (uint32_t)roundf(contextSize.height * requestScale)); - - // Default is white, but that messes up all content that uses alpha - // and doesn't match the preview code or kramv background (or Preview). - CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorBlack)); - CGContextFillRect(context, rect); - - // TODO: should this clear to NSColor clearColor ? - // don't want default white? - - // The image is scaled—disproportionately - - //CGContextSetBlendMode(context, kCGBlendModeCopy); - CGContextSetBlendMode(context, kCGBlendModeNormal); - - CGContextDrawImage(context, rect, cgImage); - - // This seems to cause plugin to fail - // Needed? - if (!skipPixelCopy) - CGImageRelease(cgImage); - - return YES; - }], nil); + + handler([QLThumbnailReply replyWithContextSize:contextSize + drawingBlock:^BOOL(CGContextRef _Nonnull context) { + KTXImage& image = imageToPass->image; + + bool isPremul = image.isPremul(); + bool isSrgb = isSrgbFormat(image.pixelFormat); + + //----------------- + + // unpack a level to get the blocks + uint32_t mipNumber = 0; + uint32_t mipCount = image.mipCount(); + + uint32_t w, h, d; + for (uint32_t i = 0; i < mipCount; ++i) { + image.mipDimensions(i, w, h, d); + if (w > request.maximumSize.width || h > request.maximumSize.height) { + mipNumber++; + } + } + + // clamp to smallest + mipNumber = std::min(mipNumber, mipCount - 1); + image.mipDimensions(mipNumber, w, h, d); + + //----------------- + + uint32_t chunkNum = 0; // TODO: could embed chunk(s) to gen thumbnail from, cube/array? + uint32_t numChunks = image.totalChunks(); + + vector mipData; + + // now decode the blocks in that chunk to Color + if (isBlockFormat(image.pixelFormat)) { + // then decode any blocks to rgba8u, not dealing with HDR formats yet + uint64_t mipLength = image.mipLevels[mipNumber].length; + + if (image.isSupercompressed()) { + const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; + + mipData.resize(mipLength * numChunks); + uint8_t* dstData = mipData.data(); + if (!image.unpackLevel(mipNumber, srcData, dstData)) { + //KLOGF("kramv %s failed to unpack mip\n", filename); + return NO; + } + + // now extract the chunk for the thumbnail out of that level + if (numChunks > 1) { + macroUnusedVar(chunkNum); + assert(chunkNum == 0); + + // this just truncate to chunk 0 instead of copying chunkNum first + mipData.resize(mipLength); + } + } + else { + // this just truncate to chunk 0 instead of copying chunkNum first + mipData.resize(mipLength); + + const uint8_t* srcData = image.fileData + image.mipLevels[mipNumber].offset; + + memcpy(mipData.data(), srcData, mipLength); + } + + KramDecoder decoder; + KramDecoderParams params; + params.decoder = decoderType; + + // TODO: should honor swizzle in the ktx image + // TODO: probaby need an snorm rgba format to convert the snorm versions, so they're not all red + // if sdf, will be signed format and that will stay red + + switch (image.pixelFormat) { + // To avoid showing single channel content in red, replicate to rgb + case MyMTLPixelFormatBC4_RUnorm: + case MyMTLPixelFormatEAC_R11Unorm: + params.swizzleText = "rrr1"; + break; + + default: + break; + } + + vector dstMipData; + + // only space for one chunk for now + dstMipData.resize(h * w * sizeof(Color)); + + // want to just decode one chunk of the level that was unpacked abovve + if (!decoder.decodeBlocks(w, h, mipData.data(), (int32_t)mipData.size(), image.pixelFormat, dstMipData, params)) { + // Can't return NSError + //error = KLOGF("kramv %s failed to decode blocks\n", filename); + return NO; + } + + // copy over original encoded data + mipData = dstMipData; + } + else if (isExplicitFormat(image.pixelFormat)) { + // explicit formats like r/rg/rgb and 16f/32F need to be converted to rgba8 here + // this should currently clamp, but could do range tonemap, see Image::convertToFourChannel() + // but this needs to be slightly different. This will decompress mip again + + Image image2D; + if (!image2D.loadThumbnailFromKTX(image, mipNumber)) { + //KLOGF("kramv %s failed to convert image to 4 channels\n", filename); + return NO; + } + + // copy from Color back to uint8_t + uint32_t mipSize = h * w * sizeof(Color); + mipData.resize(mipSize); + memcpy(mipData.data(), image2D.pixels().data(), mipSize); + } + + // https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html#//apple_ref/doc/uid/TP30001066-CH212-TPXREF101 + + uint32_t rowBytes = w * sizeof(Color); + + // use vimage in the Accelerate.framework + // https://developer.apple.com/library/archive/releasenotes/Performance/RN-vecLib/index.html#//apple_ref/doc/uid/TP40001049 + + vImage_Buffer buf = {mipData.data(), h, w, rowBytes}; + + // Declare the pixel format for the vImage_Buffer + vImage_CGImageFormat format = { + .bitsPerComponent = 8, + .bitsPerPixel = 32, + }; + + format.bitmapInfo = kCGBitmapByteOrderDefault | (CGBitmapInfo)(isPremul ? kCGImageAlphaPremultipliedLast : kCGImageAlphaLast); + format.colorSpace = isSrgb ? CGColorSpaceCreateWithName(kCGColorSpaceSRGB) : CGColorSpaceCreateDeviceRGB(); + + // don't need to allocate, can reuse memory from mip + bool skipPixelCopy = true; + + vImage_Error err = 0; + CGImageRef cgImage = vImageCreateCGImageFromBuffer(&buf, &format, NULL, NULL, skipPixelCopy ? kvImageNoAllocate : kvImageNoFlags, &err); + if (err) { + // Can't return NSError + //error = KLOGF("kramv %s failed create cgimage\n", filename); + return NO; + } + + CGRect rect = CGRectMake(0, 0, + (uint32_t)roundf(contextSize.width * requestScale), + (uint32_t)roundf(contextSize.height * requestScale)); + + // Default is white, but that messes up all content that uses alpha + // and doesn't match the preview code or kramv background (or Preview). + CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorBlack)); + CGContextFillRect(context, rect); + + // TODO: should this clear to NSColor clearColor ? + // don't want default white? + + // The image is scaled—disproportionately + + //CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextSetBlendMode(context, kCGBlendModeNormal); + + CGContextDrawImage(context, rect, cgImage); + + // This seems to cause plugin to fail + // Needed? + if (!skipPixelCopy) + CGImageRelease(cgImage); + + return YES; + }], + nil); } @end diff --git a/kramc/KramMain.cpp b/kramc/KramMain.cpp index e449bf16..11eaa875 100644 --- a/kramc/KramMain.cpp +++ b/kramc/KramMain.cpp @@ -3,11 +3,11 @@ int main(int argc, char* argv[]) { int errorCode = kram::kramAppMain(argc, argv); - + // returning -1 from main results in exit code of 255, so fix this to return 1 on failure. if (errorCode != 0) { exit(1); } - + return 0; } diff --git a/kramv/KramLoader.h b/kramv/KramLoader.h index 6ffcc49a..a47fc014 100644 --- a/kramv/KramLoader.h +++ b/kramv/KramLoader.h @@ -16,7 +16,7 @@ namespace kram { class KTXImage; class KTXImageData; -} +} //namespace kram // This loads KTX/2 and PNG data. Moving towards KTX/2 files only, with a PNG // to KTX/2 conversion. @@ -38,7 +38,7 @@ class KTXImageData; - (nullable id)loadTextureFromImage:(const kram::KTXImage &)image originalFormat: (nullable MTLPixelFormat *)originalFormat - name:(nonnull const char*)name; + name:(nonnull const char *)name; // load into KTXImage and KTXImageData, can use with loadTextureFromImage - (BOOL)loadImageFromURL:(nonnull NSURL *)url @@ -73,4 +73,4 @@ using namespace STL_NAMESPACE; // provide access to lowercase strings string toLower(const string &text); -} +} //namespace kram diff --git a/kramv/KramLoader.mm b/kramv/KramLoader.mm index 2455859d..ed8e48af 100644 --- a/kramv/KramLoader.mm +++ b/kramv/KramLoader.mm @@ -45,12 +45,12 @@ @implementation KramLoader { // only one of these for now id _buffer; - uint8_t* _data; + uint8_t *_data; uint32_t _bufferOffset; vector _blits; - NSMutableArray>* _blitTextures; - NSMutableArray>* _mipgenTextures; + NSMutableArray> *_blitTextures; + NSMutableArray> *_mipgenTextures; } - (instancetype)init @@ -72,8 +72,6 @@ - (instancetype)init originalFormat:originalFormat]; } - - // this means format isnt supported on platform, but can be decoded to rgba to // display bool isDecodeImageNeeded(MyMTLPixelFormat pixelFormat, MyMTLTextureType type) @@ -99,7 +97,7 @@ bool decodeImage(const KTXImage &image, KTXImage &imageDecoded) { KramDecoderParams decoderParams; KramDecoder decoder; - + // macOS Intel only had BC support, and already have macOS arm64 build #if SIMD_SSE if (isETCFormat(image.pixelFormat)) { @@ -120,7 +118,7 @@ bool decodeImage(const KTXImage &image, KTXImage &imageDecoded) } #endif else { - KASSERT(false); // don't call this routine if decode not needed + KASSERT(false); // don't call this routine if decode not needed } // TODO: decode BC format on iOS when not supported, but viewer only on macOS @@ -180,27 +178,23 @@ inline MyMTLPixelFormat remapInternalRGBFormat(MyMTLPixelFormat format) KTXImage image; if (imageDataLength > 3 && - imageData[0] == 0xff && imageData[1] == 0xd8 && imageData[2] == 0xff ) - { + imageData[0] == 0xff && imageData[1] == 0xd8 && imageData[2] == 0xff) { KLOGE("kramv", "loader does not support jpg files"); return nil; } - + // if png, then need to load from KTXImageData which uses loadpng // \x89, P, N, G if (imageDataLength > 4 && - imageData[0] == 137 && imageData[1] == 'P' && imageData[2] == 'N' && imageData[3] == 'G') - { + imageData[0] == 137 && imageData[1] == 'P' && imageData[2] == 'N' && imageData[3] == 'G') { KTXImageData imageDataReader; if (!imageDataReader.open(imageData, imageDataLength, image)) { return nil; } - + return [self loadTextureFromImage:image originalFormat:originalFormat name:""]; } - else - { - + else { // isInfoOnly = true keeps compressed mips on KTX2 and aliases original mip // data but have decode etc2/astc path below that uncompressed mips and the // rgb conversion path below as well in the viewer. games would want to @@ -219,7 +213,7 @@ inline MyMTLPixelFormat remapInternalRGBFormat(MyMTLPixelFormat format) - (nullable id)loadTextureFromImage:(const KTXImage &)image originalFormat: (nullable MTLPixelFormat *)originalFormat - name:(const char*)name + name:(const char *)name { #if SUPPORT_RGB if (isInternalRGBFormat(image.pixelFormat)) { @@ -236,7 +230,7 @@ inline MyMTLPixelFormat remapInternalRGBFormat(MyMTLPixelFormat format) dstImageInfoArgs.textureType = image.textureType; dstImageInfoArgs.pixelFormat = remapInternalRGBFormat(image.pixelFormat); dstImageInfoArgs.doMipmaps = - image.mipCount() > 1; // ignore 0 + image.mipCount() > 1; // ignore 0 dstImageInfoArgs.textureEncoder = kTexEncoderExplicit; // set chunk count, so it's explicit @@ -257,7 +251,7 @@ inline MyMTLPixelFormat remapInternalRGBFormat(MyMTLPixelFormat format) if (originalFormat != nullptr) { *originalFormat = (MTLPixelFormat)rbgaImage2 - .pixelFormat; // TODO: should this return rgbaImage.pixelFormat ? + .pixelFormat; // TODO: should this return rgbaImage.pixelFormat ? } return [self blitTextureFromImage:rbgaImage2 name:name]; @@ -276,18 +270,17 @@ inline MyMTLPixelFormat remapInternalRGBFormat(MyMTLPixelFormat format) return [self blitTextureFromImage:imageDecoded name:name]; } - else - { + else { // fast load path directly from mmap'ed data, decompress direct to staging return [self blitTextureFromImage:image name:name]; } } - (BOOL)loadImageFromURL:(nonnull NSURL *)url - image:(KTXImage&)image - imageData:(KTXImageData&)imageData + image:(KTXImage &)image + imageData:(KTXImageData &)imageData { - const char* path = url.absoluteURL.path.UTF8String; + const char *path = url.absoluteURL.path.UTF8String; if (!imageData.open(path, image)) { return NO; } @@ -295,9 +288,9 @@ - (BOOL)loadImageFromURL:(nonnull NSURL *)url return YES; } -- (nullable id)loadTextureFromURL:(nonnull NSURL*)url +- (nullable id)loadTextureFromURL:(nonnull NSURL *)url originalFormat: - (nullable MTLPixelFormat*)originalFormat + (nullable MTLPixelFormat *)originalFormat { KTXImage image; KTXImageData imageData; @@ -312,7 +305,7 @@ - (BOOL)loadImageFromURL:(nonnull NSURL *)url - (nullable id)createTexture:(const KTXImage &)image isPrivate:(bool)isPrivate { - MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; + MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init]; // Indicate that each pixel has a blue, green, red, and alpha channel, where // each channel is an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and @@ -330,10 +323,10 @@ - (BOOL)loadImageFromURL:(nonnull NSURL *)url // This is inefficient to set, but needed for viewwer. // Only set if texture type is toggleable. // only need this if changing components, type, etc. -// { -// textureDescriptor.usage |= MTLTextureUsagePixelFormatView; -// } - + // { + // textureDescriptor.usage |= MTLTextureUsagePixelFormatView; + // } + // ignoring 0 (auto mip), but might need to support for explicit formats // must have hw filtering support for format, and 32f filtering only first // appeared on A14/M1 and only get box filtering in API-level filters. But @@ -385,13 +378,13 @@ - (void)uploadTexturesIfNeeded:(id)blitEncoder commandBuffer:(id)commandBuffer { mylock lock(gTextureLock); - + if (!_blits.empty()) { // now upload from staging MTLBuffer to private MTLTexture - for (const auto& blit : _blits) { + for (const auto &blit : _blits) { MTLRegion region = { - {0, 0, 0}, // MTLOrigin - {(NSUInteger)blit.w, (NSUInteger)blit.h, 1} // MTLSize + {0, 0, 0}, // MTLOrigin + {(NSUInteger)blit.w, (NSUInteger)blit.h, 1} // MTLSize }; uint32_t chunkNum = blit.chunkNum; @@ -430,7 +423,7 @@ - (void)uploadTexturesIfNeeded:(id)blitEncoder self->_bufferOffset = 0; }]; } - + // mipgen possible after initial blit above if (_mipgenTextures.count > 0) { for (id texture in _mipgenTextures) { @@ -447,11 +440,11 @@ - (void)uploadTexturesIfNeeded:(id)blitEncoder - (void)releaseAllPendingTextures { mylock lock(gTextureLock); - + _bufferOffset = 0; - + _blits.clear(); - + [_mipgenTextures removeAllObjects]; [_blitTextures removeAllObjects]; } @@ -465,14 +458,14 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) // (f.e. ktx), and another path for private that uses a blitEncoder and must // have block aligned data (f.e. ktxa, ktx2). Could repack ktx data into ktxa // before writing to temporary file, or when copying NSData into MTLBuffer. -- (nullable id)blitTextureFromImage:(const KTXImage &)image name:(const char*)name +- (nullable id)blitTextureFromImage:(const KTXImage &)image name:(const char *)name { mylock lock(gTextureLock); - + if (_buffer == nil) { // Was set to 128, but models like FlightHelmet.gltf exceeded that buffer static const size_t kStagingBufferSize = 256 * 1024 * 1024; - + // this is enough to upload 4k x 4x @ RGBA8u with mips, 8k x 8k compressed // with mips @96MB [self createStagingBufffer:kStagingBufferSize]; @@ -488,10 +481,10 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) id texture = [self createTexture:image isPrivate:true]; if (!texture) return nil; - + // set a label so can identify in captures texture.label = [NSString stringWithUTF8String:name]; - + // this is index where texture will be added uint32_t textureIndex = (uint32_t)_blitTextures.count; @@ -517,8 +510,8 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) size_t blockSize = image.blockSize(); vector bufferOffsets; - uint8_t* bufferData = (uint8_t*)_buffer.contents; - const uint8_t* mipData = (const uint8_t*)image.fileData; + uint8_t *bufferData = (uint8_t *)_buffer.contents; + const uint8_t *mipData = (const uint8_t *)image.fileData; bufferOffsets.resize(image.mipLevels.size()); uint32_t numChunks = image.totalChunks(); @@ -536,8 +529,7 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) KLOGE("kramv", "Ran out of buffer space to upload images"); return nil; } - - + // this may have to decompress the level data if (!image.unpackLevel(i, mipData + mipLevel.offset, bufferData + bufferOffset)) { @@ -570,7 +562,7 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) uint32_t bytesPerRow = 0; // 1D/1DArray textures set bytesPerRow to 0 - if ( // image.textureType != MyMTLTextureType1D && + if ( // image.textureType != MyMTLTextureType1D && image.textureType != MyMTLTextureType1DArray) { // for compressed, bytesPerRow needs to be multiple of block size // so divide by the number of blocks making up the height @@ -618,7 +610,7 @@ inline uint64_t alignOffset(uint64_t offset, uint64_t alignment) mipLevelNumber, mipStorageSize, mipOffset, textureIndex, bytesPerRow, - is3D // could derive from textureIndex lookup + is3D // could derive from textureIndex lookup }); } } diff --git a/kramv/KramRenderer.h b/kramv/KramRenderer.h index de20df75..4c5a556a 100644 --- a/kramv/KramRenderer.h +++ b/kramv/KramRenderer.h @@ -8,7 +8,7 @@ #import #include "KramLib.h" -#import "KramShaders.h" // for TextureChannels +#import "KramShaders.h" // for TextureChannels // Turn on GLTF loading support for 3d models. This relies on Warren Moore's first GLTFKit // which only handles import and synchronous loading. @@ -28,19 +28,17 @@ //@import GLTFMTL; #endif - namespace kram { class ShowSettings; class Data; class KTXImage; -} +} //namespace kram // Need renderer to be able to call back up to view to update hud. @protocol MyMTKViewUpdates - (void)updateEyedropperText; @end - // Our platform independent renderer class. Implements the MTKViewDelegate // protocol which // allows it to accept per-frame update and drawable resize callbacks. @@ -53,7 +51,7 @@ class KTXImage; - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view settings: (nonnull kram::ShowSettings *)settings - data:(nonnull kram::Data *)data; + data:(nonnull kram::Data *)data; - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString timestamp:(double)timestamp @@ -66,18 +64,17 @@ class KTXImage; - (BOOL)hotloadShaders:(nonnull const char *)filename; - // unload textures and gltf model textures - (void)releaseAllPendingTextures; // load a gltf model -- (BOOL)loadModel:(nonnull const char*)url; +- (BOOL)loadModel:(nonnull const char *)url; // unload gltf model - (void)unloadModel; // called from view and renderer in render loop -- (void)updateAnimationState:(nonnull MTKView*)view; +- (void)updateAnimationState:(nonnull MTKView *)view; // So caller can respond to completed callback - (void)setEyedropperDelegate:(nullable id)delegate; @@ -86,13 +83,12 @@ class KTXImage; - (void)setFramePacingEnabled:(bool)enable; // can play animations in gltf models -@property (nonatomic) BOOL playAnimations; +@property(nonatomic) BOOL playAnimations; // can toggle on/off srgb if that is psosible -@property (nonatomic) BOOL isToggleView; +@property(nonatomic) BOOL isToggleView; // true if a toggle is present -@property (nonatomic) BOOL hasToggleView; +@property(nonatomic) BOOL hasToggleView; @end - diff --git a/kramv/KramRenderer.mm b/kramv/KramRenderer.mm index c1c30ebf..68e80edb 100644 --- a/kramv/KramRenderer.mm +++ b/kramv/KramRenderer.mm @@ -16,6 +16,7 @@ // c interface to signposts similar to dtrace on macOS/iOS #include + #include // for recursive_mutex using mymutex = std::recursive_mutex; @@ -23,8 +24,7 @@ os_log_t gLogKramv = os_log_create("com.hialec.kramv", ""); -class Signpost -{ +class Signpost { public: Signpost(const char* name) : _name(name), _ended(false) @@ -34,12 +34,12 @@ else _ended = true; } - + ~Signpost() { stop(); } - + void stop() { if (!_ended) { @@ -47,13 +47,12 @@ void stop() _ended = true; } } - + private: const char* _name; bool _ended; }; - #if USE_GLTF // TODO: make part of renderer @@ -64,12 +63,12 @@ void stop() @interface KramGLTFTextureLoader : NSObject - (instancetype)initWithLoader:(KramLoader*)loader; -- (id _Nullable)newTextureWithContentsOfURL:(NSURL *)url options:(NSDictionary * _Nullable)options error:(NSError **)error; -- (id _Nullable)newTextureWithData:(NSData *)data options:(NSDictionary * _Nullable)options error:(NSError **)error; +- (id _Nullable)newTextureWithContentsOfURL:(NSURL*)url options:(NSDictionary* _Nullable)options error:(NSError**)error; +- (id _Nullable)newTextureWithData:(NSData*)data options:(NSDictionary* _Nullable)options error:(NSError**)error; @end @interface KramGLTFTextureLoader () -@property (nonatomic, strong) KramLoader* loader; +@property(nonatomic, strong) KramLoader* loader; @end @implementation KramGLTFTextureLoader @@ -83,13 +82,13 @@ - (instancetype)initWithLoader:(KramLoader*)loader } // TODO: this ignores options and error. Default png loading may need to request srgb. -- (id _Nullable)newTextureWithContentsOfURL:(NSURL *)url options:(NSDictionary * _Nullable)options error:(NSError * __autoreleasing *)error +- (id _Nullable)newTextureWithContentsOfURL:(NSURL*)url options:(NSDictionary* _Nullable)options error:(NSError* __autoreleasing*)error { return [_loader loadTextureFromURL:url originalFormat:nil]; } // TODO: this ignores options and error. Default png loading may need to request srgb. -- (id _Nullable)newTextureWithData:(NSData *)data options:(NSDictionary * _Nullable)options error:(NSError * __autoreleasing *)error +- (id _Nullable)newTextureWithData:(NSData*)data options:(NSDictionary* _Nullable)options error:(NSError* __autoreleasing*)error { return [_loader loadTextureFromData:data originalFormat:nil]; } @@ -98,7 +97,6 @@ - (instancetype)initWithLoader:(KramLoader*)loader #endif - static const NSUInteger MaxBuffersInFlight = 3; using namespace kram; @@ -126,7 +124,7 @@ @implementation Renderer { id _pipelineStateVolume; id _pipelineStateDrawLines; - + id _pipelineState1DArrayCS; id _pipelineStateImageCS; id _pipelineStateImageArrayCS; @@ -137,7 +135,6 @@ @implementation Renderer { id _depthStateFull; id _depthStateNone; - MTLVertexDescriptor* _mtlVertexDescriptor; // TODO: Array< id > _textures; @@ -145,9 +142,9 @@ @implementation Renderer { id _colorMapView; id _normalMap; id _diffMap; - + id _lastDrawableTexture; - + // border is a better edge sample, but at edges it filters in the transparent // color around the border which is undesirable. It would be better if the hw // did clamp to edge until uv outside 0 to 1. This results in having to inset @@ -168,12 +165,11 @@ @implementation Renderer { uint8_t _uniformBufferIndex; - // float _rotation; KramLoader* _loader; MTKMesh* _mesh; - MDLVertexDescriptor *_mdlVertexDescriptor; + MDLVertexDescriptor* _mdlVertexDescriptor; MTKMesh* _meshRect; MTKMesh* _meshBox; @@ -181,7 +177,7 @@ @implementation Renderer { MTKMesh* _meshSphereMirrored; // MTKMesh* _meshCylinder; MTKMesh* _meshCapsule; - MTKMeshBufferAllocator *_metalAllocator; + MTKMeshBufferAllocator* _metalAllocator; id _shaderLibrary; NSURL* _metallibFileURL; @@ -190,22 +186,22 @@ @implementation Renderer { ShowSettings* _showSettings; Data* _data; - + #if USE_GLTF KramGLTFTextureLoader* _textureLoader; id _bufferAllocator; GLTFMTLRenderer* _gltfRenderer; GLTFAsset* _asset; // only 1 for now double _animationTime; - + id _environmentTexture; bool _environmentNeedsUpdate; - + NSURLSession* _urlSession; #endif __weak id _delegateHud; - + bool _useFramePacing; double _avgGpuTime; } @@ -214,9 +210,9 @@ @implementation Renderer { @synthesize isToggleView; @synthesize hasToggleView; -- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view - settings:(nonnull ShowSettings *)settings - data:(nonnull Data*)data +- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)view + settings:(nonnull ShowSettings*)settings + data:(nonnull Data*)data { self = [super init]; if (self) { @@ -232,25 +228,24 @@ - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view _inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight); [self _loadMetalWithView:view]; [self _loadAssets]; - + #if USE_GLTF _bufferAllocator = [[GLTFMTLBufferAllocator alloc] initWithDevice:_device]; _gltfRenderer = [[GLTFMTLRenderer alloc] initWithDevice:_device]; - + // This aliases the existing kram loader, can handle png, ktx, ktx2 _textureLoader = [[KramGLTFTextureLoader alloc] initWithLoader:_loader]; _gltfRenderer.textureLoader = _textureLoader; - + // load the environment from a cube map for now // runs this after _shaderLibrary established above - _gltfRenderer.lightingEnvironment = [[GLTFMTLLightingEnvironment alloc] initWithLibrary: _shaderLibrary]; - + _gltfRenderer.lightingEnvironment = [[GLTFMTLLightingEnvironment alloc] initWithLibrary:_shaderLibrary]; + //NSURL* environmentURL = [[NSBundle mainBundle] URLForResource:@"piazza_san_marco" withExtension:@"ktx"]; NSURL* environmentURL = [[NSBundle mainBundle] URLForResource:@"tropical_beach" withExtension:@"ktx"]; _environmentTexture = [_loader loadTextureFromURL:environmentURL originalFormat:nil]; _environmentNeedsUpdate = true; #endif - } return self; @@ -258,7 +253,7 @@ - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view - (void)_createSamplers { - MTLSamplerDescriptor *samplerDescriptor = [MTLSamplerDescriptor new]; + MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest; samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest; samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest; @@ -294,7 +289,7 @@ - (void)_createSamplers samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear; samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear; samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; - samplerDescriptor.maxAnisotropy = 4; // 1,2,4,8,16 are choices + samplerDescriptor.maxAnisotropy = 4; // 1,2,4,8,16 are choices samplerDescriptor.sAddressMode = MTLSamplerAddressModeClampToBorderColor; samplerDescriptor.tAddressMode = MTLSamplerAddressModeClampToBorderColor; @@ -332,19 +327,19 @@ - (void)_createVertexDescriptor BufferIndexMeshPosition; _mtlVertexDescriptor.attributes[VertexAttributeTexcoord].format = - MTLVertexFormatFloat2; // TODO: compress + MTLVertexFormatFloat2; // TODO: compress _mtlVertexDescriptor.attributes[VertexAttributeTexcoord].offset = 0; _mtlVertexDescriptor.attributes[VertexAttributeTexcoord].bufferIndex = BufferIndexMeshUV0; _mtlVertexDescriptor.attributes[VertexAttributeNormal].format = - MTLVertexFormatFloat3; // TODO: compress + MTLVertexFormatFloat3; // TODO: compress _mtlVertexDescriptor.attributes[VertexAttributeNormal].offset = 0; _mtlVertexDescriptor.attributes[VertexAttributeNormal].bufferIndex = BufferIndexMeshNormal; _mtlVertexDescriptor.attributes[VertexAttributeTangent].format = - MTLVertexFormatFloat4; // TODO: compress + MTLVertexFormatFloat4; // TODO: compress _mtlVertexDescriptor.attributes[VertexAttributeTangent].offset = 0; _mtlVertexDescriptor.attributes[VertexAttributeTangent].bufferIndex = BufferIndexMeshTangent; @@ -373,7 +368,7 @@ - (void)_createVertexDescriptor MDLVertexAttributeTangent; } -- (void)_loadMetalWithView:(nonnull MTKView *)view +- (void)_loadMetalWithView:(nonnull MTKView*)view { /// Load Metal state objects and initialize renderer dependent view properties @@ -382,19 +377,18 @@ - (void)_loadMetalWithView:(nonnull MTKView *)view // true is good for non-srgb -> rgba16f CGColorSpaceRef viewColorSpace; MTLPixelFormat format = MTLPixelFormatRGBA16Float; - + // This doesn't look like Figma or Photoshop for a rgb,a = 255,0 to 255,1 gradient across a 256px wide rect. The shader is saturating // the color to 0,1. So can get away with SRGB color space for now. // This also lines up with Preview. //viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); - - + //CAMetalLayer* metalLayer = (CAMetalLayer*)[view layer]; - + // was using 16f so could sample hdr images from it // and also so hdr data went out to the display uint32_t colorSpaceChoice = 1; - switch(colorSpaceChoice) { + switch (colorSpaceChoice) { default: case 0: // This is best so far @@ -402,88 +396,86 @@ - (void)_loadMetalWithView:(nonnull MTKView *)view viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); //viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceLinearSRGB); break; - + case 1: { // Display P3 is a standard made by Apple that covers the same colour space as DCI-P3, but uses the more neutral D65 as a white point instead of the green white of the DCI standard. // Ideally feed 16-bit color to P3. - + // This also works // 25% larger than srgb format = MTLPixelFormatRGBA16Float; - + // This is industry format // viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceDCIP3); - + // This isn't edr // viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3); - + // Use this because it exists from 10.14.3+ viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearDisplayP3); - + // don't set this yet. // metalLayer.wantsExtendedDynamicRangeContent = YES; - + // https://developer.apple.com/videos/play/wwdc2021/10161/ - + /* Can detect if on HDR display or not user can mod the brightness, or move to another monitor, need to listen for notification when this changes. - + NSScreen* screen = NSScreen.mainScreen; - + // This reports 1 CGFloat val1 = screen.maximumExtendedDynamicRangeColorComponentValue; - + // This is 16 CGFloat maxPot = screen.maximumPotentialExtendedDynamicRangeColorComponentValue; - + // This is 0 CGFloat maxRef = screen.maximumReferenceExtendedDynamicRangeColorComponentValue; */ - + // M1 monitor - - + break; } case 2: // This doesn't match wnen srgb is turned off on TestColorGradient format = MTLPixelFormatRGBA8Unorm_sRGB; viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - + // this looks totally wrong //viewColorSpace = CGColorSpaceCreateWithName(kCGColorLinearSpaceSRGB); break; - - /* - case 3: { - // There is an exrMetadata field on NSView to set as well. - // https://developer.apple.com/documentation/metal/hdr_content/using_color_spaces_to_display_hdr_content?language=objc - - // Rec2020 color primaries, with PQ Transfer function. - // Would have to get into Rec2020 colors to set this, also go from 10bit - format = MTLPixelFormatBGR10A2Unorm; - viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_2100_PQ); - - metalLayer.wantsExtendedDynamicRangeContent = YES; - - // https://developer.apple.com/documentation/metal/hdr_content/using_system_tone_mapping_on_video_content?language=objc - // must do os version check on this - // 1.0 is 100 nits of output - CAEDRMetadata* edrMetaData = [CAEDRMetadata HDR10MetadataWithMinLuminance: 0.005 maxLuminance: 1000 opticalOutputScale: 100]; - metalLayer.EDRMetadata = edrMetaData; - - break; - } - */ + + /* + case 3: { + // There is an exrMetadata field on NSView to set as well. + // https://developer.apple.com/documentation/metal/hdr_content/using_color_spaces_to_display_hdr_content?language=objc + + // Rec2020 color primaries, with PQ Transfer function. + // Would have to get into Rec2020 colors to set this, also go from 10bit + format = MTLPixelFormatBGR10A2Unorm; + viewColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_2100_PQ); + + metalLayer.wantsExtendedDynamicRangeContent = YES; + + // https://developer.apple.com/documentation/metal/hdr_content/using_system_tone_mapping_on_video_content?language=objc + // must do os version check on this + // 1.0 is 100 nits of output + CAEDRMetadata* edrMetaData = [CAEDRMetadata HDR10MetadataWithMinLuminance: 0.005 maxLuminance: 1000 opticalOutputScale: 100]; + metalLayer.EDRMetadata = edrMetaData; + + break; + } + */ } - - + view.colorPixelFormat = format; view.colorspace = viewColorSpace; - + CGColorSpaceRelease(viewColorSpace); - + view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; view.sampleCount = 1; @@ -501,7 +493,7 @@ - (void)_loadMetalWithView:(nonnull MTKView *)view //----------------------- - MTLDepthStencilDescriptor *depthStateDesc = + MTLDepthStencilDescriptor* depthStateDesc = [[MTLDepthStencilDescriptor alloc] init]; depthStateDesc.depthCompareFunction = MTLCompareFunctionGreaterEqual; depthStateDesc.depthWriteEnabled = YES; @@ -530,7 +522,7 @@ - (void)_loadMetalWithView:(nonnull MTKView *)view [self _createSampleRender]; } -- (BOOL)hotloadShaders:(const char *)filename +- (BOOL)hotloadShaders:(const char*)filename { _metallibFileURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filename]]; @@ -549,7 +541,7 @@ - (BOOL)hotloadShaders:(const char *)filename _metallibFileDate = fileDate; // Now dynamically load the metallib - NSData *dataNS = [NSData dataWithContentsOfURL:_metallibFileURL + NSData* dataNS = [NSData dataWithContentsOfURL:_metallibFileURL options:NSDataReadingMappedIfSafe error:&err]; if (dataNS == nil) { @@ -575,7 +567,7 @@ - (BOOL)hotloadShaders:(const char *)filename return YES; } -- (id)_createComputePipeline:(const char *)name +- (id)_createComputePipeline:(const char*)name { NSString* nameNS = [NSString stringWithUTF8String:name]; NSError* error = nil; @@ -610,8 +602,8 @@ - (void)_createComputePipelines [self _createComputePipeline:"SampleImage1DArrayCS"]; } -- (id)_createRenderPipeline:(const char *)vs - fs:(const char *)fs +- (id)_createRenderPipeline:(const char*)vs + fs:(const char*)fs { NSString* vsNameNS = [NSString stringWithUTF8String:vs]; NSString* fsNameNS = [NSString stringWithUTF8String:fs]; @@ -629,7 +621,7 @@ - (void)_createComputePipelines // Note: blending is disabled on color target, all blending done in shader // since have checkerboard and other stuff to blend against. - + // TODO: could drop these for images, but want a 3D preview of content // or might make these memoryless. pipelineStateDescriptor.depthAttachmentPixelFormat = @@ -680,10 +672,9 @@ - (void)_createRenderPipelines fs:"DrawCubeArrayPS"]; _pipelineStateVolume = [self _createRenderPipeline:"DrawVolumeVS" fs:"DrawVolumePS"]; - + _pipelineStateDrawLines = [self _createRenderPipeline:"DrawLinesVS" fs:"DrawLinesPS"]; - } - (void)_createSampleRender @@ -717,9 +708,9 @@ - (void)_createSampleRender } } -- (MTKMesh *)_createMeshAsset:(const char *)name - mdlMesh:(MDLMesh *)mdlMesh - doFlipUV:(bool)doFlipUV +- (MTKMesh*)_createMeshAsset:(const char*)name + mdlMesh:(MDLMesh*)mdlMesh + doFlipUV:(bool)doFlipUV { NSError* error = nil; @@ -733,10 +724,10 @@ - (MTKMesh *)_createMeshAsset:(const char *)name id uvs = mdlMesh.vertexBuffers[BufferIndexMeshUV0]; MDLMeshBufferMap* uvsMap = [uvs map]; - packed_float2* uvData = (packed_float2 *)uvsMap.bytes; + packed_float2* uvData = (packed_float2*)uvsMap.bytes; for (uint32_t i = 0; i < mdlMesh.vertexCount; ++i) { - auto &uv = uvData[i]; + auto& uv = uvData[i]; uv.x = 1.0f - uv.x; } @@ -754,13 +745,13 @@ - (MTKMesh *)_createMeshAsset:(const char *)name if (doFlipBitangent) { id uvs = mdlMesh.vertexBuffers[BufferIndexMeshTangent]; MDLMeshBufferMap* uvsMap = [uvs map]; - packed_float4* uvData = (packed_float4 *)uvsMap.bytes; + packed_float4* uvData = (packed_float4*)uvsMap.bytes; for (uint32_t i = 0; i < mdlMesh.vertexCount; ++i) { - // if (uvData[i].w != -1.0f && uvData[i].w != 1.0f) { - // int bp = 0; - // bp = bp; - // } + // if (uvData[i].w != -1.0f && uvData[i].w != 1.0f) { + // int bp = 0; + // bp = bp; + // } uvData[i].w = -uvData[i].w; } @@ -814,12 +805,11 @@ - (MTKMesh *)_createMeshAsset:(const char *)name float x, y, z; }; - - (void)releaseAllPendingTextures { @autoreleasepool { [_loader releaseAllPendingTextures]; - + // also release the model and cached textures in the renderer [self unloadModel]; } @@ -828,15 +818,15 @@ - (void)releaseAllPendingTextures - (void)updateAnimationState:(nonnull MTKView*)view { bool animateDisplay = self.playAnimations; - + // animate the uvPreview until it reaches endPoint, no scrubber yet _showSettings->updateUVPreviewState(); - + if (_showSettings->uvPreviewFrames > 0) { _showSettings->uvPreviewFrames--; animateDisplay = true; } - + view.enableSetNeedsDisplay = !animateDisplay; view.paused = !animateDisplay; } @@ -847,15 +837,15 @@ - (void)setEyedropperDelegate:(nullable id)delegate _delegateHud = delegate; } -- (void)updateModelSettings:(const string &)fullFilename +- (void)updateModelSettings:(const string&)fullFilename { _showSettings->isModel = true; _showSettings->numChannels = 0; // hides rgba - + // don't want any scale on view, or as little as possible _showSettings->imageBoundsX = 1; _showSettings->imageBoundsY = 1; - + BOOL isNewFile = YES; [self resetSomeImageSettings:isNewFile]; } @@ -867,15 +857,13 @@ - (BOOL)loadModel:(nonnull const char*)filename #if USE_GLTF - - - // TODO: move to async version of this, many of these load slow - // but is there a way to cancel the load. Or else move to cgltf which is faster. - // see GLTFKit2. + // TODO: move to async version of this, many of these load slow + // but is there a way to cancel the load. Or else move to cgltf which is faster. + // see GLTFKit2. #define DO_ASYNC 0 #if DO_ASYNC - // [GLTFAsset loadAssetWithURL:url bufferAllocator:_bufferAllocator delegate:self]; + // [GLTFAsset loadAssetWithURL:url bufferAllocator:_bufferAllocator delegate:self]; #else @autoreleasepool { GLTFAsset* newAsset = [[GLTFAsset alloc] initWithURL:fileURL bufferAllocator:_bufferAllocator]; @@ -905,15 +893,13 @@ - (void)unloadModel #endif } - - - (void)_createMeshRect:(float)aspectRatioXToY { // This is a box that's smashed down to a thin 2d z plane, can get very close to it // due to the thinness of the volume without nearZ intersect - + /// Load assets into metal objects - MDLMesh *mdlMesh; + MDLMesh* mdlMesh; mdlMesh = [MDLMesh newBoxWithDimensions:(vector_float3){aspectRatioXToY, 1, 0.001} segments:(vector_uint3){1, 1, 1} @@ -923,7 +909,7 @@ - (void)_createMeshRect:(float)aspectRatioXToY // for some reason normals are all n = 1,0,0 which doesn't make sense on a box // for the side that is being viewed. - + // only one of these for now, but really should store per image _meshRect = [self _createMeshAsset:"MeshRect" mdlMesh:mdlMesh doFlipUV:false]; } @@ -968,19 +954,19 @@ - (void)_loadAssets id posBuffer = mdlMesh.vertexBuffers[BufferIndexMeshPosition]; MDLMeshBufferMap* posMap = [posBuffer map]; - packed_float3* posData = (packed_float3 *)posMap.bytes; + packed_float3* posData = (packed_float3*)posMap.bytes; id normalBuffer = mdlMesh.vertexBuffers[BufferIndexMeshNormal]; MDLMeshBufferMap* normalsMap = [normalBuffer map]; - packed_float3* normalData = (packed_float3 *)normalsMap.bytes; + packed_float3* normalData = (packed_float3*)normalsMap.bytes; // vertexCount reports 306, but vertex 289+ are garbage - uint32_t numVertices = 289; // mdlMesh.vertexCount + uint32_t numVertices = 289; // mdlMesh.vertexCount for (uint32_t i = 0; i < numVertices; ++i) { { - auto &pos = posData[i]; + auto& pos = posData[i]; // dumb rotate about Y-axis auto copy = pos; @@ -990,7 +976,7 @@ - (void)_loadAssets } { - auto &normal = normalData[i]; + auto& normal = normalData[i]; auto copy = normal; normal.x = copy.x * cosSin.x - copy.z * cosSin.y; normal.z = copy.x * cosSin.y + copy.z * cosSin.x; @@ -999,7 +985,7 @@ - (void)_loadAssets // Hack - knock out all bogus tris from ModelIO that lead to garbage tris for (uint32_t i = numVertices; i < mdlMesh.vertexCount; ++i) { - auto &pos = posData[i]; + auto& pos = posData[i]; pos.x = NAN; } } @@ -1026,26 +1012,26 @@ - (void)_loadAssets id uvsBuffer = mdlMesh.vertexBuffers[BufferIndexMeshUV0]; MDLMeshBufferMap* uvsMap = [uvsBuffer map]; - packed_float2* uvData = (packed_float2 *)uvsMap.bytes; + packed_float2* uvData = (packed_float2*)uvsMap.bytes; // this is all aos id posBuffer = mdlMesh.vertexBuffers[BufferIndexMeshPosition]; MDLMeshBufferMap* posMap = [posBuffer map]; - packed_float3 *posData = (packed_float3 *)posMap.bytes; + packed_float3* posData = (packed_float3*)posMap.bytes; id normalsBuffe = mdlMesh.vertexBuffers[BufferIndexMeshNormal]; MDLMeshBufferMap* normalsMap = [normalsBuffe map]; - packed_float3* normalData = (packed_float3 *)normalsMap.bytes; + packed_float3* normalData = (packed_float3*)normalsMap.bytes; // vertexCount reports 306, but vertex 289+ are garbage - uint32_t numVertices = 289; // mdlMesh.vertexCount + uint32_t numVertices = 289; // mdlMesh.vertexCount for (uint32_t i = 0; i < numVertices; ++i) { { - auto &pos = posData[i]; + auto& pos = posData[i]; // dumb rotate about Y-axis auto copy = pos; @@ -1054,18 +1040,18 @@ - (void)_loadAssets } { - auto &normal = normalData[i]; + auto& normal = normalData[i]; auto copy = normal; normal.x = copy.x * cosSin.x - copy.z * cosSin.y; normal.z = copy.x * cosSin.y + copy.z * cosSin.x; } - auto &uv = uvData[i]; + auto& uv = uvData[i]; - // if (uv.x < 0.0 || uv.x > 1.0) { - // int bp = 0; - // bp = bp; - // } + // if (uv.x < 0.0 || uv.x > 1.0) { + // int bp = 0; + // bp = bp; + // } // this makes it counterclockwise 0 to 1 float x = uv.x; @@ -1089,7 +1075,7 @@ - (void)_loadAssets // Hack - knock out all bogus tris from ModelIO that lead to garbage tris for (uint32_t i = numVertices; i < mdlMesh.vertexCount; ++i) { - auto &pos = posData[i]; + auto& pos = posData[i]; pos.x = NAN; } @@ -1116,7 +1102,7 @@ - (void)_loadAssets // doFlipUV:true]; mdlMesh = [MDLMesh newCapsuleWithHeight:1.0 - radii:(vector_float2){1.0f/3.0f, 1.0f/3.0f} // circle + radii:(vector_float2){1.0f / 3.0f, 1.0f / 3.0f} // circle // vertical cap subtracted from height radialSegments:16 verticalSegments:1 @@ -1134,7 +1120,8 @@ - (void)_loadAssets } // this aliases the existing string, so can't chop extension -inline const char* toFilenameShort(const char* filename) { +inline const char* toFilenameShort(const char* filename) +{ const char* filenameShort = strrchr(filename, '/'); if (filenameShort == nullptr) { filenameShort = filename; @@ -1145,22 +1132,21 @@ - (void)_loadAssets return filenameShort; } - -- (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString +- (BOOL)loadTextureFromImage:(nonnull const char*)fullFilenameString timestamp:(double)timestamp - image:(kram::KTXImage &)image - imageNormal:(nullable kram::KTXImage *)imageNormal - imageDiff:(nullable kram::KTXImage *)imageDiff + image:(kram::KTXImage&)image + imageNormal:(nullable kram::KTXImage*)imageNormal + imageDiff:(nullable kram::KTXImage*)imageDiff isArchive:(BOOL)isArchive { // image can be decoded to rgba8u if platform can't display format natively // but still want to identify blockSize from original format string fullFilename = fullFilenameString; const char* filenameShort = toFilenameShort(fullFilename.c_str()); - + bool isTextureNew = _showSettings->isFileNew(fullFilename.c_str()); bool isTextureChanged = _showSettings->isFileChanged(fullFilename.c_str(), timestamp); - + if (isTextureChanged) { // synchronously cpu upload from ktx file to buffer, with eventual gpu blit // from buffer to returned texture. TODO: If buffer is full, then something @@ -1174,13 +1160,13 @@ - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString if (!texture) { return NO; } - + bool isPNG = isPNGFilename(fullFilename.c_str()); - + // to be able to turn on/off srgb, need to set a view id textureView; MyMTLPixelFormat textureFormat = (MyMTLPixelFormat)image.pixelFormat; - + // TODO: may only want to offer on png files, where format is MyMTLPixelFormat viewFormat = textureFormat; if (isPNG) // && isSrgbFormat(textureFormat)) @@ -1191,7 +1177,7 @@ - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString else { // This may fail. textureView = [texture newTextureViewWithPixelFormat:(MTLPixelFormat)viewFormat]; - + textureView.label = [texture.label stringByAppendingString:@"View"]; } @@ -1211,13 +1197,13 @@ - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString if (imageDiff) { // Note: this name may not be the same name diffTexture = [_loader loadTextureFromImage:*imageDiff - originalFormat:nil - name:filenameShort]; + originalFormat:nil + name:filenameShort]; if (!diffTexture) { return NO; } } - + // if archive contained png, then it's been converted to ktx // so the info below may not reflect original data // Would need original png data to look at header @@ -1246,13 +1232,13 @@ - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString _colorMapView = textureView; _normalMap = normalTexture; _diffMap = diffTexture; - + self.hasToggleView = _colorMapView != nil; } // this is the actual format, may have been decoded MyMTLPixelFormat format = (MyMTLPixelFormat)_colorMap.pixelFormat; - _data->updateImageSettings(fullFilename, image, format); + _data->updateImageSettings(fullFilename, image, format); } [self resetSomeImageSettings:isTextureNew]; @@ -1260,7 +1246,7 @@ - (BOOL)loadTextureFromImage:(nonnull const char *)fullFilenameString return YES; } -- (BOOL)loadTexture:(nonnull NSURL *)url +- (BOOL)loadTexture:(nonnull NSURL*)url { string fullFilename = url.path.UTF8String; @@ -1273,10 +1259,10 @@ - (BOOL)loadTexture:(nonnull NSURL *)url // DONE: tie this to url and modstamp differences double timestamp = fileDate.timeIntervalSince1970; - + bool isTextureNew = _showSettings->isFileNew(fullFilename.c_str()); bool isTextureChanged = _showSettings->isFileChanged(fullFilename.c_str(), timestamp); - + // image can be decoded to rgba8u if platform can't display format natively // but still want to identify blockSize from original format if (isTextureChanged) { @@ -1289,7 +1275,7 @@ - (BOOL)loadTexture:(nonnull NSURL *)url } const char* filenameShort = toFilenameShort(fullFilename.c_str()); - + MTLPixelFormat originalFormatMTL = MTLPixelFormatInvalid; id texture = [_loader loadTextureFromImage:image originalFormat:&originalFormatMTL @@ -1299,11 +1285,11 @@ - (BOOL)loadTexture:(nonnull NSURL *)url } bool isPNG = isPNGFilename(fullFilename.c_str()); - + // to be able to turn on/off srgb, need to set a view id textureView; MyMTLPixelFormat textureFormat = (MyMTLPixelFormat)image.pixelFormat; - + // DONE: may only want to offer on png files, where format is MyMTLPixelFormat viewFormat = textureFormat; if (isPNG) // && isSrgbFormat(textureFormat)) @@ -1314,10 +1300,10 @@ - (BOOL)loadTexture:(nonnull NSURL *)url else { // This may fail. textureView = [texture newTextureViewWithPixelFormat:(MTLPixelFormat)viewFormat]; - + textureView.label = [texture.label stringByAppendingString:@"View"]; } - + // This doesn't look for or load corresponding normal map, but should // this is not the png data, but info on converted png to ktx level @@ -1343,13 +1329,13 @@ - (BOOL)loadTexture:(nonnull NSURL *)url // TODO: should archive work with diff? id diffTexture = nil; _showSettings->hasDiffTexture = diffTexture != nil; - + @autoreleasepool { _colorMap = texture; _colorMapView = textureView; _normalMap = nil; _diffMap = nil; - + self.hasToggleView = _colorMapView != nil; } @@ -1362,44 +1348,41 @@ - (BOOL)loadTexture:(nonnull NSURL *)url return YES; } - - (void)resetSomeImageSettings:(BOOL)isNewFile { _data->resetSomeImageSettings(isNewFile); - + // the rect is ar:1 for images float aspectRatioXtoY = _showSettings->imageAspectRatio(); [self _createMeshRect:aspectRatioXtoY]; } - - - (void)_updateGameState { /// Update any game state before encoding rendering commands to our drawable - - Uniforms &uniforms = - *(Uniforms *)_dynamicUniformBuffer[_uniformBufferIndex].contents; - + + Uniforms& uniforms = + *(Uniforms*)_dynamicUniformBuffer[_uniformBufferIndex].contents; + uniforms.isNormal = _showSettings->texContentType == TexContentTypeNormal; uniforms.doShaderPremul = _showSettings->doShaderPremul; uniforms.isSrgbInput = _showSettings->isSRGBShown && isSrgbFormat(_showSettings->originalFormat); uniforms.isSigned = _showSettings->isSigned; uniforms.isSwizzleAGToRG = _showSettings->isSwizzleAGToRG; - + uniforms.isSDF = _showSettings->texContentType == TexContentTypeSDF; uniforms.numChannels = _showSettings->numChannels; uniforms.lightingMode = (ShaderLightingMode)_showSettings->lightingMode; - + MyMTLTextureType textureType = MyMTLTextureType2D; MyMTLPixelFormat textureFormat = MyMTLPixelFormatInvalid; if (_colorMap) { textureType = (MyMTLTextureType)_colorMap.textureType; textureFormat = (MyMTLPixelFormat)_colorMap.pixelFormat; } - + uniforms.isCheckerboardShown = _showSettings->isCheckerboardShown; - + // addressing mode bool isCube = (textureType == MyMTLTextureTypeCube || textureType == MyMTLTextureTypeCubeArray); @@ -1407,27 +1390,27 @@ - (void)_updateGameState bool doEdge = !doWrap; bool doZero = !doEdge; uniforms.isWrap = doWrap ? _showSettings->isWrap : false; - + uniforms.isPreview = _showSettings->isPreview; uniforms.isDiff = _showSettings->isDiff; - + uniforms.isNormalMapPreview = false; if (uniforms.isPreview) { uniforms.isNormalMapPreview = uniforms.isNormal || (_normalMap != nil); - + if (_normalMap != nil) { uniforms.isNormalMapSigned = - isSignedFormat((MyMTLPixelFormat)_normalMap.pixelFormat); - uniforms.isNormalMapSwizzleAGToRG = false; // TODO: need a prop for this + isSignedFormat((MyMTLPixelFormat)_normalMap.pixelFormat); + uniforms.isNormalMapSwizzleAGToRG = false; // TODO: need a prop for this } } - + // a few things to fix before enabling this uniforms.useTangent = _showSettings->useTangent; - + uniforms.gridX = 0; uniforms.gridY = 0; - + if (_showSettings->isPixelGridShown) { uniforms.gridX = 1; uniforms.gridY = 1; @@ -1442,19 +1425,19 @@ - (void)_updateGameState uniforms.gridX = _showSettings->gridSizeX; uniforms.gridY = _showSettings->gridSizeY; } - + // no debug mode when preview kicks on, make it possible to toggle back and // forth more easily uniforms.debugMode = (ShaderDebugMode)_showSettings->debugMode; uniforms.shapeChannel = (ShaderShapeChannel)_showSettings->shapeChannel; uniforms.channels = (ShaderTextureChannels)_showSettings->channels; - + // turn these off in preview mode, but they may be useful? if (_showSettings->isPreview) { uniforms.debugMode = ShaderDebugMode::ShDebugModeNone; uniforms.shapeChannel = ShaderShapeChannel::ShShapeChannelNone; } - + // crude shape experiment _showSettings->is3DView = true; switch (_showSettings->meshNumber) { @@ -1477,22 +1460,22 @@ - (void)_updateGameState break; } uniforms.is3DView = _showSettings->is3DView; - + // on small textures can really see missing pixel (3 instead of 4 pixels) // so only do this on the sphere/capsule which wrap-around uv space uniforms.isInsetByHalfPixel = false; if (_showSettings->meshNumber >= 2 && doZero) { uniforms.isInsetByHalfPixel = true; } - + _data->updateTransforms(); - + // this is an animated effect, that overlays the shape uv wires over the image uniforms.isUVPreview = _showSettings->uvPreview > 0.0; uniforms.uvPreview = _showSettings->uvPreview; - + uniforms.uvToShapeRatio = 1.0f; - switch(_showSettings->meshNumber) { + switch (_showSettings->meshNumber) { case 0: if (_showSettings->imageBoundsY) uniforms.uvToShapeRatio = _showSettings->imageBoundsX / (float)_showSettings->imageBoundsY; @@ -1506,7 +1489,7 @@ - (void)_updateGameState } uniforms.projectionViewMatrix = _data->_projectionViewMatrix; uniforms.cameraPosition = _data->_cameraPosition; - + // This is per object uniforms.modelMatrix = _data->_modelMatrix; uniforms.modelMatrixInvScale2 = _data->_modelMatrixInvScale2; @@ -1514,7 +1497,7 @@ - (void)_updateGameState //_rotation += .01; } -- (void)_setUniformsLevel:(UniformsLevel &)uniforms mipLOD:(int32_t)mipLOD +- (void)_setUniformsLevel:(UniformsLevel&)uniforms mipLOD:(int32_t)mipLOD { uniforms.mipLOD = mipLOD; @@ -1558,14 +1541,14 @@ - (void)_setUniformsLevel:(UniformsLevel &)uniforms mipLOD:(int32_t)mipLOD } } -- (void)drawInMTKView:(nonnull MTKView *)view +- (void)drawInMTKView:(nonnull MTKView*)view { @autoreleasepool { // Per frame updates here // update per frame state [self updateAnimationState:view]; - + // TODO: move this out, needs to get called off mouseMove, but don't want to // call drawMain [self drawSample]; @@ -1574,29 +1557,29 @@ - (void)drawInMTKView:(nonnull MTKView *)view Signpost postWait("waitOnSemaphore"); dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER); postWait.stop(); - + _uniformBufferIndex = (_uniformBufferIndex + 1) % MaxBuffersInFlight; id commandBuffer = [_commandQueue commandBuffer]; commandBuffer.label = @"MyCommand"; __block dispatch_semaphore_t block_sema = _inFlightSemaphore; - - #if USE_GLTF - GLTFMTLRenderer* gltfRenderer = _gltfRenderer; - [commandBuffer addCompletedHandler:^(id /* buffer */) { - [gltfRenderer signalFrameCompletion]; - - // increment count - dispatch_semaphore_signal(block_sema); - }]; - - #else - [commandBuffer addCompletedHandler:^(id /* buffer */) { - // increment count - dispatch_semaphore_signal(block_sema); - }]; - #endif + +#if USE_GLTF + GLTFMTLRenderer* gltfRenderer = _gltfRenderer; + [commandBuffer addCompletedHandler:^(id /* buffer */) { + [gltfRenderer signalFrameCompletion]; + + // increment count + dispatch_semaphore_signal(block_sema); + }]; + +#else + [commandBuffer addCompletedHandler:^(id /* buffer */) { + // increment count + dispatch_semaphore_signal(block_sema); + }]; +#endif [self _updateGameState]; @@ -1618,14 +1601,14 @@ - (void)drawInMTKView:(nonnull MTKView *)view [self drawMain:commandBuffer view:view]; postDraw.stop(); - + // hold onto this for sampling from it via eyedropper id drawable = view.currentDrawable; _lastDrawableTexture = drawable.texture; // These are equivalent // [commandBuffer presentDrawable:view.currentDrawable]; - + typeof(self) __weak weakSelf = self; [commandBuffer addScheduledHandler:^(id cmdBuf) { if (cmdBuf.error) return; @@ -1639,28 +1622,31 @@ - (void)drawInMTKView:(nonnull MTKView *)view double gpuTime = cmdBuf.GPUEndTime - cmdBuf.GPUStartTime; [weakSelf _updateFramePacing:gpuTime]; }]; - + [commandBuffer commit]; } } - -- (void)_present:(id)drawable { + +- (void)_present:(id)drawable +{ if (_useFramePacing) [drawable presentAfterMinimumDuration:_avgGpuTime]; else [drawable present]; } -- (void)_updateFramePacing:(double)gpuTime { +- (void)_updateFramePacing:(double)gpuTime +{ if (_useFramePacing) { _avgGpuTime = lerp(_avgGpuTime, gpuTime, 0.25); } } -- (void)setFramePacingEnabled:(bool)enable { +- (void)setFramePacingEnabled:(bool)enable +{ if (_useFramePacing != enable) { _useFramePacing = enable; - + // this will get adjusted by updateFramePacing _avgGpuTime = 1.0 / 60.0; } @@ -1668,32 +1654,32 @@ - (void)setFramePacingEnabled:(bool)enable { #if USE_GLTF -static GLTFBoundingSphere GLTFBoundingSphereFromBox2(const GLTFBoundingBox b) { +static GLTFBoundingSphere GLTFBoundingSphereFromBox2(const GLTFBoundingBox b) +{ GLTFBoundingSphere s; float3 center = 0.5f * (b.minPoint + b.maxPoint); float r = distance(b.maxPoint, center); - + s.center = center; s.radius = r; return s; } #endif - - (void)drawMain:(id)commandBuffer - view:(nonnull MTKView *)view + view:(nonnull MTKView*)view { // Delay getting the currentRenderPassDescriptor until absolutely needed. This // avoids // holding onto the drawable and blocking the display pipeline any longer // than necessary MTLRenderPassDescriptor* renderPassDescriptor = nil; - + // This retrieval can take 20ms+ when gpu is busy Signpost post("nextDrawable"); renderPassDescriptor = view.currentRenderPassDescriptor; post.stop(); - + if (renderPassDescriptor == nil) { return; } @@ -1702,8 +1688,7 @@ - (void)drawMain:(id)commandBuffer #if USE_GLTF && _asset == nil #endif - ) - { + ) { // this will clear target id renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; @@ -1719,9 +1704,8 @@ - (void)drawMain:(id)commandBuffer #if USE_GLTF { mylock lock(gModelLock); - + if (_asset) { - // TODO: needs to be done in the render loop, since it must run compute // This runs compute to generate radiance/irradiance in mip levels // Also an equirect version for a 2d image @@ -1730,14 +1714,13 @@ - (void)drawMain:(id)commandBuffer [_gltfRenderer.lightingEnvironment generateFromCubeTexture:_environmentTexture commandBuffer:commandBuffer]; else [_gltfRenderer.lightingEnvironment generateFromEquirectTexture:_environmentTexture commandBuffer:commandBuffer]; - + _environmentNeedsUpdate = false; } } } #endif - // Final pass rendering code here id renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; @@ -1755,18 +1738,18 @@ - (void)drawMain:(id)commandBuffer [renderEncoder setDepthStencilState:_depthStateFull]; bool drawShape = true; - - #if USE_GLTF + +#if USE_GLTF { mylock lock(gModelLock); if (_asset) { drawShape = false; - + // update animations if (self.playAnimations) { - _animationTime += 1.0/60.0; - + _animationTime += 1.0 / 60.0; + NSTimeInterval maxAnimDuration = 0; for (GLTFAnimation* animation in _asset.animations) { for (GLTFAnimationChannel* channel in animation.channels) { @@ -1775,20 +1758,20 @@ - (void)drawMain:(id)commandBuffer } } } - + NSTimeInterval animTime = fmod(_animationTime, maxAnimDuration); - + for (GLTFAnimation* animation in _asset.animations) { [animation runAtTime:animTime]; } } - + // regularization scales the model to 1 unit dimension, may animate out of this box // just a scale to diameter 1, and translate back from center and viewer z GLTFBoundingSphere bounds = GLTFBoundingSphereFromBox2(_asset.defaultScene.approximateBounds); float invScale = (bounds.radius > 0) ? (0.5 / (bounds.radius)) : 1.0; - float4x4 centerScale = float4x4(float4m(invScale,invScale,invScale,1)); - + float4x4 centerScale = float4x4(float4m(invScale, invScale, invScale, 1)); + #if USE_SIMDLIB float4x4 centerTranslation = float4x4::identity(); #else @@ -1796,37 +1779,37 @@ - (void)drawMain:(id)commandBuffer #endif centerTranslation.columns[3] = vector4(-bounds.center, 1.0f); float4x4 regularizationMatrix = centerScale * centerTranslation; - + // incorporate the rotation now - Uniforms &uniforms = - *(Uniforms *)_dynamicUniformBuffer[_uniformBufferIndex].contents; - + Uniforms& uniforms = + *(Uniforms*)_dynamicUniformBuffer[_uniformBufferIndex].contents; + regularizationMatrix = regularizationMatrix * uniforms.modelMatrix; - + // TODO: be able to pass regularization to affect root of modelMatrix tree, // do not modify viewMatrix here since that messes with world space. - + // set the view and projection matrix float4x4 m = _data->_viewMatrix * regularizationMatrix; - + // TODO: offer conversions to simd/simd.h _gltfRenderer.viewMatrix = reinterpret_cast(m); _gltfRenderer.projectionMatrix = reinterpret_cast(_data->_projectionMatrix); - - RenderScope drawModelScope( renderEncoder, "DrawModel" ); + + RenderScope drawModelScope(renderEncoder, "DrawModel"); [_gltfRenderer renderScene:_asset.defaultScene commandBuffer:commandBuffer commandEncoder:renderEncoder]; } } - #endif - +#endif + if (drawShape) { - RenderScope drawShapeScope( renderEncoder, "DrawShape" ); - + RenderScope drawShapeScope(renderEncoder, "DrawShape"); + // set the mesh shape for (NSUInteger bufferIndex = 0; bufferIndex < _mesh.vertexBuffers.count; bufferIndex++) { - MTKMeshBuffer *vertexBuffer = _mesh.vertexBuffers[bufferIndex]; - if ((NSNull *)vertexBuffer != [NSNull null]) { + MTKMeshBuffer* vertexBuffer = _mesh.vertexBuffers[bufferIndex]; + if ((NSNull*)vertexBuffer != [NSNull null]) { [renderEncoder setVertexBuffer:vertexBuffer.buffer offset:vertexBuffer.offset atIndex:bufferIndex]; @@ -1900,7 +1883,7 @@ - (void)drawMain:(id)commandBuffer id tex = _colorMap; if (self.isToggleView && _colorMap && _colorMapView) tex = _colorMapView; - + // set the texture up [renderEncoder setFragmentTexture:tex atIndex:TextureIndexColor]; @@ -1908,7 +1891,7 @@ - (void)drawMain:(id)commandBuffer if (_normalMap && _showSettings->isPreview) { [renderEncoder setFragmentTexture:_normalMap atIndex:TextureIndexNormal]; } - + if (_diffMap && _showSettings->isDiff) { [renderEncoder setFragmentTexture:_diffMap atIndex:TextureIndexDiff]; } @@ -1916,7 +1899,7 @@ - (void)drawMain:(id)commandBuffer UniformsLevel uniformsLevel; uniformsLevel.drawOffset = float2m(0.0f); uniformsLevel.passNumber = kPassDefault; - + if (_showSettings->isPreview) { // upload this on each face drawn, since want to be able to draw all // mips/levels at once @@ -1950,14 +1933,14 @@ - (void)drawMain:(id)commandBuffer // by the zoom int32_t gap = _showSettings - ->showAllPixelGap; // * _showSettings->viewContentScaleFactor; + ->showAllPixelGap; // * _showSettings->viewContentScaleFactor; for (int32_t mip = 0; mip < _showSettings->mipCount; ++mip) { // upload this on each face drawn, since want to be able to draw all // mips/levels at once - + [self _setUniformsLevel:uniformsLevel mipLOD:mip]; - + if (mip == 0) { uniformsLevel.drawOffset.y = 0.0f; } @@ -1965,13 +1948,13 @@ - (void)drawMain:(id)commandBuffer // all mips draw at top mip size currently uniformsLevel.drawOffset.y -= h + gap; } - + // this its ktxImage.totalChunks() int32_t numLevels = _showSettings->totalChunks(); - + for (int32_t level = 0; level < numLevels; ++level) { - RenderScope drawLevelScope( renderEncoder, "DrawLevel" ); - + RenderScope drawLevelScope(renderEncoder, "DrawLevel"); + if (isCube) { uniformsLevel.face = level % 6; uniformsLevel.arrayOrSlice = level / 6; @@ -1979,7 +1962,7 @@ - (void)drawMain:(id)commandBuffer else { uniformsLevel.arrayOrSlice = level; } - + // advance x across faces/slices/array elements, 1d array and 2d thin // array are weird though. if (level == 0) { @@ -1988,25 +1971,25 @@ - (void)drawMain:(id)commandBuffer else { uniformsLevel.drawOffset.x += w + gap; } - + [renderEncoder setVertexBytes:&uniformsLevel length:sizeof(uniformsLevel) atIndex:BufferIndexUniformsLevel]; - + [renderEncoder setFragmentBytes:&uniformsLevel length:sizeof(uniformsLevel) atIndex:BufferIndexUniformsLevel]; - + // force lod, and don't mip [renderEncoder setFragmentSamplerState:sampler lodMinClamp:mip lodMaxClamp:mip + 1 atIndex:SamplerIndexColor]; - + // TODO: since this isn't a preview, have mode to display all faces // and mips on on screen faces and arrays and slices go across in a // row, and mips are displayed down from each of those in a column - + for (MTKSubmesh* submesh in _mesh.submeshes) { [renderEncoder drawIndexedPrimitives:submesh.primitiveType indexCount:submesh.indexCount @@ -2016,11 +1999,11 @@ - (void)drawMain:(id)commandBuffer } } } - + for (int32_t mip = 0; mip < _showSettings->mipCount; ++mip) { // upload this on each face drawn, since want to be able to draw all // mips/levels at once - + [self _setUniformsLevel:uniformsLevel mipLOD:mip]; if (mip == 0) { @@ -2042,7 +2025,7 @@ - (void)drawMain:(id)commandBuffer else { uniformsLevel.arrayOrSlice = level; } - + // advance x across faces/slices/array elements, 1d array and 2d thin // array are weird though. if (level == 0) { @@ -2051,21 +2034,21 @@ - (void)drawMain:(id)commandBuffer else { uniformsLevel.drawOffset.x += w + gap; } - + [renderEncoder setVertexBytes:&uniformsLevel length:sizeof(uniformsLevel) atIndex:BufferIndexUniformsLevel]; - -// [renderEncoder setFragmentBytes:&uniformsLevel -// length:sizeof(uniformsLevel) -// atIndex:BufferIndexUniformsLevel]; - + + // [renderEncoder setFragmentBytes:&uniformsLevel + // length:sizeof(uniformsLevel) + // atIndex:BufferIndexUniformsLevel]; + // force lod, and don't mip -// [renderEncoder setFragmentSamplerState:sampler -// lodMinClamp:mip -// lodMaxClamp:mip + 1 -// atIndex:SamplerIndexColor]; -// + // [renderEncoder setFragmentSamplerState:sampler + // lodMinClamp:mip + // lodMaxClamp:mip + 1 + // atIndex:SamplerIndexColor]; + // [self drawAtlas:renderEncoder]; } } @@ -2102,23 +2085,23 @@ - (void)drawMain:(id)commandBuffer indexBuffer:submesh.indexBuffer.buffer indexBufferOffset:submesh.indexBuffer.offset]; } - + // Draw uv wire overlay if (_showSettings->is3DView && _showSettings->uvPreview > 0.0) { // need to force color in shader or it's still sampling texture // also need to add z offset - - RenderScope drawUVPreviewScope( renderEncoder, "DrawUVPreview" ); - + + RenderScope drawUVPreviewScope(renderEncoder, "DrawUVPreview"); + [renderEncoder setTriangleFillMode:MTLTriangleFillModeLines]; - + // only applies to tris, not points/lines, pushes depth away (towards 0), after clip // affects reads/tests and writes. Could also add in vertex shader. // depthBias * 2^(exp(max abs(z) in primitive) - r) + slopeScale * maxSlope - [renderEncoder setDepthBias:0.015 slopeScale:3.0 clamp: 0.02]; - + [renderEncoder setDepthBias:0.015 slopeScale:3.0 clamp:0.02]; + uniformsLevel.passNumber = kPassUVPreview; - + [renderEncoder setVertexBytes:&uniformsLevel length:sizeof(uniformsLevel) atIndex:BufferIndexUniformsLevel]; @@ -2134,15 +2117,14 @@ - (void)drawMain:(id)commandBuffer indexBuffer:submesh.indexBuffer.buffer indexBufferOffset:submesh.indexBuffer.offset]; } - + uniformsLevel.passNumber = kPassDefault; - + // restore state, even though this isn't a true state shadow [renderEncoder setDepthBias:0.0 slopeScale:0.0 clamp:0.0]; [renderEncoder setTriangleFillMode:MTLTriangleFillModeFill]; - } - + [self drawAtlas:renderEncoder]; } } @@ -2154,16 +2136,15 @@ - (void)drawMain:(id)commandBuffer // TODO: environment map preview should be done as fsq } -class RenderScope -{ +class RenderScope { public: RenderScope(id encoder_, const char* name) : encoder(encoder_) { id enc = (id)encoder; - [enc pushDebugGroup: [NSString stringWithUTF8String: name]]; + [enc pushDebugGroup:[NSString stringWithUTF8String:name]]; } - + void close() { if (encoder) { @@ -2172,51 +2153,52 @@ void close() encoder = nil; } } - + ~RenderScope() { close(); } + private: id encoder; }; -- (void)drawAtlas:(nonnull id)renderEncoder { +- (void)drawAtlas:(nonnull id)renderEncoder +{ // draw last since this changes pipeline state if (_showSettings->is3DView && _showSettings->atlas.empty()) return; - + //if (!_showSettings->drawAtlas) // return; - - RenderScope drawAtlasScope( renderEncoder, "DrawAtlas" ); - + + RenderScope drawAtlasScope(renderEncoder, "DrawAtlas"); + [renderEncoder setTriangleFillMode:MTLTriangleFillModeLines]; - [renderEncoder setDepthBias:5.0 slopeScale:0.0 clamp: 0.0]; + [renderEncoder setDepthBias:5.0 slopeScale:0.0 clamp:0.0]; [renderEncoder setCullMode:MTLCullModeNone]; - + [renderEncoder setRenderPipelineState:_pipelineStateDrawLines]; - + // TODO: draw line strip with prim reset // need atlas data in push constants or in vb - + // TOOO: also need to hover name or show names on canvas - -// [renderEncoder setVertexBytes:&uniformsLevel -// length:sizeof(uniformsLevel) -// atIndex:BufferIndexUniformsLevel]; + + // [renderEncoder setVertexBytes:&uniformsLevel + // length:sizeof(uniformsLevel) + // atIndex:BufferIndexUniformsLevel]; UniformsDebug uniformsDebug; - - for (const Atlas& atlas: _showSettings->atlas) { + + for (const Atlas& atlas : _showSettings->atlas) { // not accounting for slice uniformsDebug.rect = float4m(atlas.x, atlas.y, atlas.w, atlas.h); - - + [renderEncoder setVertexBytes:&uniformsDebug length:sizeof(uniformsDebug) atIndex:BufferIndexUniformsDebug]; - + // this will draw diagonal for (MTKSubmesh* submesh in _mesh.submeshes) { [renderEncoder drawIndexedPrimitives:submesh.primitiveType @@ -2226,7 +2208,7 @@ - (void)drawAtlas:(nonnull id)renderEncoder { indexBufferOffset:submesh.indexBuffer.offset]; } } - + // restore state, even though this isn't a true state shadow [renderEncoder setCullMode:MTLCullModeBack]; [renderEncoder setDepthBias:0.0 slopeScale:0.0 clamp:0.0]; @@ -2253,7 +2235,7 @@ - (void)drawSample // this reads directly from compressed texture via a compute shader int32_t textureLookupX = _showSettings->textureLookupX; int32_t textureLookupY = _showSettings->textureLookupY; - + bool isDrawableBlit = _showSettings->isEyedropperFromDrawable(); // TODO: only don't blit for plane + no debug or shape @@ -2319,14 +2301,14 @@ - (void)drawSample // copy from texture back to CPU, might be easier using MTLBuffer.contents MTLRegion region = { - {0, 0, 0}, // MTLOrigin - {1, 1, 1} // MTLSize + {0, 0, 0}, // MTLOrigin + {1, 1, 1} // MTLSize }; if (isDrawableBlit) { half4 data16f; [texture getBytes:&data16f bytesPerRow:8 fromRegion:region mipmapLevel:0]; - + data = float4m(data16f); } else { @@ -2340,13 +2322,13 @@ - (void)drawSample self->_showSettings->textureResult = data; self->_showSettings->textureResultX = textureLookupX; self->_showSettings->textureResultY = textureLookupY; - + [self->_delegateHud updateEyedropperText]; }); - + // TODO: This completed handler runs long after the hud has updated // so need to invalidate the hud. So the pixel location is out of date. - + // printf("Color %f %f %f %f\n", data.x, data.y, data.z, data.w); }]; @@ -2365,8 +2347,8 @@ - (void)drawSamples:(id)commandBuffer renderEncoder.label = @"SampleCompute"; - RenderScope drawShapeScope( renderEncoder, "DrawShape" ); - + RenderScope drawShapeScope(renderEncoder, "DrawShape"); + UniformsCS uniforms; uniforms.uv.x = lookupX; uniforms.uv.y = lookupY; @@ -2409,7 +2391,7 @@ - (void)drawSamples:(id)commandBuffer id tex = _colorMap; if (self.isToggleView && _colorMap && _colorMapView) tex = _colorMapView; - + // input and output texture [renderEncoder setTexture:tex atIndex:TextureIndexColor]; @@ -2427,7 +2409,7 @@ - (void)drawSamples:(id)commandBuffer [renderEncoder endEncoding]; } -- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size +- (void)mtkView:(nonnull MTKView*)view drawableSizeWillChange:(CGSize)size { // Don't crashing trying to readback from the cached drawable during a resize. _lastDrawableTexture = nil; @@ -2445,49 +2427,46 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size _showSettings->viewContentScaleFactor = framebufferScale; _data->updateProjTransform(); - + #if USE_GLTF _gltfRenderer.drawableSize = size; _gltfRenderer.colorPixelFormat = view.colorPixelFormat; _gltfRenderer.depthStencilPixelFormat = view.depthStencilPixelFormat; #endif - + _data->updateProjTransform(); } #if USE_GLTF // @protocol GLTFAssetLoadingDelegate -- (void)assetWithURL:(NSURL *)assetURL requiresContentsOfURL:(NSURL *)url completionHandler:(void (^)(NSData *_Nullable, NSError *_Nullable))completionHandler +- (void)assetWithURL:(NSURL*)assetURL requiresContentsOfURL:(NSURL*)url completionHandler:(void (^)(NSData* _Nullable, NSError* _Nullable))completionHandler { // This can handle remote assets - NSURLSessionDataTask *task = [_urlSession dataTaskWithURL:url - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - completionHandler(data, error); - }]; - + NSURLSessionDataTask* task = [_urlSession dataTaskWithURL:url + completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) { + completionHandler(data, error); + }]; + [task resume]; } -- (void)assetWithURL:(NSURL *)assetURL didFinishLoading:(GLTFAsset *)asset +- (void)assetWithURL:(NSURL*)assetURL didFinishLoading:(GLTFAsset*)asset { mylock lock(gModelLock); - + _asset = asset; - + _animationTime = 0.0; - + string fullFilename = assetURL.path.UTF8String; [self updateModelSettings:fullFilename]; } -- (void)assetWithURL:(NSURL *)assetURL didFailToLoadWithError:(NSError *)error; +- (void)assetWithURL:(NSURL*)assetURL didFailToLoadWithError:(NSError*)error; { // TODO: display this error to the user KLOGE("Renderer", "Asset load failed with error: %s", [[error localizedDescription] UTF8String]); } #endif - - @end diff --git a/kramv/KramViewerBase.cpp b/kramv/KramViewerBase.cpp index 5dd569b9..47daab45 100644 --- a/kramv/KramViewerBase.cpp +++ b/kramv/KramViewerBase.cpp @@ -26,14 +26,14 @@ using namespace STL_NAMESPACE; // Writing out to rgba32 for sampling, but unorm formats like ASTC and RGBA8 // are still off and need to use the following. -float toSnorm8(float c) { return (255.0f / 127.0f) * c - (128.0f / 127.0f); } +float toSnorm8(float c) { return (255.0f / 127.0f) * c - (128.0f / 127.0f); } float2 toSnorm8(float2 c) { return (255.0f / 127.0f) * c - (128.0f / 127.0f); } float3 toSnorm8(float3 c) { return (255.0f / 127.0f) * c - (128.0f / 127.0f); } float4 toSnorm8(float4 c) { return (255.0f / 127.0f) * c - (128.0f / 127.0f); } -float4 toSnorm(float4 c) { return 2.0f * c - 1.0f; } +float4 toSnorm(float4 c) { return 2.0f * c - 1.0f; } -inline float4 toPremul(const float4 &c) +inline float4 toPremul(const float4& c) { // premul with a float4 cpremul = c; @@ -48,28 +48,28 @@ inline bool almost_equal_elements(float3 v, float tol) return (fabs(v.x - v.y) < tol) && (fabs(v.x - v.z) < tol); } -inline const float3x3& toFloat3x3(const float4x4 &m) { return (const float3x3 &)m; } +inline const float3x3& toFloat3x3(const float4x4& m) { return (const float3x3&)m; } -float4 inverseScaleSquared(const float4x4 &m) +float4 inverseScaleSquared(const float4x4& m) { float3 scaleSquared = float3m(length_squared(m.columns[0].xyz), length_squared(m.columns[1].xyz), length_squared(m.columns[2].xyz)); - + // if uniform, then set scaleSquared all to 1 if (almost_equal_elements(scaleSquared, 1e-5f)) { scaleSquared = float3m(1.0f); } - + // don't divide by 0 float3 invScaleSquared = - recip(SIMD_NAMESPACE::max(float3m(0.0001 * 0.0001), scaleSquared)); - + recip(SIMD_NAMESPACE::max(float3m(0.0001 * 0.0001), scaleSquared)); + // identify determinant here for flipping orientation // all shapes with negative determinant need orientation flipped for // backfacing and need to be grouned together if rendering with instancing float det = determinant(toFloat3x3(m)); - + return float4m(invScaleSquared, det); } @@ -79,7 +79,7 @@ static string filenameNoExtension(const char* filename) if (dotPosStr == nullptr) return filename; auto dotPos = dotPosStr - filename; - + // now chop off the extension string filenameNoExt = filename; return filenameNoExt.substr(0, dotPos); @@ -88,47 +88,48 @@ static string filenameNoExtension(const char* filename) static void findPossibleNormalMapFromAlbedoFilename(const char* filename, vector& normalFilenames) { normalFilenames.clear(); - + string filenameShort = filename; - + const char* ext = strrchr(filename, '.'); - + const char* dotPosStr = strrchr(filenameShort.c_str(), '.'); if (dotPosStr == nullptr) return; - + auto dotPos = dotPosStr - filenameShort.c_str(); - + // now chop off the extension filenameShort = filenameShort.substr(0, dotPos); - - const char* searches[] = { "-a", "-d", "_Color", "_baseColor" }; - + + const char* searches[] = {"-a", "-d", "_Color", "_baseColor"}; + for (uint32_t i = 0; i < ArrayCount(searches); ++i) { const char* search = searches[i]; if (endsWith(filenameShort, search)) { - filenameShort = filenameShort.substr(0, filenameShort.length()-strlen(search)); + filenameShort = filenameShort.substr(0, filenameShort.length() - strlen(search)); break; } } - - const char* suffixes[] = { "-n", "_normal", "_Normal" }; - + + const char* suffixes[] = {"-n", "_normal", "_Normal"}; + string normalFilename; for (uint32_t i = 0; i < ArrayCount(suffixes); ++i) { const char* suffix = suffixes[i]; - + // may need to try various names, and see if any exist normalFilename = filenameShort; normalFilename += suffix; normalFilename += ext; - + normalFilenames.push_back(normalFilename); } } // this aliases the existing string, so can't chop extension -inline const char* toFilenameShort(const char* filename) { +inline const char* toFilenameShort(const char* filename) +{ const char* filenameShort = strrchr(filename, '/'); if (filenameShort == nullptr) { filenameShort = filename; @@ -150,24 +151,27 @@ static const vector supportedModelExt = { #endif }; - -bool isSupportedModelFilename(const char* filename) { - for (const char* ext: supportedModelExt) { +bool isSupportedModelFilename(const char* filename) +{ + for (const char* ext : supportedModelExt) { if (endsWithExtension(filename, ext)) { return true; } } return false; } -bool isSupportedArchiveFilename(const char* filename) { +bool isSupportedArchiveFilename(const char* filename) +{ return endsWithExtension(filename, ".zip"); } -bool isSupportedJsonFilename(const char* filename) { +bool isSupportedJsonFilename(const char* filename) +{ return endsWith(filename, "-atlas.json"); } -bool isDirectory(const char* filename) { +bool isDirectory(const char* filename) +{ FileHelper fileHelper; return fileHelper.isDirectory(filename); } @@ -176,19 +180,19 @@ int32_t ShowSettings::totalChunks() const { int32_t one = 1; return std::max(one, faceCount) * - std::max(one, arrayCount) * - std::max(one, sliceCount); + std::max(one, arrayCount) * + std::max(one, sliceCount); } File::File(const char* name_, int32_t urlIndex_) -: name(name_), urlIndex(urlIndex_), nameShort(toFilenameShort(name_)) + : name(name_), urlIndex(urlIndex_), nameShort(toFilenameShort(name_)) { } -const char *ShowSettings::meshNumberName(uint32_t meshNumber_) const +const char* ShowSettings::meshNumberName(uint32_t meshNumber_) const { - const char *text = ""; - + const char* text = ""; + switch (meshNumber_) { case 0: text = "Plane"; @@ -208,14 +212,14 @@ const char *ShowSettings::meshNumberName(uint32_t meshNumber_) const default: break; } - + return text; } -const char *ShowSettings::meshNumberText() const +const char* ShowSettings::meshNumberText() const { - const char *text = ""; - + const char* text = ""; + switch (meshNumber) { case 0: text = "Shape Plane"; @@ -235,14 +239,14 @@ const char *ShowSettings::meshNumberText() const default: break; } - + return text; } -const char *ShowSettings::shapeChannelText() const +const char* ShowSettings::shapeChannelText() const { - const char *text = ""; - + const char* text = ""; + switch (shapeChannel) { case ShapeChannelNone: text = "Show Off"; @@ -272,14 +276,14 @@ const char *ShowSettings::shapeChannelText() const default: break; } - + return text; } -const char *ShowSettings::debugModeText() const +const char* ShowSettings::debugModeText() const { - const char *text = ""; - + const char* text = ""; + switch (debugMode) { case DebugModeNone: text = "Debug Off"; @@ -314,10 +318,10 @@ const char *ShowSettings::debugModeText() const return text; } -const char *ShowSettings::lightingModeText() const +const char* ShowSettings::lightingModeText() const { - const char *text = ""; - + const char* text = ""; + switch (lightingMode) { case LightingModeDiffuse: text = "Light Diffuse"; @@ -337,7 +341,7 @@ const char *ShowSettings::lightingModeText() const bool ShowSettings::isEyedropperFromDrawable() { return meshNumber > 0 || isPreview || isShowingAllLevelsAndMips || - shapeChannel > 0; + shapeChannel > 0; } void ShowSettings::advanceMeshNumber(bool decrement) @@ -350,7 +354,7 @@ void ShowSettings::advanceMeshNumber(bool decrement) else { number += 1; } - + meshNumber = number % numEnums; } @@ -364,9 +368,9 @@ void ShowSettings::advanceShapeChannel(bool decrement) else { mode += 1; } - + shapeChannel = (ShapeChannel)(mode % numEnums); - + // skip this channel for now, in ortho it's mostly pure white if (shapeChannel == ShapeChannelDepth) { advanceShapeChannel(decrement); @@ -383,7 +387,7 @@ void ShowSettings::advanceLightingMode(bool decrement) else { number += 1; } - + lightingMode = (LightingMode)(number % numEnums); } @@ -397,40 +401,40 @@ void ShowSettings::advanceDebugMode(bool decrement) else { mode += 1; } - + debugMode = (DebugMode)(mode % numEnums); - + MyMTLPixelFormat format = (MyMTLPixelFormat)originalFormat; bool isHdr = isHdrFormat(format); - + // DONE: work on skipping some of these based on image bool isAlpha = isAlphaFormat(format); bool isColor = isColorFormat(format); - + if (debugMode == DebugModeTransparent && (numChannels <= 3 || !isAlpha)) { advanceDebugMode(decrement); } - + // 2 channel textures don't really have color or grayscale pixels if (debugMode == DebugModeColor && (numChannels <= 2 || !isColor)) { advanceDebugMode(decrement); } - + if (debugMode == DebugModeGray && numChannels <= 2) { advanceDebugMode(decrement); } - + if (debugMode == DebugModeHDR && !isHdr) { advanceDebugMode(decrement); } - + // for 3 and for channel textures could skip these with more info about image // (hasColor) if (_showSettings->debugMode == DebugModeGray && !hasColor) // advanceDebugMode(isShiftKeyDown); - + bool isNormal = texContentType == TexContentTypeNormal; bool isSDF = texContentType == TexContentTypeSDF; - + // for normals show directions if (debugMode == DebugModePosX && !(isNormal || isSDF)) { advanceDebugMode(decrement); @@ -441,7 +445,7 @@ void ShowSettings::advanceDebugMode(bool decrement) if (debugMode == DebugModeCircleXY && !(isNormal)) { advanceDebugMode(decrement); } - + // TODO: have a clipping mode against a variable range too, only show pixels // within that range to help isolate problem pixels. Useful for depth, and // have auto-range scaling for it and hdr. make sure to ignore 0 or 1 for @@ -456,12 +460,11 @@ void ShowSettings::updateUVPreviewState() if (uvPreview < 1.0) uvPreview += uvPreviewStep; } - else - { + else { if (uvPreview > 0.0) uvPreview -= uvPreviewStep; } - + uvPreview = std::clamp(uvPreview, 0.0f, 1.0f); } } @@ -469,14 +472,14 @@ void ShowSettings::updateUVPreviewState() // This hides the uvView even when switchig back to 3d shape //uvPreview = 0.0; } - + // stop the frame update if (uvPreview == 0.0f || uvPreview == 1.0f) { uvPreviewFrames = 0; } } -void printChannels(string &tmp, const string &label, float4 c, +void printChannels(string& tmp, const string& label, float4 c, int32_t numChannels, bool isFloat, bool isSigned) { if (isFloat || isSigned) { @@ -499,7 +502,7 @@ void printChannels(string &tmp, const string &label, float4 c, else { // unorm data, 8-bit values displayed c *= 255.1f; - + switch (numChannels) { case 1: sprintf(tmp, "%s%.0f\n", label.c_str(), c.r); @@ -528,9 +531,9 @@ string ShowSettings::windowTitleString(const char* filename) const else { filenameShort += 1; } - + string title = "kramv - "; - + if (isModel) { title += formatTypeName(originalFormat); title += " - "; @@ -540,34 +543,45 @@ string ShowSettings::windowTitleString(const char* filename) const // was using subtitle, but that's macOS 11.0 feature. title += formatTypeName(originalFormat); title += " - "; - + // identify what we think the content type is const char* typeText = ""; - switch(texContentType) { - case TexContentTypeAlbedo: typeText = "a"; break; - case TexContentTypeNormal: typeText = "n"; break; - case TexContentTypeAO: typeText = "ao"; break; - case TexContentTypeMetallicRoughness: typeText = "mr"; break; - case TexContentTypeSDF: typeText = "sdf"; break; - case TexContentTypeHeight: typeText = "h"; break; - case TexContentTypeUnknown: typeText = ""; break; + switch (texContentType) { + case TexContentTypeAlbedo: + typeText = "a"; + break; + case TexContentTypeNormal: + typeText = "n"; + break; + case TexContentTypeAO: + typeText = "ao"; + break; + case TexContentTypeMetallicRoughness: + typeText = "mr"; + break; + case TexContentTypeSDF: + typeText = "sdf"; + break; + case TexContentTypeHeight: + typeText = "h"; + break; + case TexContentTypeUnknown: + typeText = ""; + break; } title += typeText; // add some info about the texture to avoid needing to go to info // srgb src would be useful too. if (texContentType == TexContentTypeAlbedo && isPremul) { title += ",p"; - } title += " - "; title += filenameShort; } - + return title; } - - //-------------------------------- // Want to avoid Apple libs for things that have C++ equivalents. @@ -576,14 +590,14 @@ Data::Data() { #if USE_SIMDLIB && 1 vecf vfmt; - + // want to see the simd config KLOGI("SIMDK", "%s", vfmt.simd_configs().c_str()); KLOGI("SIMDK", "%s", vfmt.simd_alignments().c_str()); #endif - + _showSettings = new ShowSettings(); - + _textSlots.resize(kTextSlotCount); } Data::~Data() @@ -591,7 +605,8 @@ Data::~Data() delete _showSettings; } -void Data::clearAtlas() { +void Data::clearAtlas() +{ _showSettings->atlas.clear(); _showSettings->lastAtlas = nullptr; } @@ -601,50 +616,50 @@ void Data::clearAtlas() { bool Data::loadAtlasFile(const char* filename) { using namespace simdjson; - + clearAtlas(); - + Timer timer; - + // can just mmap the json MmapHelper mmap; if (!mmap.open(filename)) { KLOGE("kramv", "Failed to open %s", filename); return false; } - + ondemand::parser parser; - + padded_string json((const char*)mmap.data(), mmap.dataLength()); auto atlasProps = parser.iterate(json); - + // can we get at memory use numbers to do the parse? KLOGI("kramv", "parsed %.0f KB of json in %.3fms", (double)mmap.dataLength() / 1024.0, timer.timeElapsedMillis()); - + // Can use hover or a show all on these entries and names. // Draw names on screen using system text in the upper left corner if 1 // if showing all, then show names across each mip level. May want to // snap to pixels on each mip level so can see overlap. - + { std::vector values; //string_view atlasName = atlasProps["name"].get_string().value_unsafe(); - + uint64_t width = atlasProps["width"].get_uint64().value_unsafe(); uint64_t height = atlasProps["height"].get_uint64().value_unsafe(); - + uint64_t slice = atlasProps["slice"].get_uint64().value_unsafe(); - + float uPad = 0.0f; float vPad = 0.0f; - + if (atlasProps["paduv"].get_array().error() != NO_SUCH_FIELD) { values.clear(); for (auto value : atlasProps["paduv"]) values.push_back(value.get_double().value_unsafe()); - + uPad = values[0]; vPad = values[1]; } @@ -652,29 +667,27 @@ bool Data::loadAtlasFile(const char* filename) values.clear(); for (auto value : atlasProps["padpx"]) values.push_back(value.get_double().value_unsafe()); - + uPad = values[0]; vPad = values[1]; - + uPad /= width; vPad /= height; } - - for (auto regionProps: atlasProps["regions"]) - { + + for (auto regionProps : atlasProps["regions"]) { string_view name = regionProps["name"].get_string().value_unsafe(); - + float x = 0.0f; float y = 0.0f; float w = 0.0f; float h = 0.0f; - - if (regionProps["ruv"].get_array().error() != NO_SUCH_FIELD) - { + + if (regionProps["ruv"].get_array().error() != NO_SUCH_FIELD) { values.clear(); for (auto value : regionProps["ruv"]) values.push_back(value.get_double().value_unsafe()); - + // Note: could convert pixel and mip0 size to uv. // normalized uv make these easier to draw across all mips x = values[0]; @@ -682,37 +695,36 @@ bool Data::loadAtlasFile(const char* filename) w = values[2]; h = values[3]; } - else if (regionProps["rpx"].get_array().error() != NO_SUCH_FIELD) - { + else if (regionProps["rpx"].get_array().error() != NO_SUCH_FIELD) { values.clear(); for (auto value : regionProps["rpx"]) values.push_back(value.get_double().value_unsafe()); - + x = values[0]; y = values[1]; w = values[2]; h = values[3]; - + // normalize to uv using the width/height x /= width; y /= height; w /= width; h /= height; } - + const char* verticalProp = "f"; // regionProps["rot"]; bool isVertical = verticalProp && verticalProp[0] == 't'; - - Atlas atlas = {(string)name, x,y, w,h, uPad,vPad, isVertical, (uint32_t)slice}; + + Atlas atlas = {(string)name, x, y, w, h, uPad, vPad, isVertical, (uint32_t)slice}; _showSettings->atlas.emplace_back(std::move(atlas)); } } - + // TODO: also need to be able to bring in vector shapes // maybe from svg or files written out from figma or photoshop. // Can triangulate those, and use xatlas to pack those. // Also xatlas can flatten out a 3d model into a chart. - + return true; } @@ -721,16 +733,16 @@ bool Data::loadAtlasFile(const char* filename) bool Data::loadAtlasFile(const char* filename) { using namespace json11; - + clearAtlas(); - + // can just mmap the json MmapHelper mmap; if (!mmap.open(filename)) { KLOGE("kramv", "Failed to open %s", filename); return false; } - + Timer timer; JsonReader jsonReader; const Json* root = jsonReader.read((const char*)mmap.data(), mmap.dataLength()); @@ -740,37 +752,36 @@ bool Data::loadAtlasFile(const char* filename) return false; } timer.stop(); - + KLOGI("kramv", "parsed %.0f KB of json using %.0f KB of memory in %.3fms", (double)mmap.dataLength() / 1024.0, (double)jsonReader.memoryUse() / 1024.0, timer.timeElapsedMillis()); - + const Json& atlasProps = (*root)[(uint32_t)0]; - + // Can use hover or a show all on these entries and names. // Draw names on screen using system text in the upper left corner if 1 // if showing all, then show names across each mip level. May want to // snap to pixels on each mip level so can see overlap. - - + { std::vector values; // string_view atlasName = atlasProps["name"].get_string().value_unsafe(); - + int width = atlasProps["width"].int_value(); int height = atlasProps["height"].int_value(); - + int slice = atlasProps["slice"].int_value(); - + float uPad = 0.0f; float vPad = 0.0f; - + if (atlasProps["paduv"].is_array()) { values.clear(); for (const auto& value : atlasProps["paduv"]) values.push_back(value.number_value()); - + uPad = values[0]; vPad = values[1]; } @@ -778,30 +789,28 @@ bool Data::loadAtlasFile(const char* filename) values.clear(); for (const auto& value : atlasProps["padpx"]) values.push_back(value.number_value()); - + uPad = values[0]; vPad = values[1]; - + uPad /= width; vPad /= height; } - + string decodedName; - for (auto regionProps: atlasProps["regions"]) - { + for (auto regionProps : atlasProps["regions"]) { const char* name = regionProps["name"].string_value(decodedName); - + float x = 0.0f; float y = 0.0f; float w = 0.0f; float h = 0.0f; - - if (regionProps["ruv"].is_array()) - { + + if (regionProps["ruv"].is_array()) { values.clear(); for (auto value : regionProps["ruv"]) values.push_back(value.number_value()); - + // Note: could convert pixel and mip0 size to uv. // normalized uv make these easier to draw across all mips x = values[0]; @@ -809,60 +818,59 @@ bool Data::loadAtlasFile(const char* filename) w = values[2]; h = values[3]; } - else if (regionProps["rpx"].is_array()) - { + else if (regionProps["rpx"].is_array()) { values.clear(); for (auto value : regionProps["rpx"]) values.push_back(value.number_value()); - + x = values[0]; y = values[1]; w = values[2]; h = values[3]; - + // normalize to uv using the width/height x /= width; y /= height; w /= width; h /= height; } - + const char* verticalProp = "f"; // regionProps["rot"]; bool isVertical = verticalProp && verticalProp[0] == 't'; - - Atlas atlas = {name, x,y, w,h, uPad,vPad, isVertical, (uint32_t)slice}; + + Atlas atlas = {name, x, y, w, h, uPad, vPad, isVertical, (uint32_t)slice}; _showSettings->atlas.emplace_back(std::move(atlas)); } } - + // TODO: also need to be able to bring in vector shapes // maybe from svg or files written out from figma or photoshop. // Can triangulate those, and use xatlas to pack those. // Also xatlas can flatten out a 3d model into a chart. - + return true; } #endif // opens archive -bool Data::openArchive(const char * zipFilename, int32_t urlIndex) +bool Data::openArchive(const char* zipFilename, int32_t urlIndex) { // grow the array, ptrs so that existing mmaps aren't destroyed if (urlIndex >= _containers.size()) { _containers.resize(urlIndex + 1, nullptr); } - + if (_containers[urlIndex] == nullptr) _containers[urlIndex] = new FileContainer; - + FileContainer& container = *_containers[urlIndex]; MmapHelper& zipMmap = container.zipMmap; ZipHelper& zip = container.zip; - + // close any previous zip zipMmap.close(); - + // open the mmap again if (!zipMmap.open(zipFilename)) { return false; @@ -878,116 +886,119 @@ bool Data::listFilesInArchive(int32_t urlIndex) { FileContainer& container = *_containers[urlIndex]; ZipHelper& zip = container.zip; - + // filter out unsupported extensions vector extensions = { - ".ktx", ".ktx2", ".png", // textures + ".ktx", ".ktx2", ".png", // textures ".dds", ".DDS" // allow caps for dds #if USE_GLTF - // TODO: can't support these until have a loader from memory block - // GLTFAsset requires a URL. - //, ".glb", ".gltf" // models + // TODO: can't support these until have a loader from memory block + // GLTFAsset requires a URL. + //, ".glb", ".gltf" // models #endif #if USE_USD - , ".usd", ".usda", ".usb" + , + ".usd", ".usda", ".usb" #endif }; - + container.zip.filterExtensions(extensions); - + // don't switch to empty archive if (zip.zipEntrys().empty()) { return false; } - - for (const auto& entry: zip.zipEntrys()) { + + for (const auto& entry : zip.zipEntrys()) { _files.emplace_back(File(entry.filename, urlIndex)); } - + return true; } // TODO: can simplify by storing counterpart id when file list is created -bool Data::hasCounterpart(bool increment) { +bool Data::hasCounterpart(bool increment) +{ if (_files.size() <= 1) { return false; } - + const File& file = _files[_fileIndex]; string currentFilename = filenameNoExtension(file.nameShort.c_str()); - + uint32_t nextFileIndex = _fileIndex; - + size_t numEntries = _files.size(); if (increment) nextFileIndex++; else - nextFileIndex += numEntries - 1; // back 1 - + nextFileIndex += numEntries - 1; // back 1 + nextFileIndex = nextFileIndex % numEntries; - + const File& nextFile = _files[nextFileIndex]; string nextFilename = filenameNoExtension(nextFile.nameShort.c_str()); - + // if short name matches (no ext) then it's a counterpart if (currentFilename != nextFilename) return false; - + return true; } -bool Data::advanceCounterpart(bool increment) { - +bool Data::advanceCounterpart(bool increment) +{ if (_files.size() <= 1) { return false; } - + // see if file has counterparts const File& file = _files[_fileIndex]; string currentFilename = filenameNoExtension(file.nameShort.c_str()); - + // TODO: this should cycle through only the counterparts uint32_t nextFileIndex = _fileIndex; - + size_t numEntries = _files.size(); if (increment) nextFileIndex++; else - nextFileIndex += numEntries - 1; // back 1 - + nextFileIndex += numEntries - 1; // back 1 + nextFileIndex = nextFileIndex % numEntries; - + const File& nextFile = _files[nextFileIndex]; string nextFilename = filenameNoExtension(nextFile.nameShort.c_str()); - + if (currentFilename != nextFilename) return false; - + _fileIndex = nextFileIndex; - + return _delegate.loadFile(true); } -bool Data::advanceFile(bool increment) { +bool Data::advanceFile(bool increment) +{ if (_files.empty()) { return false; } - + size_t numEntries = _files.size(); if (increment) _fileIndex++; else - _fileIndex += numEntries - 1; // back 1 - + _fileIndex += numEntries - 1; // back 1 + _fileIndex = _fileIndex % numEntries; - + return _delegate.loadFile(true); } bool Data::findFilename(const string& filename) { bool isFound = false; - + // linear search for (const auto& search : _files) { if (search.name == filename) { @@ -1001,7 +1012,7 @@ bool Data::findFilename(const string& filename) bool Data::findFilenameShort(const string& filename) { bool isFound = false; - + // linear search for (const auto& search : _files) { if (search.nameShort == filename) { @@ -1033,20 +1044,20 @@ const Atlas* Data::findAtlasAtUV(float2 pt) { if (_showSettings->atlas.empty()) return nullptr; if (_showSettings->imageBoundsX == 0) return nullptr; - + const Atlas* atlas = nullptr; - + // Note: rects are in uv - + // This might need to become an atlas array index instead of ptr const Atlas* lastAtlas = _showSettings->lastAtlas; - + if (lastAtlas) { if (isPtInRect(pt, lastAtlas->rect())) { atlas = lastAtlas; } } - + if (!atlas) { // linear search for (const auto& search : _showSettings->atlas) { @@ -1055,20 +1066,19 @@ const Atlas* Data::findAtlasAtUV(float2 pt) break; } } - + _showSettings->lastAtlas = atlas; } - + return atlas; } - bool Data::isArchive() const { //NSArray* urls_ = (NSArray*)_delegate._urls; //NSURL* url = urls_[_files[_fileIndex].urlIndex]; //const char* filename = url.fileSystemRepresentation; - + string filename = _urls[_files[_fileIndex].urlIndex]; return isSupportedArchiveFilename(filename.c_str()); } @@ -1084,77 +1094,77 @@ bool Data::loadFile() if (isArchive()) { return loadFileFromArchive(); } - + // now lookup the filename and data at that entry const File& file = _files[_fileIndex]; const char* filename = file.name.c_str(); - + string fullFilename = filename; auto timestamp = FileHelper::modificationTimestamp(filename); - + bool isTextureChanged = _showSettings->isFileChanged(filename, timestamp); if (!isTextureChanged) { return true; } - + #if USE_GLTF || USE_USD bool isModel = isSupportedModelFilename(filename); if (isModel) { bool success = _delegate.loadModelFile(filename); - + if (success) { // store the filename _showSettings->lastFilename = filename; _showSettings->lastTimestamp = timestamp; } - + return success; } #endif - + // have already filtered filenames out, so this should never get hit if (!isSupportedFilename(filename)) { return false; } - + // Note: better to extract from filename instead of root of folder dropped // or just keep displaying full path of filename. - + _archiveName.clear(); - + vector possibleNormalFilenames; string normalFilename; bool hasNormal = false; - + TexContentType texContentType = findContentTypeFromFilename(filename); if (texContentType == TexContentTypeAlbedo) { findPossibleNormalMapFromAlbedoFilename(filename, possibleNormalFilenames); - - for (const auto& name: possibleNormalFilenames) { + + for (const auto& name : possibleNormalFilenames) { hasNormal = findFilename(name); - + if (hasNormal) { normalFilename = name; break; } } } - + // see if there is an atlas file too, and load the rectangles for preview // note sidecar atlas files are a pain to view with a sandbox, may want to // splice into ktx/ktx2 files, but no good metadata for png/dds. _showSettings->atlas.clear(); - + string atlasFilename = filenameNoExtension(filename); bool hasAtlas = false; - + // replace -a, -d, with -atlas.json const char* dashPosStr = strrchr(atlasFilename.c_str(), '-'); if (dashPosStr != nullptr) { atlasFilename = atlasFilename.substr(0, dashPosStr - atlasFilename.c_str()); } atlasFilename += "-atlas.json"; - if ( findFilename(atlasFilename.c_str())) { + if (findFilename(atlasFilename.c_str())) { if (loadAtlasFile(atlasFilename.c_str())) { hasAtlas = true; } @@ -1163,20 +1173,20 @@ bool Data::loadFile() clearAtlas(); atlasFilename.clear(); } - + // If it's a compressed file, then set a diff target if a corresponding png // is found. Eventually see if a src dds/ktx/ktx2 exists. Want to stop // using png as source images. Note png don't have custom mips, unless // flattened to one image. So have to fabricate mips here. KTXImage // can already load up striped png into slices, etc. - + bool hasDiff = false; string diffFilename; - + if (!isPNGFilename(filename)) { diffFilename = filenameNoExtension(filename); diffFilename += ".png"; - + diffFilename = toFilenameShort(diffFilename.c_str()); if (diffFilename != filename) { const File* diffFile = findFileShort(diffFilename.c_str()); @@ -1185,44 +1195,41 @@ bool Data::loadFile() hasDiff = true; } } - + if (!hasDiff) diffFilename.clear(); } - + //------------------------------- - + KTXImage image; KTXImageData imageDataKTX; - + KTXImage imageNormal; KTXImageData imageNormalDataKTX; - + KTXImage imageDiff; KTXImageData imageDiffDataKTX; - + // this requires decode and conversion to RGBA8u if (!imageDataKTX.open(fullFilename.c_str(), image)) { return false; } - + // load up the diff, but would prefer to defer this if (hasDiff && !imageDiffDataKTX.open(diffFilename.c_str(), imageDiff)) { hasDiff = false; - + // TODO: could also compare dimensions to see if same - + if (imageDiff.textureType == image.textureType && - (imageDiff.textureType == MyMTLTextureType2D) ) - { - + (imageDiff.textureType == MyMTLTextureType2D)) { } - else - { + else { hasDiff = false; } } - + if (hasNormal && imageNormalDataKTX.open(normalFilename.c_str(), imageNormal)) { // shaders only pull from albedo + normal on these texture types @@ -1235,22 +1242,21 @@ bool Data::loadFile() hasNormal = false; } } - + //--------------------------------- - + if (!_delegate.loadTextureFromImage(fullFilename.c_str(), (double)timestamp, - image, - hasNormal ? &imageNormal : nullptr, - hasDiff ? &imageDiff : nullptr, - false)) - { + image, + hasNormal ? &imageNormal : nullptr, + hasDiff ? &imageDiff : nullptr, + false)) { return false; } - + // store the filename _showSettings->lastFilename = filename; _showSettings->lastTimestamp = timestamp; - + return true; } @@ -1260,7 +1266,7 @@ bool Data::loadFileFromArchive() const File& file = _files[_fileIndex]; FileContainer& container = *_containers[file.urlIndex]; ZipHelper& zip = container.zip; - + const char* filename = file.name.c_str(); const auto* entry = zip.zipEntry(filename); string fullFilename = entry->filename; @@ -1270,20 +1276,20 @@ bool Data::loadFileFromArchive() if (!isTextureChanged) { return true; } - -// TODO: don't have a version which loads gltf model from memory block -// bool isModel = isSupportedModelFilename(filename); -// if (isModel) -// return [self loadModelFile:filename]; - + + // TODO: don't have a version which loads gltf model from memory block + // bool isModel = isSupportedModelFilename(filename); + // if (isModel) + // return [self loadModelFile:filename]; + //-------- - + if (!isSupportedFilename(filename)) { return false; } - + KPERFT("loadFileFromArchive"); - + const uint8_t* imageData = nullptr; uint64_t imageDataLength = 0; @@ -1292,66 +1298,65 @@ bool Data::loadFileFromArchive() // zip that compressed png files. So then the raw ptr/size // needs deflated. bool isFileUncompressed = entry->compressedSize == entry->uncompressedSize; - + vector bufferForImage; - + if (isFileUncompressed) { KPERFT("ZipExtractRaw"); - + // search for main file - can be albedo or normal if (!zip.extractRaw(filename, &imageData, imageDataLength)) { return false; } - } else { KPERFT("ZipExtract"); - + // need to decompress first if (!zip.extract(filename, bufferForImage)) { return false; } - + imageData = bufferForImage.data(); imageDataLength = bufferForImage.size(); } - + vector bufferForNormal; - + const uint8_t* imageNormalData = nullptr; uint64_t imageNormalDataLength = 0; - + string normalFilename; bool hasNormal = false; vector normalFilenames; - + TexContentType texContentType = findContentTypeFromFilename(filename); if (texContentType == TexContentTypeAlbedo) { findPossibleNormalMapFromAlbedoFilename(filename, normalFilenames); - - for (const auto& name: normalFilenames) { + + for (const auto& name : normalFilenames) { const auto* normalEntry = zip.zipEntry(name.c_str()); - + hasNormal = normalEntry != nullptr; if (hasNormal) { normalFilename = name; - + bool isNormalUncompressed = normalEntry->compressedSize == normalEntry->uncompressedSize; - + if (isNormalUncompressed) { KPERFT("ZipExtractRawNormal"); - + zip.extractRaw(name.c_str(), &imageNormalData, imageNormalDataLength); } else { KPERFT("ZipExtractNormal"); - + // need to decompress first if (!zip.extract(filename, bufferForNormal)) { return false; } - + imageNormalData = bufferForNormal.data(); imageNormalDataLength = bufferForNormal.size(); } @@ -1371,144 +1376,134 @@ bool Data::loadFileFromArchive() KTXImageData imageNormalDataKTX; // TODO: do imageDiff here? - + KPERFT_START(1, "KTXOpen"); - + if (!imageDataKTX.open(imageData, imageDataLength, image)) { return false; } KPERFT_STOP(1); - - + if (hasNormal) { KPERFT("KTXOpenNormal"); - + if (imageNormalDataKTX.open( - imageNormalData, imageNormalDataLength, imageNormal)) { - // shaders only pull from albedo + normal on these texture types - if (imageNormal.textureType == image.textureType && - (imageNormal.textureType == MyMTLTextureType2D || - imageNormal.textureType == MyMTLTextureType2DArray)) { - // hasNormal = true; - } - else { - hasNormal = false; - } + imageNormalData, imageNormalDataLength, imageNormal)) { + // shaders only pull from albedo + normal on these texture types + if (imageNormal.textureType == image.textureType && + (imageNormal.textureType == MyMTLTextureType2D || + imageNormal.textureType == MyMTLTextureType2DArray)) { + // hasNormal = true; } + else { + hasNormal = false; + } + } } - //--------------------------------- - + KPERFT_START(3, "KTXLoad"); - + if (!_delegate.loadTextureFromImage(fullFilename.c_str(), (double)timestamp, image, hasNormal ? &imageNormal : nullptr, nullptr, true)) { return false; } KPERFT_STOP(3); - + //--------------------------------- - + string archiveURL = _urls[file.urlIndex]; _archiveName = toFilenameShort(archiveURL.c_str()); - + return true; } - - - void Data::loadFilesFromUrls(vector& urls, bool skipSubdirs) { // Using a member for archives, so limited to one archive in a drop // but that's probably okay for now. Add a separate array of open // archives if want > 1. - + // copy the existing files list string existingFilename; if (_fileIndex < (int32_t)_files.size()) existingFilename = _files[_fileIndex].name; - + // Fill this out again _files.clear(); - + // clear pointers - for (FileContainer* container: _containers) + for (FileContainer* container : _containers) delete container; _containers.clear(); - + // this will flatten the list int32_t urlIndex = 0; - + vector urlsExtracted; - - for (const auto& url: urls) { + + for (const auto& url : urls) { // These will flatten out to a list of files const char* filename = url.c_str(); - + if (isSupportedArchiveFilename(filename) && openArchive(filename, urlIndex) && - listFilesInArchive(urlIndex)) - { + listFilesInArchive(urlIndex)) { urlsExtracted.push_back(filename); urlIndex++; } else if (isDirectory(filename)) { - // this first loads only models, then textures if only those listFilesInFolder(url, urlIndex, skipSubdirs); - + // could skip if nothing added urlsExtracted.push_back(url); urlIndex++; - + // handle archives within folder vector archiveFiles; listArchivesInFolder(url, archiveFiles, skipSubdirs); - - for (const File& archiveFile: archiveFiles) { + + for (const File& archiveFile : archiveFiles) { const char* archiveFilename = archiveFile.name.c_str(); if (openArchive(archiveFilename, urlIndex) && listFilesInArchive(urlIndex)) { - //NSURL* urlArchive = [NSURL fileURLWithPath:[NSString stringWithUTF8String:archiveFilename]]; //[urlsExtracted addObject:urlArchive]; urlsExtracted.push_back(archiveFilename); urlIndex++; } - } } else if (isSupportedFilename(filename) #if USE_GLTF || isSupportedModelFilename(filename) #endif - ) { + ) { _files.emplace_back(File(filename, urlIndex)); - + //[urlsExtracted addObject:url]; urlsExtracted.push_back(filename); urlIndex++; } else if (isSupportedJsonFilename(filename)) { _files.emplace_back(File(filename, urlIndex)); - + //[urlsExtracted addObject:url]; urlsExtracted.push_back(filename); urlIndex++; } - } - + // sort them by short filename #if USE_EASTL STL_NAMESPACE::quick_sort(_files.begin(), _files.end()); #else STL_NAMESPACE::sort(_files.begin(), _files.end()); #endif - + // preserve filename before load, and restore that index, by finding // that name in refreshed folder list _fileIndex = 0; @@ -1520,7 +1515,7 @@ void Data::loadFilesFromUrls(vector& urls, bool skipSubdirs) } } } - + // preserve old file selection _urls = urlsExtracted; } @@ -1533,7 +1528,7 @@ void Data::showEyedropperData(const float2& uv) float4 c = _showSettings->textureResult; int32_t x = _showSettings->textureResultX; int32_t y = _showSettings->textureResultY; - + // DONE: use these to format the text MyMTLPixelFormat format = _showSettings->originalFormat; bool isSrgb = isSrgbFormat(format); @@ -1557,18 +1552,18 @@ void Data::showEyedropperData(const float2& uv) // interpret based on shapeChannel, debugMode, etc switch (_showSettings->shapeChannel) { case ShapeChannelDepth: - isSigned = false; // using fract on uv + isSigned = false; // using fract on uv isValue = true; isFloat = true; numChannels = 1; break; case ShapeChannelUV0: - isSigned = false; // using fract on uv + isSigned = false; // using fract on uv isValue = true; isFloat = true; - numChannels = 2; // TODO: fix for 3d uvw + numChannels = 2; // TODO: fix for 3d uvw break; case ShapeChannelFaceNormal: @@ -1597,7 +1592,7 @@ void Data::showEyedropperData(const float2& uv) } // TODO: indicate px, mip, etc (f.e. showAll) - + // debug mode // preview vs. not @@ -1606,7 +1601,6 @@ void Data::showEyedropperData(const float2& uv) // this will be out of sync with gpu eval, so may want to only display px // from returned lookup this will always be a linear color - // show uv, so can relate to gpu coordinates stored in geometry and find // atlas areas append_sprintf(text, "uv:%0.3f %0.3f\n", @@ -1747,12 +1741,12 @@ void Data::showEyedropperData(const float2& uv) // TODO: Stuff these on clipboard with a click, or use cmd+C? } -void Data::setEyedropperText(const char * text) +void Data::setEyedropperText(const char* text) { setTextSlot(kTextSlotEyedropper, text); } -void Data::setAtlasText(const char * text) +void Data::setAtlasText(const char* text) { setTextSlot(kTextSlotAtlas, text); } @@ -1763,18 +1757,16 @@ string Data::textFromSlots(bool isFileListHidden) const string text = _textSlots[kTextSlotHud]; if (!text.empty() && text.back() != '\n') text += "\n"; - + // don't show eyedropper text with table up, it's many lines and overlaps - if (!isFileListHidden) - { + if (!isFileListHidden) { text += _textSlots[kTextSlotEyedropper]; if (!text.empty() && text.back() != '\n') text += "\n"; - + text += _textSlots[kTextSlotAtlas]; } - - + return text; } @@ -1798,19 +1790,19 @@ void Data::updateUIAfterLoad() bool isMipHidden = _showSettings->mipCount <= 1; bool isJumpToNextHidden = _files.size() <= 1; - + bool isJumpToCounterpartHidden = true; bool isJumpToPrevCounterpartHidden = true; - - if ( _files.size() > 1) { + + if (_files.size() > 1) { isJumpToCounterpartHidden = !hasCounterpart(true); - isJumpToPrevCounterpartHidden = !hasCounterpart(false); + isJumpToPrevCounterpartHidden = !hasCounterpart(false); } - + bool isRedHidden = _showSettings->numChannels == 0; // models don't show rgba bool isGreenHidden = _showSettings->numChannels <= 1; bool isBlueHidden = _showSettings->numChannels <= 2 && - _showSettings->texContentType != TexContentTypeNormal; // reconstruct z = b on normals + _showSettings->texContentType != TexContentTypeNormal; // reconstruct z = b on normals // TODO: also need a hasAlpha for pixels, since many compressed formats like // ASTC always have 4 channels but internally store R,RG01,... etc. Can get @@ -1828,7 +1820,7 @@ void Data::updateUIAfterLoad() bool isSignedHidden = !isSignedFormat(_showSettings->originalFormat); bool isPlayHidden = !_showSettings->isModel; // only for models - + bool isDiffHidden = false; // only for images if (!_showSettings->isModel && _showSettings->hasDiffTexture) { isDiffHidden = false; @@ -1838,28 +1830,28 @@ void Data::updateUIAfterLoad() _actionFace->setHidden(isFaceSliceHidden); _actionMip->setHidden(isMipHidden); _actionShowAll->setHidden(isShowAllHidden); - + _actionDiff->setHidden(isDiffHidden); _actionItem->setHidden(isJumpToNextHidden); _actionPrevItem->setHidden(isJumpToNextHidden); - + _actionCounterpart->setHidden(isJumpToCounterpartHidden); _actionPrevCounterpart->setHidden(isJumpToPrevCounterpartHidden); - + _actionR->setHidden(isRedHidden); _actionG->setHidden(isGreenHidden); _actionB->setHidden(isBlueHidden); _actionA->setHidden(isAlphaHidden); - + _actionPremul->setHidden(isPremulHidden); _actionSigned->setHidden(isSignedHidden); _actionChecker->setHidden(isCheckerboardHidden); - + // only allow srgb to be disabled, not toggle on if off at load MyMTLPixelFormat format = _showSettings->originalFormat; bool isSrgb = isSrgbFormat(format); _actionSrgb->setHidden(!isSrgb); - + // also need to call after each toggle updateUIControlState(); } @@ -1869,7 +1861,7 @@ void Data::updateUIControlState() // there is also mixed state, but not using that auto On = true; auto Off = false; - + #define toState(x) (x) ? On : Off auto showAllState = toState(_showSettings->isShowingAllLevelsAndMips); @@ -1881,8 +1873,8 @@ void Data::updateUIControlState() auto wrapState = toState(_showSettings->isWrap); auto debugState = toState(_showSettings->debugMode != DebugModeNone); auto hudState = toState(_showSettings->isHudShown); - - TextureChannels &channels = _showSettings->channels; + + TextureChannels& channels = _showSettings->channels; auto redState = toState(channels == TextureChannels::ModeR001); auto greenState = toState(channels == TextureChannels::Mode0G01); @@ -1905,36 +1897,36 @@ void Data::updateUIControlState() auto verticalState = toState(_showSettings->isVerticalUI); auto uiState = toState(_showSettings->isHideUI); auto diffState = toState(_showSettings->isDiff && _showSettings->hasDiffTexture); - + auto srgbState = toState(_showSettings->isSRGBShown); auto perfState = toState(_showSettings->isPerf); - + _actionVertical->setHighlight(verticalState); - + // TODO: pass boolean, and change in the call _actionPlay->setHighlight(playState); _actionHelp->setHighlight(Off); _actionInfo->setHighlight(Off); _actionHud->setHighlight(hudState); - + _actionArray->setHighlight(arrayState); _actionFace->setHighlight(faceState); _actionMip->setHighlight(mipState); - + // these never show check state _actionItem->setHighlight(Off); _actionPrevItem->setHighlight(Off); - + _actionCounterpart->setHighlight(Off); _actionPrevCounterpart->setHighlight(Off); - + _actionHideUI->setHighlight(uiState); // note below button always off, menu has state - + _actionR->setHighlight(redState); _actionG->setHighlight(greenState); _actionB->setHighlight(blueState); _actionA->setHighlight(alphaState); - + _actionShowAll->setHighlight(showAllState); _actionPreview->setHighlight(previewState); _actionDiff->setHighlight(diffState); @@ -1945,11 +1937,11 @@ void Data::updateUIControlState() _actionGrid->setHighlight(gridState); _actionDebug->setHighlight(debugState); _actionTangent->setHighlight(tangentState); - + _actionPremul->setHighlight(premulState); _actionSigned->setHighlight(signedState); _actionChecker->setHighlight(checkerboardState); - + _actionSrgb->setHighlight(srgbState); _actionPerf->setHighlight(perfState); } @@ -1960,42 +1952,42 @@ void Data::updateUIControlState() const Action* Data::actionFromMenu(kram_id menuItem) const { const Action* action = nullptr; - - for (const auto& search: _actions) { + + for (const auto& search : _actions) { if (search.menuItem == menuItem) { action = &search; break; } } - + return action; } const Action* Data::actionFromButton(kram_id button) const { const Action* action = nullptr; - - for (const auto& search: _actions) { + + for (const auto& search : _actions) { if (search.button == button) { action = &search; break; } } - + return action; } const Action* Data::actionFromKey(uint32_t keyCode) const { const Action* action = nullptr; - - for (const auto& search: _actions) { + + for (const auto& search : _actions) { if (search.keyCode == keyCode) { action = &search; break; } } - + return action; } @@ -2030,7 +2022,7 @@ void Data::setFailedText(const string& filename, string& text) // This doesn't advance with failure //string filename = _showSettings->lastFilename; - + text += toFilenameShort(filename.c_str()); // archives and file systems have folders, split that off @@ -2049,7 +2041,6 @@ void Data::setFailedText(const string& filename, string& text) text += " from archive "; text += _archiveName; } - } void Data::initActions() @@ -2066,14 +2057,14 @@ void Data::initActions() Action("D", "Debug", Key::D), Action("G", "Grid", Key::G), Action("B", "Checkerboard", Key::B), - + Action("", "", Key::A), // sep Action("P", "Preview", Key::P), Action("W", "Wrap", Key::W), Action("8", "Premul", Key::Num8), Action("7", "Signed", Key::Num7), - + Action("", "", Key::A), // sep Action("A", "Show All", Key::A), @@ -2082,12 +2073,12 @@ void Data::initActions() Action("Y", "Array", Key::Y), Action("9", "Srgb", Key::Num9), Action("5", "Perf", Key::Num5), // really a debug action - + Action("↑", "Prev Item", Key::UpArrow), Action("↓", "Next Item", Key::DownArrow), Action("←", "Prev Counterpart", Key::LeftArrow), Action("→", "Next Counterpart", Key::RightArrow), - + Action("R", "Reload", Key::R), Action("0", "Fit", Key::Num0), @@ -2108,7 +2099,7 @@ void Data::initActions() Action("3", "Blue", Key::Num3), Action("4", "Alpha", Key::Num4), }; - + // These have to be in same order as above. May want to go back to search for text above. Action** actionPtrs[] = { &_actionHelp, @@ -2116,39 +2107,39 @@ void Data::initActions() &_actionHud, &_actionHideUI, &_actionVertical, - + &_actionDiff, &_actionDebug, &_actionGrid, &_actionChecker, - + &_actionPreview, &_actionWrap, &_actionPremul, &_actionSigned, - + &_actionShowAll, &_actionMip, &_actionFace, &_actionArray, &_actionSrgb, &_actionPerf, - + &_actionPrevItem, &_actionItem, &_actionPrevCounterpart, &_actionCounterpart, - + &_actionReload, &_actionFit, - + &_actionPlay, &_actionShapeUVPreview, &_actionShapeMesh, &_actionShapeChannel, &_actionLighting, &_actionTangent, - + &_actionR, &_actionG, &_actionB, @@ -2156,7 +2147,7 @@ void Data::initActions() }; uint32_t numActions = ArrayCount(actions); - + // copy all of them to a vector, and then assign the action ptrs for (int32_t i = 0; i < numActions; ++i) { Action& action = actions[i]; @@ -2168,10 +2159,10 @@ void Data::initActions() for (int32_t i = 0; i < _actions.size(); ++i) { // skip separators Action& action = _actions[i]; - const char* icon = action.icon; // single char + const char* icon = action.icon; // single char bool isSeparator = icon[0] == 0; if (isSeparator) continue; - + *(actionPtrs[counter++]) = &_actions[i]; } KASSERT(counter == ArrayCount(actionPtrs)); @@ -2208,7 +2199,7 @@ void Data::updateEyedropper() _showSettings->lastCursorY == _showSettings->cursorY) { return; } - + if (_showSettings->isEyedropperFromDrawable()) { _showSettings->lastCursorX = _showSettings->cursorX; _showSettings->lastCursorY = _showSettings->cursorY; @@ -2221,8 +2212,8 @@ void Data::updateEyedropper() // don't wait on renderer to update this matrix float4x4 projectionViewModelMatrix = computeImageTransform(_showSettings->panX, - _showSettings->panY, - _showSettings->zoom); + _showSettings->panY, + _showSettings->zoom); // convert to clip space, or else need to apply additional viewport transform float halfX = _showSettings->viewSizeX * 0.5f; @@ -2235,37 +2226,37 @@ void Data::updateEyedropper() halfY /= (float)_showSettings->viewContentScaleFactor; float4 cursor = float4m(_showSettings->cursorX, _showSettings->cursorY, 0.0f, 1.0f); - + float4x4 pixelToClipTfm = - { - (float4){ halfX, 0, 0, 0 }, - (float4){ 0, -halfY, 0, 0 }, - (float4){ 0, 0, 1, 0 }, - (float4){ halfX, halfY, 0, 1 }, - }; + { + (float4){halfX, 0, 0, 0}, + (float4){0, -halfY, 0, 0}, + (float4){0, 0, 1, 0}, + (float4){halfX, halfY, 0, 1}, + }; pixelToClipTfm = inverse(pixelToClipTfm); - + cursor = pixelToClipTfm * cursor; - + //float4 clipPoint; //clipPoint.x = (point.x - halfX) / halfX; //clipPoint.y = -(point.y - halfY) / halfY; // convert point in window to point in texture float4x4 mInv = inverse(projectionViewModelMatrix); - + float4 pixel = mInv * float4m(cursor.x, cursor.y, 1.0f, 1.0f); pixel.xyz /= pixel.w; // in case perspective used float ar = _showSettings->imageAspectRatio(); - + // that's in model space (+/0.5f * ar, +/0.5f), so convert to texture space pixel.x = (pixel.x / ar + 0.5f); pixel.y = (-pixel.y + 0.5f); //pixel.x *= 0.999f; //pixel.y *= 0.999f; - + float2 uv = pixel.xy; // pixels are 0 based @@ -2287,33 +2278,33 @@ void Data::updateEyedropper() bool outsideImageBounds = pixel.x < 0.0f || pixel.x >= (float)_showSettings->imageBoundsX || pixel.y < 0.0f || pixel.y >= (float)_showSettings->imageBoundsY; - + // only display pixel if over image if (outsideImageBounds) { sprintf(text, "canvas: %d %d\n", (int32_t)pixel.x, (int32_t)pixel.y); - setEyedropperText(text.c_str()); // ick + setEyedropperText(text.c_str()); // ick _showSettings->outsideImageBounds = true; } else { // Note: fromView: nil returns isFlipped coordinate, fromView:self flips it // back. - + int32_t newX = (int32_t)pixel.x; int32_t newY = (int32_t)pixel.y; - + if (_showSettings->outsideImageBounds || (_showSettings->textureLookupX != newX || _showSettings->textureLookupY != newY)) { // Note: this only samples from the original texture via compute shaders // so preview mode pixel colors are not conveyed. But can see underlying // data driving preview. - + _showSettings->outsideImageBounds = false; - + // %.0f rounds the value, but want truncation _showSettings->textureLookupX = newX; _showSettings->textureLookupY = newY; - + // show block num int mipLOD = _showSettings->mipNumber; @@ -2332,27 +2323,26 @@ void Data::updateEyedropper() // Has to be set in other call, not here _showSettings->textureLookupMipX = mipX; _showSettings->textureLookupMipY = mipY; - + // showEyedropperData(uv); } } } - bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionState& actionState) { // Some data depends on the texture data (isSigned, isNormal, ..) bool isChanged = false; bool isStateChanged = false; - + // TODO: fix isChanged to only be set when value changes // f.e. clamped values don't need to re-render string text; - + if (action == _actionVertical) { _showSettings->isVerticalUI = !_showSettings->isVerticalUI; text = _showSettings->isVerticalUI ? "Vert UI" : "Horiz UI"; - + // just to update toggle state to Off isStateChanged = true; } @@ -2361,18 +2351,18 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt if (_noImageLoaded) { return true; } - + _showSettings->isHideUI = !_showSettings->isHideUI; text = _showSettings->isHideUI ? "Hide UI" : "Show UI"; - + // just to update toggle state to Off isStateChanged = true; } - + else if (action == _actionR) { if (!action->isHidden) { TextureChannels& channels = _showSettings->channels; - + if (channels == TextureChannels::ModeR001) { channels = TextureChannels::ModeRGBA; text = "Mask RGBA"; @@ -2383,12 +2373,11 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt } isChanged = true; } - } else if (action == _actionG) { if (!action->isHidden) { TextureChannels& channels = _showSettings->channels; - + if (channels == TextureChannels::Mode0G01) { channels = TextureChannels::ModeRGBA; text = "Mask RGBA"; @@ -2403,7 +2392,7 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt else if (action == _actionB) { if (!action->isHidden) { TextureChannels& channels = _showSettings->channels; - + if (channels == TextureChannels::Mode00B1) { channels = TextureChannels::ModeRGBA; text = "Mask RGBA"; @@ -2412,14 +2401,14 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt channels = TextureChannels::Mode00B1; text = "Mask 00B1"; } - + isChanged = true; } } else if (action == _actionA) { if (!action->isHidden) { TextureChannels& channels = _showSettings->channels; - + if (channels == TextureChannels::ModeAAA1) { channels = TextureChannels::ModeRGBA; text = "Mask RGBA"; @@ -2428,60 +2417,57 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt channels = TextureChannels::ModeAAA1; text = "Mask AAA1"; } - + isChanged = true; } - } else if (action == _actionPerf) { Perf* perf = Perf::instance(); - + bool isCompressed = true; if ((!_showSettings->isPerf) && perf->start("kramv", isCompressed)) { _showSettings->isPerf = true; } else { _showSettings->isPerf = false; - + if (perf->isRunning()) { perf->stop(); - + // TODO: Only open in non-sandboxed builds, it calls system("open file") // and this will have quarantine flag set if app not in app store // or notarized, signed, sandboxed for distribution outside of app store perf->openPerftrace(); } } - + text = "Perf "; text += _showSettings->isPerf ? "On" : "Off"; isChanged = true; } else if (action == _actionPlay) { if (!action->isHidden) { - - _showSettings->isPlayAnimations = ! _showSettings->isPlayAnimations; - + _showSettings->isPlayAnimations = !_showSettings->isPlayAnimations; + //Renderer* renderer = (Renderer*)self.delegate; //renderer.playAnimations = !renderer.playAnimations; - + text = _showSettings->isPlayAnimations ? "Play" : "Pause"; isChanged = true; } } else if (action == _actionShapeUVPreview) { - // toggle state _showSettings->isUVPreview = !_showSettings->isUVPreview; text = _showSettings->isUVPreview ? "Show UVPreview" : "Hide UvPreview"; isChanged = true; - + _showSettings->uvPreviewFrames = 10; } - + else if (action == _actionShapeChannel) { _showSettings->advanceShapeChannel(isShiftKeyDown); - + text = _showSettings->shapeChannelText(); isChanged = true; } @@ -2506,18 +2492,18 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt else if (action == _actionHelp) { // display the chars for now text = - "1234-rgba, Preview, Debug, A-show all\n" - "Info, Hud, Reload, 0-fit\n" - "Checker, Grid\n" - "Wrap, 8-signed, 9-premul\n" - "Mip, Face, Y-array\n" - "↓-next item, →-next counterpart\n" - "Lighting, S-shape, C-shape channel\n"; - + "1234-rgba, Preview, Debug, A-show all\n" + "Info, Hud, Reload, 0-fit\n" + "Checker, Grid\n" + "Wrap, 8-signed, 9-premul\n" + "Mip, Face, Y-array\n" + "↓-next item, →-next counterpart\n" + "Lighting, S-shape, C-shape channel\n"; + // just to update toggle state to Off isStateChanged = true; } - + else if (action == _actionFit) { float zoom; // fit image or mip @@ -2528,54 +2514,54 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt // fit to topmost image zoom = _showSettings->zoomFit; } - + // This zoom needs to be checked against zoom limits // there's a cap on the zoom multiplier. // This is reducing zoom which expands the image. zoom *= 1.0f / (1 << _showSettings->mipNumber); - + // even if zoom same, still do this since it resets the pan _showSettings->zoom = zoom; - + _showSettings->panX = 0.0f; _showSettings->panY = 0.0f; - + text = "Scale Image\n"; -// if (doPrintPanZoom) { -// string tmp; -// sprintf(tmp, -// "Pan %.3f,%.3f\n" -// "Zoom %.2fx\n", -// _showSettings->panX, _showSettings->panY, _showSettings->zoom); -// text += tmp; -// } - + // if (doPrintPanZoom) { + // string tmp; + // sprintf(tmp, + // "Pan %.3f,%.3f\n" + // "Zoom %.2fx\n", + // _showSettings->panX, _showSettings->panY, _showSettings->zoom); + // text += tmp; + // } + isChanged = true; } // reload key (also a quick way to reset the settings) else if (action == _actionReload) { //bool success = _delegate.loadFile(); - + // reload at actual size if (isShiftKeyDown) { _showSettings->zoom = 1.0f; } - + // Name change if image if (_showSettings->isModel) text = "Reload Model\n"; else text = "Reload Image\n"; -// if (doPrintPanZoom) { -// string tmp; -// sprintf(tmp, -// "Pan %.3f,%.3f\n" -// "Zoom %.2fx\n", -// _showSettings->panX, _showSettings->panY, _showSettings->zoom); -// text += tmp; -// } - + // if (doPrintPanZoom) { + // string tmp; + // sprintf(tmp, + // "Pan %.3f,%.3f\n" + // "Zoom %.2fx\n", + // _showSettings->panX, _showSettings->panY, _showSettings->zoom); + // text += tmp; + // } + isChanged = true; } else if (action == _actionPreview) { @@ -2592,7 +2578,7 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt } // TODO: might switch c to channel cycle, so could just hit that // and depending on the content, it cycles through reasonable channel masks - + // toggle checkerboard for transparency else if (action == _actionChecker) { if (!action->isHidden) { @@ -2602,75 +2588,75 @@ bool Data::handleEventAction(const Action* action, bool isShiftKeyDown, ActionSt text += _showSettings->isCheckerboardShown ? "On" : "Off"; } } - + else if (action == _actionSrgb) { if (!action->isHidden) { _showSettings->isSRGBShown = !_showSettings->isSRGBShown; - + sprintf(text, "Format srgb %s", _showSettings->isSRGBShown ? "On" : "Off"); - + isChanged = true; } } - + // toggle pixel grid when magnified above 1 pixel, can happen from mipmap // changes too else if (action == _actionGrid) { static int grid = 0; static const int kNumGrids = 7; - + #define advanceGrid(g, dec) \ -grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids - + grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids + // if block size is 1, then this shouldn't toggle _showSettings->isBlockGridShown = false; _showSettings->isAtlasGridShown = false; _showSettings->isPixelGridShown = false; - + advanceGrid(grid, isShiftKeyDown); - + static const uint32_t gridSizes[kNumGrids] = { - 0, 1, 4, 32, 64, 128, 256 // grid sizes + 0, 1, 4, 32, 64, 128, 256 // grid sizes }; - + if (grid == 0) { sprintf(text, "Grid Off"); } else if (grid == 1) { _showSettings->isPixelGridShown = true; - + sprintf(text, "Pixel Grid 1x1"); } else if (grid == 2 && _showSettings->blockX > 1) { _showSettings->isBlockGridShown = true; - + sprintf(text, "Block Grid %dx%d", _showSettings->blockX, _showSettings->blockY); } else { _showSettings->isAtlasGridShown = true; - + // want to be able to show altases tht have long entries derived from // props but right now just a square grid atlas _showSettings->gridSizeX = _showSettings->gridSizeY = gridSizes[grid]; - + sprintf(text, "Atlas Grid %dx%d", _showSettings->gridSizeX, _showSettings->gridSizeY); } - + isChanged = true; } else if (action == _actionShowAll) { if (!action->isHidden) { // TODO: have drawAllMips, drawAllLevels, drawAllLevelsAndMips _showSettings->isShowingAllLevelsAndMips = - !_showSettings->isShowingAllLevelsAndMips; + !_showSettings->isShowingAllLevelsAndMips; isChanged = true; text = "Show All "; text += _showSettings->isShowingAllLevelsAndMips ? "On" : "Off"; } } - + // toggle hud that shows name and pixel value under the cursor // this may require calling setNeedsDisplay on the UILabel as cursor moves else if (action == _actionHud) { @@ -2681,23 +2667,22 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids text += _showSettings->isHudShown ? "On" : "Off"; isStateChanged = true; } - + // info on the texture, could request info from lib, but would want to cache // that info else if (action == _actionInfo) { if (_showSettings->isHudShown) { - // also hide the file table, since this can be long //[self hideFileTable]; - + sprintf(text, "%s", isShiftKeyDown ? _showSettings->imageInfoVerbose.c_str() - : _showSettings->imageInfo.c_str()); + : _showSettings->imageInfo.c_str()); } // just to update toggle state to Off isStateChanged = true; } - + // toggle wrap/clamp else if (action == _actionWrap) { // TODO: cycle through all possible modes (clamp, repeat, mirror-once, @@ -2707,7 +2692,7 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids text = "Wrap "; text += _showSettings->isWrap ? "On" : "Off"; } - + // toggle signed vs. unsigned else if (action == _actionSigned) { if (!action->isHidden) { @@ -2717,7 +2702,7 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids text += _showSettings->isSigned ? "On" : "Off"; } } - + // toggle premul alpha vs. unmul else if (action == _actionPremul) { if (!action->isHidden) { @@ -2727,26 +2712,26 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids text += _showSettings->doShaderPremul ? "On" : "Off"; } } - + else if (action == _actionItem || action == _actionPrevItem) { if (!action->isHidden) { // invert shift key for prev, since it's reverse if (action == _actionPrevItem) { isShiftKeyDown = !isShiftKeyDown; } - + if (advanceFile(!isShiftKeyDown)) { //_hudHidden = true; //[self updateHudVisibility]; //[self setEyedropperText:""]; - + isChanged = true; - + setLoadedText(text); } } } - + else if (action == _actionCounterpart || action == _actionPrevCounterpart) { if (!action->isHidden) { // invert shift key for prev, since it's reverse @@ -2757,14 +2742,14 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids //_hudHidden = true; //[self updateHudVisibility]; //[self setEyedropperText:""]; - + isChanged = true; - + setLoadedText(text); } } } - + // test out different shapes else if (action == _actionShapeMesh) { if (_showSettings->meshCount > 1) { @@ -2773,9 +2758,9 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids isChanged = true; } } - + // TODO: should probably have these wrap and not clamp to count limits - + // mip up/down else if (action == _actionMip) { if (_showSettings->mipCount > 1) { @@ -2784,14 +2769,14 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids } else { _showSettings->mipNumber = - std::min(_showSettings->mipNumber + 1, _showSettings->mipCount - 1); + std::min(_showSettings->mipNumber + 1, _showSettings->mipCount - 1); } sprintf(text, "Mip %d/%d", _showSettings->mipNumber, _showSettings->mipCount); isChanged = true; } } - + else if (action == _actionFace) { // cube or cube array, but hit s to pick cubearray if (_showSettings->faceCount > 1) { @@ -2800,14 +2785,14 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids } else { _showSettings->faceNumber = - std::min(_showSettings->faceNumber + 1, _showSettings->faceCount - 1); + std::min(_showSettings->faceNumber + 1, _showSettings->faceCount - 1); } sprintf(text, "Face %d/%d", _showSettings->faceNumber, _showSettings->faceCount); isChanged = true; } } - + else if (action == _actionArray) { // slice if (_showSettings->sliceCount > 1) { @@ -2816,7 +2801,7 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids } else { _showSettings->sliceNumber = - std::min(_showSettings->sliceNumber + 1, _showSettings->sliceCount - 1); + std::min(_showSettings->sliceNumber + 1, _showSettings->sliceCount - 1); } sprintf(text, "Slice %d/%d", _showSettings->sliceNumber, _showSettings->sliceCount); @@ -2829,7 +2814,7 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids } else { _showSettings->arrayNumber = - std::min(_showSettings->arrayNumber + 1, _showSettings->arrayCount - 1); + std::min(_showSettings->arrayNumber + 1, _showSettings->arrayCount - 1); } sprintf(text, "Array %d/%d", _showSettings->arrayNumber, _showSettings->arrayCount); @@ -2840,11 +2825,11 @@ grid = (grid + kNumGrids + (dec ? -1 : 1)) % kNumGrids // non-handled action return false; } - + actionState.hudText = text; actionState.isChanged = isChanged; actionState.isStateChanged = isStateChanged; - + return true; } @@ -2860,7 +2845,7 @@ void Data::updateImageSettings(const string& fullFilename, KTXImage& image, MyMT _showSettings->blockY = image.blockDims().y; _showSettings->isSigned = isSignedFormat(format); - + TexContentType texContentType = findContentTypeFromFilename(fullFilename.c_str()); _showSettings->texContentType = texContentType; //_showSettings->isSDF = isSDF; @@ -2873,7 +2858,7 @@ void Data::updateImageSettings(const string& fullFilename, KTXImage& image, MyMT _showSettings->doShaderPremul = false; if (texContentType == TexContentTypeAlbedo && isPNG) { _showSettings->doShaderPremul = - true; // convert to premul in shader, so can see other channels + true; // convert to premul in shader, so can see other channels } int32_t numChannels = numChannelsOfFormat(originalFormat); @@ -2905,9 +2890,6 @@ void Data::updateImageSettings(const string& fullFilename, KTXImage& image, MyMT _showSettings->imageBoundsY = (int32_t)image.height; } - - - float zoom3D = 1.0f; void Data::updateProjTransform() @@ -2915,7 +2897,7 @@ void Data::updateProjTransform() // Want to move to always using perspective even for 2d images, but still more math // to work out to keep zoom to cursor working. #if USE_PERSPECTIVE - float aspect = _showSettings->viewSizeX / (float)_showSettings->viewSizeY; + float aspect = _showSettings->viewSizeX / (float)_showSettings->viewSizeY; _projectionMatrix = perspective_rhcs(90.0f * (M_PI / 180.0f), aspect, 0.1f); // This was used to reset zoom to a baseline that had a nice zoom. But little connected to it now. @@ -2927,17 +2909,17 @@ void Data::updateProjTransform() #else if (_showSettings->isModel) { - float aspect = _showSettings->viewSizeX / (float)_showSettings->viewSizeY; + float aspect = _showSettings->viewSizeX / (float)_showSettings->viewSizeY; _projectionMatrix = perspective_rhcs(90.0f * (M_PI / 180.0f), aspect, 0.1f); _showSettings->zoomFit = 1; } else { // ltrb - float2 rectDims = 0.5f * float2m(_showSettings->viewSizeX,_showSettings->viewSizeY); - float4 rect = float4m(-rectDims.x, rectDims.y, - rectDims.x, -rectDims.y); - + float2 rectDims = 0.5f * float2m(_showSettings->viewSizeX, _showSettings->viewSizeY); + float4 rect = float4m(-rectDims.x, rectDims.y, + rectDims.x, -rectDims.y); + _projectionMatrix = orthographic_rhcs(rect, 0.1f, 1e6f); @@ -2946,7 +2928,7 @@ void Data::updateProjTransform() std::min((float)_showSettings->viewSizeX, (float)_showSettings->viewSizeY) / std::max(1.0f, std::max((float)_showSettings->imageBoundsX, (float)_showSettings->imageBoundsY)); - + static bool useImageAndViewBounds = true; if (useImageAndViewBounds) { float invWidth = 1.0f / std::max(1.0f, (float)_showSettings->imageBoundsX); @@ -2955,8 +2937,8 @@ void Data::updateProjTransform() // DONE: adjust zoom to fit the entire image to the window // the best fit depends on dimension of image and window _showSettings->zoomFit = - std::min( (float)_showSettings->viewSizeX * invWidth, - (float)_showSettings->viewSizeY * invHeight); + std::min((float)_showSettings->viewSizeX * invWidth, + (float)_showSettings->viewSizeY * invHeight); } } #endif @@ -2971,53 +2953,52 @@ void Data::resetSomeImageSettings(bool isNewFile) _showSettings->faceNumber = 0; _showSettings->arrayNumber = 0; _showSettings->sliceNumber = 0; - + _showSettings->channels = TextureChannels::ModeRGBA; - + // wish could keep existing setting, but new texture might not // be supported debugMode for new texture _showSettings->debugMode = DebugMode::DebugModeNone; - + _showSettings->shapeChannel = ShapeChannel::ShapeChannelNone; } else { // reloaded file may have different limits _showSettings->mipNumber = - std::min(_showSettings->mipNumber, _showSettings->mipCount); + std::min(_showSettings->mipNumber, _showSettings->mipCount); _showSettings->faceNumber = - std::min(_showSettings->faceNumber, _showSettings->faceCount); + std::min(_showSettings->faceNumber, _showSettings->faceCount); _showSettings->arrayNumber = - std::min(_showSettings->arrayNumber, _showSettings->arrayCount); + std::min(_showSettings->arrayNumber, _showSettings->arrayCount); _showSettings->sliceNumber = - std::min(_showSettings->sliceNumber, _showSettings->sliceCount); + std::min(_showSettings->sliceNumber, _showSettings->sliceCount); } - + updateProjTransform(); - - + // this controls viewMatrix (global to all visible textures) _showSettings->panX = 0.0f; _showSettings->panY = 0.0f; - + _showSettings->zoom = _showSettings->zoomFit; - + // Y is always 1.0 on the plane, so scale to imageBoundsY // plane is already a non-uniform size, so can keep uniform scale - + // have one of these for each texture added to the viewer //float scaleX = MAX(1, _showSettings->imageBoundsX); float scaleY = std::max(1, _showSettings->imageBoundsY); float scaleX = scaleY; float scaleZ = scaleY; - + _modelMatrix2D = - float4x4(float4m(scaleX, scaleY, scaleZ, 1.0f)); // uniform scale + float4x4(float4m(scaleX, scaleY, scaleZ, 1.0f)); // uniform scale _modelMatrix2D = _modelMatrix2D * - translation(float3m(0.0f, 0.0f, -1.0)); // set z=-1 unit back - + translation(float3m(0.0f, 0.0f, -1.0)); // set z=-1 unit back + // uniform scaled 3d primitive float scale = scaleY; // MAX(scaleX, scaleY); - + // store the zoom into thew view matrix // fragment tangents seem to break down at high model scale due to precision // differences between worldPos and uv @@ -3026,50 +3007,50 @@ void Data::resetSomeImageSettings(bool isNewFile) // zoom3D = scale; // * _showSettings->viewSizeX / 2.0f; // scale = 1.0; // } - - _modelMatrix3D = float4x4(float4m(scale, scale, scale, 1.0f)); // uniform scale + + _modelMatrix3D = float4x4(float4m(scale, scale, scale, 1.0f)); // uniform scale _modelMatrix3D = - _modelMatrix3D * - translation(float3m(0.0f, 0.0f, -1.0f)); // set z=-1 unit back + _modelMatrix3D * + translation(float3m(0.0f, 0.0f, -1.0f)); // set z=-1 unit back } void Data::updateTransforms() { // scale float zoom = _showSettings->zoom; - + // translate float4x4 panTransform = translation(float3m(-_showSettings->panX, _showSettings->panY, 0.0)); if (_showSettings->is3DView) { - _viewMatrix3D = float4x4(float4m(zoom, zoom, 1.0f, 1.0f)); // non-uniform + _viewMatrix3D = float4x4(float4m(zoom, zoom, 1.0f, 1.0f)); // non-uniform _viewMatrix3D = panTransform * _viewMatrix3D; - + _viewMatrix = _viewMatrix3D; - + // obj specific _modelMatrix = _modelMatrix3D; } else { _viewMatrix2D = float4x4(float4m(zoom, zoom, 1.0f, 1.0f)); _viewMatrix2D = panTransform * _viewMatrix2D; - + _viewMatrix = _viewMatrix2D; - + // obj specific _modelMatrix = _modelMatrix2D; } - + // viewMatrix should typically be the inverse //_viewMatrix = simd_inverse(_viewMatrix); - + _projectionViewMatrix = _projectionMatrix * _viewMatrix; - + // cache the camera position _cameraPosition = - inverse(_viewMatrix).columns[3].xyz; // this is all ortho - + inverse(_viewMatrix).columns[3].xyz; // this is all ortho + // obj specific _modelMatrixInvScale2 = inverseScaleSquared(_modelMatrix); _showSettings->isInverted = _modelMatrixInvScale2.w < 0.0f; @@ -3099,45 +3080,44 @@ float4x4 Data::computeImageTransform(float panX, float panY, float zoom) } } - void Data::doZoomMath(float newZoom, float2& newPan) { // transform the cursor to texture coordinate, or clamped version if outside float4x4 projectionViewModelMatrix = computeImageTransform( - _showSettings->panX, - _showSettings->panY, - _showSettings->zoom); + _showSettings->panX, + _showSettings->panY, + _showSettings->zoom); // convert from pixel to clip space float halfX = _showSettings->viewSizeX * 0.5f; float halfY = _showSettings->viewSizeY * 0.5f; - + // sometimes get viewSizeX that's scaled by retina, and other times not. // account for contentScaleFactor (viewSizeX is 2x bigger than cursorX on // retina display) now passing down drawableSize instead of view.bounds.size halfX /= (float)_showSettings->viewContentScaleFactor; halfY /= (float)_showSettings->viewContentScaleFactor; - + float4x4 viewportMatrix = - { - (float4){ halfX, 0, 0, 0 }, - (float4){ 0, -halfY, 0, 0 }, - (float4){ 0, 0, 1, 0 }, - (float4){ halfX, halfY, 0, 1 }, - }; + { + (float4){halfX, 0, 0, 0}, + (float4){0, -halfY, 0, 0}, + (float4){0, 0, 1, 0}, + (float4){halfX, halfY, 0, 1}, + }; viewportMatrix = inverse(viewportMatrix); - + float4 cursor = float4m(_showSettings->cursorX, _showSettings->cursorY, 0.0f, 1.0f); - + cursor = viewportMatrix * cursor; - + //NSPoint clipPoint; //clipPoint.x = (point.x - halfX) / halfX; //clipPoint.y = -(point.y - halfY) / halfY; // convert point in window to point in model space float4x4 mInv = inverse(projectionViewModelMatrix); - + float4 pixel = mInv * float4m(cursor.x, cursor.y, 1.0f, 1.0f); pixel.xyz /= pixel.w; // in case perspective used @@ -3162,10 +3142,10 @@ void Data::doZoomMath(float newZoom, float2& newPan) // normalized coords to pixel coords pixel.x *= _showSettings->imageBoundsX; pixel.y *= _showSettings->imageBoundsY; - + // this fixes pinch-zoom on cube which are 6:1 pixel.x /= ar; - + #if USE_PERSPECTIVE // TODO: this doesn't work for perspective newPan.x = _showSettings->panX - (_showSettings->zoom - newZoom) * pixel.x; @@ -3176,6 +3156,4 @@ void Data::doZoomMath(float newZoom, float2& newPan) #endif } - - -} // namespace kram +} // namespace kram diff --git a/kramv/KramViewerBase.h b/kramv/KramViewerBase.h index 0d66d3a3..6af1f761 100644 --- a/kramv/KramViewerBase.h +++ b/kramv/KramViewerBase.h @@ -4,7 +4,7 @@ #include -#include "KramLib.h" // for MyMTLPixelFormat +#include "KramLib.h" // for MyMTLPixelFormat //#include //#include @@ -53,13 +53,13 @@ enum ShapeChannel { ShapeChannelUV0, - ShapeChannelFaceNormal, // gen from dfdx and dfdy + ShapeChannelFaceNormal, // gen from dfdx and dfdy - ShapeChannelNormal, // vertex normal + ShapeChannelNormal, // vertex normal ShapeChannelTangent, ShapeChannelBitangent, - ShapeChannelMipLevel, // can estimate mip chose off dfdx/dfdy, and pseudocolor + ShapeChannelMipLevel, // can estimate mip chose off dfdx/dfdy, and pseudocolor // don't need bump, since can already see it, but what if combined diffuse + // normal ShapeChannelBumpNormal, @@ -68,22 +68,21 @@ enum ShapeChannel { }; enum LightingMode { - LightingModeDiffuse = 0, // amb + diffuse - LightingModeSpecular = 1, // amb + diffuse + specular - LightingModeNone = 2, // no lighting, just mips - + LightingModeDiffuse = 0, // amb + diffuse + LightingModeSpecular = 1, // amb + diffuse + specular + LightingModeNone = 2, // no lighting, just mips + LightingModeCount, }; -struct Atlas -{ +struct Atlas { string name; - float x,y,w,h; - float u,v; // padding - to both or just left or right? + float x, y, w, h; + float u, v; // padding - to both or just left or right? bool isVertical; uint32_t level; - - float4 rect() const { return float4m(x,y,w,h); } + + float4 rect() const { return float4m(x, y, w, h); } }; class ShowSettings { @@ -112,15 +111,15 @@ class ShowSettings { // DONE: hook all these up to shader and view bool isHudShown = true; - + bool isHideUI = false; bool isVerticalUI = true; - + bool isPlayAnimations = false; - + // Can get a dump of perf (mostly loading a decode/transcode perf) bool isPerf = false; - + // transparency checkboard under the image bool isCheckerboardShown = false; @@ -147,17 +146,17 @@ class ShowSettings { bool isSwizzleAGToRG = false; //bool isSDF = false; TexContentType texContentType = TexContentTypeUnknown; - + // this mode shows the content with lighting or with bilinear/mips active bool isPreview = false; // Can collapse 3d to 2d and overlay the uv bool isUVPreview = false; - + uint32_t uvPreviewFrames = 0; float uvPreviewStep = 1.0f / 10.0f; float uvPreview = 0.0f; - + // the 2d view doesn't want to inset pixels for clamp, or point sampling is // thrown off expecially on small 4x4 textures #if USE_PERSPECTIVE @@ -165,7 +164,7 @@ class ShowSettings { #else bool is3DView = false; #endif - + // TODO: Might eliminate this, since mips are either built with or without // srgb and disabling with a MTLView caused many flags to have to be set on // MTLTexture @@ -176,13 +175,13 @@ class ShowSettings { // image vs. gltf model bool isModel = false; - + // if diff texture available, can show diff against source bool isDiff = false; - + // currently loading the diff texture if found, this slows loads bool hasDiffTexture = false; - + // can sample from drawable or from single source texture bool isEyedropperFromDrawable(); @@ -191,11 +190,11 @@ class ShowSettings { // this could be boundary of all visible images, so that pan doesn't go flying // off to nowhere - int32_t imageBoundsX = 0; // px - int32_t imageBoundsY = 0; // px + int32_t imageBoundsX = 0; // px + int32_t imageBoundsY = 0; // px bool outsideImageBounds = false; - + // size of the block, used in block grid drawing int32_t blockX = 1; int32_t blockY = 1; @@ -220,8 +219,8 @@ class ShowSettings { float4 textureResult; // size of the view and its contentScaleFactor - int32_t viewSizeX = 1; // px - int32_t viewSizeY = 1; // px + int32_t viewSizeX = 1; // px + int32_t viewSizeY = 1; // px float viewContentScaleFactor = 1.0f; // cursor is in view coordinates, but doesn't include contentScaleFactor @@ -258,44 +257,46 @@ class ShowSettings { void advanceShapeChannel(bool decrement); void advanceLightingMode(bool decrement); - const char *meshNumberText() const; - const char *shapeChannelText() const; - const char *debugModeText() const; - const char *lightingModeText() const; - - const char *meshNumberName(uint32_t meshNumber) const; - + const char* meshNumberText() const; + const char* shapeChannelText() const; + const char* debugModeText() const; + const char* lightingModeText() const; + + const char* meshNumberName(uint32_t meshNumber) const; + void updateUVPreviewState(); - - float imageAspectRatio() const { + + float imageAspectRatio() const + { float ar = 1.0f; if (meshNumber == 0 && !isModel && imageBoundsY > 0) ar = imageBoundsX / (float)imageBoundsY; return ar; } - - bool isFileNew(const char* fullFilename) const { + + bool isFileNew(const char* fullFilename) const + { return lastFilename != fullFilename; } - bool isFileChanged(const char* fullFilename, double timestamp) const { + bool isFileChanged(const char* fullFilename, double timestamp) const + { // Note that modstamp can change, but content data hash may be the same return isFileNew(fullFilename) || (timestamp != lastTimestamp); } - + string lastFilename; double lastTimestamp = 0.0; int32_t meshNumber = 0; int32_t meshCount = 5; - + const Atlas* lastAtlas = nullptr; // Might move to index vector atlas; }; -void printChannels(string &tmp, const string &label, float4 c, +void printChannels(string& tmp, const string& label, float4 c, int32_t numChannels, bool isFloat, bool isSigned); - enum Key { A = 0x00, S = 0x01, @@ -352,7 +353,7 @@ enum Key { RightArrow = 0x7C, DownArrow = 0x7D, UpArrow = 0x7E, - + Space = 0x31, Escape = 0x35, }; @@ -364,7 +365,7 @@ class Action { public: Action(const char* icon_, const char* tip_, Key keyCode_) : icon(icon_), tip(tip_), keyCode(keyCode_) {} - + const char* icon; const char* tip; @@ -372,11 +373,11 @@ class Action { kram_id button; // NSButton* kram_id menuItem; // NSMenuItem* Key keyCode; - + bool isHighlighted = false; bool isHidden = false; bool isButtonDisabled = false; - + // This have platform impl void setHighlight(bool enable); void setHidden(bool enable); @@ -387,46 +388,44 @@ class Action { struct FileContainer { // allow zip files to be dropped and opened, and can advance through bundle // content. - + // TODO: Add FileHelper if acrhive file is networked, but would require // full load to memory. - + ZipHelper zip; MmapHelper zipMmap; }; -struct ActionState -{ +struct ActionState { string hudText; bool isChanged; bool isStateChanged; }; -enum TextSlot -{ +enum TextSlot { kTextSlotHud, kTextSlotEyedropper, kTextSlotAtlas, - + kTextSlotCount // not a slot }; struct File { public: File(const char* name_, int32_t urlIndex_); - + // Note: not sorting by urlIndex currently - bool operator <(const File& rhs) const + bool operator<(const File& rhs) const { // sort by shortname int compare = strcasecmp(nameShort.c_str(), rhs.nameShort.c_str()); - if ( compare != 0 ) + if (compare != 0) return compare < 0; - + // if equal, then sort by longname return strcasecmp(name.c_str(), rhs.name.c_str()) < 0; } - + public: string name; int32_t urlIndex; @@ -434,14 +433,13 @@ struct File { }; // This allows wrapping all the ObjC stuff -struct DataDelegate -{ +struct DataDelegate { bool loadFile(bool clear = false); - + bool loadModelFile(const char* filename); - + bool loadTextureFromImage(const char* fullFilename, double timestamp, KTXImage& image, KTXImage* imageNormal, KTXImage* imageDiff, bool isArchive); - + public: kram_id view; // MyMTKView* }; @@ -449,11 +447,11 @@ struct DataDelegate struct Data { Data(); ~Data(); - + void clearAtlas(); bool loadAtlasFile(const char* filename); bool listFilesInArchive(int32_t urlIndex); - bool openArchive(const char * zipFilename, int32_t urlIndex); + bool openArchive(const char* zipFilename, int32_t urlIndex); bool hasCounterpart(bool increment); bool advanceCounterpart(bool increment); @@ -465,7 +463,7 @@ struct Data { const Atlas* findAtlasAtUV(float2 uv); bool isArchive() const; bool loadFile(); - + bool handleEventAction(const Action* action, bool isShiftKeyDown, ActionState& actionState); void updateUIAfterLoad(); void updateUIControlState(); @@ -476,7 +474,7 @@ struct Data { void setLoadedText(string& text); void setFailedText(const string& filename, string& text); - + void initActions(); vector& actions() { return _actions; } void initDisabledButtons(); @@ -490,9 +488,9 @@ struct Data { // See these to split off ObjC code DataDelegate _delegate; - + void updateEyedropper(); - + float4x4 computeImageTransform(float panX, float panY, float zoom); void updateProjTransform(); void resetSomeImageSettings(bool isNewFile); @@ -501,22 +499,22 @@ struct Data { void doZoomMath(float newZoom, float2& newPan); void setPerfDirectory(const char* directory); - + private: bool loadFileFromArchive(); public: void showEyedropperData(const float2& uv); - void setEyedropperText(const char * text); - void setAtlasText(const char * text); + void setEyedropperText(const char* text); + void setAtlasText(const char* text); void updateTransforms(); - + //---------------- float4x4 _projectionMatrix; - + float4x4 _projectionViewMatrix; float3 _cameraPosition; - + float4x4 _viewMatrix; float4x4 _viewMatrix2D; float4x4 _viewMatrix3D; @@ -528,42 +526,42 @@ struct Data { float4x4 _modelMatrix3D; //---------------- - + vector _textSlots; ShowSettings* _showSettings = nullptr; bool _noImageLoaded = true; string _archiveName; // archive or blank - + // folders and archives and multi-drop files are filled into this vector _files; int32_t _fileIndex = 0; - + // One of these per url in _urlss vector _containers; vector _urls; - + Action* _actionPlay; Action* _actionShapeUVPreview; Action* _actionHelp; Action* _actionInfo; Action* _actionHud; Action* _actionShowAll; - + Action* _actionPreview; Action* _actionWrap; Action* _actionPremul; Action* _actionSigned; Action* _actionSrgb; Action* _actionPerf; - + Action* _actionDiff; Action* _actionDebug; Action* _actionGrid; Action* _actionChecker; Action* _actionHideUI; Action* _actionVertical; - + Action* _actionMip; Action* _actionFace; Action* _actionArray; @@ -573,17 +571,17 @@ struct Data { Action* _actionPrevCounterpart; Action* _actionReload; Action* _actionFit; - + Action* _actionShapeMesh; Action* _actionShapeChannel; Action* _actionLighting; Action* _actionTangent; - + Action* _actionR; Action* _actionG; Action* _actionB; Action* _actionA; - + vector _actions; }; @@ -593,4 +591,4 @@ bool isSupportedJsonFilename(const char* filename); //extern bool doPrintPanZoom; -} // namespace kram +} // namespace kram diff --git a/kramv/KramViewerMain.mm b/kramv/KramViewerMain.mm index 9731897e..e6ab81ca 100644 --- a/kramv/KramViewerMain.mm +++ b/kramv/KramViewerMain.mm @@ -18,7 +18,7 @@ // C++ #include "KramLib.h" -#include "KramVersion.h" // keep kramv version in sync with libkram +#include "KramVersion.h" // keep kramv version in sync with libkram #include "TaskSystem.h" //#include "KramMipper.h" @@ -29,11 +29,10 @@ //#include "KramZipHelper.h" //#include "KramImage.h" -#include "KramViewerBase.h" - - #include // for recursive_mutex +#include "KramViewerBase.h" + using mymutex = std::recursive_mutex; using mylock = std::unique_lock; @@ -43,115 +42,112 @@ using namespace kram; using namespace STL_NAMESPACE; - // ktx, ktx2, png, and dds for images // zip, metallib // gltf, glb files for models NSArray* utis = @[ - @"public.directory", - - [UTType typeWithFilenameExtension: @"png"].identifier, - [UTType typeWithFilenameExtension: @"ktx"].identifier, - [UTType typeWithFilenameExtension: @"ktx2"].identifier, - [UTType typeWithFilenameExtension: @"dds"].identifier, - - [UTType typeWithFilenameExtension: @"zip"].identifier, - [UTType typeWithFilenameExtension: @"metallib"].identifier, - + @"public.directory", + + [UTType typeWithFilenameExtension:@"png"].identifier, + [UTType typeWithFilenameExtension:@"ktx"].identifier, + [UTType typeWithFilenameExtension:@"ktx2"].identifier, + [UTType typeWithFilenameExtension:@"dds"].identifier, + + [UTType typeWithFilenameExtension:@"zip"].identifier, + [UTType typeWithFilenameExtension:@"metallib"].identifier, + #if USE_GLTF - [UTType typeWithFilenameExtension: @"gltf"].identifier, - [UTType typeWithFilenameExtension: @"glb"].identifier, - //@"model/gltf+json", - //@"model/gltf+binary" + [UTType typeWithFilenameExtension:@"gltf"].identifier, + [UTType typeWithFilenameExtension:@"glb"].identifier, +//@"model/gltf+json", +//@"model/gltf+binary" #endif #if USE_USD - [UTType typeWithFilenameExtension: @"usd"].identifier, - [UTType typeWithFilenameExtension: @"usd"].identifier, - [UTType typeWithFilenameExtension: @"usda"].identifier, + [UTType typeWithFilenameExtension:@"usd"].identifier, + [UTType typeWithFilenameExtension:@"usd"].identifier, + [UTType typeWithFilenameExtension:@"usda"].identifier, #endif - - // read -atlas.json files - [UTType typeWithFilenameExtension: @"json"].identifier + + // read -atlas.json files + [UTType typeWithFilenameExtension:@"json"].identifier ]; NSDictionary* pasteboardOptions = @{ // This means only these uti can be droped. - NSPasteboardURLReadingContentsConformToTypesKey: utis - + NSPasteboardURLReadingContentsConformToTypesKey : utis + // Don't use this it prevents folder urls //, NSPasteboardURLReadingFileURLsOnlyKey: @YES }; - -struct MouseData -{ +struct MouseData { NSPoint originPoint; NSPoint oldPoint; NSPoint newPoint; - + NSPoint pan; }; //------------- - -void Action::setHighlight(bool enable) { +void Action::setHighlight(bool enable) +{ isHighlighted = enable; - + auto On = 1; // NSControlStateValueOn; auto Off = 0; // NSControlStateValueOff; - + if (!isButtonDisabled) { ((__bridge NSButton*)button).state = enable ? On : Off; } ((__bridge NSMenuItem*)menuItem).state = enable ? On : Off; } -void Action::setHidden(bool enable) { +void Action::setHidden(bool enable) +{ isHidden = enable; - + if (!isButtonDisabled) { ((__bridge NSButton*)button).hidden = enable; } ((__bridge NSMenuItem*)menuItem).hidden = enable; } -void Action::disableButton() { +void Action::disableButton() +{ ((__bridge NSButton*)button).hidden = true; isButtonDisabled = true; } - // These are using NSFileManager to list files, so must be ObjC void Data::listArchivesInFolder(const string& folderFilename, vector& archiveFiles, bool skipSubdirs) { NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:folderFilename.c_str()]]; - + NSDirectoryEnumerationOptions options = NSDirectoryEnumerationSkipsHiddenFiles; if (skipSubdirs) options |= NSDirectoryEnumerationSkipsSubdirectoryDescendants; - + NSDirectoryEnumerator* directoryEnumerator = - [[NSFileManager defaultManager] - enumeratorAtURL:url - includingPropertiesForKeys:[NSArray array] - options:options - errorHandler: // nil - ^BOOL(NSURL *urlArg, NSError *error) { - macroUnusedVar(urlArg); - macroUnusedVar(error); - - // handle error - return false; - }]; - + [[NSFileManager defaultManager] + enumeratorAtURL:url + includingPropertiesForKeys:[NSArray array] + options:options + errorHandler: // nil + ^BOOL(NSURL* urlArg, NSError* error) { + macroUnusedVar(urlArg); + macroUnusedVar(error); + + // handle error + return false; + }]; + // only display models in folder if found, ignore the png/jpg files while (NSURL* fileOrDirectoryURL = [directoryEnumerator nextObject]) { const char* name = fileOrDirectoryURL.fileSystemRepresentation; - + bool isArchive = isSupportedArchiveFilename(name); - if (isArchive) - { - archiveFiles.emplace_back(File(name,0)); + if (isArchive) { + archiveFiles.emplace_back(File(name, 0)); } } } @@ -160,30 +156,30 @@ { // Hope this hsas same permissions NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:archiveFilename.c_str()]]; - + NSDirectoryEnumerationOptions options = NSDirectoryEnumerationSkipsHiddenFiles; if (skipSubdirs) options |= NSDirectoryEnumerationSkipsSubdirectoryDescendants; - + NSDirectoryEnumerator* directoryEnumerator = - [[NSFileManager defaultManager] - enumeratorAtURL:url - includingPropertiesForKeys:[NSArray array] - options:options - errorHandler: // nil - ^BOOL(NSURL *urlArg, NSError *error) { - macroUnusedVar(urlArg); - macroUnusedVar(error); - - // handle error - don't change to folder if devoid of valid content - return false; - }]; - + [[NSFileManager defaultManager] + enumeratorAtURL:url + includingPropertiesForKeys:[NSArray array] + options:options + errorHandler: // nil + ^BOOL(NSURL* urlArg, NSError* error) { + macroUnusedVar(urlArg); + macroUnusedVar(error); + + // handle error - don't change to folder if devoid of valid content + return false; + }]; + while (NSURL* fileOrDirectoryURL = [directoryEnumerator nextObject]) { const char* name = fileOrDirectoryURL.fileSystemRepresentation; - + bool isValid = isSupportedFilename(name); - + #if USE_GLTF || USE_USD // note: many gltf reference jpg which will load via GltfAsset, but // kram and kramv do not import jpg files. @@ -191,12 +187,12 @@ isValid = isSupportedModelFilename(name); } #endif - + if (!isValid) { isValid = isSupportedJsonFilename(name); } if (isValid) { - _files.emplace_back(File(name,urlIndex)); + _files.emplace_back(File(name, urlIndex)); } } } @@ -210,9 +206,7 @@ @interface MyNSTextField : NSTextField @end -@implementation MyNSTextField -{ - +@implementation MyNSTextField { } // override to allow clickthrough @@ -228,7 +222,7 @@ - (NSView*)hitTest:(NSPoint)aPoint @interface MyMTKView : MTKView @property(retain, nonatomic, readwrite, nullable) - NSMagnificationGestureRecognizer *zoomGesture; + NSMagnificationGestureRecognizer* zoomGesture; @property(nonatomic, readwrite) double lastArchiveTimestamp; @@ -240,12 +234,11 @@ @interface MyMTKView : MTKView @property(nonatomic, readwrite) float validMagnification; @property(nonatomic, readwrite) MouseData mouseData; - - (BOOL)loadTextureFromURLs:(NSArray*)url; -- (void)setHudText:(const char *)text; +- (void)setHudText:(const char*)text; -- (void)tableViewSelectionDidChange:(NSNotification *)notification; +- (void)tableViewSelectionDidChange:(NSNotification*)notification; - (void)addNotifications; @@ -259,27 +252,28 @@ - (void)fixupDocumentList; // https://medium.com/@kevingutowski/how-to-setup-a-tableview-in-2019-obj-c-c7dece203333 @interface TableViewController : NSObject -@property (nonatomic, strong) NSMutableArray* items; +@property(nonatomic, strong) NSMutableArray* items; @end @implementation TableViewController -- (instancetype)init { +- (instancetype)init +{ self = [super init]; - + _items = [[NSMutableArray alloc] init]; - + return self; } // NSTableViewDataSource -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { return self.items.count; } // NSTableViewDelegate --(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +- (NSView*)tableView:(NSTableView*)tableView viewForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { NSString* identifier = tableColumn.identifier; NSTableCellView* cell = [tableView makeViewWithIdentifier:identifier owner:self]; @@ -288,18 +282,18 @@ -(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn } // NSTableViewDelegate -- (BOOL)tableView:(NSTableView *)tableView -shouldTypeSelectForEvent:(NSEvent *)event -withCurrentSearchString:(NSString *)searchString +- (BOOL)tableView:(NSTableView*)tableView + shouldTypeSelectForEvent:(NSEvent*)event + withCurrentSearchString:(NSString*)searchString { // Return NO to prevent type select (otherwise S or N key will search that key) // This is nice on long lists though. return NO; } -- (void)tableViewSelectionDidChange:(NSNotification *)notification +- (void)tableViewSelectionDidChange:(NSNotification*)notification { - // does not need to respond, have a listener on this notification + // does not need to respond, have a listener on this notification } @end @@ -326,7 +320,7 @@ - (instancetype)init + (BOOL)autosavesInPlace { - return NO; // YES; + return NO; // YES; } // call when "new" called @@ -339,8 +333,8 @@ - (void)makeWindowControllers //addWindowController:controller]; } -- (NSData *)dataOfType:(nonnull NSString *)typeName - error:(NSError *_Nullable __autoreleasing *)outError +- (NSData*)dataOfType:(nonnull NSString*)typeName + error:(NSError* _Nullable __autoreleasing*)outError { // Insert code here to write your document to data of the specified type. If // outError != NULL, ensure that you create and set an appropriate error if @@ -352,18 +346,18 @@ - (NSData *)dataOfType:(nonnull NSString *)typeName return nil; } -- (BOOL)readFromURL:(nonnull NSURL *)url - ofType:(nonnull NSString *)typeName - error:(NSError *_Nullable __autoreleasing *)outError +- (BOOL)readFromURL:(nonnull NSURL*)url + ofType:(nonnull NSString*)typeName + error:(NSError* _Nullable __autoreleasing*)outError { // called from OpenRecent documents menu - + // throw into an array - NSArray* urls = @[url]; - + NSArray* urls = @[ url ]; + NSApplication* app = [NSApplication sharedApplication]; MyMTKView* view = app.mainWindow.contentView; - + BOOL success = [view loadTextureFromURLs:urls]; if (success) { // Note: if I return NO from this call then a dialog pops up that image @@ -393,24 +387,24 @@ @interface AppDelegate () @implementation AppDelegate -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { // Insert code here to initialize your application } -- (void)applicationWillTerminate:(NSNotification *)aNotification +- (void)applicationWillTerminate:(NSNotification*)aNotification { // Insert code here to tear down your application } - (BOOL)applicationShouldTerminateAfterLastWindowClosed: - (NSApplication *)sender + (NSApplication*)sender { return YES; } -- (void)application:(NSApplication *)sender - openURLs:(nonnull NSArray *)urls +- (void)application:(NSApplication*)sender + openURLs:(nonnull NSArray*)urls { // this is called from "Open In..." MyMTKView* view = sender.mainWindow.contentView; @@ -422,7 +416,7 @@ - (void)application:(NSApplication *)sender - (void)exportDocument:(NSString*)name toType:(NSString*)typeUTI { NSWindow* window = [[[self windowControllers] objectAtIndex:0] window]; - + // Build a new name for the file using the current name and // the filename extension associated with the specified UTI. CFStringRef newExtension = UTTypeCopyPreferredTagWithClass((CFStringRef)typeUTI, @@ -430,7 +424,7 @@ - (void)exportDocument:(NSString*)name toType:(NSString*)typeUTI NSString* newName = [[name stringByDeletingPathExtension] stringByAppendingPathExtension:(NSString*)newExtension]; CFRelease(newExtension); - + // Set the default name for the file and show the panel. NSSavePanel* panel = [NSSavePanel savePanel]; [panel setNameFieldStringValue:newName]; @@ -438,9 +432,9 @@ - (void)exportDocument:(NSString*)name toType:(NSString*)typeUTI if (result == NSFileHandlingPanelOKButton) { NSURL* theFile = [panel URL]; - + // Write the contents in the new format. - + } }]; } @@ -452,7 +446,7 @@ - (IBAction)openDocument:(id)sender { // need to implement, or default NSOpenPanel can't specify a directory NSDocumentController* controller = [NSDocumentController sharedDocumentController]; - + #if 0 // Would be nice, but doesn't allow directory. // How is NSDocument aware of directory, from Info.plist? @@ -462,35 +456,33 @@ - (IBAction)openDocument:(id)sender // // } #else - + NSOpenPanel* panel = [NSOpenPanel openPanel]; [panel setCanChooseFiles:YES]; [panel setCanChooseDirectories:YES]; [panel setAllowsMultipleSelection:NO]; - if ([controller runModalOpenPanel:panel forTypes:utis] == NSModalResponseOK) - { + if ([controller runModalOpenPanel:panel forTypes:utis] == NSModalResponseOK) { NSArray* urls = [panel URLs]; NSURL* url = [urls objectAtIndex:0]; - + // This gets a file:// urls, and then openDocument won't open it if // it's a folder. - + bool isDirectory = false; if (url.isFileURL) { BOOL isDir = NO; // Verify that the file exists // and is indeed a directory (isDirectory is an out parameter) - if ([[NSFileManager defaultManager] fileExistsAtPath: url.path isDirectory: &isDir] - && isDir) { + if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir] && isDir) { isDirectory = true; } } - + if (isDirectory) { // have to open this directory URL directly //[self openURLs:[NSApplication sharedApplication] urls:urls]; - + // this is called from "Open In..." NSApplication* app = [NSApplication sharedApplication]; MyMTKView* view = app.mainWindow.contentView; @@ -501,12 +493,11 @@ - (IBAction)openDocument:(id)sender [controller openDocumentWithContentsOfURL:url display:YES completionHandler: - ^(NSDocument* doc, BOOL isAlreadOpen, NSError* error ) { - if (!error) { - // what should this do? - } - } - ]; + ^(NSDocument* doc, BOOL isAlreadOpen, NSError* error) { + if (!error) { + // what should this do? + } + }]; } } #endif @@ -567,16 +558,16 @@ - (IBAction)showAboutDialog:(id)sender @end -NSArray* pasteboardTypes = @[ +NSArray* pasteboardTypes = @[ // don't really want generic urls, but need folders to drop //NSPasteboardTypeURL - + // this is preventing folder drops ? NSPasteboardTypeFileURL ]; /* correlates with - + public.directory. public.png, org.khronos.ktx, @@ -586,33 +577,26 @@ - (IBAction)showAboutDialog:(id)sender dyn.ah62d4rv4ge8043pyqf0g24pc, // ick - metallib dyn.ah62d4rv4ge80s5dyq2, // ick - gltf dyn.ah62d4rv4ge80s5dc // ick - glb - -*/ - - - - - +*/ //---------------------------------------------------- - @implementation MyMTKView { - NSMenu* _viewMenu; // really the items + NSMenu* _viewMenu; // really the items NSStackView* _buttonStack; - NSMutableArray* _buttonArray; + NSMutableArray* _buttonArray; NSTextField* _hudLabel; NSTextField* _hudLabel2; - + // Offer list of files in archives // TODO: move to NSOutlineView since that can show archive folders with content inside IBOutlet NSTableView* _tableView; IBOutlet TableViewController* _tableViewController; - + // copy of modifier flags, can tie drop actions to this NSEventModifierFlags _modifierFlags; - + ShowSettings* _showSettings; Data _data; } @@ -620,23 +604,23 @@ @implementation MyMTKView { - (void)awakeFromNib { [super awakeFromNib]; - + // vertical offset of table down so hud can display info NSScrollView* scrollView = [_tableView enclosingScrollView]; CGRect rect = scrollView.frame; rect.origin.y += 50; scrollView.frame = rect; - + // C++ delegate _data._delegate.view = (__bridge void*)self; - + // this is sandbox or root if not sandboxed // This is objC call... // This has to be in a .mm file to call std::string traceDir = [NSHomeDirectory() UTF8String]; traceDir += "/traces/"; _data.setPerfDirectory(traceDir.c_str()); - + // TODO: see if can only open this // KLOGI("Viewer", "AwakeFromNIB"); } @@ -658,7 +642,7 @@ - (BOOL)isFlipped // TODO: Sometimes getting panels from right side popping in when trying to pan // on macOS without using pan gesture. -- (instancetype)initWithCoder:(NSCoder *)coder +- (instancetype)initWithCoder:(NSCoder*)coder { self = [super initWithCoder:coder]; @@ -677,7 +661,7 @@ - (instancetype)initWithCoder:(NSCoder *)coder // added for drag-drop support [self registerForDraggedTypes:pasteboardTypes]; - + // This gesture only works for trackpad _zoomGesture = [[NSMagnificationGestureRecognizer alloc] initWithTarget:self @@ -693,32 +677,32 @@ - (instancetype)initWithCoder:(NSCoder *)coder // hide until image loaded _showSettings->isHideUI = true; _buttonStack.hidden = YES; - + _hudLabel2 = [self _addHud:YES]; _hudLabel = [self _addHud:NO]; [self setHudText:""]; - + return self; } -- (nonnull ShowSettings *)showSettings +- (nonnull ShowSettings*)showSettings { return _showSettings; } -- (nonnull kram::Data *)data +- (nonnull kram::Data*)data { return &_data; } --(void)fixupDocumentList +- (void)fixupDocumentList { // DONE: this recent menu only seems to work the first time // and not in subsequent calls to the same entry. readFromUrl isn't even // called. So don't get a chance to switch back to a recent texture. Maybe // there's some list of documents created and so it doesn't think the file // needs to be reloaded. - + // Clear the document list so readFromURL keeps getting called // Can't remove currentDoc, so have to skip that NSDocumentController* dc = [NSDocumentController sharedDocumentController]; @@ -734,17 +718,15 @@ -(void)fixupDocumentList } } - - -- (NSStackView *)_addButtons +- (NSStackView*)_addButtons { _data.initActions(); - + NSRect rect = NSMakeRect(0, 10, 30, 30); vector& actions = _data.actions(); int32_t numActions = actions.size(); - + NSMutableArray* buttons = [[NSMutableArray alloc] init]; for (int32_t i = 0; i < numActions; ++i) { @@ -769,40 +751,40 @@ - (NSStackView *)_addButtons [button setFrame:rect]; // https://stackoverflow.com/questions/4467597/how-do-you-stroke-the-outside-of-an-nsattributedstring - + NSMutableDictionary* attribsOff = [NSMutableDictionary dictionaryWithObjectsAndKeys: - //[NSFont systemFontOfSize:64.0],NSFontAttributeName, - [NSColor whiteColor],NSForegroundColorAttributeName, - [NSNumber numberWithFloat:-2.0],NSStrokeWidthAttributeName, - [NSColor blackColor],NSStrokeColorAttributeName, - nil]; + //[NSFont systemFontOfSize:64.0],NSFontAttributeName, + [NSColor whiteColor], NSForegroundColorAttributeName, + [NSNumber numberWithFloat:-2.0], NSStrokeWidthAttributeName, + [NSColor blackColor], NSStrokeColorAttributeName, + nil]; NSMutableDictionary* attribsOn = [NSMutableDictionary dictionaryWithObjectsAndKeys: - //[NSFont systemFontOfSize:64.0],NSFontAttributeName, - [NSColor systemBlueColor],NSForegroundColorAttributeName, - [NSNumber numberWithFloat:-2.0],NSStrokeWidthAttributeName, - [NSColor blackColor],NSStrokeColorAttributeName, - nil]; + //[NSFont systemFontOfSize:64.0],NSFontAttributeName, + [NSColor systemBlueColor], NSForegroundColorAttributeName, + [NSNumber numberWithFloat:-2.0], NSStrokeWidthAttributeName, + [NSColor blackColor], NSStrokeColorAttributeName, + nil]; button.attributedTitle = [[NSMutableAttributedString alloc] initWithString:name attributes:attribsOff]; - + // Have to set this too, or button doesn't go blue button.attributedAlternateTitle = [[NSMutableAttributedString alloc] initWithString:name attributes:attribsOn]; - + // stackView seems to disperse the items evenly across the area, so this // doesn't work bool isSeparator = icon[0] == 0; - + if (isSeparator) { // rect.origin.y += 11; button.enabled = NO; } else { action.button = (__bridge void*)button; - + // rect.origin.y += 25; // TODO: add icons //button.image = ...; - + // keep all buttons, since stackView will remove and pack the stack [_buttonArray addObject:button]; } @@ -813,7 +795,7 @@ - (NSStackView *)_addButtons NSStackView* stackView = [NSStackView stackViewWithViews:buttons]; stackView.orientation = NSUserInterfaceLayoutOrientationVertical; stackView.detachesHiddenViews = - YES; // default, but why have to have _buttonArrary + YES; // default, but why have to have _buttonArrary [self addSubview:stackView]; // Want menus, so user can define their own shortcuts to commands @@ -830,41 +812,41 @@ - (NSStackView *)_addButtons for (int32_t i = 0; i < numActions; ++i) { Action& action = actions[i]; - const char* icon = action.icon; // single char + const char* icon = action.icon; // single char const char* title = action.tip; NSString* toolTip = [NSString stringWithUTF8String:icon]; NSString* name = [NSString stringWithUTF8String:title]; bool isSeparator = icon[0] == 0; - + if (isSeparator) { [_viewMenu addItem:[NSMenuItem separatorItem]]; } else { // NSString *shortcut = @""; // for now, or AppKit turns key int cmd+shift+key NSString* shortcut = [NSString stringWithUTF8String:icon]; - + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(handleAction:) keyEquivalent:shortcut]; menuItem.toolTip = toolTip; - + // All key-equivalents assume cmd, so unset cmd // still leaves shift next to keys, but better than nothing menuItem.keyEquivalentModifierMask = (NSEventModifierFlags)0; - + // TODO: add icons, also onStateImage, offStageImage, mixedStateImage //menuItem.image = ...; - + // can set an integer constant that represents menu that avoid testing string (actionID) //menuItem.tag = ...; - + // TODO: menus and buttons should reflect any toggle state // menuItem.state = Mixed/Off/On; [_viewMenu addItem:menuItem]; - + action.menuItem = (__bridge void*)menuItem; } } @@ -872,27 +854,25 @@ - (NSStackView *)_addButtons [_viewMenu addItem:[NSMenuItem separatorItem]]; //---------------------- - + // don't want some buttons showing up, menu only _data.initDisabledButtons(); - + return stackView; } - - -- (NSTextField *)_addHud:(BOOL)isShadow +- (NSTextField*)_addHud:(BOOL)isShadow { // TODO: This text field is clamping to the height, so have it set to 1200. // really want field to expand to fill the window height for large output uint32_t w = 800; uint32_t h = 1220; - + // add a label for the hud NSTextField* label = [[MyNSTextField alloc] initWithFrame:NSMakeRect(isShadow ? 21 : 20, isShadow ? 21 : 20, w, h)]; - + label.preferredMaxLayoutWidth = w; label.drawsBackground = NO; @@ -903,12 +883,12 @@ - (NSTextField *)_addHud:(BOOL)isShadow label.editable = NO; label.selectable = NO; label.lineBreakMode = NSLineBreakByClipping; - label.maximumNumberOfLines = 0; // fill to height + label.maximumNumberOfLines = 0; // fill to height // important or interferes with table view label.refusesFirstResponder = YES; label.enabled = NO; - + label.cell.scrollable = NO; label.cell.wraps = NO; @@ -923,14 +903,13 @@ - (NSTextField *)_addHud:(BOOL)isShadow return label; } - -- (void)handleGesture:(NSGestureRecognizer *)gestureRecognizer +- (void)handleGesture:(NSGestureRecognizer*)gestureRecognizer { // skip until image loaded if (_showSettings->imageBoundsX == 0) { return; } - + // https://cocoaosxrevisited.wordpress.com/2018/01/06/chapter-18-mouse-events/ if (gestureRecognizer != _zoomGesture) { return; @@ -941,10 +920,10 @@ - (void)handleGesture:(NSGestureRecognizer *)gestureRecognizer float zoom = _zoomGesture.magnification; if (isFirstGesture) { _zoomGesture.magnification = 1.0f; - + _validMagnification = 1.0f; _originalZoom = _showSettings->zoom; - + zoom = _originalZoom; } else if (zoom * _originalZoom < 0.1f) { @@ -952,7 +931,7 @@ - (void)handleGesture:(NSGestureRecognizer *)gestureRecognizer zoom = 0.1f / _originalZoom; _zoomGesture.magnification = zoom; } - + if (!isFirstGesture) { // try expontental (this causes a jump, comparison avoids an initial jump // zoom = powf(zoom, 1.05f); @@ -960,29 +939,28 @@ - (void)handleGesture:(NSGestureRecognizer *)gestureRecognizer // doing multiply instead of equals here, also does exponential zom zoom *= _originalZoom; } - + [self updateZoom:zoom]; } --(void)updateZoom:(float)zoom +- (void)updateZoom:(float)zoom { // https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_uikit_gestures/handling_pinch_gestures?language=objc // need to sync up the zoom when action begins or zoom will jump - // https://stackoverflow.com/questions/30002361/image-zoom-centered-on-mouse-position // DONE: rect is now ar:1 for rect case, so these x values need to be half ar // and that's only if it's not rotated. box/cube/ellipse make also not correspond float ar = _showSettings->imageAspectRatio(); - + // find the cursor location with respect to the image float4 bottomLeftCorner = float4m(-0.5f * ar, -0.5f, 0.0f, 1.0f); float4 topRightCorner = float4m(0.5f * ar, 0.5f, 0.0f, 1.0f); float4x4 newMatrix = _data.computeImageTransform(_showSettings->panX, - _showSettings->panY, - zoom); + _showSettings->panY, + zoom); // don't allow panning the entire image off the view boundary // transform the upper left and bottom right corner of the image @@ -1023,23 +1001,23 @@ -(void)updateZoom:(float)zoom //float minZoom = std::min(1.0f/8.0f, _showSettings->zoomFit); // TODO: 3d models have imageBoundsY of 1, so the limits are hit immediately - + int32_t gap = _showSettings->showAllPixelGap; - + // Note this includes chunks and mips even if those are not shown // so image could be not visible. float2 maxZoomXY; maxZoomXY.x = maxZoom * (_showSettings->imageBoundsX + gap) * numTexturesX; maxZoomXY.y = maxZoom * (_showSettings->imageBoundsY + gap) * numTexturesY; - + float minPixelSize = 4; float2 minZoomXY; minZoomXY.x = minPixelSize; // minZoom * (_showSettings->imageBoundsX + gap) * numTexturesX; minZoomXY.y = minPixelSize; // minZoom * (_showSettings->imageBoundsY + gap) * numTexturesY; - + // don't allow image to get too big bool isZoomChanged = true; - + if (visibleWidth > maxZoomXY.x || visibleHeight > maxZoomXY.y) { isZoomChanged = false; } @@ -1053,7 +1031,7 @@ -(void)updateZoom:(float)zoom if (!rectIntersectsRect(imageRect, viewRect)) { isZoomChanged = false; } - + if (!isZoomChanged) { _zoomGesture.magnification = _validMagnification; // objC return; @@ -1074,47 +1052,46 @@ -(void)updateZoom:(float)zoom _showSettings->panX = newPan.x; _showSettings->panY = newPan.y; -// if (doPrintPanZoom) { -// string text; -// sprintf(text, -// "Pan %.3f,%.3f\n" -// "Zoom %.2fx\n", -// _showSettings->panX, _showSettings->panY, _showSettings->zoom); -// [self setHudText:text.c_str()]; -// } + // if (doPrintPanZoom) { + // string text; + // sprintf(text, + // "Pan %.3f,%.3f\n" + // "Zoom %.2fx\n", + // _showSettings->panX, _showSettings->panY, _showSettings->zoom); + // [self setHudText:text.c_str()]; + // } // Cause a new sample for eyedropper _data.updateEyedropper(); - + self.needsDisplay = YES; // objC } } - // left mouse button down -- (void)mouseDown:(NSEvent *)event +- (void)mouseDown:(NSEvent*)event { // skip until image loaded if (_showSettings->imageBoundsX == 0) { return; } - + _mouseData.originPoint = - _mouseData.oldPoint = - _mouseData.newPoint = [self convertPoint:[event locationInWindow] fromView:nil]; + _mouseData.oldPoint = + _mouseData.newPoint = [self convertPoint:[event locationInWindow] fromView:nil]; // capture pan value and cursor value _mouseData.pan = NSMakePoint(_showSettings->panX, _showSettings->panY); } // drag is mouse movement with left button down -- (void)mouseDragged:(NSEvent *)event +- (void)mouseDragged:(NSEvent*)event { // skip until image loaded if (_showSettings->imageBoundsX == 0) { return; } - + _mouseData.oldPoint = _mouseData.newPoint; _mouseData.newPoint = [self convertPoint:[event locationInWindow] fromView:nil]; @@ -1124,38 +1101,37 @@ - (void)mouseDragged:(NSEvent *)event delta.y = _mouseData.newPoint.y - _mouseData.originPoint.y; delta.x = -delta.x; delta.y = -delta.y; - + // scale to actual px or mouse cursor doesn't track drag delta.x *= _showSettings->viewContentScaleFactor; delta.y *= _showSettings->viewContentScaleFactor; - + // This is correct, but scale to image so cursor tracks the pick location // might be over a different mip/chunk though. float panX = _mouseData.pan.x + delta.x; float panY = _mouseData.pan.y + delta.y; - + [self updatePan:panX panY:panY]; } -- (void)mouseUp:(NSEvent *)event +- (void)mouseUp:(NSEvent*)event { // ignore up even though cursor may have moved - } -- (void)mouseMoved:(NSEvent *)event +- (void)mouseMoved:(NSEvent*)event { // skip until image loaded if (_showSettings->imageBoundsX == 0) { return; } - + // pixel in non-square window coords, run through inverse to get texel space // I think magnofication of zoom gesture is affecting coordinates reported by // this NSPoint point = [event locationInWindow]; - + // This flips so upper left corner is 0,0, vs. bottom left point = [self convertPoint:point fromView:nil]; @@ -1165,35 +1141,32 @@ - (void)mouseMoved:(NSEvent *)event _showSettings->cursorY = (int32_t)point.y; _data.updateEyedropper(); - + // Cause a new sample for eyedropper (will run in Metal CompletedHandler) self.needsDisplay = YES; } - - - --(void)updateEyedropperText +- (void)updateEyedropperText { if (_showSettings->imageBoundsX == 0) return; - + float2 uv; uv.x = _showSettings->textureLookupX / (float)_showSettings->imageBoundsX; uv.y = _showSettings->textureLookupY / (float)_showSettings->imageBoundsY; - + // convert data to text _data.showEyedropperData(uv); - + const Atlas* atlas = _data.findAtlasAtUV(uv); if (atlas) { // convert back to pixels in the current mip float mipBoundsX = std::max(1, _showSettings->imageBoundsX >> _showSettings->mipNumber); float mipBoundsY = std::max(1, _showSettings->imageBoundsY >> _showSettings->mipNumber); - + float4 rect = atlas->rect(); rect.xz *= mipBoundsX; rect.yw *= mipBoundsY; - + string atlasText; sprintf(atlasText, "%d,%d %dx%d %s", (int32_t)rect.x, (int32_t)rect.y, @@ -1208,13 +1181,13 @@ -(void)updateEyedropperText [self updateHudText]; } -- (void)setEyedropperText:(const char *)text +- (void)setEyedropperText:(const char*)text { _data.setEyedropperText(text); [self updateHudText]; } -- (void)setHudText:(const char *)text +- (void)setHudText:(const char*)text { _data.setTextSlot(kTextSlotHud, text); [self updateHudText]; @@ -1225,29 +1198,29 @@ - (void)updateHudText // combine textSlots string text = _data.textFromSlots(_tableView.hidden); - NSString *textNS = [NSString stringWithUTF8String:text.c_str()]; - + NSString* textNS = [NSString stringWithUTF8String:text.c_str()]; + // This is drop shadowed by drawing same text twice _hudLabel2.stringValue = textNS; _hudLabel2.needsDisplay = YES; - + _hudLabel.stringValue = textNS; _hudLabel.needsDisplay = YES; } -- (void)scrollWheel:(NSEvent *)event +- (void)scrollWheel:(NSEvent*)event { // skip until image loaded if (_showSettings->imageBoundsX == 0) { return; } - + // From ImGui notes: // From macOS 12.1, scrolling with two fingers and then decelerating // by tapping two fingers results in two events appearing. if (event.phase == NSEventPhaseCancelled) return; - + double wheelX = [event scrollingDeltaX]; double wheelY = [event scrollingDeltaY]; @@ -1256,20 +1229,20 @@ - (void)scrollWheel:(NSEvent *)event // and trackpad fires on that too causing the image to zoom away to nothing (inertia maybe) // https://stackoverflow.com/questions/6642058/mac-cocoa-how-can-i-detect-trackpad-scroll-gestures bool isMouse = ![event hasPreciseScrollingDeltas]; - + if (isMouse) { // zoom with mouse float zoom = _zoomGesture.magnification; if (wheelY != 0.0) { wheelY *= 0.01; wheelY = std::clamp(wheelY, -0.1, 0.1); - + zoom *= 1.0 + wheelY; - + // here have to modify the magnfication, since gesture isn't driving it _zoomGesture.magnification = zoom; - - [self updateZoom: zoom]; + + [self updateZoom:zoom]; } } else { @@ -1279,7 +1252,7 @@ - (void)scrollWheel:(NSEvent *)event float panX = _showSettings->panX + wheelX; float panY = _showSettings->panY + wheelY; - + [self updatePan:panX panY:(float)panY]; } } @@ -1289,12 +1262,12 @@ bool rectIntersectsRect(float4 lhs, float4 rhs) // convert rect from (origin, size) to (min, max) float4 lRect = lhs.xyxy; lRect.zw += lhs.zw; - + float4 rRect = rhs.xyxy; rRect.zw += rhs.zw; - + return all(lRect.xy <= rRect.zw) && // min <= max - all(lRect.zw >= rRect.xy); // max >= min + all(lRect.zw >= rRect.xy); // max >= min } // TODO: move to data, but eliminate CGRect usage @@ -1303,15 +1276,15 @@ - (void)updatePan:(float)panX panY:(float)panY //Renderer* renderer = (Renderer *)self.delegate; float4x4 projectionViewModelMatrix = _data.computeImageTransform(panX, - panY, - _showSettings->zoom); + panY, + _showSettings->zoom); // don't allow panning the entire image off the view boundary // transform the upper left and bottom right corner or the image // what if zoom moves it outside? float ar = _showSettings->imageAspectRatio(); - + float4 pt0 = projectionViewModelMatrix * float4m(-0.5f * ar, -0.5f, 0.0f, 1.0f); float4 pt1 = projectionViewModelMatrix * float4m(0.5f * ar, 0.5f, 0.0f, 1.0f); @@ -1344,14 +1317,14 @@ - (void)updatePan:(float)panX panY:(float)panY _showSettings->panX = panX; _showSettings->panY = panY; -// if (doPrintPanZoom) { -// string text; -// sprintf(text, -// "Pan %.3f,%.3f\n" -// "Zoom %.2fx\n", -// _showSettings->panX, _showSettings->panY, _showSettings->zoom); -// [self setHudText:text.c_str()]; -// } + // if (doPrintPanZoom) { + // string text; + // sprintf(text, + // "Pan %.3f,%.3f\n" + // "Zoom %.2fx\n", + // _showSettings->panX, _showSettings->panY, _showSettings->zoom); + // [self setHudText:text.c_str()]; + // } // Cause a new sample from Metal to eyeDropper _data.updateEyedropper(); @@ -1372,9 +1345,6 @@ - (BOOL)validateUserInterfaceItem:(id)item return YES; } - - - - (IBAction)handleAction:(id)sender { NSEvent* theEvent = [NSApp currentEvent]; @@ -1388,21 +1358,21 @@ - (IBAction)handleAction:(id)sender else if ([sender isKindOfClass:[NSMenuItem class]]) { action = _data.actionFromMenu(senderPtr); } - + if (!action) { KLOGE("kram", "unknown UI element"); return; } - + [self handleEventAction:action isShiftKeyDown:isShiftKeyDown]; } -- (void)flagsChanged:(NSEvent *)theEvent +- (void)flagsChanged:(NSEvent*)theEvent { _modifierFlags = theEvent.modifierFlags; } -- (void)keyDown:(NSEvent *)theEvent +- (void)keyDown:(NSEvent*)theEvent { bool isShiftKeyDown = theEvent.modifierFlags & NSEventModifierFlagShift; uint32_t keyCode = theEvent.keyCode; @@ -1410,19 +1380,19 @@ - (void)keyDown:(NSEvent *)theEvent // for now hit esc to hide the table views if (keyCode == Key::Escape) { [self hideFileTable]; - + _hudHidden = false; [self updateHudVisibility]; return; } - + const Action* action = _data.actionFromKey(keyCode); if (!action) { [super keyDown:theEvent]; //KLOGE("kram", "unknown UI element"); return; } - + bool isHandled = [self handleEventAction:action isShiftKeyDown:isShiftKeyDown]; if (!isHandled) { // this will bonk @@ -1452,20 +1422,19 @@ - (void)updateHudVisibility _hudLabel2.hidden = _hudHidden || !_showSettings->isHudShown; } - - (bool)handleEventAction:(const Action*)action isShiftKeyDown:(bool)isShiftKeyDown { Renderer* renderer = (Renderer*)self.delegate; - + ActionState actionState; if (!_data.handleEventAction(action, isShiftKeyDown, actionState)) return false; - + // Do the leftover action work to call ObjC if (action == _data._actionVertical) { _buttonStack.orientation = _showSettings->isVerticalUI - ? NSUserInterfaceLayoutOrientationVertical - : NSUserInterfaceLayoutOrientationHorizontal; + ? NSUserInterfaceLayoutOrientationVertical + : NSUserInterfaceLayoutOrientationHorizontal; } else if (action == _data._actionHideUI) { _buttonStack.hidden = _showSettings->isHideUI; @@ -1475,7 +1444,6 @@ - (bool)handleEventAction:(const Action*)action isShiftKeyDown:(bool)isShiftKeyD } else if (action == _data._actionInfo) { if (_showSettings->isHudShown) { - // also hide the file table, since this can be long [self hideFileTable]; } @@ -1489,7 +1457,7 @@ - (bool)handleEventAction:(const Action*)action isShiftKeyDown:(bool)isShiftKeyD // tell the renderer to show one or other view renderer.isToggleView = !_showSettings->isSRGBShown; } - + //------------- // Update everything if (!actionState.hudText.empty()) { @@ -1506,10 +1474,6 @@ - (bool)handleEventAction:(const Action*)action isShiftKeyDown:(bool)isShiftKeyD return true; } - - - - // Note: docs state that drag&drop should be handled automatically by UTI setup // via openURLs but I find these calls are needed, or it doesn't work. Maybe // need to register for NSURL instead of NSPasteboardTypeFileURL. For example, @@ -1521,7 +1485,7 @@ - (NSDragOperation)draggingEntered:(id)sender if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) { NSPasteboard* pasteboard = [sender draggingPasteboard]; - + bool canReadPasteboardObjects = [pasteboard canReadObjectForClasses:@[ [NSURL class] ] options:pasteboardOptions]; @@ -1544,9 +1508,9 @@ - (BOOL)prepareForDragOperation:(id)sender - (BOOL)performDragOperation:(id)sender { NSPasteboard* pasteboard = [sender draggingPasteboard]; - - NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]] - options: pasteboardOptions]; + + NSArray* urls = [pasteboard readObjectsForClasses:@[ [NSURL class] ] + options:pasteboardOptions]; int filesCount = [urls count]; if (filesCount > 0) { if ([self loadTextureFromURLs:urls]) { @@ -1558,10 +1522,6 @@ - (BOOL)performDragOperation:(id)sender return NO; } - - - - - (void)updateFileSelection { // set selection @@ -1570,18 +1530,20 @@ - (void)updateFileSelection [_tableView scrollRowToVisible:fileIndex]; } -- (BOOL)setImageFromSelection:(NSInteger)index { +- (BOOL)setImageFromSelection:(NSInteger)index +{ if (!_data._files.empty()) { if (_data._fileIndex != index) { _data._fileIndex = index; return [self loadFile]; } } - + return NO; } -- (BOOL)setShapeFromSelection:(NSInteger)index { +- (BOOL)setShapeFromSelection:(NSInteger)index +{ if (_showSettings->meshNumber != index) { _showSettings->meshNumber = index; self.needsDisplay = YES; @@ -1590,137 +1552,130 @@ - (BOOL)setShapeFromSelection:(NSInteger)index { return NO; } - - - --(BOOL)loadFile +- (BOOL)loadFile { if (_data._files.empty()) return NO; - + // lookup the filename and data at that entry const File& file = _data._files[_data._fileIndex]; const char* filename = file.nameShort.c_str(); - - setErrorLogCapture( true ); - + + setErrorLogCapture(true); + bool success = _data.loadFile(); - + // Update these settings - + if (!success) { string errorText; getErrorLogCaptureText(errorText); setErrorLogCapture(false); - + string finalErrorText; // this does have previous filename set _data.setFailedText(file.name.c_str(), finalErrorText); finalErrorText += errorText; - + [self setHudText:finalErrorText.c_str()]; return NO; } - setErrorLogCapture( false ); - + setErrorLogCapture(false); + //------- Renderer* renderer = (Renderer*)self.delegate; - + _showSettings->isSRGBShown = false; if (success && renderer.hasToggleView) { _showSettings->isSRGBShown = isSrgbFormat(_showSettings->originalFormat); } - + renderer.playAnimations = _showSettings->isPlayAnimations; renderer.isToggleView = !_showSettings->isSRGBShown; - + // ------------- string title = _showSettings->windowTitleString(filename); self.window.title = [NSString stringWithUTF8String:title.c_str()]; - + // doesn't set imageURL or update the recent document menu - + // show the controls if (_data._noImageLoaded) { _showSettings->isHideUI = false; - _buttonStack.hidden = NO; // show controls + _buttonStack.hidden = NO; // show controls _data._noImageLoaded = false; } - + // show/hide button _data.updateUIAfterLoad(); - + self.needsDisplay = YES; return YES; } - - --(void)loadFilesFromUrls:(NSArray*)urls skipSubdirs:(BOOL)skipSubdirs +- (void)loadFilesFromUrls:(NSArray*)urls skipSubdirs:(BOOL)skipSubdirs { // convert urls to vector for C++ vector urlStrings; for (NSURL* url in urls) { urlStrings.push_back(url.fileSystemRepresentation); } - + // C++ to build list _data.loadFilesFromUrls(urlStrings, skipSubdirs); - + //------------------- - + NSMutableDictionary* attribsOff = [NSMutableDictionary dictionaryWithObjectsAndKeys: - //[NSFont systemFontOfSize:64.0],NSFontAttributeName, - [NSColor whiteColor],NSForegroundColorAttributeName, - [NSNumber numberWithFloat:-2.0],NSStrokeWidthAttributeName, - [NSColor blackColor],NSStrokeColorAttributeName, - nil]; - + //[NSFont systemFontOfSize:64.0],NSFontAttributeName, + [NSColor whiteColor], NSForegroundColorAttributeName, + [NSNumber numberWithFloat:-2.0], NSStrokeWidthAttributeName, + [NSColor blackColor], NSStrokeColorAttributeName, + nil]; + // add the files into the file list [_tableViewController.items removeAllObjects]; - for (const auto& file: _data._files) { + for (const auto& file : _data._files) { const char* filenameShort = file.nameShort.c_str(); - - NSString* fileMenuText = [NSString stringWithUTF8String: filenameShort]; + + NSString* fileMenuText = [NSString stringWithUTF8String:filenameShort]; NSMutableAttributedString* fileMenuStr = [[NSMutableAttributedString alloc] initWithString:fileMenuText attributes:attribsOff]; - + [_tableViewController.items addObject:fileMenuStr]; } - + // reloadData calls selectionDidChange which then sets _fileIndex = 0; uint32_t fileIndex = _data._fileIndex; [_tableView reloadData]; _data._fileIndex = fileIndex; - + [self updateFileSelection]; [self hideFileTable]; - + // add it to recent docs (only 10 slots) if (urls.count == 1) { NSDocumentController* dc = - [NSDocumentController sharedDocumentController]; + [NSDocumentController sharedDocumentController]; [dc noteNewRecentDocumentURL:urls[0]]; } } - - (BOOL)loadTextureFromURLs:(NSArray*)urls { // turn back on the hud if was in a list view _hudHidden = false; [self updateHudVisibility]; - + const char* filename = ""; NSURL* url = urls[0]; - if ([url.scheme isEqualToString:@"kram"]) - { + if ([url.scheme isEqualToString:@"kram"]) { // the resource specifier has port and other data // for now treat this as a local file path. - + // kram://filename.ktx filename = [url.resourceSpecifier UTF8String]; filename = filename + 2; // skip the // - + // can't get Slack to honor links like these // with a kram:///Users/... // or with kram://~/blah @@ -1729,44 +1684,43 @@ - (BOOL)loadTextureFromURLs:(NSArray*)urls // also need this same treatment instead // of relying on url.fileSystemRepresentation } - else - { + else { filename = url.fileSystemRepresentation; } bool isSingleFile = urls.count == 1; - - Renderer* renderer = (Renderer *)self.delegate; - + + Renderer* renderer = (Renderer*)self.delegate; + // Handle shader hotload if (isSingleFile && endsWithExtension(filename, ".metallib")) { if ([renderer hotloadShaders:filename]) { NSURL* metallibFileURL = - [NSURL fileURLWithPath:[NSString stringWithUTF8String:filename]]; - + [NSURL fileURLWithPath:[NSString stringWithUTF8String:filename]]; + // add to recent docs, so can reload quickly NSDocumentController* dc = - [NSDocumentController sharedDocumentController]; + [NSDocumentController sharedDocumentController]; [dc noteNewRecentDocumentURL:metallibFileURL]; - + return YES; } return NO; } - + // don't leave archive table open if (isSingleFile) [self hideFileTable]; // only recurse down subdirs if cmd key held during drop or recent menu item selection - bool skipSubdirs = ( _modifierFlags & NSEventModifierFlagCommand ) == 0; - + bool skipSubdirs = (_modifierFlags & NSEventModifierFlagCommand) == 0; + [self loadFilesFromUrls:urls skipSubdirs:skipSubdirs]; - + BOOL success = [self loadFile]; return success; } - --(BOOL)loadModelFile:(const char*)filename + +- (BOOL)loadModelFile:(const char*)filename { #if USE_GLTF // Right now can only load these if they are embedded, since sandbox will @@ -1774,32 +1728,32 @@ -(BOOL)loadModelFile:(const char*)filename // related items, but they must all be named the same. I think if folder // instead of the file is selected, then could search and find the gltf files // and the other files. - + //---------------------- // These assets should be combined into a single hierarchy, and be able to // save out a scene with all of them in a single scene. But that should // probably reference original content in case it's updated. - + // const char* filenameShort = toFilenameShort(filename); //double timestamp = FileHelper::modificationTimestamp(filename); - + // TODO: this used to compare filename timestamp? - + // This code only takes url, so construct one - Renderer* renderer = (Renderer *)self.delegate; + Renderer* renderer = (Renderer*)self.delegate; [renderer releaseAllPendingTextures]; BOOL success = [renderer loadModel:filename]; - + // TODO: split this off to a completion handler, since loadModel is async // and should probably also have a cancellation (or counter) - + // show/hide button _data.updateUIAfterLoad(); - + if (!success) { return NO; } - + return success; #else return NO; @@ -1816,10 +1770,9 @@ - (void)concludeDragOperation:(id)sender // did setNeedsDisplay, but already doing that in loadTextureFromURL } -- (void)tableViewSelectionDidChange:(NSNotification *)notification +- (void)tableViewSelectionDidChange:(NSNotification*)notification { - if (notification.object == _tableView) - { + if (notification.object == _tableView) { // image NSInteger selectedRow = [_tableView selectedRow]; [self setImageFromSelection:selectedRow]; @@ -1830,8 +1783,9 @@ - (void)addNotifications { // listen for the selection change messages [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(tableViewSelectionDidChange:) - name:NSTableViewSelectionDidChangeNotification object:nil]; + selector:@selector(tableViewSelectionDidChange:) + name:NSTableViewSelectionDidChangeNotification + object:nil]; } - (void)removeNotifications @@ -1840,7 +1794,6 @@ - (void)removeNotifications [[NSNotificationCenter defaultCenter] removeObserver:self]; } - - (BOOL)acceptsFirstResponder { return YES; @@ -1872,7 +1825,7 @@ - (void)viewDidLoad { [super viewDidLoad]; - _view = (MyMTKView *)self.view; + _view = (MyMTKView*)self.view; // have to disable this since reading back from textures // that slows the blit to the screen @@ -1886,9 +1839,8 @@ - (void)viewDidLoad _renderer = [[Renderer alloc] initWithMetalKitView:_view settings:_view.showSettings - data:_view.data]; + data:_view.data]; - // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html // this is better than requesting mousemoved events, they're only sent when // cursor is inside @@ -1905,7 +1857,7 @@ - (void)viewDidLoad [_view addTrackingArea:_trackingArea]; [_view addNotifications]; - + [_view setupUI]; // original sample code was sending down _view.bounds.size, but need @@ -1914,30 +1866,28 @@ - (void)viewDidLoad // ObjC++ delegate _view.delegate = _renderer; - + [_renderer setEyedropperDelegate:_view]; } - - @end bool DataDelegate::loadFile(bool clear) { MyMTKView* view_ = (__bridge MyMTKView*)view; - + if (clear) { // set selection [view_ updateFileSelection]; - + // want it to respond to arrow keys //[self.window makeFirstResponder: _tableView]; - + // show the files table [view_ showFileTable]; [view_ setEyedropperText:""]; } - + return [view_ loadFile]; } @@ -1950,9 +1900,9 @@ - (void)viewDidLoad bool DataDelegate::loadTextureFromImage(const char* fullFilename, double timestamp, KTXImage& image, KTXImage* imageNormal, KTXImage* imageDiff, bool isArchive) { MyMTKView* view_ = (__bridge MyMTKView*)view; - Renderer* renderer = (Renderer *)view_.delegate; + Renderer* renderer = (Renderer*)view_.delegate; [renderer releaseAllPendingTextures]; - + if (![renderer loadTextureFromImage:fullFilename timestamp:timestamp image:image @@ -1961,18 +1911,17 @@ - (void)viewDidLoad isArchive:isArchive]) { return false; } - + return true; } - //------------- -int main(int argc, const char *argv[]) +int main(int argc, const char* argv[]) { - ThreadInfo infoMain = { "Main", ThreadPriority::Interactive, 0 }; + ThreadInfo infoMain = {"Main", ThreadPriority::Interactive, 0}; setThreadInfo(infoMain); - + @autoreleasepool { // Setup code that might create autoreleased objects goes here. } diff --git a/scripts/formatSources.sh b/scripts/formatSources.sh index feb00d90..7c01f0cd 100755 --- a/scripts/formatSources.sh +++ b/scripts/formatSources.sh @@ -33,12 +33,12 @@ clang-format -style=file -i kram/*.(cpp|h) clang-format -style=file -i vectormath/*.(cpp|h) popd -# pushd .. -# clang-format -style=file -i kramv/*.* -# clang-format -style=file -i kramc/*.* -# clang-format -style=file -i kram-thumb/*.(cpp|h) -# clang-format -style=file -i kram-thumb-win/*.* -# clang-format -style=file -i kram-profile/*.* -# clang-format -style=file -i kram-preview/*.* -# clang-format -style=file -i hlslparser/*.* -# popd \ No newline at end of file +pushd .. +clang-format -style=file -i kramv/*.(cpp|h||mm) +clang-format -style=file -i kramc/*.(cpp|h) +clang-format -style=file -i kram-thumb/*.(cpp|h|mm) +clang-format -style=file -i kram-thumb-win/*.(cpp|h) +clang-format -style=file -i kram-profile/Source/*.(cpp|h|mm) +clang-format -style=file -i kram-preview/*.(cpp|h|mm) +clang-format -style=file -i hlslparser/src/*.(cpp|h) +popd \ No newline at end of file