From 9a1b59a73e5aeeddc5351fb208866ddee1956ec8 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Fri, 10 Oct 2014 11:29:16 +0200 Subject: [PATCH 01/17] Intermediate commit --- ext/ghoul | 2 +- include/openspace/abuffer/abuffer.h | 15 +- include/openspace/abuffer/abufferdynamic.h | 3 - include/openspace/engine/openspaceengine.h | 3 + include/openspace/rendering/renderengine.h | 4 + openspace.cfg | 4 +- shaders/ABuffer/abufferAddToBuffer.hglsl | 2 +- shaders/ABuffer/abufferResolveFragment.glsl | 23 +- shaders/ABuffer/abufferStruct.hglsl | 1 - src/abuffer/abuffer.cpp | 325 ++++++++------------ src/engine/openspaceengine.cpp | 36 ++- src/interaction/interactionhandler.cpp | 7 + src/rendering/renderablevolume.cpp | 6 +- src/rendering/renderengine.cpp | 15 +- 14 files changed, 226 insertions(+), 220 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index cec683e244..3691eec2c5 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit cec683e244ab02a4454d07f7406a5c837a4a6f97 +Subproject commit 3691eec2c5fbd52ea45d43374814487c2c647960 diff --git a/include/openspace/abuffer/abuffer.h b/include/openspace/abuffer/abuffer.h index 8ee0cf253d..1c31bcfe17 100644 --- a/include/openspace/abuffer/abuffer.h +++ b/include/openspace/abuffer/abuffer.h @@ -64,10 +64,10 @@ protected: void generateShaderSource(); bool updateShader(); - std::string openspaceHeaders(); - std::string openspaceSamplerCalls(); - std::string openspaceSamplers(); - std::string openspaceTransferFunction(); + void openspaceHeaders(); + void openspaceSamplerCalls(); + void openspaceSamplers(); + void openspaceTransferFunction(); unsigned int _width, _height, _totalPixels; @@ -75,8 +75,6 @@ private: GLuint _screenQuad; bool _validShader; - std::string _fragmentShaderPath; - ghoul::filesystem::File* _fragmentShaderFile; ghoul::opengl::ProgramObject* _resolveShader; std::vector > _volumes; @@ -84,13 +82,8 @@ private: std::vector _samplerFiles; std::vector _samplers; - // Development functionality to update shader for changes in several files - std::vector _shaderFiles; - float _volumeStepFactor; - - }; // ABuffer } // openspace diff --git a/include/openspace/abuffer/abufferdynamic.h b/include/openspace/abuffer/abufferdynamic.h index 23959f08f1..4d3b91ce59 100644 --- a/include/openspace/abuffer/abufferdynamic.h +++ b/include/openspace/abuffer/abufferdynamic.h @@ -51,9 +51,6 @@ private: GLuint _fragmentBuffer; GLuint _fragmentTexture; - - - }; // ABufferDynamic } // openspace diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 4973bb4606..4470939a4f 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -36,6 +36,7 @@ #include //#include +#include #include #include #include @@ -75,6 +76,7 @@ public: InteractionHandler& interactionHandler(); RenderEngine& renderEngine(); scripting::ScriptEngine& scriptEngine(); + ghoul::filesystem::CacheManager& cacheManager(); // SGCT callbacks bool initializeGL(); @@ -103,6 +105,7 @@ private: InteractionHandler _interactionHandler; RenderEngine _renderEngine; scripting::ScriptEngine _scriptEngine; + ghoul::filesystem::CacheManager* _cacheManager; ghoul::cmdparser::CommandlineParser _commandlineParser; #ifdef OPENSPACE_VIDEO_EXPORT bool _doVideoExport; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 8859f7a0c1..79682a95cf 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -57,6 +57,8 @@ public: void render(); void postDraw(); + void takeScreenshot(); + void serialize(std::vector& dataStream, size_t& offset); void deserialize(const std::vector& dataStream, size_t& offset); @@ -75,6 +77,8 @@ private: SceneGraph* _sceneGraph; ABuffer* _abuffer; + bool _takeScreenshot; + void generateGlslConfig(); }; diff --git a/openspace.cfg b/openspace.cfg index 24fcdc1837..2da2931978 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -3,11 +3,11 @@ return { SGCT = "${BASE_PATH}/config/sgct", SCRIPTS = "${BASE_PATH}/scripts", SHADERS = "${BASE_PATH}/shaders", + SHADERS_GENERATED = "${SHADERS}/generated", OPENSPACE_DATA = "${BASE_PATH}/openspace-data", TESTDIR = "${BASE_PATH}/src/tests", CONFIG = "${BASE_PATH}/config", - CACHE = "${BASE_PATH}/cache", - TEMPORARY = "${BASE_PATH}/tmp" + CACHE = "${BASE_PATH}/cache" }, SpiceKernel = { Time = "${OPENSPACE_DATA}/spice/naif0010.tls", diff --git a/shaders/ABuffer/abufferAddToBuffer.hglsl b/shaders/ABuffer/abufferAddToBuffer.hglsl index f930813941..6bf1624a8a 100644 --- a/shaders/ABuffer/abufferAddToBuffer.hglsl +++ b/shaders/ABuffer/abufferAddToBuffer.hglsl @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include <${SHADERS}/ABuffer/constants.hglsl> +#include <${SHADERS_GENERATED}/constants.hglsl> #if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED layout (binding = 0, r32ui) uniform uimage2D anchorPointerTexture; diff --git a/shaders/ABuffer/abufferResolveFragment.glsl b/shaders/ABuffer/abufferResolveFragment.glsl index 3c9abf186b..1a3411be7e 100644 --- a/shaders/ABuffer/abufferResolveFragment.glsl +++ b/shaders/ABuffer/abufferResolveFragment.glsl @@ -24,10 +24,13 @@ #version 430 + + // ================================================================================ // Settings // ================================================================================ -#pragma openspace insert SETTINGS +//#pragma openspace insert SETTINGS +#include <${SHADERS_GENERATED}/ABufferSettings.hglsl>:notrack // Select type of depth calculations #define PSCDEPTH 1 @@ -79,7 +82,8 @@ out vec4 out_color; // Headers, // volume and transferfunctions uniforms // ================================================================================ -#pragma openspace insert HEADERS +//#pragma openspace insert HEADERS +#include <${SHADERS_GENERATED}/ABufferHeaders.hglsl>:notrack // ================================================================================ // The ABuffer specific includes and definitions @@ -221,7 +225,11 @@ vec4 calculate_final_color(uint frag_count) { vec4 color = vec4(0); for(int k = 0; k < max_iterations && final_color.a < ALPHA_LIMIT && k < LOOP_LIMIT; ++k) { -#pragma openspace insert SAMPLERCALLS +// #pragma openspace insert SAMPLERCALLS +#include <${SHADERS_GENERATED}/ABufferSamplerCalls.hglsl>:notrack + + + } @@ -253,9 +261,13 @@ vec4 calculate_final_color(uint frag_count) { // Transferfunction visualizer // ================================================================================ #ifdef VISUALIZE_TRANSFERFUNCTIONS -#pragma openspace insert TRANSFERFUNC +// #pragma openspace insert TRANSFERFUNC +#include <${SHADERS_GENERATED}/ABufferTransferFunctionVisualizer.hglsl>:notrack #endif + + + // if(frag_count == 0) { // final_color = vec4(0.5,0.5,0.5,1.0); // } else if(frag_count == 1) { @@ -300,7 +312,8 @@ void main() { // ================================================================================ // The samplers implementations // ================================================================================ -#pragma openspace insert SAMPLERS +//#pragma openspace insert SAMPLERS +#include <${SHADERS_GENERATED}/ABufferSamplers.hglsl>:notrack diff --git a/shaders/ABuffer/abufferStruct.hglsl b/shaders/ABuffer/abufferStruct.hglsl index 5c510c4bd0..5dfde0b978 100644 --- a/shaders/ABuffer/abufferStruct.hglsl +++ b/shaders/ABuffer/abufferStruct.hglsl @@ -31,7 +31,6 @@ // #define ABUFFER_DYNAMIC 3 // #define ABUFFER_IMPLEMENTATION ABUFFER_SINGLE_LINKED - //======================================================================================== // ABufferStruct_t declaration //======================================================================================== diff --git a/src/abuffer/abuffer.cpp b/src/abuffer/abuffer.cpp index 74cd43521d..3498c7afba 100644 --- a/src/abuffer/abuffer.cpp +++ b/src/abuffer/abuffer.cpp @@ -34,12 +34,14 @@ #include namespace { - std::string _loggerCat = "ABuffer"; -std::string padGeneratedString(const std::string& content) { - std::string _content_ = "// GENERATED CONTENT\n" + content + "\n// END GENERATED CONTENT"; - return _content_; -} + const std::string generatedSettingsPath = "${SHADERS_GENERATED}/ABufferSettings.hglsl"; + const std::string generatedHeadersPath = "${SHADERS_GENERATED}/ABufferHeaders.hglsl"; + const std::string generatedSamplerCallsPath = "${SHADERS_GENERATED}/ABufferSamplerCalls.hglsl"; + const std::string generatedTransferFunctionVisualizerPath = "${SHADERS_GENERATED}/ABufferTransferFunctionVisualizer.hglsl"; + const std::string generatedSamplersPath = "${SHADERS_GENERATED}/ABufferSamplers.hglsl"; + + const std::string _loggerCat = "ABuffer"; } @@ -51,49 +53,37 @@ ABuffer::ABuffer() : _validShader(false), _resolveShader(nullptr) { _width = xSize; _height = ySize; _totalPixels = _width * _height; - const std::string fragmentShaderSourcePath = absPath("${SHADERS}/ABuffer/abufferResolveFragment.glsl"); - _fragmentShaderFile = new ghoul::filesystem::File(fragmentShaderSourcePath, true); - _fragmentShaderPath = fragmentShaderSourcePath.substr(0, fragmentShaderSourcePath.length()-4) + "gglsl"; } ABuffer::~ABuffer() { - if(_fragmentShaderFile) - delete _fragmentShaderFile; if(_resolveShader) delete _resolveShader; - + for(auto file: _samplerFiles) { delete file; } - for(auto file: _shaderFiles) { - delete file; - } } bool ABuffer::initializeABuffer() { // ============================ // SHADERS // ============================ - auto shaderCallback = [this](const ghoul::filesystem::File& file) { - _validShader = false; - }; - _fragmentShaderFile->setCallback(shaderCallback); - - // Development functionality to update shader for changes in several files - auto addFunc = [this, shaderCallback](const std::string& path) { - ghoul::filesystem::File* f = new ghoul::filesystem::File(path, false); - f->setCallback(shaderCallback); - _shaderFiles.push_back(f); + auto shaderCallback = [this](ghoul::opengl::ProgramObject* program) { + // Error for visibility in log + LERROR(program->name() << " invalidated"); + _validShader = false; }; - addFunc("${SHADERS}/ABuffer/constants.hglsl"); - addFunc("${SHADERS}/ABuffer/abufferSort.hglsl"); - addFunc("${SHADERS}/ABuffer/abufferAddToBuffer.hglsl"); - addFunc("${SHADERS}/ABuffer/abufferStruct.hglsl"); - addFunc("${SHADERS}/PowerScaling/powerScaling_fs.hglsl"); - addFunc("${SHADERS}/PowerScaling/powerScaling_fs.hglsl"); - addFunc("${SHADERS}/PowerScaling/powerScaling_vs.hglsl"); - addFunc("${SHADERS}/PowerScaling/powerScalingMath.hglsl"); + + generateShaderSource(); + _resolveShader = ghoul::opengl::ProgramObject::Build( + "ABufferResolve", + "${SHADERS}/ABuffer/abufferResolveVertex.glsl", + "${SHADERS}/ABuffer/abufferResolveFragment.glsl", + shaderCallback); + + if (!_resolveShader) + return false; // ============================ // GEOMETRY (quad) @@ -122,38 +112,40 @@ bool ABuffer::initializeABuffer() { void ABuffer::resolve() { if( ! _validShader) { - _validShader = true; - generateShaderSource(); + SleepEx(0, TRUE); + //generateShaderSource(); updateShader(); + _validShader = true; } - if(_resolveShader) { - _resolveShader->activate(); - int startAt = 0; - for(int i = 0; i < _volumes.size(); ++i) { - glActiveTexture(GL_TEXTURE0 + i); - _volumes.at(i).second->bind(); - startAt = i + 1; - } - for(int i = 0; i < _transferFunctions.size(); ++i) { - glActiveTexture(GL_TEXTURE0 + startAt + i); - _transferFunctions.at(i).second->bind(); - } + if (!_resolveShader) + return; - // Decrease stepsize in volumes if right click is pressed - // TODO: Let the interactionhandler handle this - int val = sgct::Engine::getMouseButton(0, SGCT_MOUSE_BUTTON_RIGHT); - float volumeStepFactor = (val) ? 0.2: 1.0; - if(volumeStepFactor != _volumeStepFactor) { - _volumeStepFactor = volumeStepFactor; - _resolveShader->setUniform("volumeStepFactor", _volumeStepFactor); - } - - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - - _resolveShader->deactivate(); + _resolveShader->activate(); + int startAt = 0; + for(int i = 0; i < _volumes.size(); ++i) { + glActiveTexture(GL_TEXTURE0 + i); + _volumes.at(i).second->bind(); + startAt = i + 1; } + for(int i = 0; i < _transferFunctions.size(); ++i) { + glActiveTexture(GL_TEXTURE0 + startAt + i); + _transferFunctions.at(i).second->bind(); + } + + // Decrease stepsize in volumes if right click is pressed + // TODO: Let the interactionhandler handle this + int val = sgct::Engine::getMouseButton(0, SGCT_MOUSE_BUTTON_RIGHT); + float volumeStepFactor = (val) ? 0.2: 1.0; + if(volumeStepFactor != _volumeStepFactor) { + _volumeStepFactor = volumeStepFactor; + _resolveShader->setUniform("volumeStepFactor", _volumeStepFactor); + } + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _resolveShader->deactivate(); } void ABuffer::addVolume(const std::string& tag,ghoul::opengl::Texture* volume) { @@ -182,33 +174,19 @@ int ABuffer::addSamplerfile(const std::string& filename) { } bool ABuffer::updateShader() { - - using ghoul::opengl::ShaderObject; - using ghoul::opengl::ProgramObject; - ProgramObject* resolveShader = ProgramObject::Build("ABuffer resolve", - "${SHADERS}/ABuffer/abufferResolveVertex.glsl", - _fragmentShaderPath); - - if( ! resolveShader) { - LERROR("Resolve shader not updated"); - return false; - } - - int startAt = 0; - for(int i = 0; i < _volumes.size(); ++i) { - resolveShader->setUniform(_volumes.at(i).first, i); - startAt = i + 1; + bool s = _resolveShader->rebuildFromFile(); + if (s) { + int startAt = 0; + for (int i = 0; i < _volumes.size(); ++i) { + _resolveShader->setUniform(_volumes.at(i).first, i); + startAt = i + 1; + } + for (int i = 0; i < _transferFunctions.size(); ++i) { + _resolveShader->setUniform(_transferFunctions.at(i).first, startAt + i); + } + LINFO("Successfully updated shader!"); } - for(int i = 0; i < _transferFunctions.size(); ++i) { - resolveShader->setUniform(_transferFunctions.at(i).first, startAt + i); - } - - if(_resolveShader) - delete _resolveShader; - - _resolveShader = resolveShader; - LDEBUG("Successfully updated shader!"); - return true; + return s; } void ABuffer::generateShaderSource() { @@ -225,156 +203,123 @@ void ABuffer::generateShaderSource() { _samplers.at(i) = source; } - std::string line, source = ""; - std::ifstream fragmentShaderFile(_fragmentShaderFile->path()); - if(fragmentShaderFile.is_open()) { - while(std::getline(fragmentShaderFile, line)) { - if(line == "#pragma openspace insert HEADERS") { - line = padGeneratedString(openspaceHeaders()); - } else if(line == "#pragma openspace insert SAMPLERCALLS") { - line = padGeneratedString(openspaceSamplerCalls()); - } else if(line == "#pragma openspace insert SAMPLERS") { - line = padGeneratedString(openspaceSamplers()); - } else if(line == "#pragma openspace insert SETTINGS") { - line = padGeneratedString(settings()); - } else if(line == "#pragma openspace insert TRANSFERFUNC") { - line = padGeneratedString(openspaceTransferFunction()); - } - source += line + "\n"; - } - } - fragmentShaderFile.close(); - - std::ofstream fragmentShaderOut(_fragmentShaderPath); - fragmentShaderOut << source; - fragmentShaderOut.close(); + LDEBUG("Generating shader includes"); + openspaceHeaders(); + openspaceSamplerCalls(); + openspaceSamplers(); + settings(); + openspaceTransferFunction(); } -std::string ABuffer::openspaceHeaders() { - - std::string headers; - headers += "#define MAX_VOLUMES " + std::to_string(_samplers.size()) + "\n"; - headers += "#define MAX_TF " + std::to_string(_transferFunctions.size()) + "\n"; - +void ABuffer::openspaceHeaders() { + std::ofstream f(absPath(generatedHeadersPath)); + f << "#define MAX_VOLUMES " << std::to_string(_samplers.size()) << "\n" + << "#define MAX_TF " << std::to_string(_transferFunctions.size()) << "\n"; for (int i = 0; i < _volumes.size(); ++i) { - headers += "uniform sampler3D " + _volumes.at(i).first + ";\n"; + f << "uniform sampler3D " << _volumes.at(i).first << ";\n"; } for (int i = 0; i < _transferFunctions.size(); ++i) { - headers += "uniform sampler1D " + _transferFunctions.at(i).first + ";\n"; + f << "uniform sampler1D " << _transferFunctions.at(i).first << ";\n"; } for (int i = 0; i < _samplers.size(); ++i) { auto found = _samplers.at(i).find_first_of('{'); - if(found!=std::string::npos) { - headers += _samplers.at(i).substr(0, found) + ";\n"; + if (found != std::string::npos) { + f << _samplers.at(i).substr(0, found) << ";\n"; } } - if(_volumes.size() < 1) - return headers; + if (_volumes.size() < 1) { + f.close(); + return; + } size_t maxLoop = 0; - headers += "const vec3 volume_dim[] = {\n"; + f << "const vec3 volume_dim[] = {\n"; for (int i = 0; i < _volumes.size(); ++i) { glm::size3_t size = _volumes.at(i).second->dimensions(); - for(int k = 0; k < 3; ++k) + for (int k = 0; k < 3; ++k) maxLoop = glm::max(maxLoop, size[k]); - headers += " vec3(" + std::to_string(size[0]) + ".0," + std::to_string(size[1]) + ".0," - + std::to_string(size[2]) + ".0),\n"; + f << " vec3(" << std::to_string(size[0]) << ".0," + std::to_string(size[1]) << ".0," + << std::to_string(size[2]) + ".0),\n"; } - headers += "};\n"; + f << "};\n"; - headers += "#define LOOP_LIMIT " + std::to_string(maxLoop) + "\n"; + f << "#define LOOP_LIMIT " + std::to_string(maxLoop) + "\n"; - headers += "float volumeStepSize[] = {\n"; + f << "float volumeStepSize[] = {\n"; for (int i = 0; i < _volumes.size(); ++i) { glm::size3_t size = _volumes.at(i).second->dimensions(); - headers += " stepSize,\n"; + f << " stepSize,\n"; } - headers += "};\n"; + f << "};\n"; - headers += "float volumeStepSizeOriginal[] = {\n"; + f << "float volumeStepSizeOriginal[] = {\n"; for (int i = 0; i < _volumes.size(); ++i) { glm::size3_t size = _volumes.at(i).second->dimensions(); - headers += " stepSize,\n"; + f << " stepSize,\n"; } - headers += "};\n"; + f << "};\n"; - return headers; + f.close(); } -std::string ABuffer::openspaceSamplerCalls() { - std::string samplercalls; +void ABuffer::openspaceSamplerCalls() { + std::ofstream f(absPath(generatedSamplerCallsPath)); for (int i = 0; i < _samplers.size(); ++i) { - auto found1 = _samplers.at(i).find_first_not_of("vec4 "); - auto found2 = _samplers.at(i).find_first_of("(",found1); - if(found1 != std::string::npos && found2 != std::string::npos) { + auto found2 = _samplers.at(i).find_first_of("(", found1); + if (found1 != std::string::npos && found2 != std::string::npos) { std::string functionName = _samplers.at(i).substr(found1, found2 - found1); - samplercalls += "#ifndef SKIP_VOLUME_"+std::to_string(i)+"\n"; - samplercalls += "if((currentVolumeBitmask & (1 << " + std::to_string(i) + ")) == "+std::to_string(1 << i)+") {\n"; - samplercalls += " vec4 c = " + functionName + "(final_color,volume_position[" + std::to_string(i) + "]);\n"; - // samplercalls += " if(c.a < 0.1) { \n"; - // samplercalls += " if( volumeStepSize[" + std::to_string(i) + "] < 16.0*volumeStepSizeOriginal[" + std::to_string(i) + "]) \n"; - // samplercalls += " volumeStepSize[" + std::to_string(i) + "] *= 2.0; \n"; - // samplercalls += " } else {\n"; - // samplercalls += " //volume_position[" + std::to_string(i) + "] -= volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; - // samplercalls += " volumeStepSize[" + std::to_string(i) + "] = volumeStepSizeOriginal[" + std::to_string(i) + "]; \n"; - // samplercalls += " //c = " + functionName + "(final_color,volume_position[" + std::to_string(i) + "]);\n"; - // samplercalls += " } \n"; - // samplercalls += " if(c.a > EPSILON)\n"; - samplercalls += " blendStep(final_color, c, volumeStepSize[" + std::to_string(i) + "]);\n"; - // samplercalls += " blendStep(final_color, c, stepSize);\n"; - // samplercalls += " float aaa = volume_length[i]/myMaxSteps;\n"; - samplercalls += " volume_position[" + std::to_string(i) + "] += volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; - // float aaa = ray[v].w/myMaxSteps; - // pos[v] += vec4(ray[v].xyz*vec3(aaa),aaa); - // samplercalls += " volume_position[" + std::to_string(i) + "] += volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; - samplercalls += "}\n"; - samplercalls += "#endif\n"; + f << "#ifndef SKIP_VOLUME_" << std::to_string(i) << "\n" + << "if((currentVolumeBitmask & (1 << " << std::to_string(i) << ")) == " << std::to_string(1 << i) << ") {\n" + << " vec4 c = " << functionName << "(final_color,volume_position[" << std::to_string(i) << "]);\n" + << " blendStep(final_color, c, volumeStepSize[" << std::to_string(i) << "]);\n" + << " volume_position[" << std::to_string(i) << "] += volume_direction[" << std::to_string(i) << "]*volumeStepSize[" << std::to_string(i) << "];\n" + << "}\n" + << "#endif\n"; } - - } - return samplercalls; + f.close(); } -std::string ABuffer::openspaceSamplers() { - std::string samplers; - for (int i = 0; i < _samplers.size(); ++i) { - samplers += _samplers.at(i) + "\n"; +void ABuffer::openspaceSamplers() { + + std::ofstream f(absPath(generatedSamplersPath)); + for (auto sampler : _samplers) { + f << sampler << std::endl; } - return samplers; + f.close(); } -std::string ABuffer::openspaceTransferFunction() { - std::string tf; - tf += "float showfunc_size = 20.0;\n"; - tf += "float SCREEN_HEIGHTf = float(SCREEN_HEIGHT);\n"; - tf += "float SCREEN_WIDTHf = float(SCREEN_WIDTH);\n"; - for(int i = 0; i < _transferFunctions.size(); ++i) { - tf += "if( gl_FragCoord.y > SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i+1)+ - " && gl_FragCoord.y < SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i)+") {\n"; - tf += " float normalizedIntensity = gl_FragCoord.x / (SCREEN_WIDTHf-1) ;\n"; - tf += " vec4 tfc = texture("+ _transferFunctions.at(i).first +", normalizedIntensity);\n"; - tf += " final_color = tfc;\n"; - tf += " float cmpf = SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i+1)+" + tfc.a*showfunc_size;\n"; - tf += " if(gl_FragCoord.y > cmpf) {\n"; - tf += " final_color = vec4(0,0,0,0);\n"; - tf += " } else {\n"; - tf += " final_color.a = 1.0;\n"; - tf += " }\n"; - tf += "} else if(ceil(gl_FragCoord.y) == SCREEN_HEIGHTf - showfunc_size*"+std::to_string(i+1)+") {\n"; - tf += " const float intensity = 0.4;\n"; - tf += " final_color = vec4(intensity,intensity,intensity,1.0);\n"; - tf += "}\n"; +void ABuffer::openspaceTransferFunction() { + std::ofstream f(absPath(generatedTransferFunctionVisualizerPath)); + f << "float showfunc_size = 20.0;\n" + << "float SCREEN_HEIGHTf = float(SCREEN_HEIGHT);\n" + << "float SCREEN_WIDTHf = float(SCREEN_WIDTH);\n"; + for (int i = 0; i < _transferFunctions.size(); ++i) { + f << "if( gl_FragCoord.y > SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i + 1) + << " && gl_FragCoord.y < SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i) << ") {\n" + << " float normalizedIntensity = gl_FragCoord.x / (SCREEN_WIDTHf-1) ;\n" + << " vec4 tfc = texture(" << _transferFunctions.at(i).first << ", normalizedIntensity);\n" + << " final_color = tfc;\n" + << " float cmpf = SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i + 1) << " + tfc.a*showfunc_size;\n" + << " if(gl_FragCoord.y > cmpf) {\n" + << " final_color = vec4(0,0,0,0);\n" + << " } else {\n" + << " final_color.a = 1.0;\n" + << " }\n" + << "} else if(ceil(gl_FragCoord.y) == SCREEN_HEIGHTf - showfunc_size*" << std::to_string(i + 1) << ") {\n" + << " const float intensity = 0.4;\n" + << " final_color = vec4(intensity,intensity,intensity,1.0);\n" + << "}\n"; } - - return tf; + f.close(); } void ABuffer::invalidateABuffer() { + LDEBUG("Shader invalidated"); _validShader = false; } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 72001b7977..51e1eddf2f 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -43,6 +43,9 @@ #include #include +#include +#include + using namespace ghoul::filesystem; using namespace ghoul::logging; @@ -68,6 +71,7 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName) : _commandlineParser(programName, true) + , _cacheManager(nullptr) { } @@ -76,6 +80,8 @@ OpenSpaceEngine::~OpenSpaceEngine() SpiceManager::deinitialize(); Time::deinitialize(); DeviceIdentifier::deinit(); + if (_cacheManager) + delete _cacheManager; FileSystem::deinitialize(); LogManager::deinitialize(); } @@ -184,7 +190,23 @@ bool OpenSpaceEngine::create(int argc, char** argv, LERROR("Loading of configuration file '" << configurationFilePath << "' failed"); return false; } - + + // make sure cache is registered, false since we don't want to override + FileSys.registerPathToken("${CACHE}", "${BASE_PATH}/cache", false); + + // Create directories that doesn't exsist + auto tokens = FileSys.tokens(); + for (auto token : tokens) { + if (!FileSys.directoryExists(token)) { + std::string p = absPath(token); + LDEBUG("Directory '" << p <<"' does not exsist, creating."); + FileSys.createDirectory(p, true); + } + } + + // Create the cachemanager + _engine->_cacheManager = new ghoul::filesystem::CacheManager(absPath("${CACHE}")); + // Determining SGCT configuration file LDEBUG("Determining SGCT configuration file"); std::string sgctConfigurationPath = _sgctDefaultConfigFile; @@ -347,6 +369,11 @@ ScriptEngine& OpenSpaceEngine::scriptEngine() return _scriptEngine; } +ghoul::filesystem::CacheManager& OpenSpaceEngine::cacheManager() { + assert(_cacheManager != nullptr); + return *_cacheManager; +} + bool OpenSpaceEngine::initializeGL() { return _renderEngine.initializeGL(); @@ -401,9 +428,12 @@ void OpenSpaceEngine::postDraw() glm::quat rot2 = glm::quat(euler2); _interactionHandler->orbit(rot); _interactionHandler->rotate(rot2); - if(_doVideoExport) - sgct::Engine::instance()->takeScreenshot(); + if(_doVideoExport) + _renderEngine.takeScreenshot(); #endif + + _renderEngine.postDraw(); + #ifdef FLARE_ONLY _flare->postDraw(); #endif diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index a707c6c0e7..1773f15d0d 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -382,6 +382,13 @@ void InteractionHandler::keyboardCallback(int key, int action) { OsEng.renderEngine().camera()->setScaling(s); } } + + // Screenshot + if (action == SGCT_PRESS && key == SGCT_KEY_PRINT_SCREEN) { + OsEng.renderEngine().takeScreenshot(); + } + + /* if (key == '1') { SceneGraphNode* node = getSceneGraphNode("sun"); diff --git a/src/rendering/renderablevolume.cpp b/src/rendering/renderablevolume.cpp index 7ecaf4274f..7a367e283b 100644 --- a/src/rendering/renderablevolume.cpp +++ b/src/rendering/renderablevolume.cpp @@ -148,8 +148,10 @@ ghoul::opengl::Texture* RenderableVolume::loadVolume( std::stringstream ss; ss << "." << dimensions[0] << "x" << dimensions[1] << "x" << dimensions[2] << "." << modelString << "." << variableCacheString << ".cache"; - std::string cachepath = filepath + ss.str(); - if( cache && FileSys.fileExists(cachepath)) { + + std::string cachepath; // = filepath + ss.str(); + OsEng.cacheManager().getCachedFile(filepath, ss.str(), cachepath, true); + if (cache && FileSys.fileExists(cachepath)) { FILE* file = fopen (cachepath.c_str(), "rb"); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 5f851f141a..8fab61aa09 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -72,6 +72,7 @@ RenderEngine::RenderEngine() : _mainCamera(nullptr) , _sceneGraph(nullptr) , _abuffer(nullptr) + , _takeScreenshot(false) { } @@ -298,6 +299,18 @@ void RenderEngine::render() } +void RenderEngine::postDraw() { + if (_takeScreenshot) { + sgct::Engine::instance()->takeScreenshot(); + _takeScreenshot = false; + } +} + +void RenderEngine::takeScreenshot() { + _takeScreenshot = true; +} + + SceneGraph* RenderEngine::sceneGraph() { // TODO custom assert (ticket #5) @@ -499,7 +512,7 @@ void RenderEngine::generateGlslConfig() { // TODO: Make this file creation dynamic and better in every way // TODO: If the screen size changes it is enough if this file is regenerated to // recompile all necessary files - std::ofstream os(absPath("${SHADERS}/ABuffer/constants.hglsl")); + std::ofstream os(absPath("${SHADERS_GENERATED}/constants.hglsl")); os << "#define SCREEN_WIDTH " << xSize << "\n" << "#define SCREEN_HEIGHT " << ySize << "\n" << "#define MAX_LAYERS " << ABuffer::MAX_LAYERS << "\n" From dfc085ec6f63fe5f8f31eff652a18ff638dd2987 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 11 Oct 2014 18:29:36 +0200 Subject: [PATCH 02/17] Fix Jenkins compile error --- src/rendering/renderablewavefrontobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/renderablewavefrontobject.cpp b/src/rendering/renderablewavefrontobject.cpp index 0baa8b7068..a972435a1b 100644 --- a/src/rendering/renderablewavefrontobject.cpp +++ b/src/rendering/renderablewavefrontobject.cpp @@ -265,7 +265,7 @@ bool RenderableWavefrontObject::initialize() completeSuccess &= (_texture != nullptr); //completeSuccess &= _geometry->initialize(this); - PowerScaledScalar ps = PowerScaledScalar::PowerScaledScalar(1,2); + PowerScaledScalar ps = PowerScaledScalar(1,2); setBoundingSphere(ps); From 539666384835af51da8b9e3487f983d2bcbea488 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 11 Oct 2014 18:36:36 +0200 Subject: [PATCH 03/17] Fix Jenkins compile error --- openspace.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/openspace.cfg b/openspace.cfg index 0e341a9ea4..a010b5f459 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -1,6 +1,5 @@ return { Paths = { - BASE_PATH = "C:/Users/michal/Documents/openspace3", SGCT = "${BASE_PATH}/config/sgct", SCRIPTS = "${BASE_PATH}/scripts", SHADERS = "${BASE_PATH}/shaders", From b50a11297c100d5cfb692261d4da00f99e51caa0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 12 Oct 2014 17:58:39 +0200 Subject: [PATCH 04/17] Started cleanup of OpenSpaceEngine --- src/engine/openspaceengine.cpp | 182 ++++++++++----------------------- src/rendering/renderable.cpp | 1 - 2 files changed, 53 insertions(+), 130 deletions(-) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 141ff3115e..ec002b70cf 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -71,8 +71,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName) { } -OpenSpaceEngine::~OpenSpaceEngine() -{ +OpenSpaceEngine::~OpenSpaceEngine() { SpiceManager::deinitialize(); Time::deinitialize(); DeviceIdentifier::deinit(); @@ -80,14 +79,12 @@ OpenSpaceEngine::~OpenSpaceEngine() LogManager::deinitialize(); } -OpenSpaceEngine& OpenSpaceEngine::ref() -{ +OpenSpaceEngine& OpenSpaceEngine::ref() { assert(_engine); return *_engine; } -bool OpenSpaceEngine::gatherCommandlineArguments() -{ +bool OpenSpaceEngine::gatherCommandlineArguments() { // TODO: Get commandline arguments from all modules CommandlineCommand* configurationFileCommand = new SingleCommand( @@ -98,8 +95,7 @@ bool OpenSpaceEngine::gatherCommandlineArguments() return true; } -bool OpenSpaceEngine::findConfiguration(std::string& filename) -{ +bool OpenSpaceEngine::findConfiguration(std::string& filename) { using ghoul::filesystem::Directory; Directory directory = FileSys.currentDirectory(); @@ -200,18 +196,15 @@ bool OpenSpaceEngine::create(int argc, char** argv, return true; } -void OpenSpaceEngine::destroy() -{ +void OpenSpaceEngine::destroy() { delete _engine; } -bool OpenSpaceEngine::isInitialized() -{ +bool OpenSpaceEngine::isInitialized() { return _engine != nullptr; } -bool OpenSpaceEngine::initialize() -{ +bool OpenSpaceEngine::initialize() { // clear the screen so the user don't have to see old buffer contents from the // graphics card glClearColor(0, 0, 0, 0); @@ -229,7 +222,7 @@ bool OpenSpaceEngine::initialize() // Detect and log OpenCL and OpenGL versions and available devices ghoul::systemcapabilities::SystemCapabilities::initialize(); SysCap.addComponent(new ghoul::systemcapabilities::CPUCapabilitiesComponent); - SysCap.addComponent(new ghoul::systemcapabilities::OpenCLCapabilitiesComponent); + //SysCap.addComponent(new ghoul::systemcapabilities::OpenCLCapabilitiesComponent); SysCap.addComponent(new ghoul::systemcapabilities::OpenGLCapabilitiesComponent); SysCap.detectCapabilities(); SysCap.logCapabilities(); @@ -238,10 +231,10 @@ bool OpenSpaceEngine::initialize() SpiceManager::initialize(); Time::initialize(); + // Load SPICE time kernel using constants::configurationmanager::keySpiceTimeKernel; std::string timeKernel; - bool success = OsEng.configurationManager().getValue(keySpiceTimeKernel, timeKernel); - + bool success = configurationManager().getValue(keySpiceTimeKernel, timeKernel); if (!success) { LERROR("Configuration file does not contain a '" << keySpiceTimeKernel << "'"); return false; @@ -253,11 +246,12 @@ bool OpenSpaceEngine::initialize() return false; } + // Load SPICE leap second kernel using constants::configurationmanager::keySpiceLeapsecondKernel; std::string leapSecondKernel; - success = OsEng.configurationManager().getValue(keySpiceLeapsecondKernel, leapSecondKernel); + success = configurationManager().getValue(keySpiceLeapsecondKernel, leapSecondKernel); if (!success) { - LERROR("Configuration file does not contain a '" << keySpiceLeapsecondKernel << "'"); + LERROR("Configuration file does not have a '" << keySpiceLeapsecondKernel << "'"); return false; } id = SpiceManager::ref().loadKernel(std::move(leapSecondKernel)); @@ -266,32 +260,26 @@ bool OpenSpaceEngine::initialize() return false; } - //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/de413.bsp"); - //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/jup260.bsp") + //// metakernel loading doesnt seem to work... it should. to tired to even + //// CK + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ck/merged_nhpc_2006_v011.bc"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ck/merged_nhpc_2007_v006.bc"); + //// FK + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/fk/nh_v200.tf"); + //// IK + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ik/nh_lorri_v100.ti"); + //// LSK already loaded + ////PCK + ////SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/pck/pck00008.tpc"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/pck/new_horizons_413.tsc"); + ////SPK + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/de413.bsp"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/jup260.bsp"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_nep_ura_000.bsp"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_recon_e2j_v1.bsp"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_recon_j2sep07_prelimv1.bsp"); + //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/sb_2002jf56_2.bsp"); - // metakernel loading doesnt seem to work... it should. to tired to even - // CK - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ck/merged_nhpc_2006_v011.bc"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ck/merged_nhpc_2007_v006.bc"); - // FK - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/fk/nh_v200.tf"); - // IK - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/ik/nh_lorri_v100.ti"); - // LSK already loaded - //PCK - //SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/pck/pck00008.tpc"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/pck/new_horizons_413.tsc"); - //SPK - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/de413.bsp"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/jup260.bsp"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_nep_ura_000.bsp"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_recon_e2j_v1.bsp"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/nh_recon_j2sep07_prelimv1.bsp"); - SpiceManager::ref().loadKernel("${OPENSPACE_DATA}/spice/JupiterNhKernels/spk/sb_2002jf56_2.bsp"); - - - - FactoryManager::initialize(); scriptEngine().initialize(); @@ -306,33 +294,24 @@ bool OpenSpaceEngine::initialize() SceneGraph* sceneGraph = new SceneGraph; _renderEngine.setSceneGraph(sceneGraph); - - // initialize the RenderEngine, needs ${SCENEPATH} to be set _renderEngine.initialize(); sceneGraph->initialize(); std::string sceneDescriptionPath; - success = OsEng.configurationManager().getValue( + success = configurationManager().getValue( constants::configurationmanager::keyConfigScene, sceneDescriptionPath); if (success) sceneGraph->scheduleLoadSceneFile(sceneDescriptionPath); - //_renderEngine.setSceneGraph(sceneGraph); - -#ifdef FLARE_ONLY - _flare = new Flare(); - _flare->initialize(); -#endif - // Initialize OpenSpace input devices DeviceIdentifier::init(); DeviceIdentifier::ref().scanDevices(); - _engine->_interactionHandler.connectDevices(); + _interactionHandler.connectDevices(); // Run start up scripts ghoul::Dictionary scripts; - success = _engine->configurationManager().getValue( + success = configurationManager().getValue( constants::configurationmanager::keyStartupScript, scripts); for (size_t i = 1; i <= scripts.size(); ++i) { std::stringstream stream; @@ -351,45 +330,34 @@ bool OpenSpaceEngine::initialize() _engine->scriptEngine().runScriptFile(absoluteScriptPath); } -#ifdef OPENSPACE_VIDEO_EXPORT - LINFO("OpenSpace compiled with video export; press Print Screen to start/stop recording"); -#endif - return true; } -ConfigurationManager& OpenSpaceEngine::configurationManager() -{ +ConfigurationManager& OpenSpaceEngine::configurationManager() { return _configurationManager; } -ghoul::opencl::CLContext& OpenSpaceEngine::clContext() -{ +ghoul::opencl::CLContext& OpenSpaceEngine::clContext() { return _context; } -InteractionHandler& OpenSpaceEngine::interactionHandler() -{ +InteractionHandler& OpenSpaceEngine::interactionHandler() { return _interactionHandler; } -RenderEngine& OpenSpaceEngine::renderEngine() -{ +RenderEngine& OpenSpaceEngine::renderEngine() { return _renderEngine; } -ScriptEngine& OpenSpaceEngine::scriptEngine() -{ +ScriptEngine& OpenSpaceEngine::scriptEngine() { return _scriptEngine; } -bool OpenSpaceEngine::initializeGL() -{ +bool OpenSpaceEngine::initializeGL() { return _renderEngine.initializeGL(); } -void OpenSpaceEngine::preSynchronization() -{ +void OpenSpaceEngine::preSynchronization() { #ifdef WIN32 // Sleeping for 0 milliseconds will trigger any pending asynchronous procedure calls SleepEx(0, TRUE); @@ -400,82 +368,38 @@ void OpenSpaceEngine::preSynchronization() _interactionHandler.update(dt); _interactionHandler.lockControls(); - //Time::ref().advanceTime(dt); + Time::ref().advanceTime(dt); } -#ifdef FLARE_ONLY - _flare->preSync(); -#endif } -void OpenSpaceEngine::postSynchronizationPreDraw() -{ +void OpenSpaceEngine::postSynchronizationPreDraw() { _renderEngine.postSynchronizationPreDraw(); -#ifdef FLARE_ONLY - _flare->postSyncPreDraw(); -#endif } -void OpenSpaceEngine::render() -{ -#ifdef FLARE_ONLY - _flare->render(); -#else +void OpenSpaceEngine::render() { _renderEngine.render(); -#endif } -void OpenSpaceEngine::postDraw() -{ - if (sgct::Engine::instance()->isMaster()) { +void OpenSpaceEngine::postDraw() { + if (sgct::Engine::instance()->isMaster()) _interactionHandler.unlockControls(); - } -#ifdef OPENSPACE_VIDEO_EXPORT - float speed = 0.01; - glm::vec3 euler(0.0, speed, 0.0); - glm::quat rot = glm::quat(euler); - glm::vec3 euler2(0.0, -speed, 0.0); - glm::quat rot2 = glm::quat(euler2); - _interactionHandler->orbit(rot); - _interactionHandler->rotate(rot2); - if(_doVideoExport) - sgct::Engine::instance()->takeScreenshot(); -#endif -#ifdef FLARE_ONLY - _flare->postDraw(); -#endif } -void OpenSpaceEngine::keyboardCallback(int key, int action) -{ - if (sgct::Engine::instance()->isMaster()) { +void OpenSpaceEngine::keyboardCallback(int key, int action) { + if (sgct::Engine::instance()->isMaster()) _interactionHandler.keyboardCallback(key, action); - } -#ifdef OPENSPACE_VIDEO_EXPORT - if(action == SGCT_PRESS && key == SGCT_KEY_PRINT_SCREEN) - _doVideoExport = !_doVideoExport; -#endif -#ifdef FLARE_ONLY - _flare->keyboard(key, action); -#endif } -void OpenSpaceEngine::mouseButtonCallback(int key, int action) -{ - if (sgct::Engine::instance()->isMaster()) { +void OpenSpaceEngine::mouseButtonCallback(int key, int action) { + if (sgct::Engine::instance()->isMaster()) _interactionHandler.mouseButtonCallback(key, action); - } -#ifdef FLARE_ONLY - _flare->mouse(key, action); -#endif } -void OpenSpaceEngine::mousePositionCallback(int x, int y) -{ +void OpenSpaceEngine::mousePositionCallback(int x, int y) { _interactionHandler.mousePositionCallback(x, y); } -void OpenSpaceEngine::mouseScrollWheelCallback(int pos) -{ +void OpenSpaceEngine::mouseScrollWheelCallback(int pos) { _interactionHandler.mouseScrollWheelCallback(pos); } diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index ed63628751..832a3a6f39 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -110,7 +110,6 @@ void Renderable::setPscUniforms(ghoul::opengl::ProgramObject* program, const Cam program->setUniform("campos", camera->position().vec4()); program->setUniform("objpos", position.vec4()); program->setUniform("camrot", camera->viewRotationMatrix()); - //const glm::vec2 scaletmp(1, 1); program->setUniform("scaling", camera->scaling()); } From d32978a9f7a7568197a21bcb0f1548fc314927eb Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Mon, 13 Oct 2014 10:32:42 +0200 Subject: [PATCH 05/17] RenderEngine fix for Fisheye rendering --- src/rendering/renderengine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 1a5ea93b7f..0558d9003a 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -133,7 +133,8 @@ bool RenderEngine::initializeGL() // set the tilted view and the FOV _mainCamera->setCameraDirection(glm::vec3(viewdir[0], viewdir[1], viewdir[2])); - _mainCamera->setMaxFov(wPtr->getFisheyeFOV()); + _mainCamera->setMaxFov(wPtr->getFisheyeFOV()); + _mainCamera->setLookUpVector(glm::vec3(0.0, 1.0, 0.0)); } else { // get corner positions, calculating the forth to easily calculate center glm::vec3 corners[4]; @@ -203,6 +204,9 @@ void RenderEngine::postSynchronizationPreDraw() _sceneGraph->update(a); _mainCamera->setCameraDirection(glm::vec3(0, 0, -1)); _sceneGraph->evaluate(_mainCamera); + + // clear the abuffer before rendering the scene + _abuffer->clear(); } void RenderEngine::render() @@ -234,7 +238,6 @@ void RenderEngine::render() // render the scene starting from the root node - _abuffer->clear(); _abuffer->preRender(); _sceneGraph->render({*_mainCamera, psc()}); _abuffer->postRender(); @@ -244,9 +247,12 @@ void RenderEngine::render() _abuffer->resolve(); glDisable(GL_BLEND); + #ifndef OPENSPACE_VIDEO_EXPORT + // Print some useful information on the master viewport - if (sgct::Engine::instance()->isMaster()) { + sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr(); + if (sgct::Engine::instance()->isMaster() && ! w->isUsingFisheyeRendering()) { // Apple usually has retina screens #ifdef __APPLE__ #define FONT_SIZE 18 From 572651dba73da2390ba9b56b35bbc806be091811 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Thu, 16 Oct 2014 15:38:59 +0200 Subject: [PATCH 06/17] Added cotire to speed up compilation --- CMakeLists.txt | 2 + ext/cotire.cmake | 3551 ++++++++++++++++++++++ ext/ghoul | 2 +- include/openspace/util/kameleonwrapper.h | 2 +- src/CMakeLists.txt | 1 + src/util/kameleonwrapper.cpp | 12 +- 6 files changed, 3562 insertions(+), 8 deletions(-) create mode 100644 ext/cotire.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 980e2615c3..9d0220aa72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,8 @@ set(OPENSPACE_EXT_DIR "${OPENSPACE_BASE_DIR}/ext") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_EXT_DIR}) +include(cotire) + # Make sure a build type is set. Default is Debug. if(NOT CMAKE_BUILD_TYPE) set( CMAKE_BUILD_TYPE Debug CACHE STRING diff --git a/ext/cotire.cmake b/ext/cotire.cmake new file mode 100644 index 0000000000..d855c1d411 --- /dev/null +++ b/ext/cotire.cmake @@ -0,0 +1,3551 @@ +# - cotire (compile time reducer) +# +# See the cotire manual for usage hints. +# +#============================================================================= +# Copyright 2012-2014 Sascha Kratky +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#============================================================================= + +if(__COTIRE_INCLUDED) + return() +endif() +set(__COTIRE_INCLUDED TRUE) + +# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode +# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(PUSH) +endif() +# we need the CMake variables CMAKE_SCRIPT_MODE_FILE and CMAKE_ARGV available since 2.8.5 +# we need APPEND_STRING option for set_property available since 2.8.6 +cmake_minimum_required(VERSION 2.8.6) +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(POP) +endif() + +set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") +set (COTIRE_CMAKE_MODULE_VERSION "1.6.6") + +include(CMakeParseArguments) +include(ProcessorCount) + +function (cotire_determine_compiler_version _language _versionPrefix) + if (NOT ${_versionPrefix}_VERSION) + # use CMake's predefined compiler version variable (available since CMake 2.8.8) + if (DEFINED CMAKE_${_language}_COMPILER_VERSION) + set (${_versionPrefix}_VERSION "${CMAKE_${_language}_COMPILER_VERSION}") + elseif (WIN32) + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1) + execute_process ( + COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} + ERROR_VARIABLE _versionLine OUTPUT_QUIET TIMEOUT 10) + string (REGEX REPLACE ".*Version *([0-9]+(\\.[0-9]+)*).*" "\\1" ${_versionPrefix}_VERSION "${_versionLine}") + else() + # assume GCC like command line interface + string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1) + execute_process ( + COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} "-dumpversion" + OUTPUT_VARIABLE ${_versionPrefix}_VERSION + RESULT_VARIABLE _result + OUTPUT_STRIP_TRAILING_WHITESPACE TIMEOUT 10) + if (_result) + set (${_versionPrefix}_VERSION "") + endif() + endif() + if (${_versionPrefix}_VERSION) + set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" CACHE INTERNAL "${_language} compiler version") + endif() + set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" PARENT_SCOPE) + if (COTIRE_DEBUG) + message (STATUS "${CMAKE_${_language}_COMPILER} version ${${_versionPrefix}_VERSION}") + endif() + endif() +endfunction() + +function (cotire_get_source_file_extension _sourceFile _extVar) + # get_filename_component returns extension from first occurrence of . in file name + # this function computes the extension from last occurrence of . in file name + string (FIND "${_sourceFile}" "." _index REVERSE) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) + else() + set (_sourceExt "") + endif() + set (${_extVar} "${_sourceExt}" PARENT_SCOPE) +endfunction() + +macro (cotire_check_is_path_relative_to _path _isRelativeVar) + set (${_isRelativeVar} FALSE) + if (IS_ABSOLUTE "${_path}") + foreach (_dir ${ARGN}) + file (RELATIVE_PATH _relPath "${_dir}" "${_path}") + if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) + set (${_isRelativeVar} TRUE) + break() + endif() + endforeach() + endif() +endmacro() + +function (cotire_filter_language_source_files _language _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) + set (_sourceFiles "") + set (_excludedSourceFiles "") + set (_cotiredSourceFiles "") + if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") + else() + set (_languageExtensions "") + endif() + if (CMAKE_${_language}_IGNORE_EXTENSIONS) + set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") + else() + set (_ignoreExtensions "") + endif() + if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) + set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") + else() + set (_excludeExtensions "") + endif() + if (COTIRE_DEBUG) + message (STATUS "${_language} source file extensions: ${_languageExtensions}") + message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") + message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") + endif() + foreach (_sourceFile ${ARGN}) + get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) + get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) + get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) + get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) + set (_sourceIsFiltered FALSE) + if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) + cotire_get_source_file_extension("${_sourceFile}" _sourceExt) + if (_sourceExt) + list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) + if (_ignoreIndex LESS 0) + list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) + if (_excludeIndex GREATER -1) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) + if (_sourceIndex GREATER -1) + set (_sourceIsFiltered TRUE) + elseif ("${_sourceLanguage}" STREQUAL "${_language}") + # add to excluded sources, if file is not ignored and has correct language without having the correct extension + list (APPEND _excludedSourceFiles "${_sourceFile}") + endif() + endif() + endif() + endif() + endif() + if (COTIRE_DEBUG) + message (STATUS "${_sourceFile} filtered=${_sourceIsFiltered} language=${_sourceLanguage} header=${_sourceIsHeaderOnly}") + endif() + if (_sourceIsFiltered) + get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) + get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) + get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) + if (COTIRE_DEBUG) + message (STATUS "${_sourceFile} excluded=${_sourceIsExcluded} cotired=${_sourceIsCotired} compileFlags=${_sourceCompileFlags}") + endif() + if (_sourceIsCotired) + list (APPEND _cotiredSourceFiles "${_sourceFile}") + elseif (_sourceIsExcluded OR _sourceCompileFlags) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (APPEND _sourceFiles "${_sourceFile}") + endif() + endif() + endforeach() + if (COTIRE_DEBUG) + message (STATUS "All: ${ARGN}") + message (STATUS "${_language}: ${_sourceFiles}") + message (STATUS "Excluded: ${_excludedSourceFiles}") + message (STATUS "Cotired: ${_cotiredSourceFiles}") + endif() + set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) + set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) + set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (NOT _propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_file_property_values _valuesVar _property) + set (_values "") + foreach (_sourceFile ${ARGN}) + get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) + if (_propertyValue) + list (APPEND _values "${_propertyValue}") + endif() + endforeach() + set (${_valuesVar} ${_values} PARENT_SCOPE) +endfunction() + +function (cotire_resolve_config_properites _configurations _propertiesVar) + set (_properties "") + foreach (_property ${ARGN}) + if ("${_property}" MATCHES "") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") + list (APPEND _properties ${_configProperty}) + endforeach() + else() + list (APPEND _properties ${_property}) + endif() + endforeach() + set (${_propertiesVar} ${_properties} PARENT_SCOPE) +endfunction() + +function (cotire_copy_set_properites _configurations _type _source _target) + cotire_resolve_config_properites("${_configurations}" _properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) + set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") + endif() + endforeach() +endfunction() + +function (cotire_get_target_link_libraries_for_usage_requirements _target _targetLinkLibrariesVar) + set (_targetLinkLibraries "") + get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) + while (_librariesToProcess) + # remove from head + list (GET _librariesToProcess 0 _library) + list (REMOVE_AT _librariesToProcess 0) + list (FIND _targetLinkLibraries ${_library} _index) + if (_index LESS 0) + list (APPEND _targetLinkLibraries ${_library}) + # process transitive libraries + if (TARGET ${_library}) + get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) + if (_libraries) + list (APPEND _librariesToProcess ${_libraries}) + endif() + endif() + endif() + endwhile() + set (${_targetLinkLibrariesVar} ${_targetLinkLibraries} PARENT_SCOPE) +endfunction() + +function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + set (_flagPrefix "[/-]") + else() + set (_flagPrefix "--?") + endif() + set (_optionFlag "") + set (_matchedOptions "") + set (_unmatchedOptions "") + foreach (_compileFlag ${ARGN}) + if (_compileFlag) + if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") + # option with separate argument + list (APPEND _matchedOptions "${_compileFlag}") + set (_optionFlag "") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") + # remember option + set (_optionFlag "${CMAKE_MATCH_2}") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") + # option with joined argument + list (APPEND _matchedOptions "${CMAKE_MATCH_3}") + set (_optionFlag "") + else() + # flush remembered option + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + set (_optionFlag "") + endif() + # add to unfiltered options + list (APPEND _unmatchedOptions "${_compileFlag}") + endif() + endif() + endforeach() + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + endif() + if (COTIRE_DEBUG) + message (STATUS "Filter ${_flagFilter}") + if (_matchedOptions) + message (STATUS "Matched ${_matchedOptions}") + endif() + if (_unmatchedOptions) + message (STATUS "Unmatched ${_unmatchedOptions}") + endif() + endif() + set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) + set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_flags _config _language _directory _target _flagsVar) + string (TOUPPER "${_config}" _upperConfig) + # collect options from CMake language variables + set (_compileFlags "") + if (CMAKE_${_language}_FLAGS) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") + endif() + if (CMAKE_${_language}_FLAGS_${_upperConfig}) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") + endif() + if (_target) + # add option from CMake target type variable + get_target_property(_targetType ${_target} TYPE) + if (POLICY CMP0018) + # handle POSITION_INDEPENDENT_CODE property introduced with CMake 2.8.9 if policy CMP0018 is turned on + cmake_policy(GET CMP0018 _PIC_Policy) + else() + # default to old behavior + set (_PIC_Policy "OLD") + endif() + if (COTIRE_DEBUG) + message(STATUS "CMP0018=${_PIC_Policy}") + endif() + if (_PIC_Policy STREQUAL "NEW") + # NEW behavior: honor the POSITION_INDEPENDENT_CODE target property + get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) + if (_targetPIC) + if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") + elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") + endif() + endif() + else() + # OLD behavior or policy not set: use the value of CMAKE_SHARED_LIBRARY__FLAGS + if (_targetType STREQUAL "MODULE_LIBRARY") + # flags variable for module library uses different name SHARED_MODULE + # (e.g., CMAKE_SHARED_MODULE_C_FLAGS) + set (_targetType SHARED_MODULE) + endif() + if (CMAKE_${_targetType}_${_language}_FLAGS) + set (_compileFlags "${_compileFlags} ${CMAKE_${_targetType}_${_language}_FLAGS}") + endif() + endif() + endif() + if (_directory) + # add_definitions may have been used to add flags to the compiler command + get_directory_property(_dirDefinitions DIRECTORY "${_directory}" DEFINITIONS) + if (_dirDefinitions) + set (_compileFlags "${_compileFlags} ${_dirDefinitions}") + endif() + endif() + if (_target) + # add target compile options + get_target_property(_targetflags ${_target} COMPILE_FLAGS) + if (_targetflags) + set (_compileFlags "${_compileFlags} ${_targetflags}") + endif() + get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) + if (_targetOptions) + set (_compileFlags "${_compileFlags} ${_targetOptions}") + endif() + # interface compile options from linked library targets + cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) + foreach (_library ${_linkLibraries}) + if (TARGET ${_library}) + get_target_property(_targetOptions ${_library} INTERFACE_COMPILE_OPTIONS) + if (_targetOptions) + set (_compileFlags "${_compileFlags} ${_targetOptions}") + endif() + endif() + endforeach() + endif() + if (UNIX) + separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") + elseif(WIN32) + separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") + else() + separate_arguments(_compileFlags) + endif() + # platform specific flags + if (APPLE) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) + if (NOT _architectures) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES) + endif() + if (_architectures) + foreach (_arch ${_architectures}) + list (APPEND _compileFlags "-arch" "${_arch}") + endforeach() + endif() + if (CMAKE_OSX_SYSROOT) + if (CMAKE_${_language}_SYSROOT_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") + else() + list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") + endif() + endif() + if (CMAKE_OSX_DEPLOYMENT_TARGET) + if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") + else() + list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + endif() + endif() + if (COTIRE_DEBUG AND _compileFlags) + message (STATUS "Target ${_target} compile flags ${_compileFlags}") + endif() + set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_include_directories _config _language _targetSourceDir _targetBinaryDir _target _includeDirsVar _systemIncludeDirsVar) + set (_includeDirs "") + set (_systemIncludeDirs "") + # default include dirs + if (CMAKE_INCLUDE_CURRENT_DIR) + list (APPEND _includeDirs "${_targetBinaryDir}") + list (APPEND _includeDirs "${_targetSourceDir}") + endif() + # parse additional include directories from target compile flags + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "I" _dirs _ignore ${_targetFlags}) + if (_dirs) + list (APPEND _includeDirs ${_dirs}) + endif() + # target include directories + get_directory_property(_dirs DIRECTORY "${_targetSourceDir}" INCLUDE_DIRECTORIES) + if (_target) + get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + + # interface include directories from linked library targets + cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) + foreach (_library ${_linkLibraries}) + if (TARGET ${_library}) + get_target_property(_targetDirs ${_library} INTERFACE_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_library} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + endif() + endforeach() + endif() + if (dirs) + list (REMOVE_DUPLICATES _dirs) + endif() + list (LENGTH _includeDirs _projectInsertIndex) + foreach (_dir ${_dirs}) + if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) + cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") + if (_isRelative) + list (LENGTH _includeDirs _len) + if (_len EQUAL _projectInsertIndex) + list (APPEND _includeDirs "${_dir}") + else() + list (INSERT _includeDirs _projectInsertIndex "${_dir}") + endif() + math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") + else() + list (APPEND _includeDirs "${_dir}") + endif() + else() + list (APPEND _includeDirs "${_dir}") + endif() + endforeach() + list (REMOVE_DUPLICATES _includeDirs) + list (REMOVE_DUPLICATES _systemIncludeDirs) + if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) + list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) + endif() + if (COTIRE_DEBUG AND _includeDirs) + message (STATUS "Target ${_target} include dirs ${_includeDirs}") + endif() + set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) + if (COTIRE_DEBUG AND _systemIncludeDirs) + message (STATUS "Target ${_target} system include dirs ${_systemIncludeDirs}") + endif() + set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) +endfunction() + +macro (cotire_make_C_identifier _identifierVar _str) + if (CMAKE_VERSION VERSION_LESS "2.8.12") + # mimic CMake SystemTools::MakeCindentifier behavior + if ("${_str}" MATCHES "^[0-9].+$") + set (_str "_${str}") + endif() + string (REGEX REPLACE "[^a-zA-Z0-9]" "_" ${_identifierVar} "${_str}") + else() + string (MAKE_C_IDENTIFIER "${_str}" "${_identifierVar}") + endif() +endmacro() + +function (cotire_get_target_export_symbol _target _exportSymbolVar) + set (_exportSymbol "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_enableExports ${_target} ENABLE_EXPORTS) + if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR + (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) + get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) + if (NOT _exportSymbol) + set (_exportSymbol "${_target}_EXPORTS") + endif() + cotire_make_C_identifier(_exportSymbol "${_exportSymbol}") + endif() + set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_definitions _config _language _directory _target _definitionsVar) + string (TOUPPER "${_config}" _upperConfig) + set (_configDefinitions "") + # CMAKE_INTDIR for multi-configuration build systems + if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") + list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") + endif() + # target export define symbol + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + list (APPEND _configDefinitions "${_defineSymbol}") + endif() + # directory compile definitions + get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # target compile definitions + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # interface compile definitions from linked library targets + cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) + foreach (_library ${_linkLibraries}) + if (TARGET ${_library}) + get_target_property(_definitions ${_library} INTERFACE_COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + endif() + endforeach() + # parse additional compile definitions from target compile flags + # and don't look at directory compile definitions, which we already handled + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + list (REMOVE_DUPLICATES _configDefinitions) + if (COTIRE_DEBUG AND _configDefinitions) + message (STATUS "Target ${_target} compile definitions ${_configDefinitions}") + endif() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compiler_flags _config _language _directory _target _compilerFlagsVar) + # parse target compile flags omitting compile definitions and include directives + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_directory}" "${_target}" _targetFlags) + set (_compilerFlags "") + cotire_filter_compile_flags("${_language}" "[ID]" _ignore _compilerFlags ${_targetFlags}) + if (COTIRE_DEBUG AND _compilerFlags) + message (STATUS "Target ${_target} compiler flags ${_compilerFlags}") + endif() + set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) +endfunction() + +function (cotire_add_sys_root_paths _pathsVar) + if (APPLE) + if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) + foreach (_path IN LISTS ${_pathsVar}) + if (IS_ABSOLUTE "${_path}") + get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) + if (EXISTS "${_path}") + list (APPEND ${_pathsVar} "${_path}") + endif() + endif() + endforeach() + endif() + endif() + set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) + if (COTIRE_DEBUG) + message (STATUS "${_pathsVar}=${${_pathsVar}}") + endif() +endfunction() + +function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) + set (_extraProperties ${ARGN}) + set (_result "") + if (_extraProperties) + list (FIND _extraProperties "${_sourceFile}" _index) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + list (LENGTH _extraProperties _len) + math (EXPR _len "${_len} - 1") + foreach (_index RANGE ${_index} ${_len}) + list (GET _extraProperties ${_index} _value) + if (_value MATCHES "${_pattern}") + list (APPEND _result "${_value}") + else() + break() + endif() + endforeach() + endif() + endif() + set (${_resultVar} ${_result} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) + set (_compileDefinitions "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + string (TOUPPER "${_config}" _upperConfig) + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + if (COTIRE_DEBUG AND _compileDefinitions) + message (STATUS "Source ${_sourceFile} compile definitions ${_compileDefinitions}") + endif() + set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) + set (_configDefinitions "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) + if (_sourceDefinitions) + list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") + endif() + endforeach() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) + set (_sourceUndefs "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + get_source_file_property(_undefs "${_sourceFile}" ${_property}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + if (COTIRE_DEBUG AND _sourceUndefs) + message (STATUS "Source ${_sourceFile} ${_property} undefs ${_sourceUndefs}") + endif() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_undefs _property _sourceUndefsVar) + set (_sourceUndefs "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) + if (_undefs) + list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") + endif() + endforeach() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +macro (cotire_set_cmd_to_prologue _cmdVar) + set (${_cmdVar} "${CMAKE_COMMAND}") + if (COTIRE_DEBUG) + list (APPEND ${_cmdVar} "--warn-uninitialized") + endif() + list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") + if (COTIRE_VERBOSE) + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") + elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") + endif() +endmacro() + +function (cotire_init_compile_cmd _cmdVar _language _compilerExe _compilerArg1) + if (NOT _compilerExe) + set (_compilerExe "${CMAKE_${_language}_COMPILER}") + endif() + if (NOT _compilerArg1) + set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) + endif() + string (STRIP "${_compilerArg1}" _compilerArg1) + set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) +endfunction() + +macro (cotire_add_definitions_to_cmd _cmdVar _language) + foreach (_definition ${ARGN}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + list (APPEND ${_cmdVar} "/D${_definition}") + else() + list (APPEND ${_cmdVar} "-D${_definition}") + endif() + endforeach() +endmacro() + +macro (cotire_add_includes_to_cmd _cmdVar _language _includeSystemFlag _includesVar _systemIncludesVar) + foreach (_include ${${_includesVar}}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + file (TO_NATIVE_PATH "${_include}" _include) + list (APPEND ${_cmdVar} "/I${_include}") + else() + list (FIND ${_systemIncludesVar} ${_include} _index) + if(_index GREATER -1 AND NOT "${_includeSystemFlag}" STREQUAL "") + list (APPEND ${_cmdVar} "${_includeSystemFlag}${_include}") + else() + list (APPEND ${_cmdVar} "-I${_include}") + endif() + endif() + endforeach() +endmacro() + +macro (cotire_add_frameworks_to_cmd _cmdVar _language) + if (APPLE) + set (_frameWorkDirs "") + foreach (_include ${ARGN}) + if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") + get_filename_component(_frameWorkDir "${_include}" PATH) + list (APPEND _frameWorkDirs "${_frameWorkDir}") + endif() + endforeach() + if (_frameWorkDirs) + list (REMOVE_DUPLICATES _frameWorkDirs) + foreach (_frameWorkDir ${_frameWorkDirs}) + list (APPEND ${_cmdVar} "-F${_frameWorkDir}") + endforeach() + endif() + endif() +endmacro() + +macro (cotire_add_compile_flags_to_cmd _cmdVar) + foreach (_flag ${ARGN}) + list (APPEND ${_cmdVar} "${_flag}") + endforeach() +endmacro() + +function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) + set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) + set (_triggerFile "") + foreach (_dependencyFile ${ARGN}) + if (EXISTS "${_dependencyFile}" AND "${_dependencyFile}" IS_NEWER_THAN "${_file}") + set (_triggerFile "${_dependencyFile}") + break() + endif() + endforeach() + get_filename_component(_fileName "${_file}" NAME) + if (EXISTS "${_file}") + if (_triggerFile) + if (COTIRE_VERBOSE) + message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") + endif() + else() + if (COTIRE_VERBOSE) + message (STATUS "${_fileName} is up-to-date.") + endif() + set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) + endif() + else() + if (COTIRE_VERBOSE) + message (STATUS "${_fileName} does not exist yet.") + endif() + endif() +endfunction() + +macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) + set (${_relPathVar} "") + foreach (_includeDir ${_includeDirs}) + if (IS_DIRECTORY "${_includeDir}") + file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") + if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") + string (LENGTH "${${_relPathVar}}" _closestLen) + string (LENGTH "${_relPath}" _relLen) + if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) + set (${_relPathVar} "${_relPath}") + endif() + endif() + elseif ("${_includeDir}" STREQUAL "${_headerFile}") + # if path matches exactly, return short non-empty string + set (${_relPathVar} "1") + break() + endif() + endforeach() +endmacro() + +macro (cotire_check_header_file_location _headerFile _insideIncudeDirs _outsideIncudeDirs _headerIsInside) + # check header path against ignored and honored include directories + cotire_find_closest_relative_path("${_headerFile}" "${_insideIncudeDirs}" _insideRelPath) + if (_insideRelPath) + # header is inside, but could be become outside if there is a shorter outside match + cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncudeDirs}" _outsideRelPath) + if (_outsideRelPath) + string (LENGTH "${_insideRelPath}" _insideRelPathLen) + string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) + if (_outsideRelPathLen LESS _insideRelPathLen) + set (${_headerIsInside} FALSE) + else() + set (${_headerIsInside} TRUE) + endif() + else() + set (${_headerIsInside} TRUE) + endif() + else() + # header is outside + set (${_headerIsInside} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) + if (NOT EXISTS "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif (IS_DIRECTORY "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") + # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path + # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation + # with the error message "error: no include path in which to search for header.h" + set (${_headerIsIgnoredVar} TRUE) + else() + set (${_headerIsIgnoredVar} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) + # check header file extension + cotire_get_source_file_extension("${_headerFile}" _headerFileExt) + set (${_headerIsIgnoredVar} FALSE) + if (_headerFileExt) + list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) + if (_index GREATER -1) + set (${_headerIsIgnoredVar} TRUE) + endif() + endif() +endmacro() + +macro (cotire_parse_line _line _headerFileVar _headerDepthVar) + if (MSVC) + # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: + # English: "Note: including file: C:\directory\file" + # German: "Hinweis: Einlesen der Datei: C:\directory\file" + # We use a very general regular expression, relying on the presence of the : characters + if (_line MATCHES ":( +)([^:]+:[^:]+)$") + # Visual Studio compiler output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + else() + if (_line MATCHES "^(\\.+) (.*)$") + # GCC like output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + if (IS_ABSOLUTE "${CMAKE_MATCH_2}") + set (${_headerFileVar} "${CMAKE_MATCH_2}") + else() + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) + endif() + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + endif() +endmacro() + +function (cotire_parse_includes _language _scanOutput _ignoredIncudeDirs _honoredIncudeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) + if (WIN32) + # prevent CMake macro invocation errors due to backslash characters in Windows paths + string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") + endif() + # canonize slashes + string (REPLACE "//" "/" _scanOutput "${_scanOutput}") + # prevent semicolon from being interpreted as a line separator + string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") + # then separate lines + string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") + list (LENGTH _scanOutput _len) + # remove duplicate lines to speed up parsing + list (REMOVE_DUPLICATES _scanOutput) + list (LENGTH _scanOutput _uniqueLen) + if (COTIRE_VERBOSE OR COTIRE_DEBUG) + message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") + if (_ignoredExtensions) + message (STATUS "Ignored extensions: ${_ignoredExtensions}") + endif() + if (_ignoredIncudeDirs) + message (STATUS "Ignored paths: ${_ignoredIncudeDirs}") + endif() + if (_honoredIncudeDirs) + message (STATUS "Included paths: ${_honoredIncudeDirs}") + endif() + endif() + set (_sourceFiles ${ARGN}) + set (_selectedIncludes "") + set (_unparsedLines "") + # stack keeps track of inside/outside project status of processed header files + set (_headerIsInsideStack "") + foreach (_line IN LISTS _scanOutput) + if (_line) + cotire_parse_line("${_line}" _headerFile _headerDepth) + if (_headerFile) + cotire_check_header_file_location("${_headerFile}" "${_ignoredIncudeDirs}" "${_honoredIncudeDirs}" _headerIsInside) + if (COTIRE_DEBUG) + message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") + endif() + # update stack + list (LENGTH _headerIsInsideStack _stackLen) + if (_headerDepth GREATER _stackLen) + math (EXPR _stackLen "${_stackLen} + 1") + foreach (_index RANGE ${_stackLen} ${_headerDepth}) + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endforeach() + else() + foreach (_index RANGE ${_headerDepth} ${_stackLen}) + list (REMOVE_AT _headerIsInsideStack -1) + endforeach() + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerIsInsideStack}") + endif() + # header is a candidate if it is outside project + if (NOT _headerIsInside) + # get parent header file's inside/outside status + if (_headerDepth GREATER 1) + math (EXPR _index "${_headerDepth} - 2") + list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) + else() + set (_parentHeaderIsInside TRUE) + endif() + # select header file if parent header file is inside project + # (e.g., a project header file that includes a standard header file) + if (_parentHeaderIsInside) + cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) + if (NOT _headerIsIgnored) + cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) + if (NOT _headerIsIgnored) + list (APPEND _selectedIncludes "${_headerFile}") + else() + # fix header's inside status on stack, it is ignored by extension now + list (REMOVE_AT _headerIsInsideStack -1) + list (APPEND _headerIsInsideStack TRUE) + endif() + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") + endif() + endif() + endif() + else() + if (MSVC) + # for cl.exe do not keep unparsed lines which solely consist of a source file name + string (FIND "${_sourceFiles}" "${_line}" _index) + if (_index LESS 0) + list (APPEND _unparsedLines "${_line}") + endif() + else() + list (APPEND _unparsedLines "${_line}") + endif() + endif() + endif() + endforeach() + list (REMOVE_DUPLICATES _selectedIncludes) + set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) + set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) +endfunction() + +function (cotire_scan_includes _includesVar) + set(_options "") + set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_VERSION INCLUDE_SYSTEM_FLAG LANGUAGE UNPARSED_LINES) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + set (_cmd "${_option_COMPILER_EXECUTABLE}" ${_option_COMPILER_ARG1}) + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" "${_option_INCLUDE_SYSTEM_FLAG}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES}) + cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) + # only consider existing source files for scanning + set (_existingSourceFiles "") + foreach (_sourceFile ${_sourceFiles}) + if (EXISTS "${_sourceFile}") + list (APPEND _existingSourceFiles "${_sourceFile}") + endif() + endforeach() + if (NOT _existingSourceFiles) + set (${_includesVar} "" PARENT_SCOPE) + return() + endif() + list (APPEND _cmd ${_existingSourceFiles}) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + if (COTIRE_DEBUG) + message (STATUS "clearing VS_UNICODE_OUTPUT") + endif() + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + endif() + execute_process( + COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result OUTPUT_QUIET ERROR_VARIABLE _output) + if (_result) + message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") + endif() + cotire_parse_includes( + "${_option_LANGUAGE}" "${_output}" + "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" + "${_option_IGNORE_EXTENSIONS}" + _includes _unparsedLines + ${_sourceFiles}) + set (${_includesVar} ${_includes} PARENT_SCOPE) + if (_option_UNPARSED_LINES) + set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_append_undefs _contentsVar) + set (_undefs ${ARGN}) + if (_undefs) + list (REMOVE_DUPLICATES _undefs) + foreach (_definition ${_undefs}) + list (APPEND ${_contentsVar} "#undef ${_definition}") + endforeach() + endif() +endmacro() + +macro (cotire_comment_str _language _commentText _commentVar) + if ("${_language}" STREQUAL "CMAKE") + set (${_commentVar} "# ${_commentText}") + else() + set (${_commentVar} "/* ${_commentText} */") + endif() +endmacro() + +function (cotire_write_file _language _file _contents _force) + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) + cotire_comment_str("${_language}" "${_file}" _header2) + set (_contents "${_header1}\n${_header2}\n${_contents}") + if (COTIRE_DEBUG) + message (STATUS "${_contents}") + endif() + if (_force OR NOT EXISTS "${_file}") + file (WRITE "${_file}" "${_contents}") + else() + file (READ "${_file}" _oldContents) + if (NOT "${_oldContents}" STREQUAL "${_contents}") + file (WRITE "${_file}" "${_contents}") + else() + if (COTIRE_DEBUG) + message (STATUS "${_file} unchanged") + endif() + endif() + endif() +endfunction() + +function (cotire_generate_unity_source _unityFile) + set(_options "") + set(_oneValueArgs LANGUAGE) + set(_multiValueArgs + DEPENDS SOURCES_COMPILE_DEFINITIONS + PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (_option_DEPENDS) + cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) + if (_unityFileIsUpToDate) + return() + endif() + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_PRE_UNDEFS) + set (_option_PRE_UNDEFS "") + endif() + if (NOT _option_SOURCES_PRE_UNDEFS) + set (_option_SOURCES_PRE_UNDEFS "") + endif() + if (NOT _option_POST_UNDEFS) + set (_option_POST_UNDEFS "") + endif() + if (NOT _option_SOURCES_POST_UNDEFS) + set (_option_SOURCES_POST_UNDEFS "") + endif() + set (_contents "") + if (_option_PROLOGUE) + list (APPEND _contents ${_option_PROLOGUE}) + endif() + if (_option_LANGUAGE AND _sourceFiles) + if ("${_option_LANGUAGE}" STREQUAL "CXX") + list (APPEND _contents "#ifdef __cplusplus") + elseif ("${_option_LANGUAGE}" STREQUAL "C") + list (APPEND _contents "#ifndef __cplusplus") + endif() + endif() + set (_compileUndefinitions "") + foreach (_sourceFile ${_sourceFiles}) + cotire_get_source_compile_definitions( + "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions + ${_option_SOURCES_COMPILE_DEFINITIONS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) + if (_option_PRE_UNDEFS) + list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) + endif() + if (_sourcePreUndefs) + list (APPEND _compileUndefinitions ${_sourcePreUndefs}) + endif() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_sourcePostUndefs) + list (APPEND _compileUndefinitions ${_sourcePostUndefs}) + endif() + if (_option_POST_UNDEFS) + list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) + endif() + foreach (_definition ${_compileDefinitions}) + if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") + list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") + list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") + else() + list (APPEND _contents "#define ${_definition}") + list (INSERT _compileUndefinitions 0 "${_definition}") + endif() + endforeach() + get_filename_component(_sourceFile "${_sourceFile}" ABSOLUTE) + if (WIN32) + file (TO_NATIVE_PATH "${_sourceFile}" _sourceFile) + endif() + list (APPEND _contents "#include \"${_sourceFile}\"") + endforeach() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_option_LANGUAGE AND _sourceFiles) + list (APPEND _contents "#endif") + endif() + if (_option_EPILOGUE) + list (APPEND _contents ${_option_EPILOGUE}) + endif() + list (APPEND _contents "") + string (REPLACE ";" "\n" _contents "${_contents}") + if (COTIRE_VERBOSE) + message ("${_contents}") + endif() + cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) +endfunction() + +function (cotire_generate_prefix_header _prefixFile) + set(_options "") + set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION INCLUDE_SYSTEM_FLAG) + set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS + INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (_option_DEPENDS) + cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) + if (_prefixFileIsUpToDate) + set (_unparsedLinesFile "${_prefixFile}.log") + file (WRITE "${_unparsedLinesFile}" "") + return() + endif() + endif() + set (_prologue "") + set (_epilogue "") + if (_option_COMPILER_ID MATCHES "Clang") + set (_prologue "#pragma clang system_header") + elseif (_option_COMPILER_ID MATCHES "GNU") + set (_prologue "#pragma GCC system_header") + elseif (_option_COMPILER_ID MATCHES "MSVC") + set (_prologue "#pragma warning(push, 0)") + set (_epilogue "#pragma warning(pop)") + elseif (_option_COMPILER_ID MATCHES "Intel") + # Intel compiler requires hdrstop pragma to stop generating PCH file + set (_epilogue "#pragma hdrstop") + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + cotire_scan_includes(_selectedHeaders ${_sourceFiles} + LANGUAGE "${_option_LANGUAGE}" + COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" + COMPILER_ID "${_option_COMPILER_ID}" + COMPILER_VERSION "${_option_COMPILER_VERSION}" + COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} + COMPILE_FLAGS ${_option_COMPILE_FLAGS} + INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} + INCLUDE_SYSTEM_FLAG ${_option_INCLUDE_SYSTEM_FLAG} + SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} + IGNORE_PATH ${_option_IGNORE_PATH} + INCLUDE_PATH ${_option_INCLUDE_PATH} + IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} + UNPARSED_LINES _unparsedLines) + cotire_generate_unity_source("${_prefixFile}" + PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) + set (_unparsedLinesFile "${_prefixFile}.log") + if (_unparsedLines) + if (COTIRE_VERBOSE OR NOT _selectedHeaders) + list (LENGTH _unparsedLines _skippedLineCount) + file (RELATIVE_PATH _unparsedLinesFileRelPath "${CMAKE_BINARY_DIR}" "${_unparsedLinesFile}") + message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFileRelPath}") + endif() + string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") + endif() + file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") +endfunction() + +function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + # cl.exe options used + # /nologo suppresses display of sign-on banner + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /EP preprocess to stdout without #line directives + # /showIncludes list include files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /showIncludes") + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -H print the name of each header file used + # -E invoke preprocessor + # -fdirectives-only do not expand macros, requires GCC >= 4.3 + if (_flags) + # append to list + list (APPEND _flags -H -E) + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + list (APPEND _flags "-fdirectives-only") + endif() + else() + # return as a flag string + set (_flags "-H -E") + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + set (_flags "${_flags} -fdirectives-only") + endif() + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -H print the name of each header file used + # -E invoke preprocessor + if (_flags) + # append to list + list (APPEND _flags -H -E) + else() + # return as a flag string + set (_flags "-H -E") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + # Windows Intel options used + # /nologo do not display compiler version information + # /QH display the include file order + # /EP preprocess to stdout, omitting #line directives + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /QH") + endif() + else() + # Linux / Mac OS X Intel options used + # -H print the name of each header file used + # -EP preprocess to stdout, omitting #line directives + # -Kc++ process all source or unrecognized file types as C++ source files + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags -H -EP) + else() + # return as a flag string + if ("${_language}" STREQUAL "CXX") + set (_flags "-Kc++ ") + endif() + set (_flags "${_flags}-H -EP") + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # cl.exe options used + # /Yc creates a precompiled header file + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /Zs syntax check only + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + else() + # return as a flag string + set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + endif() + elseif (_compilerID MATCHES "GNU|Clang") + # GCC / Clang options used + # -x specify the source language + # -c compile but do not link + # -o place output in file + # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may + # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + if (_flags) + # append to list + list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") + else() + # return as a flag string + set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # Windows Intel options used + # /nologo do not display compiler version information + # /Yc create a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + # /Zs syntax check only + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-create name of the precompiled header (PCH) to create + # -Kc++ process all source or unrecognized file types as C++ source files + # -fsyntax-only check only for correct syntax + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + get_filename_component(_pchDir "${_pchFile}" PATH) + get_filename_component(_pchName "${_pchFile}" NAME) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "-Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # cl.exe options used + # /Yu uses a precompiled header file during build + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -include process include file as the first line of the primary source file + # -Winvalid-pch warns if precompiled header is found but cannot be used + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -include process include file as the first line of the primary source file + # -include-pch include precompiled header file + # -Qunused-arguments don't emit warning for unused driver arguments + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # Windows Intel options used + # /Yu use a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-use name of the precompiled header (PCH) to use + # -include process include file as the first line of the primary source file + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + get_filename_component(_pchDir "${_pchFile}" PATH) + get_filename_component(_pchName "${_pchFile}" NAME) + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "-Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\"") + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) + set(_options "") + set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION INCLUDE_SYSTEM_FLAG LANGUAGE) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" "${_option_INCLUDE_SYSTEM_FLAG}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES}) + cotire_add_pch_compilation_flags( + "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + if (COTIRE_DEBUG) + message (STATUS "clearing VS_UNICODE_OUTPUT") + endif() + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + endif() + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result) + if (_result) + message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") + endif() +endfunction() + +function (cotire_check_precompiled_header_support _language _targetSourceDir _target _msgVar) + set (_unsupportedCompiler + "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # supported since Visual Studio C++ 6.0 + # and CMake does not support an earlier version + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC PCH support requires version >= 3.4 + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND + "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") + set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # all Clang versions have PCH support + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel PCH support requires version >= 8.0.0 + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND + "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") + set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + else() + set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) + endif() + if (CMAKE_${_language}_COMPILER MATCHES "ccache") + if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros") + set (${_msgVar} + "ccache requires the environment variable CCACHE_SLOPPINESS to be set to time_macros." + PARENT_SCOPE) + endif() + endif() + if (APPLE) + # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) + if (CMAKE_CONFIGURATION_TYPES) + set (_configs ${CMAKE_CONFIGURATION_TYPES}) + elseif (CMAKE_BUILD_TYPE) + set (_configs ${CMAKE_BUILD_TYPE}) + else() + set (_configs "None") + endif() + foreach (_config ${_configs}) + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) + list (LENGTH _architectures _numberOfArchitectures) + if (_numberOfArchitectures GREATER 1) + string (REPLACE ";" ", " _architectureStr "${_architectures}") + set (${_msgVar} + "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." + PARENT_SCOPE) + break() + endif() + endforeach() + endif() +endfunction() + +macro (cotire_get_intermediate_dir _cotireDir) + get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) +endmacro() + +macro (cotire_setup_file_extension_variables) + set (_unityFileExt_C ".c") + set (_unityFileExt_CXX ".cxx") + set (_prefixFileExt_C ".h") + set (_prefixFileExt_CXX ".hxx") + set (_prefixSourceFileExt_C ".c") + set (_prefixSourceFileExt_CXX ".cxx") +endmacro() + +function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") + cotire_get_intermediate_dir(_baseDir) + set (_unityFile "${_baseDir}/${_unityFileName}") + set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) + if (COTIRE_DEBUG) + message(STATUS "${_unityFile}") + endif() +endfunction() + +function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + cotire_get_intermediate_dir(_baseDir) + set (_startIndex 0) + set (_index 0) + set (_unityFiles "") + set (_sourceFiles ${ARGN}) + foreach (_sourceFile ${_sourceFiles}) + get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) + math (EXPR _unityFileCount "${_index} - ${_startIndex}") + if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) + if (_index GREATER 0) + # start new unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (_startIndex ${_index}) + endif() + math (EXPR _index "${_index} + 1") + endforeach() + list (LENGTH _sourceFiles _numberOfSources) + if (_startIndex EQUAL 0) + # there is only a single unity file + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) + elseif (_startIndex LESS _numberOfSources) + # end with final unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) + if (COTIRE_DEBUG) + message(STATUS "${_unityFiles}") + endif() +endfunction() + +function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_prefixFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") + string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") + set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) +endfunction() + +function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _prefixSourceFileExt_${_language}) + set (${_prefixSourceFileVar} "" PARENT_SCOPE) + return() + endif() + string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") + set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) + cotire_setup_file_extension_variables() + if (NOT _language) + set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") + elseif (DEFINED _prefixFileExt_${_language}) + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") + else() + set (_prefixFileBaseName "") + set (_prefixFileName "") + endif() + set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) + set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_path _language _target _prefixFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_prefixFileVar} "" PARENT_SCOPE) + if (_prefixFileName) + if (NOT _language) + set (_language "C") + endif() + if (MSVC OR CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel") + cotire_get_intermediate_dir(_baseDir) + set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) + endif() + endif() +endfunction() + +function (cotire_make_pch_file_path _language _targetSourceDir _target _pchFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_pchFileVar} "" PARENT_SCOPE) + if (_prefixFileBaseName AND _prefixFileName) + cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _msg) + if (NOT _msg) + if (XCODE) + # For Xcode, we completely hand off the compilation of the prefix header to the IDE + return() + endif() + cotire_get_intermediate_dir(_baseDir) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # MSVC uses the extension .pch added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel uses the extension .pchi added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + +function (cotire_select_unity_source_files _unityFile _sourcesVar) + set (_sourceFiles ${ARGN}) + if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") + set (_startIndex ${CMAKE_MATCH_1}) + set (_endIndex ${CMAKE_MATCH_2}) + list (LENGTH _sourceFiles _numberOfSources) + if (NOT _startIndex LESS _numberOfSources) + math (EXPR _startIndex "${_numberOfSources} - 1") + endif() + if (NOT _endIndex LESS _numberOfSources) + math (EXPR _endIndex "${_numberOfSources} - 1") + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${_endIndex}) + list (GET _sourceFiles ${_index} _file) + list (APPEND _files "${_file}") + endforeach() + else() + set (_files ${_sourceFiles}) + endif() + set (${_sourcesVar} ${_files} PARENT_SCOPE) +endfunction() + +function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) + set (_dependencySources "") + # depend on target's generated source files + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN}) + if (_generatedSources) + # but omit all generated source files that have the COTIRE_EXCLUDED property set to true + cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) + if (_excludedGeneratedSources) + list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) + endif() + # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly + cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) + if (_excludedNonDependencySources) + list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) + endif() + if (_generatedSources) + list (APPEND _dependencySources ${_generatedSources}) + endif() + endif() + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} unity source depends on ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) + # depend on target source files marked with custom COTIRE_DEPENDENCY property + set (_dependencySources "") + cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GCC and clang raise a fatal error if a file is not found during preprocessing + # thus we depend on target's generated source files for prefix header generation + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN}) + if (_generatedSources) + list (APPEND _dependencySources ${_generatedSources}) + endif() + endif() + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} prefix header DEPENDS ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_generate_target_script _language _configurations _targetSourceDir _targetBinaryDir _target _targetScriptVar _targetConfigScriptVar) + set (COTIRE_TARGET_SOURCES ${ARGN}) + cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${COTIRE_TARGET_SOURCES}) + cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${COTIRE_TARGET_SOURCES}) + # set up variables to be configured + set (COTIRE_TARGET_LANGUAGE "${_language}") + cotire_determine_compiler_version("${COTIRE_TARGET_LANGUAGE}" COTIRE_${_language}_COMPILER) + get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) + get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) + get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) + get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) + get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${COTIRE_TARGET_SOURCES}) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${COTIRE_TARGET_SOURCES}) + string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" COTIRE_INCLUDE_SYSTEM_FLAG) + set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + cotire_get_target_include_directories( + "${_config}" "${_language}" "${_targetSourceDir}" "${_targetBinaryDir}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) + cotire_get_target_compile_definitions( + "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) + cotire_get_target_compiler_flags( + "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) + cotire_get_source_files_compile_definitions( + "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${COTIRE_TARGET_SOURCES}) + endforeach() + get_cmake_property(_vars VARIABLES) + string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") + # remove COTIRE_VERBOSE which is passed as a CMake define on command line + list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) + set (_contents "") + set (_contentsHasGeneratorExpressions FALSE) + foreach (_var IN LISTS _matchVars ITEMS + MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES + CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 + CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + if (DEFINED ${_var}) + string (REPLACE "\"" "\\\"" _value "${${_var}}") + set (_contents "${_contents}set (${_var} \"${_value}\")\n") + if (NOT _contentsHasGeneratorExpressions) + if ("${_value}" MATCHES "\\$<.*>") + set (_contentsHasGeneratorExpressions TRUE) + endif() + endif() + endif() + endforeach() + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") + cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) + if (_contentsHasGeneratorExpressions) + # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time + if (NOT CMAKE_VERSION VERSION_LESS "2.8.12") + # the file(GENERATE ...) command requires cmake 2.8.12 or later + set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") + set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") + file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") + else() + message (WARNING "cotire: generator expression used in target ${_target}. This requires CMake 2.8.12 or later.") + set (_targetCotireConfigScript "${_targetCotireScript}") + endif() + else() + set (_targetCotireConfigScript "${_targetCotireScript}") + endif() + set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) + set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) +endfunction() + +function (cotire_setup_pch_file_compilation _language _target _targetSourceDir _targetScript _prefixFile _pchFile) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we attach the precompiled header compilation to the first source file + # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion + if (_sourceFiles) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + list (GET _sourceFiles 0 _hostFile) + set (_flags "") + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + cotire_add_pch_compilation_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) + set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") + # make first source file depend on prefix header + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") + # mark first source file as cotired to prevent it from being used in another cotired target + set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") + # for makefile based generator, we add a custom command to precompile the prefix header + if (_targetScript) + cotire_set_cmd_to_prologue(_cmds) + list (GET _sourceFiles 0 _hostFile) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") + file (RELATIVE_PATH _pchFileRelPath "${CMAKE_BINARY_DIR}" "${_pchFile}") + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") + endif() + set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) + add_custom_command( + OUTPUT "${_pchFile}" + COMMAND ${_cmds} + DEPENDS "${_prefixFile}" + IMPLICIT_DEPENDS ${_language} "${_prefixFile}" + WORKING_DIRECTORY "${_targetSourceDir}" + COMMENT "Building ${_language} precompiled header ${_pchFileRelPath}" VERBATIM) + endif() + endif() +endfunction() + +function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we include the precompiled header in all but the first source file + # the first source file does the precompiled header compilation, see cotire_setup_pch_file_compilation + list (LENGTH _sourceFiles _numberOfSourceFiles) + if (_numberOfSourceFiles GREATER 1) + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + list (REMOVE_AT _sourceFiles 0) + set (_flags "") + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # make source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") + if (NOT _wholeTarget) + # for makefile based generator, we force the inclusion of the prefix header for a subset + # of the source files, if this is a multi-language target or has excluded files + set (_flags "") + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + endif() + # make source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() +endfunction() + +function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) + set (_sourceFiles ${ARGN}) + # force the inclusion of the prefix header for the given source files + set (_flags "") + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + # make source files depend on prefix header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") +endfunction() + +function (cotire_get_first_set_property_value _propertyValueVar _type _object) + set (_properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) + return() + endif() + endforeach() + set (${_propertyValueVar} "" PARENT_SCOPE) +endfunction() + +function (cotire_setup_combine_command _language _sourceDir _targetScript _joinedFile _cmdsVar) + set (_files ${ARGN}) + set (_filesPaths "") + foreach (_file ${_files}) + if (IS_ABSOLUTE "${_file}") + set (_filePath "${_file}") + else() + get_filename_component(_filePath "${_sourceDir}/${_file}" ABSOLUTE) + endif() + file (RELATIVE_PATH _fileRelPath "${_sourceDir}" "${_filePath}") + if (NOT IS_ABSOLUTE "${_fileRelPath}" AND NOT "${_fileRelPath}" MATCHES "^\\.\\.") + list (APPEND _filesPaths "${_fileRelPath}") + else() + list (APPEND _filesPaths "${_filePath}") + endif() + endforeach() + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") + if (_targetScript) + list (APPEND _prefixCmd "${_targetScript}") + endif() + list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") + endif() + set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) + file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") + get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) + get_filename_component(_joinedFileExt "${_joinedFile}" EXT) + if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") + set (_comment "Generating ${_language} unity source ${_joinedFileRelPath}") + elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") + if (_joinedFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_joinedFileRelPath}") + else() + set (_comment "Generating ${_language} prefix header ${_joinedFileRelPath}") + endif() + else() + set (_comment "Generating ${_joinedFileRelPath}") + endif() + add_custom_command( + OUTPUT "${_joinedFile}" + COMMAND ${_prefixCmd} + DEPENDS ${_files} + COMMENT "${_comment}" + WORKING_DIRECTORY "${_sourceDir}" VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_target_pch_usage _languages _targetSourceDir _target _wholeTarget) + if (XCODE) + # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers + # if necessary, we also generate a single prefix header which includes all language specific prefix headers + set (_prefixFiles "") + foreach (_language ${_languages}) + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_prefixFile) + list (APPEND _prefixFiles "${_prefixFile}") + endif() + endforeach() + set (_cmds ${ARGN}) + list (LENGTH _prefixFiles _numberOfPrefixFiles) + if (_numberOfPrefixFiles GREATER 1) + cotire_make_prefix_file_path("" ${_target} _prefixHeader) + cotire_setup_combine_command("" "${_targetSourceDir}" "" "${_prefixHeader}" _cmds ${_prefixFiles}) + else() + set (_prefixHeader "${_prefixFiles}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") + endif() + add_custom_command(TARGET "${_target}" + PRE_BUILD ${_cmds} + WORKING_DIRECTORY "${_targetSourceDir}" + COMMENT "Updating target ${_target} prefix headers" VERBATIM) + # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") + elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") + # for makefile based generator, we force inclusion of the prefix header for all target source files + # if this is a single-language target without any excluded files + if (_wholeTarget) + set (_language "${_languages}") + # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level + # see cotire_setup_pch_file_inclusion + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) + set (_flags "") + cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property(TARGET ${_target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + endif() + endif() + endif() +endfunction() + +function (cotire_setup_unity_generation_commands _language _targetSourceDir _target _targetScript _targetConfigScript _unityFiles _cmdsVar) + set (_dependencySources "") + cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) + foreach (_unityFile ${_unityFiles}) + file (RELATIVE_PATH _unityFileRelPath "${CMAKE_BINARY_DIR}" "${_unityFile}") + set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) + # set up compiled unity source dependencies + # this ensures that missing source files are generated before the unity file is compiled + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") + endif() + if (_dependencySources) + set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_dependencySources}) + endif() + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel + set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") + endif() + cotire_set_cmd_to_prologue(_unityCmd) + list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_targetScript}") + endif() + add_custom_command( + OUTPUT "${_unityFile}" + COMMAND ${_unityCmd} + DEPENDS "${_targetScript}" + COMMENT "Generating ${_language} unity source ${_unityFileRelPath}" + WORKING_DIRECTORY "${_targetSourceDir}" VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) + endforeach() + list (LENGTH _unityFiles _numberOfUnityFiles) + if (_numberOfUnityFiles GREATER 1) + # create a joint unity file from all unity file segments + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) + cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetConfigScript}" "${_unityFile}" ${_cmdsVar} ${_unityFiles}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFile _cmdsVar) + set (_sourceFiles ${ARGN}) + set (_dependencySources "") + cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" "${_unityFile}") + set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources}") + endif() + file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") + get_filename_component(_prefixFileExt "${_prefixFile}" EXT) + if (_prefixFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_prefixFileRelPath}") + else() + set (_comment "Generating ${_language} prefix header ${_prefixFileRelPath}") + endif() + add_custom_command( + OUTPUT "${_prefixFile}" "${_prefixFile}.log" + COMMAND ${_prefixCmd} + DEPENDS "${_unityFile}" ${_dependencySources} + COMMENT "${_comment}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_unity_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + list (LENGTH _unityFiles _numberOfUnityFiles) + if (_numberOfUnityFiles GREATER 1) + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) + cotire_setup_prefix_generation_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" + "${_prefixSourceFile}" "${_unityFile}" ${_cmdsVar} ${_sourceFiles}) + else() + cotire_setup_prefix_generation_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" + "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) + endif() + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" ${_cmdsVar} ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_provided_command _language _target _targetSourceDir _targetScript _prefixFile _cmdsVar) + set (_prefixHeaderFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_init_cotire_target_properties _target) + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") + cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") + if (NOT _isRelative) + set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") + endif() + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) + if (NOT _isSet) + if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") + else() + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") + endif() + endif() +endfunction() + +function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + string (REPLACE ";" " " _languagesStr "${_languages}") + math (EXPR _numberOfExcludedFiles "${ARGC} - 4") + if (_numberOfExcludedFiles EQUAL 0) + set (_excludedStr "") + elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) + string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") + else() + set (_excludedStr "excluding ${_numberOfExcludedFiles} files") + endif() + set (_targetMsg "") + if (NOT _languages) + set (_targetMsg "Target ${_target} cannot be cotired.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH AND NOT _targetAddSCU) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") + endif() + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetAddSCU) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") + endif() + else() + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired.") + endif() + endif() + set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) +endfunction() + +function (cotire_choose_target_languages _targetSourceDir _target _targetLanguagesVar) + set (_languages ${ARGN}) + set (_allSourceFiles "") + set (_allExcludedSourceFiles "") + set (_allCotiredSourceFiles "") + set (_targetLanguages "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + set (_disableMsg "") + foreach (_language ${_languages}) + get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) + get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) + if (_prefixHeader OR _unityBuildFile) + message (STATUS "cotire: target ${_target} has already been cotired.") + set (${_targetLanguagesVar} "" PARENT_SCOPE) + return() + endif() + if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$") + cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _disableMsg) + if (_disableMsg) + set (_targetUsePCH FALSE) + endif() + endif() + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _excludedSources OR _cotiredSources) + list (APPEND _targetLanguages ${_language}) + endif() + if (_sourceFiles) + list (APPEND _allSourceFiles ${_sourceFiles}) + endif() + if (_excludedSources) + list (APPEND _allExcludedSourceFiles ${_excludedSources}) + endif() + if (_cotiredSources) + list (APPEND _allCotiredSourceFiles ${_cotiredSources}) + endif() + endforeach() + set (_targetMsgLevel STATUS) + if (NOT _targetLanguages) + string (REPLACE ";" " or " _languagesStr "${_languages}") + set (_disableMsg "No ${_languagesStr} source files.") + set (_targetUsePCH FALSE) + set (_targetAddSCU FALSE) + endif() + if (_targetUsePCH) + list (LENGTH _allSourceFiles _numberOfSources) + if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + set (_disableMsg "Too few applicable sources.") + set (_targetUsePCH FALSE) + elseif (_allCotiredSourceFiles) + cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) + list (REMOVE_DUPLICATES _cotireTargets) + string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") + set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") + set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") + set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") + set (_targetMsgLevel SEND_ERROR) + set (_targetUsePCH FALSE) + elseif (XCODE AND _allExcludedSourceFiles) + # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target + set (_disableMsg "Exclusion of source files not supported for generator Xcode.") + set (_targetUsePCH FALSE) + elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") + # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target + set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") + set (_targetUsePCH FALSE) + endif() + endif() + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) + cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) + if (_targetMsg) + if (NOT DEFINED COTIREMSG_${_target}) + set (COTIREMSG_${_target} "") + endif() + if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR + NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") + # cache message to avoid redundant messages on re-configure + set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") + message (${_targetMsgLevel} "${_targetMsg}") + endif() + endif() + set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) +endfunction() + +function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) + set (_sourceFiles ${ARGN}) + get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)") + set (_numberOfThreads "${CMAKE_MATCH_2}") + if (NOT _numberOfThreads) + # use all available cores + ProcessorCount(_numberOfThreads) + endif() + list (LENGTH _sourceFiles _numberOfSources) + math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") + # a unity source segment must not contain less than COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES files + if (_maxIncludes LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + set (_maxIncludes ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + endif() + elseif (NOT _maxIncludes MATCHES "[0-9]+") + set (_maxIncludes 0) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_target} unity source max includes = ${_maxIncludes}") + endif() + set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) +endfunction() + +function (cotire_process_target_language _language _configurations _targetSourceDir _targetBinaryDir _target _wholeTargetVar _cmdsVar) + set (${_cmdsVar} "" PARENT_SCOPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (NOT _sourceFiles AND NOT _cotiredSources) + return() + endif() + set (_wholeTarget ${${_wholeTargetVar}}) + set (_cmds "") + # check for user provided unity source file list + get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) + if (NOT _unitySourceFiles) + set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) + endif() + cotire_generate_target_script( + ${_language} "${_configurations}" "${_targetSourceDir}" "${_targetBinaryDir}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) + cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) + cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) + if (NOT _unityFiles) + return() + endif() + cotire_setup_unity_generation_commands( + ${_language} "${_targetSourceDir}" ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) + cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) + if (_prefixFile) + # check for user provided prefix header files + get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) + if (_prefixHeaderFiles) + cotire_setup_prefix_generation_from_provided_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) + else() + cotire_setup_prefix_generation_from_unity_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" "${_unityFiles}" _cmds ${_unitySourceFiles}) + endif() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + if (_targetUsePCH) + cotire_make_pch_file_path(${_language} "${_targetSourceDir}" ${_target} _pchFile) + if (_pchFile) + cotire_setup_pch_file_compilation( + ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + if (_excludedSources) + set (_wholeTarget FALSE) + endif() + cotire_setup_pch_file_inclusion( + ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + endif() + elseif (_prefixHeaderFiles) + # user provided prefix header must be included + cotire_setup_prefix_file_inclusion( + ${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) + endif() + endif() + # mark target as cotired for language + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") + if (_prefixFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") + if (_targetUsePCH AND _pchFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") + endif() + endif() + set (${_wholeTargetVar} ${_wholeTarget} PARENT_SCOPE) + set (${_cmdsVar} ${_cmds} PARENT_SCOPE) +endfunction() + +function (cotire_setup_clean_target _target) + set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") + if (NOT TARGET "${_cleanTargetName}") + cotire_set_cmd_to_prologue(_cmds) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") + add_custom_target(${_cleanTargetName} COMMAND ${_cmds} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Cleaning up target ${_target} cotire generated files" VERBATIM) + cotire_init_target("${_cleanTargetName}") + endif() +endfunction() + +function (cotire_setup_pch_target _languages _configurations _target) + if ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") + # for makefile based generators, we add a custom target to trigger the generation of the cotire related files + set (_dependsFiles "") + foreach (_language ${_languages}) + set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # Visual Studio and Intel only create precompiled header as a side effect + list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) + endif() + cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) + if (_dependsFile) + list (APPEND _dependsFiles "${_dependsFile}") + endif() + endforeach() + if (_dependsFiles) + set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") + add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) + cotire_init_target("${_pchTargetName}") + cotire_add_to_pch_all_target(${_pchTargetName}) + endif() + else() + # for other generators, we add the "clean all" target to clean up the precompiled header + cotire_setup_clean_all_target() + endif() +endfunction() + +function (cotire_setup_unity_build_target _languages _configurations _targetSourceDir _target) + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (NOT _unityTargetName) + set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") + endif() + # determine unity target sub type + get_target_property(_targetType ${_target} TYPE) + if ("${_targetType}" STREQUAL "EXECUTABLE") + set (_unityTargetSubType "") + elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + set (_unityTargetSubType "${CMAKE_MATCH_1}") + else() + message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") + return() + endif() + # determine unity target sources + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_unityTargetSources ${_targetSourceFiles}) + foreach (_language ${_languages}) + get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) + if (_unityFiles) + # remove source files that are included in the unity source + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _cotiredSources) + list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) + endif() + # if cotire is applied to a target which has not been added in the current source dir, + # non-existing files cannot be referenced from the unity build target (this is a CMake restriction) + if (NOT "${_targetSourceDir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + set (_nonExistingFiles "") + foreach (_file ${_unityTargetSources}) + if (NOT EXISTS "${_file}") + list (APPEND _nonExistingFiles "${_file}") + endif() + endforeach() + if (_nonExistingFiles) + if (COTIRE_VERBOSE) + message (STATUS "removing non-existing ${_nonExistingFiles} from ${_unityTargetName}") + endif() + list (REMOVE_ITEM _unityTargetSources ${_nonExistingFiles}) + endif() + endif() + # add unity source files instead + list (APPEND _unityTargetSources ${_unityFiles}) + endif() + endforeach() + if (COTIRE_DEBUG) + message (STATUS "add ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") + endif() + # generate unity target + if ("${_targetType}" STREQUAL "EXECUTABLE") + add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + else() + add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + endif() + set (_outputDirProperties + ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ + LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ + RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) + # copy output location properties + if (COTIRE_UNITY_OUTPUT_DIRECTORY) + set (_setDefaultOutputDir TRUE) + if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + else() + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) + cotire_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties}) + foreach (_property ${_properties}) + get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) + if (_outputDir) + get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") + set (_setDefaultOutputDir FALSE) + endif() + endforeach() + if (_setDefaultOutputDir) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + endif() + endif() + if (_setDefaultOutputDir) + set_target_properties(${_unityTargetName} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" + LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" + RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") + endif() + else() + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) + endif() + # copy output name + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ + LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ + OUTPUT_NAME OUTPUT_NAME_ + RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ + PREFIX _POSTFIX SUFFIX) + # copy compile stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ + COMPILE_FLAGS COMPILE_OPTIONS + Fortran_FORMAT Fortran_MODULE_DIRECTORY + INCLUDE_DIRECTORIES + INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ + POSITION_INDEPENDENT_CODE + C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN) + # copy interface stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN COMPATIBLE_INTERFACE_STRING + INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES + INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + INTERFACE_AUTOUIC_OPTIONS) + # copy link stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH + LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED + LINK_FLAGS LINK_FLAGS_ + LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ + LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ + LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC + STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ + NO_SONAME SOVERSION VERSION) + # copy Qt stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + AUTOMOC AUTOMOC_MOC_OPTIONS AUTOUIC AUTOUIC_OPTIONS AUTORCC AUTORCC_OPTIONS + AUTOGEN_TARGET_DEPENDS) + # copy cmake stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) + # copy Apple platform specific stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUNDLE BUNDLE_EXTENSION FRAMEWORK INSTALL_NAME_DIR MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST + MACOSX_RPATH OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE) + # copy Windows platform specific stuff + cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} + GNUtoMS + PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ + VS_DOTNET_REFERENCES VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE VS_KEYWORD + VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER + VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES WIN32_EXECUTABLE) + # use output name from original target + get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) + if (NOT _targetOutputName) + set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") + endif() + # use export symbol from original target + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") + if ("${_targetType}" STREQUAL "EXECUTABLE") + set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) + endif() + endif() + cotire_init_target(${_unityTargetName}) + cotire_add_to_unity_all_target(${_unityTargetName}) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") +endfunction(cotire_setup_unity_build_target) + +function (cotire_target _target) + set(_options "") + set(_oneValueArgs SOURCE_DIR BINARY_DIR) + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_SOURCE_DIR) + set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + if (NOT _option_BINARY_DIR) + set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if (NOT _option_LANGUAGES) + get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + endif() + if (NOT _option_CONFIGURATIONS) + if (CMAKE_CONFIGURATION_TYPES) + set (_option_CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES}) + elseif (CMAKE_BUILD_TYPE) + set (_option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}") + else() + set (_option_CONFIGURATIONS "None") + endif() + endif() + # trivial checks + get_target_property(_imported ${_target} IMPORTED) + if (_imported) + message (WARNING "cotire: imported target ${_target} cannot be cotired.") + return() + endif() + # resolve alias + get_target_property(_aliasName ${_target} ALIASED_TARGET) + if (_aliasName) + if (COTIRE_DEBUG) + message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") + endif() + set (_target ${_aliasName}) + endif() + # check if target needs to be cotired for build type + # when using configuration types, the test is performed at build time + cotire_init_cotire_target_properties(${_target}) + if (NOT CMAKE_CONFIGURATION_TYPES) + if (CMAKE_BUILD_TYPE) + list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) + else() + list (FIND _option_CONFIGURATIONS "None" _index) + endif() + if (_index EQUAL -1) + if (COTIRE_DEBUG) + message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") + endif() + return() + endif() + endif() + # choose languages that apply to the target + cotire_choose_target_languages("${_option_SOURCE_DIR}" "${_target}" _targetLanguages ${_option_LANGUAGES}) + if (NOT _targetLanguages) + return() + endif() + list (LENGTH _targetLanguages _numberOfLanguages) + if (_numberOfLanguages GREATER 1) + set (_wholeTarget FALSE) + else() + set (_wholeTarget TRUE) + endif() + set (_cmds "") + foreach (_language ${_targetLanguages}) + cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" + "${_option_SOURCE_DIR}" "${_option_BINARY_DIR}" ${_target} _wholeTarget _cmd) + if (_cmd) + list (APPEND _cmds ${_cmd}) + endif() + endforeach() + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + if (_targetAddSCU) + cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" "${_option_SOURCE_DIR}" ${_target}) + endif() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + if (_targetUsePCH) + cotire_setup_target_pch_usage("${_targetLanguages}" "${_option_SOURCE_DIR}" ${_target} ${_wholeTarget} ${_cmds}) + cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) + endif() + get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) + if (_targetAddCleanTarget) + cotire_setup_clean_target(${_target}) + endif() +endfunction(cotire_target) + +function (cotire_map_libraries _strategy _mappedLibrariesVar) + set (_mappedLibraries "") + foreach (_library ${ARGN}) + if (TARGET "${_library}" AND "${_strategy}" MATCHES "COPY_UNITY") + get_target_property(_libraryUnityTargetName ${_library} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_libraryUnityTargetName}") + list (APPEND _mappedLibraries "${_libraryUnityTargetName}") + else() + list (APPEND _mappedLibraries "${_library}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + endforeach() + list (REMOVE_DUPLICATES _mappedLibraries) + set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) +endfunction() + +function (cotire_target_link_libraries _target) + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_unityTargetName}") + get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") + endif() + if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") + if (CMAKE_VERSION VERSION_LESS "2.8.11") + message (WARNING "cotire: unity target link strategy ${_linkLibrariesStrategy} requires CMake 2.8.11 or later. Defaulting to NONE for ${_target}.") + else() + get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) + get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries} ${_interfaceLinkLibraries}) + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} libraries: ${_unityLinkLibraries}") + endif() + if (_unityLinkLibraries) + target_link_libraries(${_unityTargetName} ${_unityLinkLibraries}) + endif() + endif() + endif() + endif() +endfunction(cotire_target_link_libraries) + +function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) + if (_targetName) + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") + else() + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") + endif() + # filter files in intermediate directory + set (_filesToRemove "") + foreach (_file ${_cotireFiles}) + get_filename_component(_dir "${_file}" PATH) + get_filename_component(_dirName "${_dir}" NAME) + if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") + list (APPEND _filesToRemove "${_file}") + endif() + endforeach() + if (_filesToRemove) + if (COTIRE_VERBOSE) + message (STATUS "removing ${_filesToRemove}") + endif() + file (REMOVE ${_filesToRemove}) + endif() +endfunction() + +function (cotire_init_target _targetName) + if (COTIRE_TARGETS_FOLDER) + set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") + endif() + if (MSVC_IDE) + set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) + endif() +endfunction() + +function (cotire_add_to_pch_all_target _pchTargetName) + set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_pchTargetName}) +endfunction() + +function (cotire_add_to_unity_all_target _unityTargetName) + set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_unityTargetName}) +endfunction() + +function (cotire_setup_clean_all_target) + set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + cotire_set_cmd_to_prologue(_cmds) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") + add_custom_target(${_targetName} COMMAND ${_cmds} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "Cleaning up all cotire generated files" VERBATIM) + cotire_init_target("${_targetName}") + endif() +endfunction() + +function (cotire) + set(_options "") + set(_oneValueArgs SOURCE_DIR BINARY_DIR) + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_targets ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_SOURCE_DIR) + set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + if (NOT _option_BINARY_DIR) + set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS} + SOURCE_DIR "${_option_SOURCE_DIR}" BINARY_DIR "${_option_BINARY_DIR}") + else() + message (WARNING "cotire: ${_target} is not a target.") + endif() + endforeach() + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target_link_libraries(${_target}) + endif() + endforeach() +endfunction() + +if (CMAKE_SCRIPT_MODE_FILE) + + # cotire is being run in script mode + # locate -P on command args + set (COTIRE_ARGC -1) + foreach (_index RANGE ${CMAKE_ARGC}) + if (COTIRE_ARGC GREATER -1) + set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") + math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") + elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") + set (COTIRE_ARGC 0) + endif() + endforeach() + + # include target script if available + if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") + # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) + include("${COTIRE_ARGV2}") + endif() + + if (COTIRE_DEBUG) + message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") + endif() + + if (WIN32) + # for MSVC, compiler IDs may not always be set correctly + if (MSVC) + set (CMAKE_C_COMPILER_ID "MSVC") + set (CMAKE_CXX_COMPILER_ID "MSVC") + endif() + endif() + + if (NOT COTIRE_BUILD_TYPE) + set (COTIRE_BUILD_TYPE "None") + endif() + string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) + set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) + set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) + # check if target has been cotired for actual build type COTIRE_BUILD_TYPE + list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) + if (_index GREATER -1) + set (_sources ${COTIRE_TARGET_SOURCES}) + set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) + else() + if (COTIRE_DEBUG) + message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") + endif() + set (_sources "") + set (_sourcesDefinitions "") + endif() + set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) + set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) + set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) + set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) + + if ("${COTIRE_ARGV1}" STREQUAL "unity") + + cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) + cotire_generate_unity_source( + "${COTIRE_ARGV3}" ${_sources} + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV2}" + SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} + PRE_UNDEFS ${_targetPreUndefs} + POST_UNDEFS ${_targetPostUndefs} + SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} + SOURCES_POST_UNDEFS ${_sourcesPostUndefs}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") + + set (_files "") + foreach (_index RANGE 4 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_generate_prefix_header( + "${COTIRE_ARGV3}" ${_files} + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS} + IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" + INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} + IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" + INCLUDE_SYSTEM_FLAG "${COTIRE_INCLUDE_SYSTEM_FLAG}" + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") + + set (_files "") + foreach (_index RANGE 5 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_precompile_prefix_header( + "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + INCLUDE_SYSTEM_FLAG "${COTIRE_INCLUDE_SYSTEM_FLAG}" + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "combine") + + if (COTIRE_TARGET_LANGUAGE) + set (_startIndex 3) + else() + set (_startIndex 2) + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + if (COTIRE_TARGET_LANGUAGE) + cotire_generate_unity_source(${_files} LANGUAGE "${COTIRE_TARGET_LANGUAGE}") + else() + cotire_generate_unity_source(${_files}) + endif() + + elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") + + cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") + + else() + message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") + endif() + +else() + + # cotire is being run in include mode + # set up all variable and property definitions + + unset (COTIRE_C_COMPILER_VERSION CACHE) + unset (COTIRE_CXX_COMPILER_VERSION CACHE) + + if (NOT DEFINED COTIRE_DEBUG_INIT) + if (DEFINED COTIRE_DEBUG) + set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) + else() + set (COTIRE_DEBUG_INIT FALSE) + endif() + endif() + option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) + + if (NOT DEFINED COTIRE_VERBOSE_INIT) + if (DEFINED COTIRE_VERBOSE) + set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) + else() + set (COTIRE_VERBOSE_INIT FALSE) + endif() + endif() + option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING + "Ignore headers with the listed file extensions from the generated prefix header.") + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING + "Ignore headers from these directories when generating the prefix header.") + + set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING + "Ignore sources with the listed file extensions from the generated unity source.") + + set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING + "Minimum number of sources in target required to enable use of precompiled header.") + + if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) + if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) + elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") + # enable parallelization for generators that run multiple jobs by default + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") + else() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") + endif() + endif() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING + "Maximum number of source files to include in a single unity source file.") + + if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) + set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") + endif() + if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) + set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") + endif() + if (NOT COTIRE_INTDIR) + set (COTIRE_INTDIR "cotire") + endif() + if (NOT COTIRE_PCH_ALL_TARGET_NAME) + set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") + endif() + if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) + set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") + endif() + if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) + set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") + endif() + if (NOT COTIRE_CLEAN_TARGET_SUFFIX) + set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") + endif() + if (NOT COTIRE_PCH_TARGET_SUFFIX) + set (COTIRE_PCH_TARGET_SUFFIX "_pch") + endif() + if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) + set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") + endif() + if (NOT DEFINED COTIRE_TARGETS_FOLDER) + set (COTIRE_TARGETS_FOLDER "cotire") + endif() + if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) + if ("${CMAKE_GENERATOR}" MATCHES "Ninja") + # generated Ninja build files do not work if the unity target produces the same output file as the cotired target + set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") + else() + set (COTIRE_UNITY_OUTPUT_DIRECTORY "") + endif() + endif() + + # define cotire cache variables + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of include directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "If not defined, defaults to empty list." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" + BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a header file extension matches one in the list, it will be excluded from the generated prefix header." + "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." + "If not defined, defaults to inc;inl;ipp." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" + BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a source file extension matches one in the list, it will be excluded from the generated unity source file." + "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." + "If not defined, defaults to m;mm." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" + BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." + FULL_DOCS + "The variable can be set to an integer > 0." + "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." + "If not defined, defaults to 3." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer >= 0." + "If 0, cotire will only create a single unity source file." + "If a target contains more than that number of source files, cotire will create multiple unity source files for it." + "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." + "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." + "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." + ) + + # define cotire directory properties + + define_property( + DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" + BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." + FULL_DOCS + "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" + BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_UNITY_BUILD." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" + BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_CLEAN." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" + BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." + FULL_DOCS + "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." + ) + + # define cotire target properties + + define_property( + TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED + BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." + FULL_DOCS + "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." + "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." + "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." + "The target name will be set to this target's name with the suffix _pch appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED + BRIEF_DOCS "Add a new target that performs a unity build for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." + "Most of the relevant target properties will be copied from this target to the new unity build target." + "Target dependencies and linked libraries have to be manually set up for the new unity build target." + "The unity target name will be set to this target's name with the suffix _unity appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED + BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." + "The clean target name will be set to this target's name with the suffix _clean_cotire appended." + "Inherited from directory." + "Defaults to FALSE." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "Inherited from directory." + "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." + "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," + "the option which yields the closer relative path match wins." + "Inherited from directory." + "If not set, this property is initialized to the empty list." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer > 0." + "If a target contains more than that number of source files, cotire will create multiple unity build files for it." + "If not set, cotire will only create a single unity source file." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" + BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will only add the given file(s) to the generated unity source file." + "If not set, cotire will add all the target source files to the generated unity source file." + "The property can be set to a user provided unity source file." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" + BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will add the given header file(s) to the generated prefix header file." + "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." + "The property can be set to a user provided prefix header file (e.g., stdafx.h)." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED + BRIEF_DOCS "Define strategy for setting up unity target's link libraries." + FULL_DOCS + "If this property is empty, the generated unity target's link libraries have to be set up manually." + "If this property is set to COPY, the unity target's link libraries will be copied from this target." + "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE" + BRIEF_DOCS "Read-only property. The generated unity source file(s)." + FULL_DOCS + "cotire sets this property to the path of the generated single computation unit source file for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER" + BRIEF_DOCS "Read-only property. The generated prefix header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language prefix header for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" + BRIEF_DOCS "Read-only property. The generated precompiled header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language precompiled header binary for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" + BRIEF_DOCS "The name of the generated unity build target corresponding to this target." + FULL_DOCS + "This property can be set to the desired name of the unity target that will be created by cotire." + "If not set, the unity target name will be set to this target's name with the suffix _unity appended." + "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." + "Defaults to empty string." + ) + + # define cotire source properties + + define_property( + SOURCE PROPERTY "COTIRE_EXCLUDED" + BRIEF_DOCS "Do not modify source file's build command." + FULL_DOCS + "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." + "The source file will also be excluded from the generated unity source file." + "Source files that have their COMPILE_FLAGS property set will be excluded by default." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_DEPENDENCY" + BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." + FULL_DOCS + "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." + "If the file is modified, cotire will re-generate the prefix header source upon build." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" + BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." + FULL_DOCS + "If this property is set to TRUE, cotire will complete the current unity file and start a new one." + "The new unity source file will include this source file as the first one." + "This property essentially works as a separator for unity source files." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_TARGET" + BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." + FULL_DOCS + "cotire sets this property to the name of target, that the source file's build command has been altered for." + "Defaults to empty string." + ) + + message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") + +endif() diff --git a/ext/ghoul b/ext/ghoul index 1f1386215e..ba68d54517 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 1f1386215e517179f7a4e80e64693fd3ebc2b339 +Subproject commit ba68d5451755ed20baccaf82dcb886186b5a1834 diff --git a/include/openspace/util/kameleonwrapper.h b/include/openspace/util/kameleonwrapper.h index 1bd768e72a..3580e6076a 100644 --- a/include/openspace/util/kameleonwrapper.h +++ b/include/openspace/util/kameleonwrapper.h @@ -60,7 +60,7 @@ public: enum class FieldlineEnd { NORTH, SOUTH, - OUT + FAROUT }; KameleonWrapper(const std::string& filename, Model model); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b193bdc0f..b7f34fc96f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -147,6 +147,7 @@ include_directories("${HEADER_ROOT_DIR}") add_executable(OpenSpace ${SOURCE_ROOT_DIR}/main.cpp ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) target_link_libraries(OpenSpace ${DEPENDENT_LIBS}) +cotire(OpenSpace) if (WIN32) if (CMAKE_CL_64) diff --git a/src/util/kameleonwrapper.cpp b/src/util/kameleonwrapper.cpp index 7a84174649..8d97b0b3c3 100644 --- a/src/util/kameleonwrapper.cpp +++ b/src/util/kameleonwrapper.cpp @@ -467,7 +467,7 @@ std::vector KameleonWrapper::traceCartesianFieldline( else if (pos.z < 0.0 && (pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < 1.0)) end = FieldlineEnd::SOUTH; else - end = FieldlineEnd::OUT; + end = FieldlineEnd::FAROUT; return line; } @@ -610,15 +610,15 @@ glm::vec4 KameleonWrapper::classifyFieldline(FieldlineEnd fEnd, FieldlineEnd bEn && (bEnd == FieldlineEnd::NORTH || bEnd == FieldlineEnd::SOUTH)) { // closed color = glm::vec4(1.0, 0.0, 0.0, 1.0); - } else if ((fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::NORTH) - || (bEnd == FieldlineEnd::OUT && fEnd == FieldlineEnd::NORTH)) { + } else if ((fEnd == FieldlineEnd::FAROUT && bEnd == FieldlineEnd::NORTH) + || (bEnd == FieldlineEnd::FAROUT && fEnd == FieldlineEnd::NORTH)) { // north color = glm::vec4(1.0, 1.0, 0.0, 1.0); - } else if ((fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::SOUTH) - || (bEnd == FieldlineEnd::OUT && fEnd == FieldlineEnd::SOUTH)) { + } else if ((fEnd == FieldlineEnd::FAROUT && bEnd == FieldlineEnd::SOUTH) + || (bEnd == FieldlineEnd::FAROUT && fEnd == FieldlineEnd::SOUTH)) { // south color = glm::vec4(0.0, 1.0, 0.0, 1.0); - } else if (fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::OUT) { + } else if (fEnd == FieldlineEnd::FAROUT && bEnd == FieldlineEnd::FAROUT) { // solar wind color = glm::vec4(0.0, 0.0, 1.0, 1.0); } From 13bdd33f7eff33155922b6b9c986e59b9195ae27 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Thu, 16 Oct 2014 15:52:37 +0200 Subject: [PATCH 07/17] Disable cotire in case it breaks on Linux --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d0220aa72..997c3d8bc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ set(OPENSPACE_EXT_DIR "${OPENSPACE_BASE_DIR}/ext") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_EXT_DIR}) -include(cotire) +#include(cotire) # Make sure a build type is set. Default is Debug. if(NOT CMAKE_BUILD_TYPE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7f34fc96f..b2918c1ca4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -147,7 +147,8 @@ include_directories("${HEADER_ROOT_DIR}") add_executable(OpenSpace ${SOURCE_ROOT_DIR}/main.cpp ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) target_link_libraries(OpenSpace ${DEPENDENT_LIBS}) -cotire(OpenSpace) + +# cotire(OpenSpace) if (WIN32) if (CMAKE_CL_64) From 18a87ef99e41e33b53524264d87458c794e4e7d8 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Fri, 17 Oct 2014 12:20:23 +0200 Subject: [PATCH 08/17] Added ScreenLog - Added first version of a ScreenLog mechanism - Moved the info box to the upper left corner - Added Ubuntu fonts - Made RenderEngine a PropertyOwner with _showInfo and _showScreenLog as bool properties that can be edited through Lua. --- include/openspace/rendering/renderengine.h | 10 +- include/openspace/util/constants.h | 6 + include/openspace/util/screenlog.h | 67 +++++++++ openspace-data | 2 +- openspace.cfg | 3 +- src/abuffer/abuffer.cpp | 4 +- src/engine/openspaceengine.cpp | 5 + src/rendering/renderengine.cpp | 161 ++++++++++++++------- src/util/screenlog.cpp | 51 +++++++ 9 files changed, 248 insertions(+), 61 deletions(-) create mode 100644 include/openspace/util/screenlog.h create mode 100644 src/util/screenlog.cpp diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 8859f7a0c1..ea99843de0 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -33,12 +33,15 @@ #include #include +#include +#include +#include namespace openspace { class Camera; -class RenderEngine { +class RenderEngine: public properties::PropertyOwner { public: RenderEngine(); ~RenderEngine(); @@ -74,6 +77,11 @@ private: Camera* _mainCamera; SceneGraph* _sceneGraph; ABuffer* _abuffer; + ScreenLog* _log; + + properties::BoolProperty _showInfo; + properties::BoolProperty _showScreenLog; + void generateGlslConfig(); }; diff --git a/include/openspace/util/constants.h b/include/openspace/util/constants.h index 49e8787045..5825956674 100644 --- a/include/openspace/util/constants.h +++ b/include/openspace/util/constants.h @@ -30,6 +30,12 @@ namespace openspace { namespace constants { +namespace fonts { + const std::string keySGCT = "SGCTFont"; + const std::string keyMono = "UbuntuMono"; + const std::string keyLight = "UbuntuLight"; +} // namespace fonts + namespace configurationmanager { const std::string keyPaths = "Paths"; const std::string keyConfigSgct = "SGCTConfig"; diff --git a/include/openspace/util/screenlog.h b/include/openspace/util/screenlog.h new file mode 100644 index 0000000000..b6ce0b8908 --- /dev/null +++ b/include/openspace/util/screenlog.h @@ -0,0 +1,67 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include +#include // pair + +namespace openspace { + +class ScreenLog : public ghoul::logging::Log { +public: + //typedef std::tuple LogEntry; + + struct LogEntry { + LogEntry(ghoul::logging::LogManager::LogLevel l, double t, std::string ts, std::string c, std::string m) : level(l), timeStamp(t), timeString(ts), category(c), message(m) {}; + ghoul::logging::LogManager::LogLevel level; + double timeStamp; + std::string timeString; + std::string category; + std::string message; + }; + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; + + typedef std::pair range; + typedef std::pair const_range; + + const size_t MaximumSize = 1000; + + ScreenLog(); + + virtual void log(ghoul::logging::LogManager::LogLevel level, const std::string& category, + const std::string& message); + + const_range last(size_t n = 10); + +private: + + std::vector _entries; + +}; +} \ No newline at end of file diff --git a/openspace-data b/openspace-data index 4d3fc5402c..d415918525 160000 --- a/openspace-data +++ b/openspace-data @@ -1 +1 @@ -Subproject commit 4d3fc5402c0f4fe271dbff7f437423cd956245c8 +Subproject commit d415918525c1ec8ca4486d520bb01844e97ce4b6 diff --git a/openspace.cfg b/openspace.cfg index a010b5f459..9567b7fcfa 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,7 +7,8 @@ return { TESTDIR = "${BASE_PATH}/src/tests", CONFIG = "${BASE_PATH}/config", CACHE = "${BASE_PATH}/cache", - TEMPORARY = "${BASE_PATH}/tmp" + TEMPORARY = "${BASE_PATH}/tmp", + FONTS = "${OPENSPACE_DATA}/fonts" }, SpiceKernel = { Time = "${OPENSPACE_DATA}/spice/naif0010.tls", diff --git a/src/abuffer/abuffer.cpp b/src/abuffer/abuffer.cpp index 74cd43521d..93abff5ae3 100644 --- a/src/abuffer/abuffer.cpp +++ b/src/abuffer/abuffer.cpp @@ -190,7 +190,7 @@ bool ABuffer::updateShader() { _fragmentShaderPath); if( ! resolveShader) { - LERROR("Resolve shader not updated"); + LWARNING("ABuffer shader not updated"); return false; } @@ -207,7 +207,7 @@ bool ABuffer::updateShader() { delete _resolveShader; _resolveShader = resolveShader; - LDEBUG("Successfully updated shader!"); + LINFO("Successfully updated ABuffer shader!"); return true; } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index ec002b70cf..2bf45020bf 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -330,6 +330,11 @@ bool OpenSpaceEngine::initialize() { _engine->scriptEngine().runScriptFile(absoluteScriptPath); } + // Load a light and a monospaced font + sgct_text::FontManager::instance()->setDefaultFontPath(absPath("${FONTS}/")); + sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, "ubuntu-font-family/UbuntuMono-R.ttf"); + sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, "ubuntu-font-family/Ubuntu-L.ttf"); + return true; } diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 0558d9003a..0343ac84fc 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -30,6 +30,7 @@ #include // We need to decide where this is set +#include #include #include #include "sgct.h" @@ -70,9 +71,13 @@ int printImage(lua_State* L) { RenderEngine::RenderEngine() : _mainCamera(nullptr) - , _sceneGraph(nullptr) - , _abuffer(nullptr) + , _sceneGraph(nullptr) + , _abuffer(nullptr) + , _log(nullptr) + , _showInfo("info", "Display info", true) + , _showScreenLog("log", "Display screen log", true) { + setName("renderEngine"); } RenderEngine::~RenderEngine() @@ -178,6 +183,9 @@ bool RenderEngine::initializeGL() _abuffer->initialize(); + _log = new ScreenLog(); + ghoul::logging::LogManager::ref().addLog(_log); + // successful init return true; } @@ -253,61 +261,102 @@ void RenderEngine::render() // Print some useful information on the master viewport sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr(); if (sgct::Engine::instance()->isMaster() && ! w->isUsingFisheyeRendering()) { -// Apple usually has retina screens -#ifdef __APPLE__ -#define FONT_SIZE 18 -#else -#define FONT_SIZE 10 -#endif - - - const glm::vec2 scaling = _mainCamera->scaling(); - const glm::vec3 viewdirection = _mainCamera->viewDirection(); - const psc position = _mainCamera->position(); - const psc origin = OsEng.interactionHandler().getOrigin(); - const PowerScaledScalar pssl = (position - origin).length(); - - /* GUI PRINT */ - - std::string&& time = Time::ref().currentTimeUTC().c_str(); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 18, "Date: %s", time.c_str() - ); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 16, "Avg. Frametime: %.10f", sgct::Engine::instance()->getAvgDt() - ); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 14, "Drawtime: %.10f", sgct::Engine::instance()->getDrawTime() - ); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 12, "Frametime: %.10f", sgct::Engine::instance()->getDt() - ); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 10, "Origin: (%.5f, %.5f, %.5f, %.5f)", origin[0], - origin[1], origin[2], origin[3]); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 8, "Camera position: (%.5f, %.5f, %.5f, %.5f)", - position[0], position[1], position[2], position[3]); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 6, "Distance to origin: (%.15f, %.2f)", pssl[0], - pssl[1]); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 4, "View direction: (%.3f, %.3f, %.3f)", - viewdirection[0], viewdirection[1], viewdirection[2]); - Freetype::print( - sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), - FONT_SIZE, FONT_SIZE * 2, "Scaling: (%.10f, %.2f)", scaling[0], scaling[1]); - - } + + // TODO: Adjust font_size properly when using retina screen + const int font_size = 8; + const int font_with = font_size*0.7; + const sgct_text::Font* fontLight = sgct_text::FontManager::instance()->getFont(constants::fonts::keyLight, font_size); + const sgct_text::Font* fontMono = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); + + if (_showInfo) { + const sgct_text::Font* font = fontMono; + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + int startY = ySize - 2 * font_size; + const glm::vec2 scaling = _mainCamera->scaling(); + const glm::vec3 viewdirection = _mainCamera->viewDirection(); + const psc position = _mainCamera->position(); + const psc origin = OsEng.interactionHandler().getOrigin(); + const PowerScaledScalar pssl = (position - origin).length(); + + // GUI PRINT +// Using a macro to shorten line length and increase readability +#define PrintText(i, format, ...) Freetype::print(font, 10, startY - font_size * i * 2, format, __VA_ARGS__); + int i = 0; + PrintText(i++, "Date: %s", Time::ref().currentTimeUTC().c_str()); + PrintText(i++, "Avg. Frametime: %.5f", sgct::Engine::instance()->getAvgDt()); + PrintText(i++, "Drawtime: %.5f", sgct::Engine::instance()->getDrawTime()); + PrintText(i++, "Frametime: %.5f", sgct::Engine::instance()->getDt()); + PrintText(i++, "Origin: (% .5f, % .5f, % .5f, % .5f)", origin[0], origin[1], origin[2], origin[3]); + PrintText(i++, "Cam pos: (% .5f, % .5f, % .5f, % .5f)", position[0], position[1], position[2], position[3]); + PrintText(i++, "View dir: (% .5f, % .5f, % .5f)", viewdirection[0], viewdirection[1], viewdirection[2]); + PrintText(i++, "Cam->origin: (% .15f, % .4f)", pssl[0], pssl[1]); + PrintText(i++, "Scaling: (% .5f, % .5f)", scaling[0], scaling[1]); +#undef PrintText + } + + if (_showScreenLog) + { + const sgct_text::Font* font = fontLight; + const int max = 10; + const int category_length = 20; + const int msg_length = 120; + const double ttl = 10.0; + auto entries = _log->last(max); + + const glm::vec4 white(1, 1, 1, 1); + const glm::vec4 red(1, 0, 0, 1); + const glm::vec4 yellow(1, 1, 0, 1); + const glm::vec4 green(0, 1, 0, 1); + const glm::vec4 blue(0, 0, 1, 1); + + size_t nr = 1; + for (auto it = entries.first; it != entries.second; ++it) { + const ScreenLog::LogEntry* e = &(*it); + + const double t = sgct::Engine::instance()->getTime(); + double diff = t - e->timeStamp; + + // Since all log entries are ordered, once one is exceeding TTL, all have + if (diff > ttl) + break; + + float alpha = 1; + float ttf = ttl - 5.0; + if (diff > ttf) { + diff = diff - ttf; + float p = 0.8 - diff / ttf; + alpha = (p <= 0.0) ? 0.0 : pow(p, 0.3); + } + + // Since all log entries are ordered, once one exceeds alpha, all have + if (alpha <= 0.0) + break; + + std::string lvl = "(" + ghoul::logging::LogManager::stringFromLevel(e->level) + ")"; + Freetype::print(font, 10, font_size * nr * 2, white*alpha, + "%-14s %s%s", // Format + e->timeString.c_str(), // Time string + e->category.substr(0, category_length).c_str(), // Category string (up to category_length) + e->category.length() > 20 ? "..." : ""); // Pad category with "..." if exceeds category_length + + glm::vec4 color = white; + if (e->level == ghoul::logging::LogManager::LogLevel::Debug) + color = green; + if (e->level == ghoul::logging::LogManager::LogLevel::Warning) + color = yellow; + if (e->level == ghoul::logging::LogManager::LogLevel::Error) + color = red; + if (e->level == ghoul::logging::LogManager::LogLevel::Fatal) + color = blue; + + Freetype::print(font, 10 + 39 * font_with, font_size * nr * 2, color*alpha, "%s", lvl.c_str()); + Freetype::print(font, 10 + 53 * font_with, font_size * nr * 2, white*alpha, "%s", e->message.substr(0, msg_length).c_str()); + ++nr; + } + } #endif + } } diff --git a/src/util/screenlog.cpp b/src/util/screenlog.cpp new file mode 100644 index 0000000000..5e972692b1 --- /dev/null +++ b/src/util/screenlog.cpp @@ -0,0 +1,51 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include // sgct::Engine::instance()->getTime() + +namespace openspace { + +ScreenLog::ScreenLog() {} + +void ScreenLog::log(ghoul::logging::LogManager::LogLevel level, const std::string& category, const std::string& message) { + if (level >= ghoul::logging::LogManager::LogLevel::Info) + _entries.emplace_back(level, sgct::Engine::instance()->getTime(), Log::getTimeString(), category, message); + + // Once reaching maximum size, reduce to half + if (_entries.size() > MaximumSize) { + _entries.erase(_entries.begin(), _entries.begin() + MaximumSize / 2); + } +} + +ScreenLog::const_range ScreenLog::last(size_t n) { + if (_entries.size() > n) { + return std::make_pair(_entries.rbegin(), _entries.rbegin() + n); + } else { + return std::make_pair(_entries.rbegin(), _entries.rend()); + } +} + +} \ No newline at end of file From 7ef5295bb7108809b9581fe05486e875f7b6ea5f Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Fri, 17 Oct 2014 14:50:40 +0200 Subject: [PATCH 09/17] Added ABuffer reinitialization - Fixed so ABuffer reinitializes properly (could probably be optimized by not resizing of smaller than before) - Now setting size properly from window dimensions - SGCT side-by-side stereo working --- ext/ghoul | 2 +- include/openspace/abuffer/abuffer.h | 5 ++ .../openspace/abuffer/abufferSingleLinked.h | 2 + include/openspace/abuffer/abuffer_i.h | 1 + include/openspace/abuffer/abufferdynamic.h | 2 + include/openspace/abuffer/abufferfixed.h | 2 + shaders/ABuffer/abufferAddToBuffer.hglsl | 6 +-- src/abuffer/abuffer.cpp | 47 ++++++++++++------- src/abuffer/abufferSingleLinked.cpp | 32 ++++++++----- src/abuffer/abufferdynamic.cpp | 4 ++ src/abuffer/abufferfixed.cpp | 4 ++ src/rendering/renderengine.cpp | 31 ++++++------ 12 files changed, 87 insertions(+), 51 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 3691eec2c5..a2f137941a 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 3691eec2c5fbd52ea45d43374814487c2c647960 +Subproject commit a2f137941a5eae85b620674eb90407bb5be349df diff --git a/include/openspace/abuffer/abuffer.h b/include/openspace/abuffer/abuffer.h index 1c31bcfe17..aa12cb63f5 100644 --- a/include/openspace/abuffer/abuffer.h +++ b/include/openspace/abuffer/abuffer.h @@ -49,6 +49,7 @@ public: ABuffer(); virtual ~ABuffer(); virtual void resolve(); + virtual bool reinitialize(); void addVolume(const std::string& tag,ghoul::opengl::Texture* volume); void addTransferFunction(const std::string& tag,ghoul::opengl::Texture* transferFunction); @@ -58,6 +59,7 @@ public: protected: virtual std::string settings() = 0; + virtual bool reinitializeInternal() = 0; bool initializeABuffer(); @@ -72,6 +74,9 @@ protected: unsigned int _width, _height, _totalPixels; private: + + void updateDimensions(); + GLuint _screenQuad; bool _validShader; diff --git a/include/openspace/abuffer/abufferSingleLinked.h b/include/openspace/abuffer/abufferSingleLinked.h index c348abee52..efedb34228 100644 --- a/include/openspace/abuffer/abufferSingleLinked.h +++ b/include/openspace/abuffer/abufferSingleLinked.h @@ -41,6 +41,8 @@ public: virtual void postRender(); virtual std::string settings(); +protected: + virtual bool reinitializeInternal(); private: diff --git a/include/openspace/abuffer/abuffer_i.h b/include/openspace/abuffer/abuffer_i.h index 04a8e4277c..b6e568deae 100644 --- a/include/openspace/abuffer/abuffer_i.h +++ b/include/openspace/abuffer/abuffer_i.h @@ -31,6 +31,7 @@ class ABuffer_I { public: virtual ~ABuffer_I() {}; virtual bool initialize() = 0; + virtual bool reinitialize() = 0; virtual void clear() = 0; virtual void preRender() = 0; diff --git a/include/openspace/abuffer/abufferdynamic.h b/include/openspace/abuffer/abufferdynamic.h index 4d3b91ce59..81732e77a8 100644 --- a/include/openspace/abuffer/abufferdynamic.h +++ b/include/openspace/abuffer/abufferdynamic.h @@ -41,6 +41,8 @@ public: virtual void postRender(); virtual std::string settings(); +protected: + virtual bool reinitializeInternal(); private: diff --git a/include/openspace/abuffer/abufferfixed.h b/include/openspace/abuffer/abufferfixed.h index cc211e0b57..46d1b37a8c 100644 --- a/include/openspace/abuffer/abufferfixed.h +++ b/include/openspace/abuffer/abufferfixed.h @@ -41,6 +41,8 @@ public: virtual void postRender(); virtual std::string settings(); +protected: + virtual bool reinitializeInternal(); private: diff --git a/shaders/ABuffer/abufferAddToBuffer.hglsl b/shaders/ABuffer/abufferAddToBuffer.hglsl index 6bf1624a8a..fc5bcf2c27 100644 --- a/shaders/ABuffer/abufferAddToBuffer.hglsl +++ b/shaders/ABuffer/abufferAddToBuffer.hglsl @@ -34,9 +34,9 @@ layout (binding = 0, offset = 0) uniform atomic_uint atomicCounterBuffer; layout (binding = 0, r32ui) uniform uimage2D anchorPointerTexture; layout (binding = 1, rgba32ui) uniform uimageBuffer fragmentTexture; - #define _MAX_LAYERS_ 64 - #define _SCREEN_WIDTH_ 1280 - #define _SCREEN_HEIGHT_ 720 + #define _MAX_LAYERS_ MAX_LAYERS + #define _SCREEN_WIDTH_ SCREEN_WIDTH + #define _SCREEN_HEIGHT_ SCREEN_HEIGHT #endif ABufferStruct_t createGeometryFragment(vec4 fragColor, vec4 position, float z = gl_FragCoord.z) { diff --git a/src/abuffer/abuffer.cpp b/src/abuffer/abuffer.cpp index 3498c7afba..45adb1274a 100644 --- a/src/abuffer/abuffer.cpp +++ b/src/abuffer/abuffer.cpp @@ -48,11 +48,7 @@ namespace { namespace openspace { ABuffer::ABuffer() : _validShader(false), _resolveShader(nullptr) { - int x1, xSize, y1, ySize; - sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); - _width = xSize; - _height = ySize; - _totalPixels = _width * _height; + updateDimensions(); } ABuffer::~ABuffer() { @@ -71,7 +67,6 @@ bool ABuffer::initializeABuffer() { // ============================ auto shaderCallback = [this](ghoul::opengl::ProgramObject* program) { // Error for visibility in log - LERROR(program->name() << " invalidated"); _validShader = false; }; @@ -110,10 +105,17 @@ bool ABuffer::initializeABuffer() { return true; } +bool ABuffer::reinitialize() { + + // set the total resolution for all viewports + updateDimensions(); + return reinitializeInternal(); +} + void ABuffer::resolve() { if( ! _validShader) { SleepEx(0, TRUE); - //generateShaderSource(); + generateShaderSource(); updateShader(); _validShader = true; } @@ -184,7 +186,10 @@ bool ABuffer::updateShader() { for (int i = 0; i < _transferFunctions.size(); ++i) { _resolveShader->setUniform(_transferFunctions.at(i).first, startAt + i); } - LINFO("Successfully updated shader!"); + LINFO("Successfully updated ABuffer resolve shader!"); + } + else { + LWARNING("Couldn't update ABuffer resolve shader"); } return s; } @@ -215,7 +220,7 @@ void ABuffer::openspaceHeaders() { std::ofstream f(absPath(generatedHeadersPath)); f << "#define MAX_VOLUMES " << std::to_string(_samplers.size()) << "\n" - << "#define MAX_TF " << std::to_string(_transferFunctions.size()) << "\n"; + << "#define MAX_TF " << _transferFunctions.size() << "\n"; for (int i = 0; i < _volumes.size(); ++i) { f << "uniform sampler3D " << _volumes.at(i).first << ";\n"; } @@ -246,7 +251,7 @@ void ABuffer::openspaceHeaders() { } f << "};\n"; - f << "#define LOOP_LIMIT " + std::to_string(maxLoop) + "\n"; + f << "#define LOOP_LIMIT " << maxLoop << "\n"; f << "float volumeStepSize[] = {\n"; for (int i = 0; i < _volumes.size(); ++i) { @@ -272,11 +277,11 @@ void ABuffer::openspaceSamplerCalls() { auto found2 = _samplers.at(i).find_first_of("(", found1); if (found1 != std::string::npos && found2 != std::string::npos) { std::string functionName = _samplers.at(i).substr(found1, found2 - found1); - f << "#ifndef SKIP_VOLUME_" << std::to_string(i) << "\n" - << "if((currentVolumeBitmask & (1 << " << std::to_string(i) << ")) == " << std::to_string(1 << i) << ") {\n" - << " vec4 c = " << functionName << "(final_color,volume_position[" << std::to_string(i) << "]);\n" - << " blendStep(final_color, c, volumeStepSize[" << std::to_string(i) << "]);\n" - << " volume_position[" << std::to_string(i) << "] += volume_direction[" << std::to_string(i) << "]*volumeStepSize[" << std::to_string(i) << "];\n" + f << "#ifndef SKIP_VOLUME_" << i << "\n" + << "if((currentVolumeBitmask & (1 << " << i << ")) == " << std::to_string(1 << i) << ") {\n" + << " vec4 c = " << functionName << "(final_color,volume_position[" << i << "]);\n" + << " blendStep(final_color, c, volumeStepSize[" << i << "]);\n" + << " volume_position[" << i << "] += volume_direction[" << i << "]*volumeStepSize[" << i << "];\n" << "}\n" << "#endif\n"; } @@ -299,18 +304,18 @@ void ABuffer::openspaceTransferFunction() { << "float SCREEN_HEIGHTf = float(SCREEN_HEIGHT);\n" << "float SCREEN_WIDTHf = float(SCREEN_WIDTH);\n"; for (int i = 0; i < _transferFunctions.size(); ++i) { - f << "if( gl_FragCoord.y > SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i + 1) + f << "if( gl_FragCoord.y > SCREEN_HEIGHTf-showfunc_size*" << i + 1 << " && gl_FragCoord.y < SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i) << ") {\n" << " float normalizedIntensity = gl_FragCoord.x / (SCREEN_WIDTHf-1) ;\n" << " vec4 tfc = texture(" << _transferFunctions.at(i).first << ", normalizedIntensity);\n" << " final_color = tfc;\n" - << " float cmpf = SCREEN_HEIGHTf-showfunc_size*" << std::to_string(i + 1) << " + tfc.a*showfunc_size;\n" + << " float cmpf = SCREEN_HEIGHTf-showfunc_size*" << i + 1 << " + tfc.a*showfunc_size;\n" << " if(gl_FragCoord.y > cmpf) {\n" << " final_color = vec4(0,0,0,0);\n" << " } else {\n" << " final_color.a = 1.0;\n" << " }\n" - << "} else if(ceil(gl_FragCoord.y) == SCREEN_HEIGHTf - showfunc_size*" << std::to_string(i + 1) << ") {\n" + << "} else if(ceil(gl_FragCoord.y) == SCREEN_HEIGHTf - showfunc_size*" << i + 1 << ") {\n" << " const float intensity = 0.4;\n" << " final_color = vec4(intensity,intensity,intensity,1.0);\n" << "}\n"; @@ -323,5 +328,11 @@ void ABuffer::invalidateABuffer() { _validShader = false; } +void ABuffer::updateDimensions() { + _width = sgct::Engine::instance()->getActiveWindowPtr()->getXFramebufferResolution(); + _height = sgct::Engine::instance()->getActiveWindowPtr()->getYFramebufferResolution(); + _totalPixels = _width * _height; +} + } // openspace \ No newline at end of file diff --git a/src/abuffer/abufferSingleLinked.cpp b/src/abuffer/abufferSingleLinked.cpp index 37d96745c1..b671f35d3c 100644 --- a/src/abuffer/abufferSingleLinked.cpp +++ b/src/abuffer/abufferSingleLinked.cpp @@ -59,10 +59,22 @@ bool ABufferSingleLinked::initialize() { // BUFFERS // ============================ glGenTextures(1, &_anchorPointerTexture); + glGenBuffers(1, &_anchorPointerTextureInitializer); + glGenBuffers(1, &_atomicCounterBuffer); + glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, _atomicCounterBuffer); + glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_COPY); + glGenBuffers(1, &_fragmentBuffer); + glGenTextures(1, &_fragmentTexture); + + reinitialize(); + + return initializeABuffer(); +} + +bool ABufferSingleLinked::reinitializeInternal() { glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); - glGenBuffers(1, &_anchorPointerTextureInitializer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); glBufferData(GL_PIXEL_UNPACK_BUFFER, _totalPixels * sizeof(GLuint), NULL, GL_STATIC_DRAW); @@ -71,22 +83,16 @@ bool ABufferSingleLinked::initialize() { glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glGenBuffers(1, &_atomicCounterBuffer); - glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, _atomicCounterBuffer); - glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_COPY); - - glGenBuffers(1, &_fragmentBuffer); glBindBuffer(GL_TEXTURE_BUFFER, _fragmentBuffer); - glBufferData(GL_TEXTURE_BUFFER, MAX_LAYERS*_totalPixels*sizeof(GLfloat)*4, NULL, GL_DYNAMIC_COPY); + glBufferData(GL_TEXTURE_BUFFER, MAX_LAYERS*_totalPixels*sizeof(GLfloat) * 4, NULL, GL_DYNAMIC_COPY); - glGenTextures(1, &_fragmentTexture); - glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); - glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); - glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); - glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI); + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI); - return initializeABuffer(); + return true; } void ABufferSingleLinked::clear() { diff --git a/src/abuffer/abufferdynamic.cpp b/src/abuffer/abufferdynamic.cpp index 3ec7051f8e..695ac52c80 100644 --- a/src/abuffer/abufferdynamic.cpp +++ b/src/abuffer/abufferdynamic.cpp @@ -89,6 +89,10 @@ bool ABufferDynamic::initialize() { return initializeABuffer(); } +bool ABufferDynamic::reinitializeInternal() { + return false; +} + void ABufferDynamic::clear() { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); diff --git a/src/abuffer/abufferfixed.cpp b/src/abuffer/abufferfixed.cpp index 4f1693a269..008582cb5c 100644 --- a/src/abuffer/abufferfixed.cpp +++ b/src/abuffer/abufferfixed.cpp @@ -97,6 +97,10 @@ bool ABufferFixed::initialize() { return initializeABuffer(); } +bool ABufferFixed::reinitializeInternal() { + return false; +} + void ABufferFixed::clear() { // Bind texture initializer diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 8fab61aa09..db61ae4c0b 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -185,15 +185,17 @@ bool RenderEngine::initializeGL() void RenderEngine::postSynchronizationPreDraw() { sgct_core::SGCTNode * thisNode = sgct_core::ClusterManager::instance()->getThisNodePtr(); - for (unsigned int i = 0; i < thisNode->getNumberOfWindows(); i++) - if (sgct::Engine::instance()->getWindowPtr(i)->isWindowResized()) - generateGlslConfig(); - // Move time forward. - //_runtimeData->advanceTimeBy(1, DAY); - - //_runtimeData->advanceTimeBy(1, HOUR); - //_runtimeData->advanceTimeBy(30, MINUTE); - //_runtimeData->advanceTimeBy(1, MILLISECOND); + bool updateAbuffer = false; + for (unsigned int i = 0; i < thisNode->getNumberOfWindows(); i++) { + if (sgct::Engine::instance()->getWindowPtr(i)->isWindowResized()) { + updateAbuffer = true; + break; + } + } + if (updateAbuffer) { + generateGlslConfig(); + _abuffer->reinitialize(); + } // converts the quaternion used to rotation matrices _mainCamera->compileViewRotationMatrix(); @@ -202,13 +204,13 @@ void RenderEngine::postSynchronizationPreDraw() _sceneGraph->update({Time::ref().currentTime()}); _mainCamera->setCameraDirection(glm::vec3(0, 0, -1)); _sceneGraph->evaluate(_mainCamera); + + _abuffer->clear(); } void RenderEngine::render() { // SGCT resets certain settings - //glEnable(GL_DEPTH_TEST); - //glEnable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -232,7 +234,6 @@ void RenderEngine::render() // render the scene starting from the root node - _abuffer->clear(); _abuffer->preRender(); _sceneGraph->render({*_mainCamera, psc()}); _abuffer->postRender(); @@ -504,10 +505,8 @@ ABuffer* RenderEngine::abuffer() const { void RenderEngine::generateGlslConfig() { LDEBUG("Generating GLSLS config, expect shader recompilation"); - int x1, xSize, y1, ySize; - sgct::Engine::instance()-> - getActiveWindowPtr()-> - getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + int xSize = sgct::Engine::instance()->getActiveWindowPtr()->getXFramebufferResolution();; + int ySize = sgct::Engine::instance()->getActiveWindowPtr()->getYFramebufferResolution();; // TODO: Make this file creation dynamic and better in every way // TODO: If the screen size changes it is enough if this file is regenerated to From dbef0d36e4c3f756ec2f3e0d124f5ac02be5320a Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Mon, 20 Oct 2014 15:58:37 +0200 Subject: [PATCH 10/17] Initial command input support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Access the command input prompt with the § button on swedish keyboard layout. It is whatever key is corresponding to SGCT_KEY_BACKSLASH on other layouts. --- include/openspace/engine/openspaceengine.h | 13 +- scripts/default_startup.lua | 2 +- src/engine/openspaceengine.cpp | 237 ++++++++++++++++++++- src/interaction/interactionhandler.cpp | 2 +- src/main.cpp | 12 +- src/rendering/renderengine.cpp | 11 +- 6 files changed, 261 insertions(+), 16 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 4973bb4606..cb90bd29ae 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -81,8 +81,9 @@ public: void preSynchronization(); void postSynchronizationPreDraw(); void render(); - void postDraw(); - void keyboardCallback(int key, int action); + void postDraw(); + void keyboardCallback(int key, int action); + void charCallback(unsigned int codepoint); void mouseButtonCallback(int key, int action); void mousePositionCallback(int x, int y); void mouseScrollWheelCallback(int pos); @@ -114,6 +115,14 @@ private: ghoul::opencl::CLContext _context; sgct::SharedVector _synchronizationBuffer; + + bool _inputCommand; + size_t _inputPosition; + std::string _activeCommand; + + void renderActiveCommand(); + void handleCommandInput(int key, int action); + void addToCommand(std::string c); }; #define OsEng (openspace::OpenSpaceEngine::ref()) diff --git a/scripts/default_startup.lua b/scripts/default_startup.lua index 84024e2267..5509eb36c2 100644 --- a/scripts/default_startup.lua +++ b/scripts/default_startup.lua @@ -3,6 +3,6 @@ openspace.time.setTime("2007-02-26T12:00:00") --openspace.time.setTime("2006-08-22T20:00:00") --openspace.time.setDeltaTime(200000.0) -openspace.time.setDeltaTime(2000.0) +openspace.time.setDeltaTime(0.0) --openspace.time.setDeltaTime(30000.0) -- print(openspace.time.currentTimeUTC()) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 2bf45020bf..ad1f732bb7 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -58,6 +58,67 @@ namespace { struct { std::string configurationName; } commandlineArgumentPlaceholders; + + // TODO: Put this functio nsomewhere appropriate + // get text from clipboard + std::string getClipboardText() + { +#ifdef WIN32 + // Try opening the clipboard + if (!OpenClipboard(nullptr)) + return ""; + + // Get handle of clipboard object for ANSI text + HANDLE hData = GetClipboardData(CF_TEXT); + if (hData == nullptr) + return ""; + + // Lock the handle to get the actual text pointer + char * pszText = static_cast(GlobalLock(hData)); + if (pszText == nullptr) + return ""; + + // Save text in a string class instance + std::string text(pszText); + + // Release the lock + GlobalUnlock(hData); + + // Release the clipboard + CloseClipboard(); + + text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); + return text; +#else + return ""; +#endif + } + + std::string UnicodeToUTF8(unsigned int codepoint){ + std::string out; + + if (codepoint <= 0x7f) + out.append(1, static_cast(codepoint)); + else if (codepoint <= 0x7ff) + { + out.append(1, static_cast(0xc0 | ((codepoint >> 6) & 0x1f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else if (codepoint <= 0xffff) + { + out.append(1, static_cast(0xe0 | ((codepoint >> 12) & 0x0f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else + { + out.append(1, static_cast(0xf0 | ((codepoint >> 18) & 0x07))); + out.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + return out; + } } using namespace ghoul::cmdparser; @@ -68,6 +129,9 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName) : _commandlineParser(programName, true) + , _inputCommand(false) + , _inputPosition(0) + , _activeCommand("") { } @@ -331,9 +395,15 @@ bool OpenSpaceEngine::initialize() { } // Load a light and a monospaced font - sgct_text::FontManager::instance()->setDefaultFontPath(absPath("${FONTS}/")); - sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, "ubuntu-font-family/UbuntuMono-R.ttf"); - sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, "ubuntu-font-family/Ubuntu-L.ttf"); + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, "ubuntu-font-family/UbuntuMono-R.ttf", absPath("${FONTS}/")); + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, "ubuntu-font-family/Ubuntu-L.ttf", absPath("${FONTS}/")); + sgct_text::FontManager::FontPath local = sgct_text::FontManager::FontPath::FontPath_Local; + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/adobe-source-code-pro/SourceCodePro-Regular.ttf"), local); + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/monaco.ttf"), local); + sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf"), local); + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/adobe-source-sans-pro/SourceSansPro-Regular.ttf"), local); + //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/Roboto_Slab/RobotoSlab-Regular.ttf"), local); + sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/Roboto/Roboto-Regular.ttf"), local); return true; } @@ -383,6 +453,45 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { void OpenSpaceEngine::render() { _renderEngine.render(); + + // If currently writing a command, render it to screen + sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr(); + if (sgct::Engine::instance()->isMaster() && !w->isUsingFisheyeRendering() && _inputCommand) { + renderActiveCommand(); + } +} + +void OpenSpaceEngine::renderActiveCommand() { + const int font_size = 12; + const int font_with = font_size*0.7; + const glm::vec4 red(1, 0, 0, 1); + const glm::vec4 green(0, 1, 0, 1); + const glm::vec4 white(1, 1, 1, 1); + const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); + Freetype::print(font, 10, 400, red, "$"); + Freetype::print(font, 10 + font_size, 400, white, "%s", _activeCommand.c_str()); + + size_t n = std::count(_activeCommand.begin(), _activeCommand.begin() + _inputPosition, '\n'); + size_t p = _activeCommand.find_last_of('\n', _inputPosition); + size_t linepos = _inputPosition; + + if (n>0) { + if (p == _inputPosition) { + p = _activeCommand.find_last_of('\n', _inputPosition - 1); + if (p != std::string::npos) { + linepos -= p + 1; + } + else { + linepos = _inputPosition - 1; + } + } + else{ + linepos -= p + 1; + } + } + char buffer[10]; + sprintf(buffer, "%%%is", linepos + 1); + Freetype::print(font, 10 + static_cast(font_size)*0.5, 400 - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); } void OpenSpaceEngine::postDraw() { @@ -390,9 +499,127 @@ void OpenSpaceEngine::postDraw() { _interactionHandler.unlockControls(); } +void OpenSpaceEngine::addToCommand(std::string c) { + size_t length = c.length(); + _activeCommand.insert(_inputPosition, c); + _inputPosition += length; +} + void OpenSpaceEngine::keyboardCallback(int key, int action) { - if (sgct::Engine::instance()->isMaster()) - _interactionHandler.keyboardCallback(key, action); + if (sgct::Engine::instance()->isMaster()) { + + if (key == SGCT_KEY_BACKSLASH && (action == SGCT_PRESS || action == SGCT_REPEAT)) { + _inputCommand = !_inputCommand; + } + + if (!_inputCommand) { + _interactionHandler.keyboardCallback(key, action); + } + else { + handleCommandInput(key, action); + } + } +} + +void OpenSpaceEngine::handleCommandInput(int key, int action) { + if (action == SGCT_PRESS || action == SGCT_REPEAT) { + const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); + const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); + const bool mod_SHIFT = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_SHIFT) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_SHIFT); + + // Paste from clipboard + if (key == SGCT_KEY_V) { + if (mod_CONTROL) { + addToCommand(getClipboardText()); + } + } + + // Go to the previous character + if (key == SGCT_KEY_LEFT) { + if (_inputPosition > 0) + _inputPosition -= 1; + } + + // Go to the next character + if (key == SGCT_KEY_RIGHT) { + if (_inputPosition < _activeCommand.length()) + ++_inputPosition; + } + + // Go to ending of previous line + if (key == SGCT_KEY_UP) { + if (_inputPosition > 0) { + size_t p = _activeCommand.find_last_of('\n', _inputPosition - 1); + if (p != std::string::npos) + _inputPosition = p; + else + _inputPosition = 0; + } + } + + // Go to ending of line (or end of next line) + if (key == SGCT_KEY_DOWN) { + size_t p = _activeCommand.find_first_of('\n', _inputPosition + 1); + if (p != std::string::npos) + _inputPosition = p; + else + _inputPosition = _activeCommand.size(); + } + + // Remove character before _inputPosition + if (key == SGCT_KEY_BACKSPACE) { + if (_inputPosition > 0) { + _activeCommand.erase(_inputPosition - 1, 1); + --_inputPosition; + } + } + + // Remove character after _inputPosition + if (key == SGCT_KEY_DELETE) { + if (_inputPosition <= _activeCommand.size()) { + _activeCommand.erase(_inputPosition, 1); + } + } + + // Go to the beginning of command string + if (key == SGCT_KEY_HOME) { + _inputPosition = 0; + } + + // Go to the end of command string + if (key == SGCT_KEY_END) { + _inputPosition = _activeCommand.size(); + } + + if (key == SGCT_KEY_ENTER) { + + // SHIFT+ENTER == new line + if (mod_SHIFT) { + addToCommand("\n"); + } + // CTRL+ENTER == Debug print the command + else if (mod_CONTROL) { + LDEBUG("Active command from next line:\n" <<_activeCommand); + } + // ENTER == run lua script + else { + _scriptEngine.runScript(_activeCommand); + _activeCommand = ""; + _inputPosition = 0; + _inputCommand = false; + } + } + } +} + +void OpenSpaceEngine::charCallback(unsigned int codepoint) { + + // SGCT_KEY_BACKSLASH == 92 but that corresponds to codepoint 167 + if (_inputCommand && codepoint != 167) { + addToCommand(UnicodeToUTF8(codepoint)); + } } void OpenSpaceEngine::mouseButtonCallback(int key, int action) { diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 433e03b297..8afd384e56 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -313,7 +313,7 @@ void InteractionHandler::keyboardCallback(int key, int action) { // TODO package in script const double speed = 2.75; const double dt = getDt(); - if(action == SGCT_PRESS || action == SGCT_REPEAT) { + if (action == SGCT_PRESS || action == SGCT_REPEAT) { if (key == SGCT_KEY_S) { glm::vec3 euler(speed * dt, 0.0, 0.0); glm::quat rot = glm::quat(euler); diff --git a/src/main.cpp b/src/main.cpp index 0fcf03cb55..159e54ff50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,6 +37,7 @@ void mainPostSyncPreDrawFunc(); void mainRenderFunc(); void mainPostDrawFunc(); void mainKeyboardCallback(int key, int action); +void mainCharCallback(unsigned int codepoint); void mainMouseButtonCallback(int key, int action); void mainMousePosCallback(double x, double y); void mainMouseScrollCallback(double posX, double posY); @@ -77,8 +78,9 @@ int main(int argc, char** argv) _sgctEngine->setKeyboardCallbackFunction(mainKeyboardCallback); _sgctEngine->setMouseButtonCallbackFunction(mainMouseButtonCallback); _sgctEngine->setMousePosCallbackFunction(mainMousePosCallback); - _sgctEngine->setMouseScrollCallbackFunction(mainMouseScrollCallback); - _sgctEngine->setExternalControlCallback(mainExternalControlCallback); + _sgctEngine->setMouseScrollCallbackFunction(mainMouseScrollCallback); + _sgctEngine->setExternalControlCallback(mainExternalControlCallback); + _sgctEngine->setCharCallbackFunction(mainCharCallback); // set encode and decode functions // NOTE: starts synchronizing before init functions @@ -177,6 +179,12 @@ void mainMouseScrollCallback(double posX, double posY) OsEng.mouseScrollWheelCallback(static_cast(posY)); } +void mainCharCallback(unsigned int codepoint) { + + if (_sgctEngine->isMaster()) + OsEng.charCallback(codepoint); +} + void mainEncodeFun() { OsEng.encode(); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 0343ac84fc..a10546ed5a 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -300,11 +300,12 @@ void RenderEngine::render() const sgct_text::Font* font = fontLight; const int max = 10; const int category_length = 20; - const int msg_length = 120; - const double ttl = 10.0; + const int msg_length = 140; + const double ttl = 15.0; + const double fade = 5.0; auto entries = _log->last(max); - const glm::vec4 white(1, 1, 1, 1); + const glm::vec4 white(0.9, 0.9, 0.9, 1); const glm::vec4 red(1, 0, 0, 1); const glm::vec4 yellow(1, 1, 0, 1); const glm::vec4 green(0, 1, 0, 1); @@ -322,10 +323,10 @@ void RenderEngine::render() break; float alpha = 1; - float ttf = ttl - 5.0; + float ttf = ttl - fade; if (diff > ttf) { diff = diff - ttf; - float p = 0.8 - diff / ttf; + float p = 0.8 - diff / fade; alpha = (p <= 0.0) ? 0.0 : pow(p, 0.3); } From 5cd90db2396f1c35f2bc7a75819e9f4f928756c8 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Mon, 20 Oct 2014 17:12:53 +0200 Subject: [PATCH 11/17] Added seconds version of the command input - Using unix terminal style input history - ctrl+c support to copy current command to clipboard - ctrl+v support to paste current text from clipboard --- include/openspace/engine/openspaceengine.h | 4 +- openspace-data | 2 +- src/engine/openspaceengine.cpp | 115 ++++++++++++++------- src/rendering/renderengine.cpp | 19 ++-- 4 files changed, 93 insertions(+), 47 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index cb90bd29ae..d5b8e699ba 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -118,7 +118,9 @@ private: bool _inputCommand; size_t _inputPosition; - std::string _activeCommand; + std::vector _commandsHistory; + size_t _activeCommand; + std::vector _commands; void renderActiveCommand(); void handleCommandInput(int key, int action); diff --git a/openspace-data b/openspace-data index d415918525..c874620736 160000 --- a/openspace-data +++ b/openspace-data @@ -1 +1 @@ -Subproject commit d415918525c1ec8ca4486d520bb01844e97ce4b6 +Subproject commit c874620736f7c900a282c565592f7cef2f9fe2e1 diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index ad1f732bb7..92f4481cf2 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -94,6 +94,35 @@ namespace { #endif } + // TODO: Put this function somewhere appropriate + // set text to clipboard + bool setClipboardText(std::string text) + { +#ifdef WIN32 + char *ptrData = nullptr; + HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, text.length() + 1); + + ptrData = (char*)GlobalLock(hData); + memcpy(ptrData, text.c_str(), text.length() + 1); + + GlobalUnlock(hData); + + if (!OpenClipboard(nullptr)) + return false; + + if (!EmptyClipboard()) + return false; + + SetClipboardData(CF_TEXT, hData); + + CloseClipboard(); + + return true; +#else + return false; +#endif + } + std::string UnicodeToUTF8(unsigned int codepoint){ std::string out; @@ -131,7 +160,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName) : _commandlineParser(programName, true) , _inputCommand(false) , _inputPosition(0) - , _activeCommand("") + , _activeCommand(0) + , _commands({""}) { } @@ -398,11 +428,7 @@ bool OpenSpaceEngine::initialize() { //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, "ubuntu-font-family/UbuntuMono-R.ttf", absPath("${FONTS}/")); //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, "ubuntu-font-family/Ubuntu-L.ttf", absPath("${FONTS}/")); sgct_text::FontManager::FontPath local = sgct_text::FontManager::FontPath::FontPath_Local; - //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/adobe-source-code-pro/SourceCodePro-Regular.ttf"), local); - //sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/monaco.ttf"), local); sgct_text::FontManager::instance()->addFont(constants::fonts::keyMono, absPath("${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf"), local); - //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/adobe-source-sans-pro/SourceSansPro-Regular.ttf"), local); - //sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/Roboto_Slab/RobotoSlab-Regular.ttf"), local); sgct_text::FontManager::instance()->addFont(constants::fonts::keyLight, absPath("${FONTS}/Roboto/Roboto-Regular.ttf"), local); return true; @@ -462,22 +488,28 @@ void OpenSpaceEngine::render() { } void OpenSpaceEngine::renderActiveCommand() { - const int font_size = 12; + + const int font_size = 10; + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + int startY = ySize - 2 * font_size; + startY = startY - font_size * 10 * 2; + const int font_with = font_size*0.7; const glm::vec4 red(1, 0, 0, 1); const glm::vec4 green(0, 1, 0, 1); const glm::vec4 white(1, 1, 1, 1); const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); - Freetype::print(font, 10, 400, red, "$"); - Freetype::print(font, 10 + font_size, 400, white, "%s", _activeCommand.c_str()); + Freetype::print(font, 10, startY, red, "$"); + Freetype::print(font, 10 + font_size, startY, white, "%s", _commands.at(_activeCommand).c_str()); - size_t n = std::count(_activeCommand.begin(), _activeCommand.begin() + _inputPosition, '\n'); - size_t p = _activeCommand.find_last_of('\n', _inputPosition); + size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n'); + size_t p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition); size_t linepos = _inputPosition; if (n>0) { if (p == _inputPosition) { - p = _activeCommand.find_last_of('\n', _inputPosition - 1); + p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition - 1); if (p != std::string::npos) { linepos -= p + 1; } @@ -491,7 +523,7 @@ void OpenSpaceEngine::renderActiveCommand() { } char buffer[10]; sprintf(buffer, "%%%is", linepos + 1); - Freetype::print(font, 10 + static_cast(font_size)*0.5, 400 - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); + Freetype::print(font, 10 + static_cast(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); } void OpenSpaceEngine::postDraw() { @@ -501,7 +533,7 @@ void OpenSpaceEngine::postDraw() { void OpenSpaceEngine::addToCommand(std::string c) { size_t length = c.length(); - _activeCommand.insert(_inputPosition, c); + _commands.at(_activeCommand).insert(_inputPosition, c); _inputPosition += length; } @@ -536,6 +568,13 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { } } + // Copy to clipboard + if (key == SGCT_KEY_C) { + if (mod_CONTROL) { + setClipboardText(_commands.at(_activeCommand)); + } + } + // Go to the previous character if (key == SGCT_KEY_LEFT) { if (_inputPosition > 0) @@ -544,42 +583,36 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { // Go to the next character if (key == SGCT_KEY_RIGHT) { - if (_inputPosition < _activeCommand.length()) + if (_inputPosition < _commands.at(_activeCommand).length()) ++_inputPosition; } - // Go to ending of previous line + // Go to previous command if (key == SGCT_KEY_UP) { - if (_inputPosition > 0) { - size_t p = _activeCommand.find_last_of('\n', _inputPosition - 1); - if (p != std::string::npos) - _inputPosition = p; - else - _inputPosition = 0; - } + if (_activeCommand > 0) + --_activeCommand; + _inputPosition = _commands.at(_activeCommand).length(); } - // Go to ending of line (or end of next line) + // Go to next command (the last is empty) if (key == SGCT_KEY_DOWN) { - size_t p = _activeCommand.find_first_of('\n', _inputPosition + 1); - if (p != std::string::npos) - _inputPosition = p; - else - _inputPosition = _activeCommand.size(); + if (_activeCommand < _commands.size()-1) + ++_activeCommand; + _inputPosition = _commands.at(_activeCommand).length(); } // Remove character before _inputPosition if (key == SGCT_KEY_BACKSPACE) { if (_inputPosition > 0) { - _activeCommand.erase(_inputPosition - 1, 1); + _commands.at(_activeCommand).erase(_inputPosition - 1, 1); --_inputPosition; } } // Remove character after _inputPosition if (key == SGCT_KEY_DELETE) { - if (_inputPosition <= _activeCommand.size()) { - _activeCommand.erase(_inputPosition, 1); + if (_inputPosition <= _commands.at(_activeCommand).size()) { + _commands.at(_activeCommand).erase(_inputPosition, 1); } } @@ -590,7 +623,7 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { // Go to the end of command string if (key == SGCT_KEY_END) { - _inputPosition = _activeCommand.size(); + _inputPosition = _commands.at(_activeCommand).size(); } if (key == SGCT_KEY_ENTER) { @@ -605,10 +638,20 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { } // ENTER == run lua script else { - _scriptEngine.runScript(_activeCommand); - _activeCommand = ""; - _inputPosition = 0; - _inputCommand = false; + if (_commands.at(_activeCommand) != "") { + + _scriptEngine.runScript(_commands.at(_activeCommand)); + _commandsHistory.push_back(_commands.at(_activeCommand)); + _commands = _commandsHistory; + _commands.push_back(""); + _activeCommand = _commands.size() - 1; + _inputPosition = 0; + } + else { + _commands = _commandsHistory; + _commands.push_back(""); + _inputCommand = false; + } } } } diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index a10546ed5a..d3482c2c08 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -263,16 +263,17 @@ void RenderEngine::render() if (sgct::Engine::instance()->isMaster() && ! w->isUsingFisheyeRendering()) { // TODO: Adjust font_size properly when using retina screen - const int font_size = 8; - const int font_with = font_size*0.7; - const sgct_text::Font* fontLight = sgct_text::FontManager::instance()->getFont(constants::fonts::keyLight, font_size); - const sgct_text::Font* fontMono = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); + const int font_size_mono = 10; + const int font_size_light = 8; + const int font_with_light = font_size_light*0.7; + const sgct_text::Font* fontLight = sgct_text::FontManager::instance()->getFont(constants::fonts::keyLight, font_size_light); + const sgct_text::Font* fontMono = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size_mono); if (_showInfo) { const sgct_text::Font* font = fontMono; int x1, xSize, y1, ySize; sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); - int startY = ySize - 2 * font_size; + int startY = ySize - 2 * font_size_mono; const glm::vec2 scaling = _mainCamera->scaling(); const glm::vec3 viewdirection = _mainCamera->viewDirection(); const psc position = _mainCamera->position(); @@ -281,7 +282,7 @@ void RenderEngine::render() // GUI PRINT // Using a macro to shorten line length and increase readability -#define PrintText(i, format, ...) Freetype::print(font, 10, startY - font_size * i * 2, format, __VA_ARGS__); +#define PrintText(i, format, ...) Freetype::print(font, 10, startY - font_size_mono * i * 2, format, __VA_ARGS__); int i = 0; PrintText(i++, "Date: %s", Time::ref().currentTimeUTC().c_str()); PrintText(i++, "Avg. Frametime: %.5f", sgct::Engine::instance()->getAvgDt()); @@ -335,7 +336,7 @@ void RenderEngine::render() break; std::string lvl = "(" + ghoul::logging::LogManager::stringFromLevel(e->level) + ")"; - Freetype::print(font, 10, font_size * nr * 2, white*alpha, + Freetype::print(font, 10, font_size_light * nr * 2, white*alpha, "%-14s %s%s", // Format e->timeString.c_str(), // Time string e->category.substr(0, category_length).c_str(), // Category string (up to category_length) @@ -351,8 +352,8 @@ void RenderEngine::render() if (e->level == ghoul::logging::LogManager::LogLevel::Fatal) color = blue; - Freetype::print(font, 10 + 39 * font_with, font_size * nr * 2, color*alpha, "%s", lvl.c_str()); - Freetype::print(font, 10 + 53 * font_with, font_size * nr * 2, white*alpha, "%s", e->message.substr(0, msg_length).c_str()); + Freetype::print(font, 10 + 39 * font_with_light, font_size_light * nr * 2, color*alpha, "%s", lvl.c_str()); + Freetype::print(font, 10 + 53 * font_with_light, font_size_light * nr * 2, white*alpha, "%s", e->message.substr(0, msg_length).c_str()); ++nr; } } From 3f72adc854b3fef99a0ebc7417b731c97b22c773 Mon Sep 17 00:00:00 2001 From: jonasstrandstedt Date: Mon, 20 Oct 2014 22:13:59 +0200 Subject: [PATCH 12/17] Added copy/paste for Linux - Requires xclip installed (otherwise nothing happens) --- src/engine/openspaceengine.cpp | 60 ++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 92f4481cf2..baec9a7ef0 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -54,6 +54,35 @@ namespace { const std::string _sgctDefaultConfigFile = "${SGCT}/single.xml"; const std::string _sgctConfigArgumentCommand = "-config"; + +#ifdef WIN32 + const unsigned int CommandInputButton = SGCT_KEY_BACKSLASH; // Button left of 1 and abobe TAB + const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint +#else + const unsigned int CommandInputButton = SGCT_KEY_GRAVE_ACCENT; // Button left of 1 and abobe TAB + const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint + + // Dangerus as fuck + bool exec(const std::string& cmd, std::string& value) + { + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) + return false; + + const int buffer_size = 1024; + char buffer[buffer_size]; + value = ""; + while(!feof(pipe)) + { + if(fgets(buffer, buffer_size, pipe) != NULL) + { + value += buffer; + } + } + pclose(pipe); + return true; + } +#endif struct { std::string configurationName; @@ -90,7 +119,11 @@ namespace { text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); return text; #else - return ""; + std::string text; + if(exec("xclip -o -sel c -f", text)) + return text.substr(0, text.length()-1); + return ""; // remove a line ending + #endif } @@ -119,7 +152,10 @@ namespace { return true; #else - return false; + std::stringstream cmd; + cmd << "echo \"" << text << "\" | xclip -i -sel c -f"; + std::string buf; + return exec(cmd.str(), buf); #endif } @@ -522,7 +558,7 @@ void OpenSpaceEngine::renderActiveCommand() { } } char buffer[10]; - sprintf(buffer, "%%%is", linepos + 1); + sprintf(buffer, "%%%lus", linepos + 1); Freetype::print(font, 10 + static_cast(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); } @@ -540,7 +576,7 @@ void OpenSpaceEngine::addToCommand(std::string c) { void OpenSpaceEngine::keyboardCallback(int key, int action) { if (sgct::Engine::instance()->isMaster()) { - if (key == SGCT_KEY_BACKSLASH && (action == SGCT_PRESS || action == SGCT_REPEAT)) { + if (key == CommandInputButton && (action == SGCT_PRESS || action == SGCT_REPEAT)) { _inputCommand = !_inputCommand; } @@ -634,7 +670,7 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { } // CTRL+ENTER == Debug print the command else if (mod_CONTROL) { - LDEBUG("Active command from next line:\n" <<_activeCommand); + LDEBUG("Active command from next line:\n" << _commands.at(_activeCommand)); } // ENTER == run lua script else { @@ -660,7 +696,19 @@ void OpenSpaceEngine::handleCommandInput(int key, int action) { void OpenSpaceEngine::charCallback(unsigned int codepoint) { // SGCT_KEY_BACKSLASH == 92 but that corresponds to codepoint 167 - if (_inputCommand && codepoint != 167) { + if (_inputCommand && codepoint != IgnoreCodepoint) { + +#ifndef WIN32 + const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); + const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); + + const int codepoint_C = 99; + const int codepoint_V = 118; + if(mod_CONTROL && (codepoint == codepoint_C || codepoint == codepoint_V)) { + return; + } +#endif addToCommand(UnicodeToUTF8(codepoint)); } } From 0e52e759dbbe82886b8df526f6ddd01cf1106f43 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Tue, 21 Oct 2014 17:04:58 +0200 Subject: [PATCH 13/17] Improved interaction for distance and origin --- .../interaction/interactionhandler.h | 13 ++- src/engine/openspaceengine.cpp | 1 + src/interaction/interactionhandler.cpp | 96 ++++++++++++++++--- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index 80b867dd91..f27a20604c 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -36,6 +36,8 @@ public: void addExternalControl(ExternalControl* controller); void setCamera(Camera *camera = nullptr); + void setOrigin(SceneGraphNode* node); + Camera * getCamera() const; const psc getOrigin() const; void lockControls(); @@ -45,7 +47,7 @@ public: void orbit(const glm::quat &rotation); void rotate(const glm::quat &rotation); - void distance(const PowerScaledScalar &distance); + void distance(const PowerScaledScalar &distance, size_t iterations = 0); void lookAt(const glm::quat &rotation); void setRotation(const glm::quat &rotation); @@ -60,6 +62,15 @@ public: void mouseScrollWheelCallback(int pos); void addKeyCallback(int key, std::function f); + + /** + * Returns the Lua library that contains all Lua functions available to affect the + * interaction. The functions contained are + * - openspace::luascriptfunctions::printScreen + * \return The Lua library that contains all Lua functions available to affect the + * interaction + */ + static scripting::ScriptEngine::LuaLibrary luaLibrary(); private: glm::vec3 mapToTrackball(glm::vec2 mousePos); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 8ceb40ad30..09296ef4bd 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -438,6 +438,7 @@ bool OpenSpaceEngine::initialize() { scriptEngine().addLibrary(RenderEngine::luaLibrary()); scriptEngine().addLibrary(SceneGraph::luaLibrary()); scriptEngine().addLibrary(Time::luaLibrary()); + scriptEngine().addLibrary(InteractionHandler::luaLibrary()); // Load scenegraph SceneGraph* sceneGraph = new SceneGraph; diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 34c76e232b..8da7b42048 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -19,6 +19,40 @@ std::string _loggerCat = "InteractionHandler"; namespace openspace { +namespace luascriptfunctions { + +/** + * \ingroup LuaScripts + * setOrigin(): + * Set the origin of the camera + */ +int setOrigin(lua_State* L) { + using ghoul::lua::luaTypeToString; + const std::string _loggerCat = "LuaInteractionHandler"; + + int nArguments = lua_gettop(L); + if (nArguments != 1) + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + + const int type = lua_type(L, -1); + if (type != LUA_TSTRING) + return luaL_error(L, "Expected string, got %i", type); + + std::string s = luaL_checkstring(L, -1); + + SceneGraphNode* node = sceneGraphNode(s); + if (!node) { + LWARNING("Could not find a node in scenegraph called '" << s <<"'"); + return 0; + } + + OsEng.interactionHandler().setOrigin(node); + + return 0; +} + +} // namespace luascriptfunctions + InteractionHandler::InteractionHandler() { // initiate pointers camera_ = nullptr; @@ -111,6 +145,11 @@ void InteractionHandler::setCamera(Camera *camera) { camera_ = camera; } +void InteractionHandler::setOrigin(SceneGraphNode* node) { + if (node) + node_ = node; +} + Camera * InteractionHandler::getCamera() const { //assert(this_); if (enabled_) { @@ -177,7 +216,9 @@ void InteractionHandler::orbit(const glm::quat &rotation) { unlockControls(); } -void InteractionHandler::distance(const PowerScaledScalar &distance) { +void InteractionHandler::distance(const PowerScaledScalar &dist, size_t iterations) { + if (iterations > 5) + return; //assert(this_); lockControls(); @@ -186,19 +227,28 @@ void InteractionHandler::distance(const PowerScaledScalar &distance) { psc relative_origin_coordinate = relative - origin; const glm::vec3 dir(relative_origin_coordinate.direction()); - glm:: vec3 newdir = dir * distance[0]; + glm::vec3 newdir = dir * dist[0]; relative_origin_coordinate = newdir; - relative_origin_coordinate[3] = distance[1]; + relative_origin_coordinate[3] = dist[1]; relative = relative + relative_origin_coordinate; relative_origin_coordinate = relative - origin; newdir = relative_origin_coordinate.direction(); // update only if on the same side of the origin - if(glm::angle(newdir, dir) < 90.0f) + if (glm::angle(newdir, dir) < 90.0f) { camera_->setPosition(relative); + unlockControls(); + + } + else { + unlockControls(); + PowerScaledScalar d2 = dist; + d2[0] *= 0.75; + d2[1] *= 0.85; + distance(d2, iterations + 1); + } - unlockControls(); } void InteractionHandler::lookAt(const glm::quat &rotation) { @@ -307,7 +357,6 @@ void InteractionHandler::trackballRotate(int x, int y) { _lastTrackballPos = curTrackballPos; } } -double acc = 1; void InteractionHandler::keyboardCallback(int key, int action) { // TODO package in script @@ -358,28 +407,35 @@ void InteractionHandler::keyboardCallback(int key, int action) { rotate(rot); } if (key == SGCT_KEY_R) { - PowerScaledScalar dist(-speed * dt, 0.0); + PowerScaledScalar dist(-speed * dt, 5.0); distance(dist); } if (key == SGCT_KEY_F) { - PowerScaledScalar dist(speed * dt, 0.0); + PowerScaledScalar dist(speed * dt, 5.0); distance(dist); } if (key == SGCT_KEY_T) { - PowerScaledScalar dist(-speed * pow(10, 11) * dt, 0.0); + PowerScaledScalar dist(-speed * dt, 10.0); distance(dist); } if (key == SGCT_KEY_G) { - acc += 0.001; - PowerScaledScalar dist(speed * pow(10, 8 * acc) * dt, 0.0); + PowerScaledScalar dist(speed * dt, 10.0); distance(dist); } if (key == SGCT_KEY_Y) { - PowerScaledScalar dist(-speed * 100.0 * dt, 6.0); + PowerScaledScalar dist(-speed * dt, 11.5); distance(dist); } if (key == SGCT_KEY_H) { - PowerScaledScalar dist(speed * 100.0 * dt, 6.0); + PowerScaledScalar dist(speed * dt, 11.5); + distance(dist); + } + if (key == SGCT_KEY_U) { + PowerScaledScalar dist(-speed * dt, 13.0); + distance(dist); + } + if (key == SGCT_KEY_J) { + PowerScaledScalar dist(speed * dt, 13.0); distance(dist); } @@ -479,4 +535,18 @@ void InteractionHandler::addKeyCallback(int key, std::function f) { _keyCallbacks.insert(std::make_pair(key, f)); } +scripting::ScriptEngine::LuaLibrary InteractionHandler::luaLibrary() { + return{ + "", + { + { + "setOrigin", + &luascriptfunctions::setOrigin, + "setOrigin(): set the camera origin node by name" + } + } + }; + +} + } // namespace openspace From 490fbc4869e9ace2c13a8c52f557b0e0b79eb9cd Mon Sep 17 00:00:00 2001 From: jonasstrandstedt Date: Tue, 21 Oct 2014 21:44:29 +0200 Subject: [PATCH 14/17] Linux fix --- ext/ghoul | 2 +- include/openspace/rendering/renderablewavefrontobject.h | 4 ++-- src/abuffer/abuffer.cpp | 1 - src/engine/openspaceengine.cpp | 3 ++- src/rendering/renderablewavefrontobject.cpp | 8 ++++++++ src/rendering/stars/renderablestars.cpp | 4 ++++ 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 999399a275..68c53264aa 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 999399a27548c4adf5267d1569af4edb5f794658 +Subproject commit 68c53264aaf05e1fc9526a857ac38db2d620557e diff --git a/include/openspace/rendering/renderablewavefrontobject.h b/include/openspace/rendering/renderablewavefrontobject.h index c0370d1a25..4785c18451 100644 --- a/include/openspace/rendering/renderablewavefrontobject.h +++ b/include/openspace/rendering/renderablewavefrontobject.h @@ -78,8 +78,8 @@ private: GLenum _mode; unsigned int _isize; unsigned int _vsize; - Vertex *_varray; - int *_iarray; + Vertex* _varray; + int* _iarray; glm::dmat3 _stateMatrix; // might need this diff --git a/src/abuffer/abuffer.cpp b/src/abuffer/abuffer.cpp index 45adb1274a..714df95445 100644 --- a/src/abuffer/abuffer.cpp +++ b/src/abuffer/abuffer.cpp @@ -114,7 +114,6 @@ bool ABuffer::reinitialize() { void ABuffer::resolve() { if( ! _validShader) { - SleepEx(0, TRUE); generateShaderSource(); updateShader(); _validShader = true; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 09296ef4bd..eb68261a24 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -323,7 +323,8 @@ bool OpenSpaceEngine::create(int argc, char** argv, if (!FileSys.directoryExists(token)) { std::string p = absPath(token); LDEBUG("Directory '" << p <<"' does not exsist, creating."); - FileSys.createDirectory(p, true); + if(FileSys.createDirectory(p, true)) + LERROR("Directory '" << p <<"' could not be created"); } } diff --git a/src/rendering/renderablewavefrontobject.cpp b/src/rendering/renderablewavefrontobject.cpp index a972435a1b..1dfb81e42c 100644 --- a/src/rendering/renderablewavefrontobject.cpp +++ b/src/rendering/renderablewavefrontobject.cpp @@ -51,6 +51,10 @@ RenderableWavefrontObject::RenderableWavefrontObject(const ghoul::Dictionary& di , _programObject(nullptr) , _fovProgram(nullptr) , _texture(nullptr) + , _isize(0) + , _vsize(0) + , _varray(nullptr) + , _iarray(nullptr) { std::string name; bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); @@ -108,6 +112,7 @@ void RenderableWavefrontObject::loadObj(const char *filename){ fi = fopen(filename, "r"); if (fi == NULL) { LERROR("Null Object\n"); + } while (fgets(line, 150, fi) != NULL) { @@ -256,6 +261,9 @@ RenderableWavefrontObject::~RenderableWavefrontObject(){ bool RenderableWavefrontObject::initialize() { + if(_isize == 0) + return false; + bool completeSuccess = true; if (_programObject == nullptr) completeSuccess diff --git a/src/rendering/stars/renderablestars.cpp b/src/rendering/stars/renderablestars.cpp index ac210c8192..7b4dc96e1a 100644 --- a/src/rendering/stars/renderablestars.cpp +++ b/src/rendering/stars/renderablestars.cpp @@ -292,6 +292,10 @@ bool RenderableStars::deinitialize(){ //#define TMAT void RenderableStars::render(const RenderData& data){ + if(!_haloProgram) + return; + if(!_texture) + return; assert(_haloProgram); //printOpenGLError(); // activate shader From a8f3923659754f1d75300729d435ec46fcb8ac3d Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Wed, 22 Oct 2014 13:04:55 +0200 Subject: [PATCH 15/17] Moved the lua command input to separete class - Added functionality for keeping the input history --- .gitignore | 1 + include/openspace/engine/openspaceengine.h | 12 +- .../interaction/interactionhandler.h | 24 ++ include/openspace/interaction/luaconsole.h | 60 +++ src/engine/openspaceengine.cpp | 313 +------------- src/interaction/interactionhandler.cpp | 23 ++ src/interaction/luaconsole.cpp | 391 ++++++++++++++++++ 7 files changed, 519 insertions(+), 305 deletions(-) create mode 100644 include/openspace/interaction/luaconsole.h create mode 100644 src/interaction/luaconsole.cpp diff --git a/.gitignore b/.gitignore index cbb57e35f8..edb9b19705 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ ext/SGCT # generated glsl files *.gglsl *.OpenSpaceGenerated.glsl +shaders/generated/* # CMake stuff CMakeCache.txt diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index d5b8e699ba..0a852455e7 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -34,6 +34,7 @@ #include #include #include +#include //#include #include @@ -92,6 +93,8 @@ public: void encode(); void decode(); + void setInputCommand(bool b); + private: OpenSpaceEngine(std::string programName); ~OpenSpaceEngine(); @@ -117,14 +120,7 @@ private: sgct::SharedVector _synchronizationBuffer; bool _inputCommand; - size_t _inputPosition; - std::vector _commandsHistory; - size_t _activeCommand; - std::vector _commands; - - void renderActiveCommand(); - void handleCommandInput(int key, int action); - void addToCommand(std::string c); + LuaConsole* _console; }; #define OsEng (openspace::OpenSpaceEngine::ref()) diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index f27a20604c..711240916b 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #ifndef INTERACTIONHANDLER_H #define INTERACTIONHANDLER_H diff --git a/include/openspace/interaction/luaconsole.h b/include/openspace/interaction/luaconsole.h new file mode 100644 index 0000000000..ee6087f53c --- /dev/null +++ b/include/openspace/interaction/luaconsole.h @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef LUACONSOLE_H +#define LUACONSOLE_H + +#include +#include + +namespace openspace { + +class LuaConsole { +public: + LuaConsole(); + ~LuaConsole(); + + void keyboardCallback(int key, int action); + void charCallback(unsigned int codepoint); + + void render(); + + unsigned int commandInputButton(); + unsigned int ignoreCodepoint(); + + +private: + void addToCommand(std::string c); + std::string UnicodeToUTF8(unsigned int codepoint); + + size_t _inputPosition; + std::vector _commandsHistory; + size_t _activeCommand; + std::vector _commands; + +}; + +} // namespace openspace + +#endif diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index eb68261a24..bdfd3b116f 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -57,136 +58,10 @@ namespace { const std::string _sgctDefaultConfigFile = "${SGCT}/single.xml"; const std::string _sgctConfigArgumentCommand = "-config"; - -#ifdef WIN32 - const unsigned int CommandInputButton = SGCT_KEY_BACKSLASH; // Button left of 1 and abobe TAB - const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint -#else - const unsigned int CommandInputButton = SGCT_KEY_GRAVE_ACCENT; // Button left of 1 and abobe TAB - const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint - - // Dangerus as fuck - bool exec(const std::string& cmd, std::string& value) - { - FILE* pipe = popen(cmd.c_str(), "r"); - if (!pipe) - return false; - - const int buffer_size = 1024; - char buffer[buffer_size]; - value = ""; - while(!feof(pipe)) - { - if(fgets(buffer, buffer_size, pipe) != NULL) - { - value += buffer; - } - } - pclose(pipe); - return true; - } -#endif struct { std::string configurationName; } commandlineArgumentPlaceholders; - - // TODO: Put this functio nsomewhere appropriate - // get text from clipboard - std::string getClipboardText() - { -#ifdef WIN32 - // Try opening the clipboard - if (!OpenClipboard(nullptr)) - return ""; - - // Get handle of clipboard object for ANSI text - HANDLE hData = GetClipboardData(CF_TEXT); - if (hData == nullptr) - return ""; - - // Lock the handle to get the actual text pointer - char * pszText = static_cast(GlobalLock(hData)); - if (pszText == nullptr) - return ""; - - // Save text in a string class instance - std::string text(pszText); - - // Release the lock - GlobalUnlock(hData); - - // Release the clipboard - CloseClipboard(); - - text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); - return text; -#else - std::string text; - if(exec("xclip -o -sel c -f", text)) - return text.substr(0, text.length()-1); - return ""; // remove a line ending - -#endif - } - - // TODO: Put this function somewhere appropriate - // set text to clipboard - bool setClipboardText(std::string text) - { -#ifdef WIN32 - char *ptrData = nullptr; - HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, text.length() + 1); - - ptrData = (char*)GlobalLock(hData); - memcpy(ptrData, text.c_str(), text.length() + 1); - - GlobalUnlock(hData); - - if (!OpenClipboard(nullptr)) - return false; - - if (!EmptyClipboard()) - return false; - - SetClipboardData(CF_TEXT, hData); - - CloseClipboard(); - - return true; -#else - std::stringstream cmd; - cmd << "echo \"" << text << "\" | xclip -i -sel c -f"; - std::string buf; - return exec(cmd.str(), buf); -#endif - } - - std::string UnicodeToUTF8(unsigned int codepoint){ - std::string out; - - if (codepoint <= 0x7f) - out.append(1, static_cast(codepoint)); - else if (codepoint <= 0x7ff) - { - out.append(1, static_cast(0xc0 | ((codepoint >> 6) & 0x1f))); - out.append(1, static_cast(0x80 | (codepoint & 0x3f))); - } - else if (codepoint <= 0xffff) - { - out.append(1, static_cast(0xe0 | ((codepoint >> 12) & 0x0f))); - out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); - out.append(1, static_cast(0x80 | (codepoint & 0x3f))); - } - else - { - out.append(1, static_cast(0xf0 | ((codepoint >> 18) & 0x07))); - out.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3f))); - out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); - out.append(1, static_cast(0x80 | (codepoint & 0x3f))); - } - return out; - } } using namespace ghoul::cmdparser; @@ -198,13 +73,14 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName) : _commandlineParser(programName, true) , _inputCommand(false) - , _inputPosition(0) - , _activeCommand(0) - , _commands({""}) + , _console(nullptr) { } OpenSpaceEngine::~OpenSpaceEngine() { + if (_console) + delete _console; + SpiceManager::deinitialize(); Time::deinitialize(); DeviceIdentifier::deinit(); @@ -331,6 +207,8 @@ bool OpenSpaceEngine::create(int argc, char** argv, // Create the cachemanager FileSys.createCacheManager("${CACHE}"); + _engine->_console = new LuaConsole(); + // Determining SGCT configuration file LDEBUG("Determining SGCT configuration file"); std::string sgctConfigurationPath = _sgctDefaultConfigFile; @@ -541,48 +419,10 @@ void OpenSpaceEngine::render() { // If currently writing a command, render it to screen sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr(); if (sgct::Engine::instance()->isMaster() && !w->isUsingFisheyeRendering() && _inputCommand) { - renderActiveCommand(); + _console->render(); } } -void OpenSpaceEngine::renderActiveCommand() { - - const int font_size = 10; - int x1, xSize, y1, ySize; - sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); - int startY = ySize - 2 * font_size; - startY = startY - font_size * 10 * 2; - - const int font_with = font_size*0.7; - const glm::vec4 red(1, 0, 0, 1); - const glm::vec4 green(0, 1, 0, 1); - const glm::vec4 white(1, 1, 1, 1); - const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); - Freetype::print(font, 10, startY, red, "$"); - Freetype::print(font, 10 + font_size, startY, white, "%s", _commands.at(_activeCommand).c_str()); - - size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n'); - size_t p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition); - size_t linepos = _inputPosition; - - if (n>0) { - if (p == _inputPosition) { - p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition - 1); - if (p != std::string::npos) { - linepos -= p + 1; - } - else { - linepos = _inputPosition - 1; - } - } - else{ - linepos -= p + 1; - } - } - char buffer[10]; - sprintf(buffer, "%%%lus", linepos + 1); - Freetype::print(font, 10 + static_cast(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); -} void OpenSpaceEngine::postDraw() { if (sgct::Engine::instance()->isMaster()) @@ -606,16 +446,9 @@ void OpenSpaceEngine::postDraw() { #endif } -void OpenSpaceEngine::addToCommand(std::string c) { - size_t length = c.length(); - _commands.at(_activeCommand).insert(_inputPosition, c); - _inputPosition += length; -} - void OpenSpaceEngine::keyboardCallback(int key, int action) { if (sgct::Engine::instance()->isMaster()) { - - if (key == CommandInputButton && (action == SGCT_PRESS || action == SGCT_REPEAT)) { + if (key == _console->commandInputButton() && (action == SGCT_PRESS || action == SGCT_REPEAT)) { _inputCommand = !_inputCommand; } @@ -623,132 +456,14 @@ void OpenSpaceEngine::keyboardCallback(int key, int action) { _interactionHandler.keyboardCallback(key, action); } else { - handleCommandInput(key, action); - } - } -} - -void OpenSpaceEngine::handleCommandInput(int key, int action) { - if (action == SGCT_PRESS || action == SGCT_REPEAT) { - const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); - const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || - sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); - const bool mod_SHIFT = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_SHIFT) || - sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_SHIFT); - - // Paste from clipboard - if (key == SGCT_KEY_V) { - if (mod_CONTROL) { - addToCommand(getClipboardText()); - } - } - - // Copy to clipboard - if (key == SGCT_KEY_C) { - if (mod_CONTROL) { - setClipboardText(_commands.at(_activeCommand)); - } - } - - // Go to the previous character - if (key == SGCT_KEY_LEFT) { - if (_inputPosition > 0) - _inputPosition -= 1; - } - - // Go to the next character - if (key == SGCT_KEY_RIGHT) { - if (_inputPosition < _commands.at(_activeCommand).length()) - ++_inputPosition; - } - - // Go to previous command - if (key == SGCT_KEY_UP) { - if (_activeCommand > 0) - --_activeCommand; - _inputPosition = _commands.at(_activeCommand).length(); - } - - // Go to next command (the last is empty) - if (key == SGCT_KEY_DOWN) { - if (_activeCommand < _commands.size()-1) - ++_activeCommand; - _inputPosition = _commands.at(_activeCommand).length(); - } - - // Remove character before _inputPosition - if (key == SGCT_KEY_BACKSPACE) { - if (_inputPosition > 0) { - _commands.at(_activeCommand).erase(_inputPosition - 1, 1); - --_inputPosition; - } - } - - // Remove character after _inputPosition - if (key == SGCT_KEY_DELETE) { - if (_inputPosition <= _commands.at(_activeCommand).size()) { - _commands.at(_activeCommand).erase(_inputPosition, 1); - } - } - - // Go to the beginning of command string - if (key == SGCT_KEY_HOME) { - _inputPosition = 0; - } - - // Go to the end of command string - if (key == SGCT_KEY_END) { - _inputPosition = _commands.at(_activeCommand).size(); - } - - if (key == SGCT_KEY_ENTER) { - - // SHIFT+ENTER == new line - if (mod_SHIFT) { - addToCommand("\n"); - } - // CTRL+ENTER == Debug print the command - else if (mod_CONTROL) { - LDEBUG("Active command from next line:\n" << _commands.at(_activeCommand)); - } - // ENTER == run lua script - else { - if (_commands.at(_activeCommand) != "") { - - _scriptEngine.runScript(_commands.at(_activeCommand)); - _commandsHistory.push_back(_commands.at(_activeCommand)); - _commands = _commandsHistory; - _commands.push_back(""); - _activeCommand = _commands.size() - 1; - _inputPosition = 0; - } - else { - _commands = _commandsHistory; - _commands.push_back(""); - _inputCommand = false; - } - } + _console->keyboardCallback(key, action); } } } void OpenSpaceEngine::charCallback(unsigned int codepoint) { - - // SGCT_KEY_BACKSLASH == 92 but that corresponds to codepoint 167 - if (_inputCommand && codepoint != IgnoreCodepoint) { - -#ifndef WIN32 - const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); - const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || - sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); - - const int codepoint_C = 99; - const int codepoint_V = 118; - if(mod_CONTROL && (codepoint == codepoint_C || codepoint == codepoint_V)) { - return; - } -#endif - addToCommand(UnicodeToUTF8(codepoint)); + if (_inputCommand) { + _console->charCallback(codepoint); } } @@ -795,6 +510,10 @@ void OpenSpaceEngine::decode() //#endif } +void OpenSpaceEngine::setInputCommand(bool b) { + _inputCommand = b; +} + void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int size, int clientId) { diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 8da7b42048..6d08d3762b 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -1,3 +1,26 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ // open space includes #include diff --git a/src/interaction/luaconsole.cpp b/src/interaction/luaconsole.cpp new file mode 100644 index 0000000000..9fed2973bd --- /dev/null +++ b/src/interaction/luaconsole.cpp @@ -0,0 +1,391 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include + +#include +#include + +#include + +#include + +namespace { + const std::string _loggerCat = "LuaConsole"; + const std::string _filename = "${TEMPORARY}/history"; + +#if !defined(WIN32) + // Dangerus as fuck (if malicious input) + bool exec(const std::string& cmd, std::string& value) + { + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) + return false; + + const int buffer_size = 1024; + char buffer[buffer_size]; + value = ""; + while (!feof(pipe)) + { + if (fgets(buffer, buffer_size, pipe) != NULL) + { + value += buffer; + } + } + pclose(pipe); + return true; + } +#endif + + // TODO: Put this functio nsomewhere appropriate + // get text from clipboard + std::string getClipboardText() { +#if defined(WIN32) + // Try opening the clipboard + if (!OpenClipboard(nullptr)) + return ""; + + // Get handle of clipboard object for ANSI text + HANDLE hData = GetClipboardData(CF_TEXT); + if (hData == nullptr) + return ""; + + // Lock the handle to get the actual text pointer + char * pszText = static_cast(GlobalLock(hData)); + if (pszText == nullptr) + return ""; + + // Save text in a string class instance + std::string text(pszText); + + // Release the lock + GlobalUnlock(hData); + + // Release the clipboard + CloseClipboard(); + + text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); + return text; +#elif defined(__APPLE__) + std::string text; + if (exec("pbpaste", text)) + return text.substr(0, text.length() - 1); + return ""; // remove a line ending +#else + std::string text; + if (exec("xclip -o -sel c -f", text)) + return text.substr(0, text.length() - 1); + return ""; // remove a line ending +#endif +} + + // TODO: Put this function somewhere appropriate + // set text to clipboard + bool setClipboardText(std::string text) + { +#if defined(WIN32) + char *ptrData = nullptr; + HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, text.length() + 1); + + ptrData = (char*)GlobalLock(hData); + memcpy(ptrData, text.c_str(), text.length() + 1); + + GlobalUnlock(hData); + + if (!OpenClipboard(nullptr)) + return false; + + if (!EmptyClipboard()) + return false; + + SetClipboardData(CF_TEXT, hData); + + CloseClipboard(); + + return true; +#elif defined(__APPLE__) + std::stringstream cmd; + cmd << "echo \"" << text << "\" | pbcopy"; + std::string buf; + return exec(cmd.str(), buf); +#else + std::stringstream cmd; + cmd << "echo \"" << text << "\" | xclip -i -sel c -f"; + std::string buf; + return exec(cmd.str(), buf); +#endif + } +} + +namespace openspace { + +LuaConsole::LuaConsole() + : _inputPosition(0) + , _activeCommand(0) +{ + FILE* file = fopen(absPath(_filename).c_str(), "rb"); + if (file) { + size_t n; + fread(&n, sizeof(size_t), 1, file); + for (size_t i = 0; i < n; ++i) { + size_t length; + fread(&length, sizeof(size_t), 1, file); + char* tmp = new char[length + 1]; + fread(tmp, sizeof(char), length, file); + tmp[length] = '\0'; + _commandsHistory.emplace_back(tmp); + delete[] tmp; + } + fclose(file); + _commands = _commandsHistory; + } + _commands.push_back(""); + _activeCommand = _commands.size() - 1; +} + +LuaConsole::~LuaConsole() { + FILE* file = fopen(absPath(_filename).c_str(), "wb"); + if (file) { + size_t n = _commandsHistory.size(); + fwrite(&n, sizeof(size_t), 1, file); + for (auto s : _commandsHistory) { + size_t length = s.length(); + fwrite(&length, sizeof(size_t), 1, file); + fwrite(s.c_str(), sizeof(char), length, file); + } + fclose(file); + } +} + +void LuaConsole::keyboardCallback(int key, int action) { + if (action == SGCT_PRESS || action == SGCT_REPEAT) { + const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); + const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); + const bool mod_SHIFT = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_SHIFT) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_SHIFT); + + // Paste from clipboard + if (key == SGCT_KEY_V) { + if (mod_CONTROL) { + addToCommand(getClipboardText()); + } + } + + // Copy to clipboard + if (key == SGCT_KEY_C) { + if (mod_CONTROL) { + setClipboardText(_commands.at(_activeCommand)); + } + } + + // Go to the previous character + if (key == SGCT_KEY_LEFT) { + if (_inputPosition > 0) + _inputPosition -= 1; + } + + // Go to the next character + if (key == SGCT_KEY_RIGHT) { + if (_inputPosition < _commands.at(_activeCommand).length()) + ++_inputPosition; + } + + // Go to previous command + if (key == SGCT_KEY_UP) { + if (_activeCommand > 0) + --_activeCommand; + _inputPosition = _commands.at(_activeCommand).length(); + } + + // Go to next command (the last is empty) + if (key == SGCT_KEY_DOWN) { + if (_activeCommand < _commands.size() - 1) + ++_activeCommand; + _inputPosition = _commands.at(_activeCommand).length(); + } + + // Remove character before _inputPosition + if (key == SGCT_KEY_BACKSPACE) { + if (_inputPosition > 0) { + _commands.at(_activeCommand).erase(_inputPosition - 1, 1); + --_inputPosition; + } + } + + // Remove character after _inputPosition + if (key == SGCT_KEY_DELETE) { + if (_inputPosition <= _commands.at(_activeCommand).size()) { + _commands.at(_activeCommand).erase(_inputPosition, 1); + } + } + + // Go to the beginning of command string + if (key == SGCT_KEY_HOME) { + _inputPosition = 0; + } + + // Go to the end of command string + if (key == SGCT_KEY_END) { + _inputPosition = _commands.at(_activeCommand).size(); + } + + if (key == SGCT_KEY_ENTER) { + + // SHIFT+ENTER == new line + if (mod_SHIFT) { + addToCommand("\n"); + } + // CTRL+ENTER == Debug print the command + else if (mod_CONTROL) { + LDEBUG("Active command from next line:\n" << _commands.at(_activeCommand)); + } + // ENTER == run lua script + else { + if (_commands.at(_activeCommand) != "") { + + OsEng.scriptEngine().runScript(_commands.at(_activeCommand)); + _commandsHistory.push_back(_commands.at(_activeCommand)); + _commands = _commandsHistory; + _commands.push_back(""); + _activeCommand = _commands.size() - 1; + _inputPosition = 0; + } + else { + _commands = _commandsHistory; + _commands.push_back(""); + OsEng.setInputCommand(false); + } + } + } + } +} + +void LuaConsole::charCallback(unsigned int codepoint) { + if (codepoint == ignoreCodepoint()) + return; + +#ifndef WIN32 + const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex(); + const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) || + sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL); + + const int codepoint_C = 99; + const int codepoint_V = 118; + if (mod_CONTROL && (codepoint == codepoint_C || codepoint == codepoint_V)) { + return; + } +#endif + addToCommand(UnicodeToUTF8(codepoint)); + +} + +void LuaConsole::render() { + const int font_size = 10; + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + int startY = ySize - 2 * font_size; + startY = startY - font_size * 10 * 2; + + const int font_with = font_size*0.7; + const glm::vec4 red(1, 0, 0, 1); + const glm::vec4 green(0, 1, 0, 1); + const glm::vec4 white(1, 1, 1, 1); + const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size); + Freetype::print(font, 10, startY, red, "$"); + Freetype::print(font, 10 + font_size, startY, white, "%s", _commands.at(_activeCommand).c_str()); + + size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n'); + size_t p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition); + size_t linepos = _inputPosition; + + if (n>0) { + if (p == _inputPosition) { + p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition - 1); + if (p != std::string::npos) { + linepos -= p + 1; + } + else { + linepos = _inputPosition - 1; + } + } + else{ + linepos -= p + 1; + } + } + char buffer[10]; + sprintf(buffer, "%%%lus", linepos + 1); + Freetype::print(font, 10 + static_cast(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^"); +} + +unsigned int LuaConsole::commandInputButton(){ + // Button left of 1 and abobe TAB +#ifdef WIN32 + return SGCT_KEY_BACKSLASH; +#else + return SGCT_KEY_GRAVE_ACCENT; +#endif +} + +unsigned int LuaConsole::ignoreCodepoint() { + // Correesponding codepoint for commandInputButton() + return 167; +} + +void LuaConsole::addToCommand(std::string c) { + size_t length = c.length(); + _commands.at(_activeCommand).insert(_inputPosition, c); + _inputPosition += length; +} + +std::string LuaConsole::UnicodeToUTF8(unsigned int codepoint) { + std::string out; + + if (codepoint <= 0x7f) + out.append(1, static_cast(codepoint)); + else if (codepoint <= 0x7ff) + { + out.append(1, static_cast(0xc0 | ((codepoint >> 6) & 0x1f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else if (codepoint <= 0xffff) + { + out.append(1, static_cast(0xe0 | ((codepoint >> 12) & 0x0f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else + { + out.append(1, static_cast(0xf0 | ((codepoint >> 18) & 0x07))); + out.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + return out; +} + + +} // namespace openspace From a7da4d84cc33f23b6238cb22094d56576c6ca80c Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Wed, 22 Oct 2014 16:37:54 +0200 Subject: [PATCH 16/17] Added SyncBuffer class - Added SyncBuffer class for easy and effecient synchronization - Small changes to Camera class - Forward declared a few classes to minimize dependencies --- include/openspace/engine/openspaceengine.h | 15 ++-- include/openspace/rendering/renderengine.h | 26 +++---- include/openspace/util/camera.h | 7 +- include/openspace/util/syncbuffer.h | 80 ++++++++++++++++++++++ src/engine/openspaceengine.cpp | 8 +++ src/rendering/renderablevolumegl.cpp | 1 + src/rendering/renderengine.cpp | 34 +++++++-- src/scenegraph/scenegraph.cpp | 1 + src/util/camera.cpp | 10 ++- src/util/syncbuffer.cpp | 51 ++++++++++++++ 10 files changed, 198 insertions(+), 35 deletions(-) create mode 100644 include/openspace/util/syncbuffer.h create mode 100644 src/util/syncbuffer.cpp diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 0a852455e7..8d2eea0d72 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -29,13 +29,11 @@ // sgct header has to be included before all others due to Windows header #define SGCT_WINDOWS_INCLUDE -#include "sgct.h" +#include #include #include #include -#include -//#include #include #include @@ -47,15 +45,14 @@ #include -#define ABUFFER_SINGLE_LINKED 1 -#define ABUFFER_FIXED 2 -#define ABUFFER_DYNAMIC 3 -#define ABUFFER_IMPLEMENTATION ABUFFER_SINGLE_LINKED - // #define OPENSPACE_VIDEO_EXPORT namespace openspace { +// Forward declare to minimize dependencies +class SyncBuffer; +class LuaConsole; + namespace scripting { class ScriptEngine; } @@ -117,7 +114,7 @@ private: // ScriptEngine* _scriptEngine; ghoul::opencl::CLContext _context; - sgct::SharedVector _synchronizationBuffer; + SyncBuffer* _syncBuffer; bool _inputCommand; LuaConsole* _console; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index d71a4f2050..0f410a09eb 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -25,23 +25,21 @@ #ifndef __RENDERENGINE_H__ #define __RENDERENGINE_H__ -#include - #include #include #include -#include -#include -#include -#include - namespace openspace { +// Forward declare to minimize dependencies class Camera; +class SyncBuffer; +class SceneGraph; +class ABuffer; +class ScreenLog; -class RenderEngine: public properties::PropertyOwner { +class RenderEngine { public: RenderEngine(); ~RenderEngine(); @@ -62,13 +60,13 @@ public: void takeScreenshot(); - void serialize(std::vector& dataStream, size_t& offset); - void deserialize(const std::vector& dataStream, size_t& offset); + void serialize(SyncBuffer* syncBuffer); + void deserialize(SyncBuffer* syncBuffer); /** * Returns the Lua library that contains all Lua functions available to affect the * rendering. The functions contained are - * - openspace::luascriptfunctions::printScreen + * - openspace::luascriptfunctions::printImage * \return The Lua library that contains all Lua functions available to affect the * rendering */ @@ -81,10 +79,8 @@ private: ABuffer* _abuffer; ScreenLog* _log; - properties::BoolProperty _showInfo; - properties::BoolProperty _showScreenLog; - - + bool _showInfo; + bool _showScreenLog; bool _takeScreenshot; void generateGlslConfig(); diff --git a/include/openspace/util/camera.h b/include/openspace/util/camera.h index 9a509ef94a..c076fc067d 100644 --- a/include/openspace/util/camera.h +++ b/include/openspace/util/camera.h @@ -111,7 +111,8 @@ public: void setCameraDirection(glm::vec3 cameraDirection); glm::vec3 cameraDirection() const; - glm::mat4 viewRotationMatrix() const; + void setViewRotationMatrix(glm::mat4 m); + const glm::mat4& viewRotationMatrix() const; void compileViewRotationMatrix(); void rotate(const glm::quat& rotation); @@ -119,7 +120,7 @@ public: // const glm::quat& rotation() const; void setRotation(glm::mat4 rotation); - const glm::vec3& viewDirection() const; + const glm::vec3& viewDirection() const; const float& maxFov() const; const float& sinMaxFov() const; @@ -128,7 +129,7 @@ public: const glm::vec2& scaling() const; void setLookUpVector(glm::vec3 lookUp); - const glm::vec3 lookUpVector() const; + const glm::vec3& lookUpVector() const; private: float _maxFov; diff --git a/include/openspace/util/syncbuffer.h b/include/openspace/util/syncbuffer.h new file mode 100644 index 0000000000..791c4e33d1 --- /dev/null +++ b/include/openspace/util/syncbuffer.h @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef SYNCBUFFER_H +#define SYNCBUFFER_H + +#include +#include + +namespace openspace { + +class SyncBuffer { +public: + + SyncBuffer(size_t n); + + template + void encode(const T& v) { + const size_t size = sizeof(T); + assert(_encodeOffset + size < _n); + + memcpy(_dataStream.data() + _encodeOffset, &v, size); + _encodeOffset += size; + } + + template + T decode() { + const size_t size = sizeof(T); + assert(_decodeOffset + size < _n); + T value; + memcpy(&value, _dataStream.data() + _decodeOffset, size); + _decodeOffset += size; + return value; + } + + + template + void decode(T& value) { + const size_t size = sizeof(T); + assert(_decodeOffset + size < _n); + memcpy(&value, _dataStream.data() + _decodeOffset, size); + _decodeOffset += size; + } + + void write(); + + void read(); + +private: + size_t _n; + size_t _encodeOffset; + size_t _decodeOffset; + std::vector _dataStream; + sgct::SharedVector _synchronizationBuffer; +}; + +} // namespace openspace + +#endif // SYNCBUFFER_H \ No newline at end of file diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index bdfd3b116f..c80e0dae14 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -74,6 +76,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName) : _commandlineParser(programName, true) , _inputCommand(false) , _console(nullptr) + , _syncBuffer(nullptr) { } @@ -208,6 +211,7 @@ bool OpenSpaceEngine::create(int argc, char** argv, FileSys.createCacheManager("${CACHE}"); _engine->_console = new LuaConsole(); + _engine->_syncBuffer = new SyncBuffer(1024); // Determining SGCT configuration file LDEBUG("Determining SGCT configuration file"); @@ -494,6 +498,8 @@ void OpenSpaceEngine::encode() // _synchronizationBuffer.setVal(dataStream); // sgct::SharedData::instance()->writeVector(&_synchronizationBuffer); //#endif + _renderEngine.serialize(_syncBuffer); + _syncBuffer->write(); } void OpenSpaceEngine::decode() @@ -508,6 +514,8 @@ void OpenSpaceEngine::decode() // // deserialize in the same order as done in serialization // _renderEngine->deserialize(dataStream, offset); //#endif + _syncBuffer->read(); + _renderEngine.deserialize(_syncBuffer); } void OpenSpaceEngine::setInputCommand(bool b) { diff --git a/src/rendering/renderablevolumegl.cpp b/src/rendering/renderablevolumegl.cpp index 86d2f9c4b8..2e6ab274f5 100644 --- a/src/rendering/renderablevolumegl.cpp +++ b/src/rendering/renderablevolumegl.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 12f264835b..edf8c9e5af 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "sgct.h" #include @@ -41,9 +42,12 @@ #include #include +#include +#include #include #include #include +#include namespace { const std::string _loggerCat = "RenderEngine"; @@ -75,10 +79,9 @@ RenderEngine::RenderEngine() , _abuffer(nullptr) , _takeScreenshot(false) , _log(nullptr) - , _showInfo("info", "Display info", true) - , _showScreenLog("log", "Display screen log", true) + , _showInfo(true) + , _showScreenLog(true) { - setName("renderEngine"); } RenderEngine::~RenderEngine() @@ -387,7 +390,7 @@ void RenderEngine::setSceneGraph(SceneGraph* sceneGraph) _sceneGraph = sceneGraph; } -void RenderEngine::serialize(std::vector& dataStream, size_t& offset) { +void RenderEngine::serialize(SyncBuffer* syncBuffer) { // TODO: This has to be redone properly (ab) [new class providing methods to serialize // variables] @@ -397,6 +400,12 @@ void RenderEngine::serialize(std::vector& dataStream, size_t& offset) { // camera->viewRotationMatrix // camera->scaling + syncBuffer->encode(_mainCamera->scaling()); + syncBuffer->encode(_mainCamera->position()); + syncBuffer->encode(_mainCamera->viewRotationMatrix()); + //syncBuffer->encode(_mainCamera->lookUpVector()); + //syncBuffer->encode(_mainCamera->rotation()); + //const glm::vec2 scaling = _mainCamera->scaling(); //const psc position = _mainCamera->position(); @@ -476,8 +485,23 @@ void RenderEngine::serialize(std::vector& dataStream, size_t& offset) { //dataStream[offset++] = s.representation[3]; } -void RenderEngine::deserialize(const std::vector& dataStream, size_t& offset) { +void RenderEngine::deserialize(SyncBuffer* syncBuffer) { // TODO: This has to be redone properly (ab) + + glm::vec2 scaling; + psc position; + glm::mat4 viewRotation; + //glm::vec3 lookUpVector; + syncBuffer->decode(scaling); + syncBuffer->decode(position); + syncBuffer->decode(viewRotation); + + _mainCamera->setScaling(scaling); + _mainCamera->setPosition(position); + _mainCamera->setViewRotationMatrix(viewRotation); + //_mainCamera->setLookUpVector(lookUpVector); + //_mainCamera->compileViewRotationMatrix(); + // union storage { // float value; diff --git a/src/scenegraph/scenegraph.cpp b/src/scenegraph/scenegraph.cpp index 26d5d6d9e9..e2165bf01a 100644 --- a/src/scenegraph/scenegraph.cpp +++ b/src/scenegraph/scenegraph.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // ghoul includes #include "ghoul/opengl/programobject.h" diff --git a/src/util/camera.cpp b/src/util/camera.cpp index a3f229039f..59ffc6cf09 100644 --- a/src/util/camera.cpp +++ b/src/util/camera.cpp @@ -100,9 +100,13 @@ glm::vec3 Camera::cameraDirection() const return _cameraDirection; } -glm::mat4 Camera::viewRotationMatrix() const +void Camera::setViewRotationMatrix(glm::mat4 m) { + _viewRotationMatrix = m; +} + +const glm::mat4& Camera::viewRotationMatrix() const { - return glm::mat4(_viewRotationMatrix); + return _viewRotationMatrix; } void Camera::compileViewRotationMatrix() @@ -176,7 +180,7 @@ void Camera::setLookUpVector(glm::vec3 lookUp) _lookUp = std::move(lookUp); } -const glm::vec3 Camera::lookUpVector() const +const glm::vec3& Camera::lookUpVector() const { return _lookUp; } diff --git a/src/util/syncbuffer.cpp b/src/util/syncbuffer.cpp new file mode 100644 index 0000000000..a49a2d0855 --- /dev/null +++ b/src/util/syncbuffer.cpp @@ -0,0 +1,51 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { + +SyncBuffer::SyncBuffer(size_t n) + : _n(n) + , _encodeOffset(0) + , _decodeOffset(0) +{ + _dataStream.resize(_n); +} + +void SyncBuffer::write() { + _synchronizationBuffer.setVal(_dataStream); + sgct::SharedData::instance()->writeVector(&_synchronizationBuffer); + _encodeOffset = 0; + _decodeOffset = 0; +} + +void SyncBuffer::read() { + sgct::SharedData::instance()->readVector(&_synchronizationBuffer); + _dataStream = std::move(_synchronizationBuffer.getVal()); + _encodeOffset = 0; + _decodeOffset = 0; +} + +} // namespace openspace \ No newline at end of file From 5ece54cdc08ccbfd58aba00931b6a2fd827eedb9 Mon Sep 17 00:00:00 2001 From: michal Date: Wed, 22 Oct 2014 16:09:05 -0400 Subject: [PATCH 17/17] openspace-data issue in sourcetree, pushing --- openspace-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspace-data b/openspace-data index 8607807557..48d8d0c0c4 160000 --- a/openspace-data +++ b/openspace-data @@ -1 +1 @@ -Subproject commit 8607807557c508d64a9d38bafa6f3cf771618490 +Subproject commit 48d8d0c0c415012a9cb1969a2336d4d536c1391f