Files
OpenSpace/src/abuffer/abuffer.cpp
T
Alexander Bock e7767bff11 More work on SceneGraph
First working and sorted version
2015-04-13 16:07:27 +02:00

350 lines
12 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2015 *
* *
* 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 <openspace/abuffer/abuffer.h>
#include <openspace/engine/openspaceengine.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/texture.h>
#include <sgct.h>
#include <iostream>
#include <fstream>
#include <string>
namespace {
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";
}
namespace openspace {
ABuffer::ABuffer()
: _validShader(false)
, _resolveShader(nullptr)
, _volumeStepFactor(0.0f)
{
updateDimensions();
}
ABuffer::~ABuffer() {
if(_resolveShader)
delete _resolveShader;
for(auto file: _samplerFiles) {
delete file;
}
}
bool ABuffer::initializeABuffer() {
// ============================
// SHADERS
// ============================
auto shaderCallback = [this](ghoul::opengl::ProgramObject* program) {
// Error for visibility in log
_validShader = false;
};
generateShaderSource();
_resolveShader = ghoul::opengl::ProgramObject::Build(
"ABufferResolve",
"${SHADERS}/ABuffer/abufferResolveVertex.glsl",
"${SHADERS}/ABuffer/abufferResolveFragment.glsl");
if (!_resolveShader)
return false;
_resolveShader->setProgramObjectCallback(shaderCallback);
#ifndef __APPLE__
// ============================
// GEOMETRY (quad)
// ============================
const GLfloat size = 1.0f;
const GLfloat vertex_data[] = { // square of two triangles (sigh)
// x y z w s t
-size, -size, 0.0f, 1.0f,
size, size, 0.0f, 1.0f,
-size, size, 0.0f, 1.0f,
-size, -size, 0.0f, 1.0f,
size, -size, 0.0f, 1.0f,
size, size, 0.0f, 1.0f,
};
GLuint vertexPositionBuffer;
glGenVertexArrays(1, &_screenQuad); // generate array
glBindVertexArray(_screenQuad); // bind array
glGenBuffers(1, &vertexPositionBuffer); // generate buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast<void*>(0));
glEnableVertexAttribArray(0);
#endif
return true;
}
bool ABuffer::reinitialize() {
// set the total resolution for all viewports
updateDimensions();
return reinitializeInternal();
}
void ABuffer::resolve() {
#ifndef __APPLE__
if( ! _validShader) {
generateShaderSource();
updateShader();
_validShader = true;
}
if (!_resolveShader)
return;
_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.2f: 1.0f;
//if(volumeStepFactor != _volumeStepFactor) {
// _volumeStepFactor = volumeStepFactor;
// _resolveShader->setUniform("volumeStepFactor", _volumeStepFactor);
//}
glBindVertexArray(_screenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
_resolveShader->deactivate();
#endif
}
void ABuffer::addVolume(const std::string& tag,ghoul::opengl::Texture* volume) {
_volumes.push_back(std::make_pair(tag, volume));
}
void ABuffer::addTransferFunction(const std::string& tag,ghoul::opengl::Texture* transferFunction) {
_transferFunctions.push_back(std::make_pair(tag, transferFunction));
}
int ABuffer::addSamplerfile(const std::string& filename) {
if( ! FileSys.fileExists(filename))
return -1;
#ifndef __APPLE__
auto fileCallback = [this](const ghoul::filesystem::File& file) {
_validShader = false;
};
ghoul::filesystem::File* file = new ghoul::filesystem::File(filename);
file->setCallback(fileCallback);
_samplerFiles.push_back(file);
_samplers.push_back("");
// ID is one more than "actual" position since ID=0 is considered geometry
//return 1 << (_samplers.size()-1);
return static_cast<int>(_samplers.size());
#else
return 0;
#endif
}
bool ABuffer::updateShader() {
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 ABuffer resolve shader!");
}
else {
LWARNING("Couldn't update ABuffer resolve shader");
}
return s;
}
void ABuffer::generateShaderSource() {
for(int i = 0; i < _samplerFiles.size(); ++i) {
std::string line, source = "";
std::ifstream samplerFile(_samplerFiles.at(i)->path());
if(samplerFile.is_open()) {
while(std::getline(samplerFile, line)) {
source += line + "\n";
}
}
samplerFile.close();
_samplers.at(i) = source;
}
LDEBUG("Generating shader includes");
openspaceHeaders();
openspaceSamplerCalls();
openspaceSamplers();
openspaceTransferFunction();
}
void ABuffer::openspaceHeaders() {
std::ofstream f(absPath(generatedHeadersPath));
f << "#define MAX_VOLUMES " << std::to_string(_samplers.size()) << "\n"
<< "#define MAX_TF " << _transferFunctions.size() << "\n";
for (int i = 0; i < _volumes.size(); ++i) {
f << "uniform sampler3D " << _volumes.at(i).first << ";\n";
}
for (int i = 0; i < _transferFunctions.size(); ++i) {
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) {
f << _samplers.at(i).substr(0, found) << ";\n";
}
}
if (_volumes.size() < 1) {
f.close();
return;
}
size_t maxLoop = 0;
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)
maxLoop = glm::max(maxLoop, size[k]);
f << " vec3(" << std::to_string(size[0]) << ".0," + std::to_string(size[1]) << ".0,"
<< std::to_string(size[2]) + ".0),\n";
}
f << "};\n";
f << "#define LOOP_LIMIT " << maxLoop << "\n";
f << "float volumeStepSize[] = {\n";
for (int i = 0; i < _volumes.size(); ++i) {
glm::size3_t size = _volumes.at(i).second->dimensions();
f << " stepSize,\n";
}
f << "};\n";
f << "float volumeStepSizeOriginal[] = {\n";
for (int i = 0; i < _volumes.size(); ++i) {
glm::size3_t size = _volumes.at(i).second->dimensions();
f << " stepSize,\n";
}
f << "};\n";
f.close();
}
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) {
std::string functionName = _samplers.at(i).substr(found1, found2 - found1);
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";
}
}
f.close();
}
void ABuffer::openspaceSamplers() {
std::ofstream f(absPath(generatedSamplersPath));
for (const std::string& sampler : _samplers)
f << sampler << std::endl;
f.close();
}
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*" << 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*" << 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*" << i + 1 << ") {\n"
<< " const float intensity = 0.4;\n"
<< " final_color = vec4(intensity,intensity,intensity,1.0);\n"
<< "}\n";
}
f.close();
}
void ABuffer::invalidateABuffer() {
LDEBUG("Shader invalidated");
_validShader = false;
}
void ABuffer::updateDimensions() {
_width = sgct::Engine::instance()->getActiveWindowPtr()->getXFramebufferResolution();
_height = sgct::Engine::instance()->getActiveWindowPtr()->getYFramebufferResolution();
_totalPixels = _width * _height;
}
} // openspace