From 9ca60496552c371b0f24f1dc768851f2d153747c Mon Sep 17 00:00:00 2001 From: Andrew Caudwell Date: Fri, 22 Oct 2010 11:12:39 +1300 Subject: [PATCH] Support for adding captions to the time line. --- Makefile.am | 1 + src/caption.cpp | 50 ++++++++++++++++++ src/caption.h | 52 ++++++++++++++++++ src/core | 2 +- src/gource.cpp | 114 +++++++++++++++++++++++++++++++++++++++- src/gource.h | 9 +++- src/gource_settings.cpp | 60 ++++++++++++++++++++- src/gource_settings.h | 9 +++- 8 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 src/caption.cpp create mode 100644 src/caption.h diff --git a/Makefile.am b/Makefile.am index 252d9cef..a9742e4a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,7 @@ gource_SOURCES = \ src/apache.cpp src/apache.h \ src/bzr.cpp src/bzr.h \ src/commitlog.cpp src/commitlog.h \ + src/caption.cpp src/caption.h \ src/core/bounds.h \ src/core/camera.cpp src/core/camera.h \ src/core/conffile.cpp src/core/conffile.h \ diff --git a/src/caption.cpp b/src/caption.cpp new file mode 100644 index 00000000..f49343e2 --- /dev/null +++ b/src/caption.cpp @@ -0,0 +1,50 @@ +/* + Copyright (C) 2010 Andrew Caudwell (acaudwell@gmail.com) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "caption.h" + +RCaption::RCaption(const std::string& caption, time_t timestamp, const FXFont& font) { + this->caption = caption; + this->timestamp = timestamp; + this->font = font; + + alpha = 1.0f; + colour = gGourceSettings.caption_colour; + decay = 1.0f / gGourceSettings.caption_duration; +} + +const vec2f& RCaption::getPos() { + return pos; +} + +void RCaption::setPos(const vec2f& pos) { + this->pos = pos; +} + +bool RCaption::isFinished() { + return alpha <= 0.0f; +} + +void RCaption::logic(float dt) { + alpha = std::max(0.0f, alpha - dt * decay); +} + +void RCaption::draw() const { + glColor4f(colour.x, colour.y, colour.z, 1.0f - fabs(alpha - 0.5) * 2.0f); + + font.draw(pos.x, pos.y, caption); +} \ No newline at end of file diff --git a/src/caption.h b/src/caption.h new file mode 100644 index 00000000..4c5c986c --- /dev/null +++ b/src/caption.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2010 Andrew Caudwell (acaudwell@gmail.com) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef RCAPTION_H +#define RCAPTION_H + +#include "core/display.h" +#include "core/fxfont.h" +#include "gource_settings.h" + +class RCaption { + float alpha; + float decay; + + vec2f pos; + + vec3f colour; + + FXFont font; + FXFont font2; + +public: + std::string caption; + time_t timestamp; + + RCaption(const std::string& caption, time_t timestamp, const FXFont& font); + + void setPos(const vec2f& pos); + const vec2f& getPos(); + + bool isFinished(); + + void logic(float dt); + + void draw() const; +}; + +#endif diff --git a/src/core b/src/core index b5294f9c..7edae410 160000 --- a/src/core +++ b/src/core @@ -1 +1 @@ -Subproject commit b5294f9cf1d957a167c6fefce5d6b9333fe547b7 +Subproject commit 7edae410b10c7bdcfd9c77ec680b7b04511220a1 diff --git a/src/gource.cpp b/src/gource.cpp index e6e874a3..76a86116 100644 --- a/src/gource.cpp +++ b/src/gource.cpp @@ -41,6 +41,11 @@ Gource::Gource(FrameExporter* exporter) { fontmedium.dropShadow(true); fontmedium.roundCoordinates(false); + fontcaption = fontmanager.grab("FreeSans.ttf", gGourceSettings.caption_size); + fontcaption.dropShadow(true); + fontcaption.roundCoordinates(false); + fontcaption.alignTop(false); + font = fontmanager.grab("FreeSans.ttf", 14); font.dropShadow(true); font.roundCoordinates(true); @@ -813,9 +818,19 @@ void Gource::reset() { delete it->second; } - last_percent = 0.0; + for(std::list::iterator it = captions.begin(); it!=captions.end();it++) { + delete (*it); + } + + for(std::list::iterator it = active_captions.begin(); it!=active_captions.end();it++) { + delete (*it); + } files.clear(); + captions.clear(); + active_captions.clear(); + + last_percent = 0.0; idle_time=0; currtime=0; @@ -890,6 +905,45 @@ void Gource::seekTo(float percent) { commitlog->seekTo(percent); } +Regex caption_regex("^([0-9]+)\\|(.+)$"); + +void Gource::loadCaptions() { + if(!gGourceSettings.caption_file.size()) return; + + std::ifstream cf(gGourceSettings.caption_file.c_str()); + + if(!cf.is_open()) return; + + std::string line; + std::vector matches; + + time_t last_timestamp = 0; + + while(std::getline(cf, line)) { + + ConfFile::trim(line); + + if(!caption_regex.match(line, &matches)) continue; + + time_t timestamp = atol(matches[0].c_str()); + + //ignore older captions + if(timestamp 0) { + RCaption* caption = captions.front(); + + if(caption->timestamp > currtime) break; + + float font_height = fontcaption.getHeight(); + + //determine next free height + float y = display.height - 20.0f; + float cap_height = font_height * 1.3f; + + while(1) { + + bool found = false; + + for(std::list::iterator it = active_captions.begin(); it!=active_captions.end();it++) { + RCaption* actcap = *it; + vec2f cappos = actcap->getPos(); + + if(cappos.y == y) { + found = true; + break; + } + } + + if(!found) break; + + y -= cap_height; + } + + caption->setPos(vec2f(20.0f, y)); + + captions.pop_front(); + active_captions.push_back(caption); + } + + for(std::list::iterator it = active_captions.begin(); it!=active_captions.end();) { + RCaption* caption = *it; + + caption->logic(dt); + + if(caption->isFinished()) { + it = active_captions.erase(it); + delete caption; + continue; + } + + it++; + } + //reset loop counters gGourceUserInnerLoops = 0; gGourceDirNodeInnerLoops = 0; @@ -1952,6 +2058,12 @@ void Gource::draw(float t, float dt) { fontmedium.alignTop(true); } + for(std::list::iterator it = active_captions.begin(); it!=active_captions.end(); it++) { + RCaption* caption = *it; + + caption->draw(); + } + if(message_timer>0.0f) { fontmedium.draw(1, 3, message); } diff --git a/src/gource.h b/src/gource.h index f45ac1a3..778fa6cb 100644 --- a/src/gource.h +++ b/src/gource.h @@ -23,6 +23,7 @@ #endif #include +#include #include #include "core/display.h" @@ -48,6 +49,7 @@ #include "slider.h" #include "action.h" +#include "caption.h" #include "file.h" #include "user.h" #include "dirnode.h" @@ -107,7 +109,7 @@ class Gource : public SDLApp { TextureResource* logotex; TextureResource* backgroundtex; - FXFont font, fontlarge, fontmedium; + FXFont font, fontlarge, fontmedium, fontcaption; bool first_read; bool draw_loading; @@ -145,6 +147,9 @@ class Gource : public SDLApp { std::map files; std::map tagfilemap; std::map tagusermap; + + std::list captions; + std::list active_captions; QuadTree* dirNodeTree; QuadTree* userTree; @@ -164,6 +169,8 @@ class Gource : public SDLApp { void selectFile(RFile* file); void selectNextUser(); + void loadCaptions(); + void readLog(); void processCommit(RCommit& commit, float t); diff --git a/src/gource_settings.cpp b/src/gource_settings.cpp index 015de374..f6b67a87 100644 --- a/src/gource_settings.cpp +++ b/src/gource_settings.cpp @@ -118,6 +118,11 @@ if(extended_help) { printf(" --highlight-dirs Highlight the names of all directories\n"); printf(" --highlight-colour Font colour for highlighted text\n\n"); + printf(" --caption-file FILE Caption file\n"); + printf(" --caption-size SIZE Caption font size\n"); + printf(" --caption-colour FFFFFF Caption colour in hex\n"); + printf(" --caption-duration SECONDS Caption duration (default: 10.0)\n\n"); + printf(" --hash-seed SEED Change the seed of hash function.\n\n"); printf(" --path PATH\n\n"); @@ -234,6 +239,7 @@ GourceSettings::GourceSettings() { arg_types["load-config"] = "string"; arg_types["save-config"] = "string"; arg_types["output-custom-log"] = "string"; + arg_types["caption-file"] = "string"; arg_types["path"] = "string"; arg_types["log-command"] = "string"; arg_types["background-colour"] = "string"; @@ -305,7 +311,7 @@ void GourceSettings::setGourceDefaults() { background_colour = vec3f(0.1f, 0.1f, 0.1f); background_image = ""; - + title = ""; font_size = 16; @@ -332,6 +338,11 @@ void GourceSettings::setGourceDefaults() { highlight_all_users = false; highlight_dirs = false; + caption_file = ""; + caption_duration = 10.0f; + caption_size = 24; + caption_colour = vec3f(1.0f, 1.0f, 1.0f); + gStringHashSeed = 31; //delete file filters @@ -619,6 +630,53 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc } } + if((entry = gource_settings->getEntry("caption-file")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify caption file (filename)"); + + caption_file = entry->getString(); + } + + if((entry = gource_settings->getEntry("caption-duration")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify caption duration (seconds)"); + + caption_duration = entry->getFloat(); + + if(caption_duration <= 0.0f) { + conffile.invalidValueException(entry); + } + } + + if((entry = gource_settings->getEntry("caption-size")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify caption size"); + + caption_size = entry->getInt(); + + if(caption_size<1 || caption_size>100) { + conffile.invalidValueException(entry); + } + } + + if((entry = gource_settings->getEntry("caption-colour")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify caption colour (FFFFFF)"); + + int r,g,b; + + std::string colstring = entry->getString(); + + if(entry->isVec3()) { + caption_colour = entry->getVec3(); + } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) { + caption_colour = vec3f(r,g,b); + caption_colour /= 255.0f; + } else { + conffile.invalidValueException(entry); + } + } + if((entry = gource_settings->getEntry("bloom-intensity")) != 0) { if(!entry->hasValue()) conffile.entryException(entry, "specify bloom-intensity (float)"); diff --git a/src/gource_settings.h b/src/gource_settings.h index e38bc7f3..be796281 100644 --- a/src/gource_settings.h +++ b/src/gource_settings.h @@ -118,8 +118,13 @@ class GourceSettings : public SDLAppSettings { std::vector user_filters; bool file_extensions; - std::string output_custom_filename; - + std::string caption_file; + vec3f caption_colour; + float caption_duration; + int caption_size; + + std::string output_custom_filename; + TextureResource* file_graphic; GourceSettings();