Browse Source

Scrolling Text, Font, Second window added

main
cailean 3 days ago
parent
commit
b10c108355
  1. BIN
      bin/data/Avara-Bold.otf
  2. BIN
      bin/data/Avara.otf
  3. 2
      src/main.cpp
  4. 3
      src/ofApp.cpp
  5. 3
      src/ofApp.h
  6. 128
      src/ofTeleprompter.cpp
  7. 19
      src/ofTeleprompter.h

BIN
bin/data/Avara-Bold.otf

Binary file not shown.

BIN
bin/data/Avara.otf

Binary file not shown.

2
src/main.cpp

@ -19,6 +19,8 @@ int main( ){
shared_ptr<ofApp> mainApp(new ofApp); shared_ptr<ofApp> mainApp(new ofApp);
shared_ptr<ofTeleprompter> teleprompterApp(new ofTeleprompter); shared_ptr<ofTeleprompter> teleprompterApp(new ofTeleprompter);
mainApp->teleprompter = teleprompterApp;
ofRunApp(mainWindow, mainApp); ofRunApp(mainWindow, mainApp);
ofRunApp(secondWindow, teleprompterApp); ofRunApp(secondWindow, teleprompterApp);

3
src/ofApp.cpp

@ -25,6 +25,9 @@ void ofApp::update(){
videoFrame.setFromPixels(p); videoFrame.setFromPixels(p);
} }
onnx.update(videoFrame); onnx.update(videoFrame);
teleprompter->updateCVData(onnx.detectedFaces.size());
ofLog() << ofGetFrameRate(); ofLog() << ofGetFrameRate();
} }

3
src/ofApp.h

@ -2,6 +2,7 @@
#include "ofMain.h" #include "ofMain.h"
#include "onxProcess.h" #include "onxProcess.h"
#include "ofTeleprompter.h"
class ofApp : public ofBaseApp{ class ofApp : public ofBaseApp{
@ -20,4 +21,6 @@ class ofApp : public ofBaseApp{
ofImage inputImage; ofImage inputImage;
ofImage videoFrame; ofImage videoFrame;
shared_ptr<ofTeleprompter> teleprompter;
}; };

128
src/ofTeleprompter.cpp

@ -6,19 +6,44 @@ void ofTeleprompter::setup() {
ofSetVerticalSync(false); ofSetVerticalSync(false);
setupGUI(); setupGUI();
loadText(); loadText();
textFont.load("Avara.otf", 32);
detailsFont.load("Avara-Bold.otf", 24);
// Prepare first line for teleprompter
currentSentence = script[currentLine].sentence;
displayedSentence.clear();
currentLetterIndex = 0;
lastWordTime = ofGetElapsedTimeMillis();
} }
void ofTeleprompter::update() { void ofTeleprompter::update() {
// set labels
currentSpeaker = script[currentLine].speaker;
currentEmotion = script[currentLine].emotion;
currentLineIndex = ofToString(currentLine);
// Teleprompter logic (letter by letter)
if (currentLetterIndex < currentSentence.size()) {
uint64_t now = ofGetElapsedTimeMillis();
if (now - lastWordTime > wordDelay) {
displayedSentence += currentSentence[currentLetterIndex];
currentLetterIndex++;
lastWordTime = now;
}
}
} }
void ofTeleprompter::draw() { void ofTeleprompter::draw() {
gui.draw(); gui.draw();
drawText();
} }
void ofTeleprompter::setupGUI() { void ofTeleprompter::setupGUI() {
nextLine.addListener(this, &ofTeleprompter::nextLinePressed); nextLine.addListener(this, &ofTeleprompter::nextLinePressed);
gui.setDefaultWidth(400);
gui.setup(); gui.setup();
gui.add(currentLineIndex.setup("Current Line Index", "NULL")); gui.add(currentLineIndex.setup("Current Line Index", "NULL"));
gui.add(currentSpeaker.setup("Current Speaker", "NULL")); gui.add(currentSpeaker.setup("Current Speaker", "NULL"));
@ -34,9 +59,112 @@ void ofTeleprompter::setupGUI() {
void ofTeleprompter::nextLinePressed() { void ofTeleprompter::nextLinePressed() {
ofLog() << "Next Line!"; ofLog() << "Next Line!";
currentLine++;
// Prepare teleprompter effect for letter-by-letter
currentSentence = script[currentLine].sentence;
displayedSentence.clear();
currentLetterIndex = 0;
lastWordTime = ofGetElapsedTimeMillis();
} }
void ofTeleprompter::loadText() { void ofTeleprompter::loadText() {
script.clear(); script.clear();
ofFile jsonFile(filePath);
if(jsonFile.exists()) {
ofJson json = ofLoadJson(jsonFile);
int idx = 0;
for (const auto& entry : json) {
Line l;
int randomIdx = ofRandom(7);
l.idx = idx++;
l.speaker = entry.value("speaker", "");
l.sentence = entry.value("content", "");
l.emotion = emotions[(int)randomIdx];
script.push_back(l);
}
} else {
ofLogError() << "JSON file not found: " << filePath;
}
// Random Check
if (!script.empty()) {
int randomIdx = ofRandom(script.size()); // returns float
int idx = static_cast<int>(randomIdx); // convert to int
ofLog() << "Random line: " << script[idx].speaker << ": " << script[idx].sentence;
ofLog() << "Number of lines: " << script.size();
}
// Set initial current line
currentLine = 0;
}
void ofTeleprompter::drawText() {
ofSetColor(ofColor::white);
// --- Display speaker and emotion centered at the top ---
std::string speakerText = "Speaker: " + script[currentLine].speaker;
std::string emotionText = "Emotion: " + script[currentLine].emotion;
ofRectangle speakerBox = detailsFont.getStringBoundingBox(speakerText, 0, 0);
float speakerX = (ofGetWidth() - speakerBox.width) / 2.0f;
float speakerY = 128; // Top margin
ofRectangle emotionBox = detailsFont.getStringBoundingBox(emotionText, 0, 0);
float emotionX = (ofGetWidth() - emotionBox.width) / 2.0f;
float emotionY = speakerY + speakerBox.height + 10; // 10px below speaker
detailsFont.drawString(speakerText, speakerX, speakerY);
detailsFont.drawString(emotionText, emotionX, emotionY);
// -------
ofSetColor(ofColor::yellow);
float margin = 128; // pixels
float maxWidth = ofGetWidth() - margin * 2;
std::string wrapped = wrapStringToWidth(displayedSentence, maxWidth);
// Split wrapped into lines
std::vector<std::string> lines;
std::istringstream iss(wrapped);
std::string line;
while (std::getline(iss, line)) {
lines.push_back(line);
}
// Calculate total height for vertical centering
float totalHeight = lines.size() * textFont.getLineHeight();
float startY = (ofGetHeight() / 2.0f) - (totalHeight / 2.0f);
// Draw each line centered horizontally
for (size_t i = 0; i < lines.size(); ++i) {
ofRectangle bbox = textFont.getStringBoundingBox(lines[i], 0, 0);
float x = (ofGetWidth() - bbox.width) / 2.0f;
float y = startY + i * textFont.getLineHeight();
textFont.drawString(lines[i], x, y);
}
}
std::string ofTeleprompter::wrapStringToWidth(const std::string& text, float maxWidth) {
std::istringstream iss(text);
std::string word;
std::string wrapped, line;
while (iss >> word) {
std::string testLine = line.empty() ? word : line + " " + word;
ofRectangle bbox = textFont.getStringBoundingBox(testLine, 0, 0);
if (bbox.width > maxWidth && !line.empty()) {
wrapped += line + "\n";
line = word;
} else {
line = testLine;
}
}
if (!line.empty()) wrapped += line;
return wrapped;
}
void ofTeleprompter::updateCVData(int numOfFacesDetected) {
facesDetected = ofToString(numOfFacesDetected);
} }

19
src/ofTeleprompter.h

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "ofMain.h" #include "ofMain.h"
#include "ofxGui.h" #include "ofxGui.h"
#include "csv.h"
struct Line { struct Line {
int idx; int idx;
@ -18,6 +17,10 @@ class ofTeleprompter: public ofBaseApp{
void setupGUI(); void setupGUI();
void nextLinePressed(); void nextLinePressed();
void loadText(); void loadText();
void drawText();
void updateCVData(int numOfFacesDetected);
std::string wrapStringToWidth(const std::string& text, float maxWidth);
ofxPanel gui; ofxPanel gui;
@ -37,7 +40,19 @@ class ofTeleprompter: public ofBaseApp{
/* script */ /* script */
std::vector<Line> script; std::vector<Line> script;
std::string filePath = "text/Macebth.json"; std::string filePath = "text/Macbeth.json";
int currentLine = 0;
std::string currentLineString = "N/A";
const char* emotions[7] = {"anger", "disgust", "fear", "happiness", "neutral", "sadness", "surprise"};
/* scrolling text */
int currentLetterIndex = 0;
std::string currentSentence;
uint64_t lastWordTime = 0;
uint64_t wordDelay = 10;
std::string displayedSentence;
ofTrueTypeFont textFont;
ofTrueTypeFont detailsFont;
private: private:

Loading…
Cancel
Save