ok now it works nicely in VR
[vrtris] / src / osd.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <drawtext.h>
5 #include <cgmath/cgmath.h>
6 #include "opengl.h"
7 #include "osd.h"
8 #include "game.h"
9
10 #define FONTSZ  16
11
12 static int init(void);
13
14 struct message {
15         long start_time, show_until;
16         char *str;
17         cgm_vec3 color;
18         struct message *next;
19 };
20 static struct message *msglist;
21
22 struct text {
23         char *str;
24         cgm_vec2 pos;
25         cgm_vec3 color;
26         struct text *next;
27 };
28 static struct text *txlist;
29
30 static long timeout = 2000;
31 static long trans_time = 250;
32
33 int ui_font_size = FONTSZ;
34
35 void set_message_timeout(long tm)
36 {
37         timeout = tm;
38 }
39
40 void osd_printf(const char *fmt, ...)
41 {
42         va_list ap;
43         va_start(ap, fmt);
44         show_messagev(timeout, 1, 1, 1, fmt, ap);
45         va_end(ap);
46 }
47
48 void show_message(long timeout, float r, float g, float b, const char *fmt, ...)
49 {
50         va_list ap;
51         va_start(ap, fmt);
52         show_messagev(timeout, r, g, b, fmt, ap);
53         va_end(ap);
54 }
55
56 void show_messagev(long timeout, float r, float g, float b, const char *fmt, va_list ap)
57 {
58         char buf[512];
59         struct message *msg;
60         struct message dummy;
61         int len;
62
63         init();
64
65         vsnprintf(buf, sizeof buf, fmt, ap);
66
67         if(!(msg = malloc(sizeof *msg))) {
68                 perror("failed to allocate memory");
69                 abort();
70         }
71         len = strlen(buf);
72         if(!(msg->str = malloc(len + 1))) {
73                 perror("failed to allocate memory");
74                 abort();
75         }
76         memcpy(msg->str, buf, len + 1);
77         msg->start_time = time_msec;
78         msg->show_until = time_msec + timeout;
79         msg->color.x = r;
80         msg->color.y = g;
81         msg->color.z = b;
82
83         dummy.next = msglist;
84         struct message *prev = &dummy;
85         while(prev->next && prev->next->show_until < msg->show_until) {
86                 prev = prev->next;
87         }
88         msg->next = prev->next;
89         prev->next = msg;
90         msglist = dummy.next;
91 }
92
93 void print_text(float x, float y, float r, float g, float b, const char *fmt, ...)
94 {
95         va_list ap;
96         va_start(ap, fmt);
97         print_textv(x, y, r, g, b, fmt, ap);
98         va_end(ap);
99 }
100
101 void print_textv(float x, float y, float r, float g, float b, const char *fmt, va_list ap)
102 {
103         char buf[512];
104         int len;
105         struct text *tx;
106
107         init();
108
109         vsnprintf(buf, sizeof buf, fmt, ap);
110
111         if(!(tx = malloc(sizeof *tx))) {
112                 perror("failed to allocate memory");
113                 abort();
114         }
115         len = strlen(buf);
116         if(!(tx->str = malloc(len + 1))) {
117                 perror("failed to allocate memory");
118                 abort();
119         }
120         memcpy(tx->str, buf, len + 1);
121         tx->color.x = r;
122         tx->color.y = g;
123         tx->color.z = b;
124         tx->pos.x = x;
125         tx->pos.y = -y;
126
127         tx->next = txlist;
128         txlist = tx;
129 }
130
131 void draw_osd(void)
132 {
133         if(!ui_font) return;
134
135         while(msglist && msglist->show_until <= time_msec) {
136                 struct message *msg = msglist;
137                 msglist = msg->next;
138                 free(msg->str);
139                 free(msg);
140         }
141
142         dtx_use_font(ui_font, ui_font_size);
143
144         glMatrixMode(GL_PROJECTION);
145         glPushMatrix();
146         glLoadIdentity();
147         glOrtho(0, win_width, -win_height, 0, -1, 1);
148         glMatrixMode(GL_MODELVIEW);
149         glPushMatrix();
150         glLoadIdentity();
151
152         glPushAttrib(GL_ENABLE_BIT);
153         glDisable(GL_LIGHTING);
154         glDisable(GL_DEPTH_TEST);
155         glEnable(GL_BLEND);
156         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
157         glUseProgram(0);
158
159         struct message *msg = msglist;
160         while(msg) {
161                 long t = time_msec - msg->start_time;
162                 long dur = msg->show_until - msg->start_time;
163                 float alpha = cgm_smoothstep(0, trans_time, t) *
164                         (1.0 - cgm_smoothstep(dur - trans_time, dur, t));
165                 glColor4f(msg->color.x, msg->color.y, msg->color.z, alpha);
166                 glTranslatef(0, -dtx_line_height(), 0);
167                 dtx_string(msg->str);
168                 msg = msg->next;
169         }
170
171         while(txlist) {
172                 struct text *tx = txlist;
173                 txlist = txlist->next;
174
175                 glMatrixMode(GL_MODELVIEW);
176                 glLoadIdentity();
177                 glTranslatef(tx->pos.x, tx->pos.y, 0);
178
179                 glColor3f(tx->color.x, tx->color.y, tx->color.z);
180                 dtx_string(tx->str);
181
182                 free(tx->str);
183                 free(tx);
184         }
185
186         glPopAttrib();
187
188         glMatrixMode(GL_PROJECTION);
189         glPopMatrix();
190         glMatrixMode(GL_MODELVIEW);
191         glPopMatrix();
192 }
193
194 static int init(void)
195 {
196         static int done_init;
197         if(done_init) return 0;
198
199         done_init = 1;
200
201         if(!(ui_font = dtx_open_font("data/ui.font", 0))) {
202                 fprintf(stderr, "failed to open font: data/ui.font\n");
203                 return -1;
204         }
205         dtx_prepare_range(ui_font, ui_font_size, 32, 127);
206         return 0;
207 }