#include <stdio.h>
#include <math.h>
#include <string.h>
+#include <locale.h>
#include <assert.h>
#include <GL/glew.h>
// without any explicit recursion.
void EffectChain::construct_glsl_programs(Node *output)
{
- // Which effects have already been completed in this phase?
+ // Which effects have already been completed?
// We need to keep track of it, as an effect with multiple outputs
// could otherwise be calculated multiple times.
std::set<Node *> completed_effects;
// This should currently only happen for effects that are inputs
// (either true inputs or phase outputs). We special-case inputs,
// and then deduplicate phase outputs in compile_glsl_program().
- if (node->effect->num_inputs() == 0 && completed_effects.count(node)) {
- continue;
+ if (node->effect->num_inputs() == 0) {
+ if (find(this_phase_effects.begin(), this_phase_effects.end(), node) != this_phase_effects.end()) {
+ continue;
+ }
+ } else {
+ assert(completed_effects.count(node) == 0);
}
- assert(completed_effects.count(node) == 0);
this_phase_effects.push_back(node);
completed_effects.insert(node);
fprintf(fp, " output [shape=box label=\"(output)\"];\n");
for (unsigned i = 0; i < nodes.size(); ++i) {
// Find out which phase this event belongs to.
- int in_phase = -1;
+ std::vector<int> in_phases;
for (unsigned j = 0; j < phases.size(); ++j) {
const Phase* p = phases[j];
if (std::find(p->effects.begin(), p->effects.end(), nodes[i]) != p->effects.end()) {
- assert(in_phase == -1);
- in_phase = j;
+ in_phases.push_back(j);
}
}
- if (in_phase == -1) {
+ if (in_phases.empty()) {
fprintf(fp, " n%ld [label=\"%s\"];\n", (long)nodes[i], nodes[i]->effect->effect_type_id().c_str());
- } else {
+ } else if (in_phases.size() == 1) {
fprintf(fp, " n%ld [label=\"%s\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n",
(long)nodes[i], nodes[i]->effect->effect_type_id().c_str(),
- (in_phase % 8) + 1);
+ (in_phases[0] % 8) + 1);
+ } else {
+ // If we had new enough Graphviz, style="wedged" would probably be ideal here.
+ // But alas.
+ fprintf(fp, " n%ld [label=\"%s [in multiple phases]\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n",
+ (long)nodes[i], nodes[i]->effect->effect_type_id().c_str(),
+ (in_phases[0] % 8) + 1);
}
char from_node_id[256];
default:
assert(false);
}
+
+ if (node->output_alpha_type == ALPHA_PREMULTIPLIED) {
+ assert(node->output_gamma_curve == GAMMA_LINEAR);
+ }
}
}
}
}
// Go through each input that is not sRGB, and insert
- // a colorspace conversion before it.
+ // a colorspace conversion after it.
for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
Node *input = node->incoming_links[j];
assert(input->output_color_space != COLORSPACE_INVALID);
CHECK(conversion->effect->set_int("source_space", input->output_color_space));
CHECK(conversion->effect->set_int("destination_space", COLORSPACE_sRGB));
conversion->output_color_space = COLORSPACE_sRGB;
- insert_node_between(input, conversion, node);
+ replace_sender(input, conversion);
+ connect_nodes(input, conversion);
}
// Re-sort topologically, and propagate the new information.
conversion = add_node(new AlphaDivisionEffect());
}
conversion->output_alpha_type = desired_type;
- insert_node_between(input, conversion, node);
+ replace_sender(input, conversion);
+ connect_nodes(input, conversion);
}
// Re-sort topologically, and propagate the new information.
}
// If not, go through each input that is not linear gamma,
- // and insert a gamma conversion before it.
+ // and insert a gamma conversion after it.
for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
Node *input = node->incoming_links[j];
assert(input->output_gamma_curve != GAMMA_INVALID);
Node *conversion = add_node(new GammaExpansionEffect());
CHECK(conversion->effect->set_int("source_curve", input->output_gamma_curve));
conversion->output_gamma_curve = GAMMA_LINEAR;
- insert_node_between(input, conversion, node);
+ replace_sender(input, conversion);
+ connect_nodes(input, conversion);
}
// Re-sort topologically, and propagate the new information.
void EffectChain::finalize()
{
+ // Save the current locale, and set it to C, so that we can output decimal
+ // numbers with printf and be sure to get them in the format mandated by GLSL.
+ char *saved_locale = setlocale(LC_NUMERIC, "C");
+
// Output the graph as it is before we do any conversions on it.
output_dot("step0-start.dot");
assert(phases[0]->inputs.empty());
finalized = true;
+ setlocale(LC_NUMERIC, saved_locale);
}
void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height)