Cleanup
This commit is contained in:
parent
aae1a9224c
commit
383f8c057f
@ -1,54 +0,0 @@
|
||||
#include "csv.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
long int string2timestamp(const string &str)
|
||||
{
|
||||
struct tm tm{};
|
||||
if(strptime(str.c_str(), "%Y-%m-%d %H:%M:%S",&tm) == NULL)
|
||||
return -1;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
void read_record()
|
||||
{
|
||||
|
||||
// File pointer
|
||||
fstream fin;
|
||||
|
||||
// Open an existing file
|
||||
fin.open("danmaku.csv", ios::in);
|
||||
|
||||
// Read the Data from the file
|
||||
// as String Vector
|
||||
vector<string> row;
|
||||
string line, word, temp;
|
||||
|
||||
while (fin >> temp) {
|
||||
|
||||
row.clear();
|
||||
|
||||
// read an entire row and
|
||||
// store it in a string variable 'line'
|
||||
getline(fin, line);
|
||||
|
||||
// used for breaking words
|
||||
stringstream s(line);
|
||||
|
||||
// read every column data of a row and
|
||||
// store it in a string variable, 'word'
|
||||
while (getline(s, word, '|')) {
|
||||
|
||||
// add all the column data
|
||||
// of a row to a vector
|
||||
row.push_back(word);
|
||||
}
|
||||
|
||||
cout << "Time:" << row[0] << "Timestamp" << string2timestamp("2022-01-08" + row[0]) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
read_record();
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#ifndef _CSV_H_
|
||||
#define _CSV_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <locale.h>
|
||||
#include <time.h>
|
||||
|
||||
void read_record();
|
||||
long int string2timestamp(const std::string &);
|
||||
#endif
|
33391
src/old/csv/danmaku.csv
33391
src/old/csv/danmaku.csv
File diff suppressed because it is too large
Load Diff
BIN
src/old/csv/main
BIN
src/old/csv/main
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,54 +0,0 @@
|
||||
POLLING_URL_1 = 'https://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=polling&t=OLd_JZ8'
|
||||
POLLING_URL_2 = 'https://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=polling&t=OLd_JZ8-&sid={}'
|
||||
POLLING_URL_3 = 'https://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=polling&t=OLd_JZY_&sid={}'
|
||||
POLLING_URL_4 = 'https://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=polling&t=OLd_JZ8&sid={}'
|
||||
POLLING_URL_5 = 'https://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=polling&t=OLd_JZ8&sid={}'
|
||||
|
||||
HEADER = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'
|
||||
}
|
||||
HEADER_WSS = {
|
||||
'Host': 'bigapple.cytu.be:8443',
|
||||
'Connection': 'Upgrade',
|
||||
'Pragma': 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Upgrade': 'websocket',
|
||||
'Origin': 'https://cytu.be',
|
||||
'Sec-WebSocket-Version': '13',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
'Sec-GPC': '1',
|
||||
'Sec-WebSocket-Key': '7wfF6vVBt2fOUj5JRhVoPA==',
|
||||
'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits'}
|
||||
|
||||
WSS_URL = 'wss://bigapple.cytu.be:8443/socket.io/?EIO=4&transport=websocket&sid={}'
|
||||
|
||||
class Parser:
|
||||
'''
|
||||
Makes socket messages into a python objects if possible and returns a representation (dict, df, ts, ...) thereof.
|
||||
'''
|
||||
def parser(self, message):
|
||||
#def pyify(obj):
|
||||
# # Check if obj is already a pyobj
|
||||
# if not type(obj) in [str]: return obj
|
||||
# try: return eval(obj)
|
||||
# except Exception as e: print('Parser::parser: Error {}'.format(e))
|
||||
|
||||
## Check for bools
|
||||
#pretty = message.replace('true', 'True')
|
||||
#pretty = pretty.replace('false', 'False')
|
||||
#pretty = pretty.replace('null', 'None')
|
||||
|
||||
# Send the raw payload to a specific sub-parser
|
||||
try:
|
||||
res = getattr(self, message_type)(raw_payload)
|
||||
return message_type, res
|
||||
except Exception as e: print('Parser::parser: Error while sending a message of type "{}" to sub-parser:\n{}'.format(message_type), e)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,99 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Reader
|
||||
from datetime import datetime
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import sys
|
||||
|
||||
import csv
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import fcntl, os
|
||||
|
||||
|
||||
FILENAME = "data/danmaku.csv"
|
||||
DATE_FORMAT = "%d/%m/%Y %H:%M:%S"
|
||||
READER_REFRESH_RATE = 100
|
||||
SEND_BUFFER_SIZE = 2048
|
||||
|
||||
class CSV_Reader(threading.Thread):
|
||||
def __init__(self, queue, videoStartTime, *args, **kwargs):
|
||||
super(CSV_Reader, self).__init__(*args, **kwargs)
|
||||
|
||||
self._stop_event = threading.Event()
|
||||
self.queue = queue
|
||||
self.is_on = False
|
||||
|
||||
self.video_zero_time = videoStartTime
|
||||
self.video_zero_time_relative = None
|
||||
self.danmaku_zero_time = None
|
||||
self.danmaku_time_delta = 0
|
||||
|
||||
# SOCKET
|
||||
self.server_ip = "localhost"
|
||||
self.server_port = 10000
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((self.server_ip, self.server_port))
|
||||
fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
|
||||
def run(self):
|
||||
print("::Running CSV_Reader")
|
||||
self.is_on = True
|
||||
|
||||
with open(FILENAME, newline='') as csvfile:
|
||||
spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
|
||||
|
||||
while self.is_on:
|
||||
raw_time, raw_data = next(spamreader)
|
||||
d_time = datetime.strptime(raw_time, DATE_FORMAT)
|
||||
ts_time = int(datetime.timestamp(d_time))
|
||||
|
||||
# Set starting point
|
||||
if self.danmaku_zero_time == None:
|
||||
self.video_zero_time_relative = time.time()
|
||||
self.video_zero_time_zero = ts_time
|
||||
self.danmaku_zero_time = ts_time
|
||||
|
||||
video_elapsed = 0
|
||||
delta_time = 1
|
||||
while delta_time > video_elapsed:
|
||||
# Time elapsed relative to the video
|
||||
video_elapsed = time.time() - self.video_zero_time_relative
|
||||
delta_time = ts_time - self.danmaku_zero_time
|
||||
|
||||
# Sleep
|
||||
time.sleep(READER_REFRESH_RATE*0.001)
|
||||
|
||||
print("time: {} ## data: {} ## delta: {}".format(raw_time, raw_data, delta_time))
|
||||
data = bytes(raw_data, "utf-8")
|
||||
data += bytes(SEND_BUFFER_SIZE-len(data))
|
||||
self.sock.send(data)
|
||||
|
||||
def stop(self):
|
||||
print("::Stopping Watcher")
|
||||
self.is_on = False
|
||||
self._stop_event.set()
|
||||
|
||||
def toggle(self):
|
||||
if self.is_on:
|
||||
print("::Pausing Watcher")
|
||||
self.is_on = False
|
||||
elif not self.is_on:
|
||||
self.run()
|
||||
|
||||
def stopped(self):
|
||||
return self._stop_event.is_set()
|
||||
|
||||
def main():
|
||||
videoStartTime = 0
|
||||
if len(sys.argv) == 2:
|
||||
VideoStartTime = sys.argv[1]
|
||||
|
||||
Q = queue.Queue()
|
||||
R = CSV_Reader(Q, videoStartTime)
|
||||
R.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Binary file not shown.
Binary file not shown.
@ -1,84 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
# Reader
|
||||
from datetime import datetime
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import sys
|
||||
|
||||
import csv
|
||||
|
||||
FILENAME = "data/danmaku.csv"
|
||||
DATE_FORMAT = "%d/%m/%Y %H:%M:%S"
|
||||
READER_REFRESH_RATE = 100
|
||||
|
||||
class CSV_Reader(threading.Thread):
|
||||
def __init__(self, queue, videoStartTime, *args, **kwargs):
|
||||
super(CSV_Reader, self).__init__(*args, **kwargs)
|
||||
|
||||
self._stop_event = threading.Event()
|
||||
self.queue = queue
|
||||
self.is_on = False
|
||||
|
||||
self.video_zero_time = videoStartTime
|
||||
self.video_zero_time_relative = None
|
||||
self.danmaku_zero_time = None
|
||||
self.danmaku_time_delta = 0
|
||||
|
||||
def run(self):
|
||||
print("::Running CSV_Reader")
|
||||
self.is_on = True
|
||||
|
||||
with open(FILENAME, newline='') as csvfile:
|
||||
spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
|
||||
|
||||
while self.is_on:
|
||||
raw_time, raw_data = next(spamreader)
|
||||
d_time = datetime.strptime(raw_time, DATE_FORMAT)
|
||||
ts_time = int(datetime.timestamp(d_time))
|
||||
|
||||
# Set starting point
|
||||
if self.danmaku_zero_time == None:
|
||||
self.video_zero_time_relative = time.time()
|
||||
self.video_zero_time_zero = ts_time
|
||||
self.danmaku_zero_time = ts_time
|
||||
|
||||
video_elapsed = 0
|
||||
delta_time = 1
|
||||
while delta_time > video_elapsed:
|
||||
# Time elapsed relative to the video
|
||||
video_elapsed = time.time() - self.video_zero_time_relative
|
||||
delta_time = ts_time - self.danmaku_zero_time
|
||||
|
||||
# Sleep
|
||||
time.sleep(READER_REFRESH_RATE*0.001)
|
||||
|
||||
print("time: {} ## data: {} ## delta: {}".format(raw_time, raw_data, delta_time))
|
||||
self.queue.put(raw_data)
|
||||
|
||||
def stop(self):
|
||||
print("::Stopping Watcher")
|
||||
self.is_on = False
|
||||
self._stop_event.set()
|
||||
|
||||
def toggle(self):
|
||||
if self.is_on:
|
||||
print("::Pausing Watcher")
|
||||
self.is_on = False
|
||||
elif not self.is_on:
|
||||
self.run()
|
||||
|
||||
def stopped(self):
|
||||
return self._stop_event.is_set()
|
||||
|
||||
def main():
|
||||
videoStartTime = 0
|
||||
if len(sys.argv) == 2:
|
||||
VideoStartTime = sys.argv[1]
|
||||
|
||||
Q = queue.Queue()
|
||||
R = CSV_Reader(Q, videoStartTime)
|
||||
R.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,21 +0,0 @@
|
||||
from csv_reader import *
|
||||
from csv_socket import *
|
||||
|
||||
def main():
|
||||
Q = queue.Queue()
|
||||
|
||||
S = CSV_Socket(Q)
|
||||
R = CSV_Reader(Q)
|
||||
|
||||
S.start()
|
||||
R.start()
|
||||
|
||||
try:
|
||||
while 1:
|
||||
time.sleep(0.1)
|
||||
except KeyboardInterrupt:
|
||||
S.stop()
|
||||
R.stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,87 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
""" client.py - Echo client for sending/receiving C-like structs via socket
|
||||
References:
|
||||
- Ctypes: https://docs.python.org/3/library/ctypes.html
|
||||
- Sockets: https://docs.python.org/3/library/socket.html
|
||||
"""
|
||||
|
||||
|
||||
import threading
|
||||
import socket
|
||||
import queue
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
from ctypes import *
|
||||
|
||||
DATE_FORMAT = "%d/%m/%Y %H:%M:%S"
|
||||
SERVER_REFRESH_RATE = 100
|
||||
|
||||
""" This class defines a C-like struct """
|
||||
class Payload(Structure):
|
||||
_fields_ = [("id", c_uint32),
|
||||
("counter", c_uint32),
|
||||
("data", c_wchar_p)]
|
||||
|
||||
class CSV_Socket(threading.Thread):
|
||||
def __init__(self, queue, *args, **kwargs):
|
||||
super(CSV_Socket, self).__init__(*args, **kwargs)
|
||||
self._stop_event = threading.Event()
|
||||
self.queue = queue
|
||||
self.is_on = False
|
||||
|
||||
self.server_addr = ('localhost', 2300)
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
def run(self):
|
||||
print("::Running CSV_Server")
|
||||
self.is_on = True
|
||||
|
||||
try:
|
||||
self.socket.connect(self.server_addr)
|
||||
print("Connected to {:s}".format(repr(self.server_addr)))
|
||||
|
||||
c = 0
|
||||
while self.is_on:
|
||||
if not self.queue.empty():
|
||||
raw_data = self.queue.get() + "\0"
|
||||
payload_out = Payload(c, len(raw_data), raw_data)
|
||||
print("Sending id={:d}, counter={:d}, data={}".format(payload_out.id,
|
||||
payload_out.counter,
|
||||
payload_out.data))
|
||||
nsent = self.socket.send(payload_out)
|
||||
# Alternative: s.sendall(...): coontinues to send data until either
|
||||
# all data has been sent or an error occurs. No return value.
|
||||
print("Sent {:d} bytes".format(nsent))
|
||||
|
||||
#buff = s.recv(sizeof(Payload))
|
||||
#payload_in = Payload.from_buffer_copy(buff)
|
||||
#print("Received id={:d}, counter={:d}, temp={}".format(payload_in.id,
|
||||
# payload_in.counter,
|
||||
# payload_in.data))
|
||||
|
||||
c += 1
|
||||
time.sleep(SERVER_REFRESH_RATE*0.001)
|
||||
except AttributeError as ae:
|
||||
print("Error creating the socket: {}".format(ae))
|
||||
except socket.error as se:
|
||||
print("Exception on socket: {}".format(se))
|
||||
finally:
|
||||
print("Closing socket")
|
||||
self.socket.close()
|
||||
|
||||
def stop(self):
|
||||
print("::Stopping Server")
|
||||
self.is_on = False
|
||||
self._stop_event.set()
|
||||
|
||||
def toggle(self):
|
||||
if self.is_on:
|
||||
print("::Pausing Server")
|
||||
self.is_on = False
|
||||
elif not self.is_on:
|
||||
self.run()
|
||||
|
||||
def stopped(self):
|
||||
return self._stop_event.is_set()
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
""" server.py - Echo server for sending/receiving C-like structs via socket
|
||||
References:
|
||||
- Ctypes: https://docs.python.org/3/library/ctypes.html
|
||||
- Sockets: https://docs.python.org/3/library/socket.html
|
||||
"""
|
||||
import codecs
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import random
|
||||
from ctypes import *
|
||||
|
||||
|
||||
""" This class defines a C-like struct """
|
||||
class Payload(Structure):
|
||||
_fields_ = [("id", c_uint32),
|
||||
("counter", c_uint32),
|
||||
("data", c_wchar_p)]
|
||||
def main():
|
||||
PORT = 2300
|
||||
server_addr = ('localhost', PORT)
|
||||
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
print("Socket created")
|
||||
|
||||
try:
|
||||
# bind the server socket and listen
|
||||
ssock.bind(server_addr)
|
||||
print("Bind done")
|
||||
ssock.listen(3)
|
||||
print("Server listening on port {:d}".format(PORT))
|
||||
|
||||
while True:
|
||||
csock, client_address = ssock.accept()
|
||||
print("Accepted connection from {:s}".format(client_address[0]))
|
||||
|
||||
buff = csock.recv(512)
|
||||
while buff:
|
||||
print("\nReceived {:d} bytes".format(len(buff)))
|
||||
payload_in = Payload.from_buffer_copy(buff)
|
||||
t = payload_in.data
|
||||
#print("Received contents id={:d}, counter={:d}, data={}".format(payload_in.id, payload_in.counter, payload_in.data))
|
||||
buff = csock.recv(512)
|
||||
|
||||
print("Closing connection to client")
|
||||
print("----------------------------")
|
||||
csock.close()
|
||||
|
||||
except AttributeError as ae:
|
||||
print("Error creating the socket: {}".format(ae))
|
||||
except socket.error as se:
|
||||
print("Exception on socket: {}".format(se))
|
||||
except KeyboardInterrupt:
|
||||
ssock.close()
|
||||
finally:
|
||||
print("Closing socket")
|
||||
ssock.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,5 +0,0 @@
|
||||
from wsInterface import *
|
||||
|
||||
if __name__ == "__main__":
|
||||
S = Socket_()
|
||||
S.listenForever()
|
@ -1,104 +0,0 @@
|
||||
import json
|
||||
import queue
|
||||
import requests
|
||||
import websocket
|
||||
|
||||
from helper import *
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import fcntl, os
|
||||
|
||||
SEND_BUFFER_SIZE = 2048
|
||||
connected = 0
|
||||
|
||||
try: import thread
|
||||
except ImportError: import _thread as thread
|
||||
|
||||
class Socket_:
|
||||
def __init__(self, queue = None):
|
||||
self.URL = None
|
||||
self.sid = None
|
||||
self.sidWSS = None
|
||||
self.parser = Parser().parser
|
||||
self.queue = queue
|
||||
self.ws = None
|
||||
|
||||
self.sock = None
|
||||
|
||||
# Start the connection
|
||||
self.handshake()
|
||||
|
||||
def handshake(self):
|
||||
# First, establish a polling-transport HTTP connection
|
||||
resp_1 = requests.get(POLLING_URL_1, headers = HEADER)
|
||||
print('Resp 1: ', resp_1.text)
|
||||
# Ignore the bin-packed preliminaries and extract the session ID
|
||||
# WOTOS: self.sid = json.loads(str(resp_1.content)[3:-1])['sid']
|
||||
self.sid = json.loads(str(resp_1.content)[3:-1])['sid']
|
||||
# Second polling with POST, response should be 'ok'
|
||||
resp_2 = requests.post(POLLING_URL_2.format(self.sid), headers = HEADER, data = b'40')
|
||||
print('Resp 2: ', resp_2.text)
|
||||
# Third polling
|
||||
resp_3 = requests.get(POLLING_URL_3.format(self.sid), headers = HEADER)
|
||||
print('Resp 3: ', resp_3.text)
|
||||
# WOTOS: self.sid = json.loads(str(resp_1.content)[3:-1])['sid']
|
||||
index = str(resp_3.content).find('\\x1e42[')
|
||||
substr = str(resp_3.content)[4:index]
|
||||
self.sidWSS = json.loads(substr)['sid']
|
||||
# Fourth polling with POST
|
||||
resp_4 = requests.post(POLLING_URL_4.format(self.sid), headers = HEADER, data = b'42["joinChannel",{"name":"testam"}]')
|
||||
print('Resp 4: ', resp_4.text)
|
||||
# Fourth polling with GET
|
||||
resp_5 = requests.get(POLLING_URL_5.format(self.sid), headers = HEADER)
|
||||
print('Resp 5: ', resp_5.text)
|
||||
|
||||
|
||||
# WSS url
|
||||
self.URL = WSS_URL.format(self.sid)
|
||||
print(self.URL)
|
||||
|
||||
def on_open(self, ws):
|
||||
print('### Socket open ###')
|
||||
ws.send("2probe")
|
||||
def on_close(self, ws):
|
||||
print("### Socket closed ###")
|
||||
self.sock.close()
|
||||
def on_error(self, ws, error):
|
||||
print('\nSocket error :\n{}\n'.format(error))
|
||||
|
||||
def on_message(self, ws, message):
|
||||
if message == '2': ws.send('3')
|
||||
elif message == '3probe': ws.send('5')
|
||||
elif message[:2] == '42':
|
||||
j = message[2:].replace("'", '"')
|
||||
parsed = json.loads(j)
|
||||
print("received: ", message)
|
||||
reason = parsed[0]
|
||||
if reason == 'chatMsg':
|
||||
data = bytes(parsed[1]['msg'], "utf-8")
|
||||
data += bytes(SEND_BUFFER_SIZE-len(data))
|
||||
self.sock.send(data)
|
||||
print(data)
|
||||
else: pass
|
||||
|
||||
def listenForever(self):
|
||||
# SOCKET
|
||||
server_ip = "localhost"
|
||||
server_port = 10000
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((server_ip, server_port))
|
||||
fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
|
||||
try:
|
||||
#websocket.enableTrace(True)
|
||||
self.ws = websocket.WebSocketApp(self.URL,
|
||||
on_open = self.on_open,
|
||||
on_message = self.on_message,
|
||||
on_error = self.on_error,
|
||||
on_close = self.on_close,
|
||||
header = HEADER_WSS
|
||||
)
|
||||
self.ws.run_forever(ping_interval = 25, ping_timeout = 5 )
|
||||
except Exception as e:
|
||||
print("Socket::ListenForever: Exception {}", format(e))
|
@ -1,208 +0,0 @@
|
||||
#include "danmaku.h"
|
||||
|
||||
/// This is so fucking bad, just store everything and redraw with a translation in the shader holy shit
|
||||
float RenderText(Shader s, std::string text, float x, float y, float scale, glm::vec3 color, uint &VAO, uint &VBO, std::map<char, Character>& Characters, float window_width)
|
||||
{
|
||||
|
||||
// activate corresponding render state
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
s.use();
|
||||
|
||||
glUniform3f(glGetUniformLocation(s.ID, "textColor"), color.x, color.y, color.z);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
Character ch;
|
||||
|
||||
float xpos;
|
||||
float ypos;
|
||||
float w;
|
||||
float h;
|
||||
|
||||
// iterate through all characters
|
||||
std::string::const_iterator c;
|
||||
for (c = text.begin(); c != text.end(); c++)
|
||||
{
|
||||
ch = Characters[*c];
|
||||
|
||||
xpos = x + ch.Bearing.x * scale;
|
||||
ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
|
||||
|
||||
w = ch.Size.x * scale;
|
||||
h = ch.Size.y * scale;
|
||||
// update VBO for each character
|
||||
float vertices[6][4] = {
|
||||
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||
{ xpos, ypos, 0.0f, 1.0f },
|
||||
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||
|
||||
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||
{ xpos + w, ypos + h, 1.0f, 0.0f }
|
||||
};
|
||||
// render glyph texture over quad
|
||||
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
|
||||
// update content of VBO memory
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
// render quad
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
||||
x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return xpos;
|
||||
}
|
||||
|
||||
//// Create bitmaps for text rendering
|
||||
void makeBitmaps(std::map<char, Character>& Characters){
|
||||
///////// FREETYPE2 INIT
|
||||
FT_Library ft;
|
||||
if (FT_Init_FreeType(&ft)){
|
||||
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
FT_Face face;
|
||||
if (FT_New_Face(ft, "/usr/share/fonts/TTF/DejaVuSans.ttf", 0, &face)){
|
||||
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
|
||||
for (unsigned char c = 0; c < 128; c++){
|
||||
// load character glyph
|
||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
|
||||
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
|
||||
continue;
|
||||
}
|
||||
// generate texture
|
||||
unsigned int texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RED,
|
||||
face->glyph->bitmap.width,
|
||||
face->glyph->bitmap.rows,
|
||||
0,
|
||||
GL_RED,
|
||||
GL_UNSIGNED_BYTE,
|
||||
face->glyph->bitmap.buffer
|
||||
);
|
||||
// set texture options
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// now store character for later use
|
||||
Character character = {
|
||||
texture,
|
||||
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
|
||||
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
|
||||
face->glyph->advance.x
|
||||
};
|
||||
Characters.insert(std::pair<char, Character>(c, character));
|
||||
}
|
||||
/// Clear glyphs
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(ft);
|
||||
}
|
||||
|
||||
//TODO: Status <->
|
||||
|
||||
/*
|
||||
Sets nextRow to the index of the next free danmaku row and returns 1 if one is available, returns 0 otherwise.
|
||||
*/
|
||||
int getNextDanmakuRow(uint *ph_danmakuRows, int length, uint *nextRow) {
|
||||
for(int row = 0; row < length; row++) {
|
||||
if( (ph_danmakuRows)[row] ){
|
||||
*nextRow = row;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Flips the status of the danmaku row.
|
||||
*/
|
||||
int updateDanmakuRow(uint *ph_danmakuRows, uint row) {
|
||||
ph_danmakuRows[row] = !ph_danmakuRows[row];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Updates danmaku array according to the delta between last frame and current frame.
|
||||
*/
|
||||
int updateDanmakus(Render *r){
|
||||
|
||||
// Amount of pixels to translate the danmakus by
|
||||
float deltaPix = DANMAKU_SPEED*delta;
|
||||
// Last glyph x-position (last pixel on the string)
|
||||
float lastPix = 0.0f;
|
||||
|
||||
// Keep track of danmaku index
|
||||
uint danmakuIndex = 0;
|
||||
|
||||
for(Danmaku &danmaku : danmakus) {
|
||||
if(danmaku.isNew) {
|
||||
// Try to assign the new danmaku's row to a free slot
|
||||
if(getNextDanmakuRow(ph_danmakuRows, nb_danmakuRows, &(danmaku.row))){
|
||||
// Compute the height for that row
|
||||
danmaku.ypos = (r->h - DANMAKU_MARGIN_TOP) -
|
||||
(danmaku.row + 1) * (DANMAKU_PADDING_V + GLYPH_SIZE);
|
||||
danmaku.xpos = r->w;
|
||||
// Set the slot to unavailable
|
||||
updateDanmakuRow(ph_danmakuRows, danmaku.row);
|
||||
danmaku.tailCheck = 0;
|
||||
}
|
||||
danmaku.isNew = 0;
|
||||
}
|
||||
else {
|
||||
// Translate danmaku
|
||||
danmaku.xpos -= deltaPix;
|
||||
}
|
||||
|
||||
// Draw the danmaku and get tail position
|
||||
lastPix = RenderText(r, danmaku.text, danmaku.xpos, danmaku.ypos, 1.0f, glm::vec3(0.0, 0.26f, 0.0f));
|
||||
if(lastPix + DANMAKU_PADDING_H < 0) {
|
||||
danmakus.erase(danmakus.begin() + danmakuIndex);
|
||||
}
|
||||
|
||||
// Check if the tail of the danmaku is free (only check once)
|
||||
if(!danmaku.tailCheck && (r->w > lastPix + (float)DANMAKU_PADDING_H)) {
|
||||
// Free the row slot
|
||||
updateDanmakuRow(ph_danmakuRows, danmaku.row);
|
||||
danmaku.tailCheck = 1;
|
||||
}
|
||||
}
|
||||
danmakuIndex++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
OverlayHandler() {
|
||||
init();
|
||||
}
|
||||
|
||||
int OverlayHandler::init() {
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
#ifndef _DANMAKU_H_
|
||||
#define _DANMAKU_H_
|
||||
|
||||
#include <shader.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#define GLYPH_SIZE 36
|
||||
#define DANMAKU_MARGIN_TOP 50
|
||||
#define DANMAKU_MARGIN_BOT 50
|
||||
#define DANMAKU_PADDING_H 200
|
||||
#define DANMAKU_PADDING_V 20
|
||||
#define DANMAKU_SPEED_V 200.0f
|
||||
|
||||
// Glyphs
|
||||
typedef struct Character {
|
||||
unsigned int TextureID; // ID handle of the glyph texture
|
||||
glm::ivec2 Size; // Size of glyph
|
||||
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
|
||||
long int Advance; // Offset to advance to next glyph
|
||||
} Character;
|
||||
|
||||
// Danmaku
|
||||
typedef struct Danmaku {
|
||||
std::string text;
|
||||
uint isActive;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint isNew;
|
||||
uint row;
|
||||
uint tailCheck;
|
||||
} Danmaku;
|
||||
|
||||
class OverlayHandler() {
|
||||
public:
|
||||
OverlayHandler();
|
||||
|
||||
float RenderText(Shader, std::string, float, float, float, glm::vec3, uint &, uint &, std::map<char, Character>&);
|
||||
|
||||
int init();
|
||||
|
||||
private:
|
||||
unsigned int VAO, VBO;
|
||||
|
||||
void makeBitmaps(std::map<char, Character> &);
|
||||
|
||||
Shader *glyphShader = new Shader("shaders/glyph_vs.glsl", "shaders/glyph_fs.glsl");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int getNextDanmakuRow(uint *, int, uint* );
|
||||
int updateDanmakuRow(uint *, uint);
|
||||
|
||||
int updateDanmakus(Danmaku *, float);
|
||||
#endif
|
@ -1,59 +0,0 @@
|
||||
#include "danmaku.h"
|
||||
|
||||
//// Create bitmaps for text rendering
|
||||
void makeBitmaps(std::map<char, Character>& Characters){
|
||||
///////// FREETYPE2 INIT
|
||||
FT_Library ft;
|
||||
if (FT_Init_FreeType(&ft)){
|
||||
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
FT_Face face;
|
||||
if (FT_New_Face(ft, "/usr/share/fonts/TTF/DejaVuSans.ttf", 0, &face)){
|
||||
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
|
||||
for (unsigned char c = 0; c < 128; c++){
|
||||
// load character glyph
|
||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
|
||||
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
|
||||
continue;
|
||||
}
|
||||
// generate texture
|
||||
unsigned int texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RED,
|
||||
face->glyph->bitmap.width,
|
||||
face->glyph->bitmap.rows,
|
||||
0,
|
||||
GL_RED,
|
||||
GL_UNSIGNED_BYTE,
|
||||
face->glyph->bitmap.buffer
|
||||
);
|
||||
// set texture options
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// now store character for later use
|
||||
Character character = {
|
||||
texture,
|
||||
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
|
||||
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
|
||||
face->glyph->advance.x
|
||||
};
|
||||
Characters.insert(std::pair<char, Character>(c, character));
|
||||
}
|
||||
/// Clear glyphs
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(ft);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#ifndef _OVERLAY_H_
|
||||
#define _OVERLAY_H_
|
||||
|
||||
#include <shader.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#define GLYPH_SIZE 36
|
||||
#define DANMAKU_MARGIN_TOP 50
|
||||
#define DANMAKU_MARGIN_BOT 50
|
||||
#define DANMAKU_PADDING_H 200
|
||||
#define DANMAKU_PADDING_V 20
|
||||
#define DANMAKU_SPEED_V 200.0f
|
||||
|
||||
// Glyphs
|
||||
typedef struct Character {
|
||||
unsigned int TextureID; // ID handle of the glyph texture
|
||||
glm::ivec2 Size; // Size of glyph
|
||||
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
|
||||
long int Advance; // Offset to advance to next glyph
|
||||
} Character;
|
||||
|
||||
// Danmaku
|
||||
typedef struct Danmaku {
|
||||
std::string text;
|
||||
uint isActive;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint isNew;
|
||||
uint row;
|
||||
uint tailCheck;
|
||||
} Danmaku;
|
||||
|
||||
class Overlay() {
|
||||
public:
|
||||
OverlayHandler();
|
||||
int init();
|
||||
|
||||
private:
|
||||
void makeBitmaps(std::map<char, Character> &);
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user