Move Tournament and FetchCurrentTournament into its own file.
[ccbs] / bigscreen / ccbs_bigscreen.cpp
1 #include <cstdio>
2 #include <cstring>
3 #include <iconv.h>
4 #include <unistd.h>
5 #include <pqxx/pqxx>
6 #include <ft2build.h>
7 #include FT_FREETYPE_H
8 #include <tinyptc.h>
9 #include "flagtrigger.h"
10 #include "widestring.h"
11 #include "fetch_current_tournament.h"
12
13 int my_draw_text(const widestring &str, unsigned char *buf, int xpos, int ypos, bool real_render, int r, int g, int b, std::vector<FT_Face> &fontlist);
14
15 Tournament active_tournament;
16 std::vector<FT_Face> fonts;
17
18 void init(pqxx::connection &conn)
19 {
20         conn.perform(FetchCurrentTournament(&active_tournament));
21
22         if (active_tournament.id == -1) {
23                 std::fprintf(stderr, "No active tournament\n");
24         } else {
25                 std::fprintf(stderr, "Current tournament is %d (name: '%s')\n",
26                         active_tournament.id, active_tournament.name.c_str());
27         }
28 }
29
30 unsigned char framebuf[800 * 600 * 4];
31
32 void main_loop(pqxx::connection &conn)
33 {
34         if (active_tournament.id == -1) {
35                 // No active tournament, sleep a second or so and exit
36                 sleep(1);
37                 return;
38         }
39
40         memset(framebuf, 0, 800*600*4);
41         
42         pqxx::work t(conn, "trx");
43
44         // fetch all songs
45         pqxx::result res( t.exec("SELECT * FROM songs WHERE title LIKE 'M%'") );
46         unsigned y = 0;
47         for (pqxx::result::const_iterator i = res.begin(); i != res.end(); ++i) {
48                 my_draw_text(i["title"].as(widestring()), framebuf, 0, y, 1, 255, 255, 255, fonts);
49                 y += 20;
50 //              std::fprintf(stderr, "%s\n", i["title"].c_str());
51         }
52         t.commit();
53
54         ptc_update(framebuf);
55         sleep(1);
56 }
57
58 void init_freetype()
59 {
60         FT_Library library;
61         FT_Face face;
62         if (FT_Init_FreeType(&library))
63                 throw std::runtime_error("FreeType init failed.");
64
65         // Georgia
66         if (FT_New_Face(library, "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf", 0, &face))
67                 throw std::runtime_error("Face opening failed.");
68         if (FT_Set_Char_Size(face, 0, 12 * 64, 96, 96))
69                 throw std::runtime_error("Size set failed.");
70         fonts.push_back(face);
71
72         // FreeSerif
73         if (FT_New_Face(library, "/usr/share/fonts/truetype/freefont/FreeSerif.ttf", 0, &face)) {
74                 std::fprintf(stderr, "Warning: Couldn't open FreeSerif, some glyphs might not be available\n");
75         } else {
76                 if (FT_Set_Char_Size(face, 0, 12 * 64, 96, 96))
77                         throw std::runtime_error("Size set failed.");
78                 fonts.push_back(face);
79         }
80         
81         // Arial Unicode MS
82         if (FT_New_Face(library, "arialuni.ttf", 0, &face)) {
83                 std::fprintf(stderr, "Warning: Couldn't open Arial Unicode MS, some glyphs might not be available\n");
84         } else {
85                 if (FT_Set_Char_Size(face, 0, 12 * 64, 96, 96))
86                         throw std::runtime_error("Size set failed.");
87                 fonts.push_back(face);
88         }
89 }
90
91 int my_draw_text(const widestring &str, unsigned char *buf, int xpos, int ypos, bool real_render, int r, int g, int b, std::vector<FT_Face> &fontlist)
92 {
93         FT_GlyphSlot slot;
94         int x = 0;
95
96         for (widestring::const_iterator i = str.begin(); i != str.end(); ++i) {
97                 int glyph_index;
98                 for (std::vector<FT_Face>::const_iterator j = fontlist.begin(); j != fontlist.end(); ++j) {
99                         glyph_index = FT_Get_Char_Index(*j, *i);
100                         if (glyph_index == 0)
101                                 continue;
102
103                         if (FT_Load_Glyph(*j, glyph_index, FT_LOAD_RENDER))
104                                 throw std::runtime_error("Couldn't load glyph");
105                         slot = (*j)->glyph;
106                         break;
107                 }
108                 if (glyph_index == 0) {
109                         std::fprintf(stderr, "Warning: Could not find a glyph in any font for U+%x, ignoring\n", *i);
110                         continue;
111                 }
112
113                 if (real_render) {
114                         int y;
115                         FT_Bitmap *bm = &(slot->bitmap);
116                         for (y = 0; y < bm->rows; y++) {
117                                 int xx;
118                                 int dsty = ypos - slot->bitmap_top + y;
119                                 if (dsty < 0 || dsty > 599) continue;
120
121                                 unsigned char *dst = buf + dsty * 800*4 + (x + xpos + slot->bitmap_left)*4;
122                                 unsigned char *src = bm->buffer + y * bm->width;
123                                 for (xx = 0; xx < bm->width; xx++) {
124                                         *dst = (*dst * (256-*src) + r * *src) >> 8;
125                                         *dst++;
126                                         *dst = (*dst * (256-*src) + g * *src) >> 8;
127                                         *dst++;
128                                         *dst = (*dst * (256-*src) + b * *src) >> 8;
129                                         *dst++;
130                                         *dst++ = 0;
131                                         src++;
132                                 }
133                         }
134                 }
135
136                 x += slot->advance.x >> 6;
137         }
138
139         return x;
140 }
141
142
143 int main(int argc, char **argv)
144 {
145         ptc_open("CCBS bigscreen", 800, 600);
146         
147         try {
148                 init_freetype();
149                 pqxx::connection conn("dbname=ccbs host=altersex.samfundet.no user=ccbs password=GeT|>>B_");
150                 FlagTrigger tournament_changed(conn, "active_tournament");
151                 FlagTrigger rounds_changed(conn, "active_groups");
152                 
153                 // when active_tournament or active_rounds is changed, we destroy everything and start from scratch
154                 // (at least currently)
155                 for ( ;; ) {
156                         tournament_changed.reset_flag();
157                         rounds_changed.reset_flag();
158                         init(conn);
159                         do {
160                                 main_loop(conn);
161                                 conn.get_notifs();
162                         } while (!tournament_changed.get_flag() && !rounds_changed.get_flag());
163                         std::fprintf(stderr, "active_tournament or active_groups changed, resetting...\n");
164                 }
165         } catch (const std::exception &e) {
166                 std::fprintf(stderr, "Exception: %s\n", e.what());
167                 exit(1);
168         }
169         
170         return 0;
171 }