blob: df1997d1f0b6e57a2304d481597e50eebeb5f150 [file] [log] [blame]
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "glimp/shaders/hash_glsl_source.h"
namespace glimp {
namespace shaders {
namespace {
// Takes the current hash and combines it with a new character to produce a
// new hash.
uint32_t UpdateHash(uint32_t hash, char update_char) {
hash += update_char;
hash += (hash << 10);
hash ^= (hash >> 6);
return hash;
}
// Applies some additional calculations to the hash after all characters
// have been accumulated.
uint32_t FinalizeHash(uint32_t hash) {
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
const char* ScanUntilNonWhitespace(const char* source) {
uint32_t i = 0;
for (; source[i] != '\0'; ++i) {
if (source[i] == ' ' || source[i] == '\t' || source[i] == '\n') {
continue;
}
if (source[i] == '/' && source[i + 1] == '/') {
// If we see a comment, leave it out of the hash.
while (source[i] != '\n' && source[i] != '\0') {
++i;
}
if (source[i] == '\0') {
break;
} else {
continue;
}
}
break;
}
return &source[i];
}
const char* ScanUntilHashableCharacter(const char* source) {
while (true) {
const char* next_char = ScanUntilNonWhitespace(source);
// If we find empty scopes (e.g:
//
// {
// // Stage 0: Texture
// }
//
// Skip past them without hashing those characters.
if (*next_char == '{') {
const char* next_next_char = ScanUntilNonWhitespace(next_char + 1);
if (*next_next_char == '}') {
source = next_next_char + 1;
continue;
}
}
return next_char;
}
}
} // namespace
uint32_t HashGLSLSource(const char* source) {
uint32_t hash = 0;
const char* cur_char = source;
while (true) {
cur_char = ScanUntilHashableCharacter(cur_char);
if (*cur_char == '\0') {
break;
}
hash = UpdateHash(hash, *cur_char);
++cur_char;
}
return FinalizeHash(hash);
}
} // namespace shaders
} // namespace glimp