Subversion Repositories gelsvn

Rev

Rev 563 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
561 awk 1
/**
2
 * @file   Console.h
3
 * @author Anders Wang Kristensen <awk@imm.dtu.dk>
4
 * @date   Fri Oct 22 18:32:06 2011
5
 *
6
 * @brief  OpenGL 'Quake'-like console
7
 */
8
 
9
#ifndef __GEL_GLGRAPHICS_CONSOLE_H__
10
#define __GEL_GLGRAPHICS_CONSOLE_H__
11
 
12
#include <GLGraphics/gel_gl.h>
13
 
14
#include <functional> //make_shared, bind
15
#include <map> //multimap
16
#include <sstream> //stringstream
17
#include <vector>
18
#include <cassert>
19
 
20
namespace GLGraphics {
21
 
22
class Console
23
{
24
public:
25
    Console();
26
    ~Console() throw();
27
 
28
    //GLUT functions
29
    void display();
30
    void keyboard(unsigned char key);
31
    void special(int key);
32
 
33
    //stdio-like io
34
    void print(const char* buffer);
35
    void printf(const char* format, ...);
36
    void newline();
37
 
38
    //execute command
39
    void execute(const char* buffer);
40
    void executef(const char* format, ...);
41
 
42
    typedef int cmd_token;
43
 
44
    //0-ary
45
    inline cmd_token reg_cmd(const std::string& name,
46
                             const std::function<void ()>& f,
47
                             const std::string& help);
48
 
49
    //1-ary
50
    template <typename A0>
51
    cmd_token reg_cmd(const std::string& name,
52
                      const std::function<void (const A0&)>& f,
53
                      const std::string& help);
54
 
55
    //2-ary
56
    template <typename A0, typename A1>
57
    cmd_token reg_cmd(const std::string& name,
58
                      const std::function<void (const A0&,const A1&)>& f,
59
                      const std::string& help);
60
 
61
    //3-ary
62
    template <typename A0, typename A1, typename A2>
63
    cmd_token reg_cmd(const std::string& name,
64
                      const std::function<void (const A0&,
65
                                                const A1&,const A2&)>& f,
66
                      const std::string& help);
67
 
68
    //remove
69
    inline void unreg_cmd(cmd_token);
70
 
71
    //get name/help of registrered command
72
    const char* get_name(cmd_token) const;
73
    const char* get_help(cmd_token) const;
74
 
75
    //helper classes
76
    class command;
77
 
78
    template <typename T>
79
    class variable;
80
 
81
private:
82
    //make noncopyable
83
    Console(Console&);
84
    const Console& operator=(const Console&);
85
 
86
    static inline void from_string(const std::string& source,
87
                                   std::string& target)
88
    {
89
        target = source;
90
    }
91
 
92
    template <typename T>
93
    static inline void from_string(const std::string& source, T& target)
94
    {
95
        std::stringstream ss(source);
96
        if (!(ss >> target))
97
        {
98
            std::stringstream ss;
99
            ss << "Cannot convert "
100
               << source << " to '" << typeid(T).name() << "'.";
101
            throw std::invalid_argument(ss.str());
102
        }
103
    }
104
 
105
    //from string
106
    template <typename T>
107
    static T lexical_cast(const std::string& source)
108
    {
109
        T target;
110
        from_string(source, target);
111
        return target;
112
    }
113
 
114
    //to string
115
    template <typename S>
116
    static std::string to_string(const S& source)
117
    {
118
        std::stringstream ss;
119
        if (!(ss << source))
120
        {
121
            //converting *to* string should never fail
122
            throw std::invalid_argument("Cannot convert argument to string.");
123
        }
124
 
125
        return ss.str();
126
    }
127
 
128
    class command_base
129
    {
130
    public:
131
        inline command_base(Console& c, const std::string& help)
132
            : m_console(c), m_help(help) { m_id = c.m_id_counter++; }
133
        virtual ~command_base() {}
134
 
135
        virtual void execute(const std::vector<std::string>& args) const = 0;
136
        virtual size_t arity() const = 0;
137
 
138
        inline cmd_token get_id() const { return m_id; }
139
 
140
        inline const char* get_help() const { return m_help.c_str(); }
141
 
142
    protected:
143
        Console& m_console;
144
        cmd_token m_id;
145
        std::string m_help;
146
    };
147
 
148
    //no need to be a template
149
    class command0 : public command_base
150
    {
151
    public:
152
        typedef std::function<void ()> function_type;
153
 
154
        inline command0(Console& c,
155
                        const std::string& h, const function_type& f)
156
            : command_base(c,h), m_callback(f) {}
157
 
158
        inline void execute(const std::vector<std::string>& args) const;
159
        inline size_t arity() const { return 0; }
160
 
161
    private:
162
        function_type m_callback;
163
    };
164
 
165
    template <typename A0>
166
    class command1 : public command_base
167
    {
168
    public:
169
        typedef typename std::function<void (const A0&)> function_type;
170
 
171
        command1(Console& c, const std::string& h, const function_type& f)
172
            : command_base(c,h), m_callback(f) {}
173
 
174
        void execute(const std::vector<std::string>& args) const;
175
        size_t arity() const { return 1; }
176
 
177
    private:
178
        function_type m_callback;
179
    };
180
 
181
    template <typename A0, typename A1>
182
    class command2 : public command_base
183
    {
184
    public:
185
        typedef typename std::function<void (const A0&,
186
                                             const A1&)> function_type;
187
 
188
        command2(Console& c, const std::string& h, const function_type& f)
189
            : command_base(c,h), m_callback(f) {}
190
 
191
        void execute(const std::vector<std::string>& args) const;
192
        size_t arity() const { return 2; }
193
 
194
    private:
195
        function_type m_callback;
196
    };
197
 
198
    template <typename A0, typename A1, typename A2>
199
    class command3 : public command_base
200
    {
201
    public:
202
        typedef typename std::function<void (const A0&,
203
                                             const A1&,
204
                                             const A2&)> function_type;
205
 
206
        command3(Console& c, const std::string& h, const function_type& f)
207
            : command_base(c,h), m_callback(f) {}
208
 
209
        void execute(const std::vector<std::string>& args) const;
210
        size_t arity() const { return 3; }
211
 
212
    private:
213
        function_type m_callback;
214
    };
215
 
216
    //multi, so we can have multiple cmds with same name (but different arity)
217
    typedef std::multimap<std::string,
218
                          std::unique_ptr<command_base> > command_map_t;
219
 
220
    cmd_token add_command(const std::string& name,
221
                           std::unique_ptr<command_base>&& ptr);
222
    void remove_command(cmd_token);
223
 
224
    void tab_completion();
225
 
226
    std::vector<std::string> parse_cmdline(const char* buffer) const;
227
 
228
    //builtin commands
229
    void help();
230
    void help(const std::string&);
231
    void clear();
232
    void history();
233
 
234
    void load_history();
235
    void save_history() const;
236
    void clear_history();
237
 
238
    //draw commands
239
    void draw_text(int x, int y,
240
                   float r, float g, float b,
241
                   const char* buffer);
242
 
243
    void draw_textf(int x, int y,
244
                    float r, float g, float b,
245
                    const char* fmt, ...);
246
    //state
247
    command_map_t m_commands;
248
    std::vector<std::string> m_buffer;
249
 
250
    size_t m_history_index;
251
    std::vector<std::string> m_history;
252
 
253
    std::string::size_type m_caret;
254
    std::string m_current_command;
255
 
256
    int m_id_counter;
257
    bool m_is_executing;
258
 
259
    GLuint m_font;
260
 
261
    static const unsigned char g_png_data[];
262
    static const size_t g_png_size;
263
};
264
 
265
//0-ary
266
Console::cmd_token Console::reg_cmd(const std::string& name,
267
                                    const std::function<void ()>& f,
268
                                    const std::string& help)
269
{
270
    typedef command0 command_type;
271
    return add_command(name,
272
        std::unique_ptr<command_type>(
273
            new command_type(std::ref(*this), help, f)));
274
}
275
 
276
void Console::command0::execute(const std::vector<std::string>& args) const
277
{
278
    assert(args.size() == arity());
279
    m_callback();
280
}
281
 
282
//1-ary
283
template <typename A0>
284
Console::cmd_token Console::reg_cmd(const std::string& name,
285
                                    const std::function<void (const A0&)>& f,
286
                                    const std::string& help)
287
{
288
    typedef command1<A0> command_type;
289
    return add_command(name,
290
        std::unique_ptr<command_type>(
291
            new command_type(std::ref(*this), help, f)));
292
}
293
 
294
template <typename A0>
295
void Console::command1<A0>::execute(const std::vector<std::string>& args) const
296
{
297
    assert(args.size() == arity());
298
    m_callback(lexical_cast<A0>(args[0]));
299
}
300
 
301
//2-ary
302
template <typename A0, typename A1>
303
Console::cmd_token Console::reg_cmd(const std::string& name,
304
                                    const std::function<void (const A0&,
305
                                      const A1&)>& f,
306
                                    const std::string& help)
307
{
308
    typedef command2<A0,A1> command_type;
309
    return add_command(name,
310
        std::unique_ptr<command_type>(
311
            new command_type(std::ref(*this), help, f)));
312
}
313
 
314
template <typename A0,typename A1>
315
void Console::command2<A0,A1>::execute(
316
    const std::vector<std::string>& args) const
317
{
318
    assert(args.size() == arity());
319
    m_callback(lexical_cast<A0>(args[0]),
320
               lexical_cast<A1>(args[1]));
321
}
322
 
323
//3-ary
324
template <typename A0, typename A1, typename A2>
325
Console::cmd_token Console::reg_cmd(const std::string& name,
326
                                    const std::function<void (const A0&,
327
                                      const A1&,const A2&)>& f,
328
                                    const std::string& help)
329
{
330
    typedef command3<A0,A1,A2> command_type;
331
    return add_command(name,
332
        std::unique_ptr<command_type>(
333
            new command_type(std::ref(*this), help, f)));
334
}
335
 
336
template <typename A0,typename A1, typename A2>
337
void Console::command3<A0,A1,A2>::execute(
338
    const std::vector<std::string>& args) const
339
{
340
    assert(args.size() == arity());
341
    m_callback(lexical_cast<A0>(args[0]),
342
               lexical_cast<A1>(args[1]),
343
               lexical_cast<A2>(args[2]));
344
}
345
 
346
void Console::unreg_cmd(cmd_token id)
347
{
348
    remove_command(id);
349
}
350
 
351
class Console::command
352
{
353
public:
354
    inline command() : m_console(NULL) {}
355
 
356
    inline void reg(Console& cs,
357
        const std::string& name,
358
        const std::function<void ()>& function,
359
        const std::string& help)
360
    {
361
        assert(!m_console);
362
        m_console = &cs;
363
        m_id = m_console->reg_cmd(name, function, help);
364
    }
365
 
366
    template <typename A0>
367
    void reg(Console& cs,
368
        const std::string& name,
369
        const std::function<void (const A0&)>& function,
370
        const std::string& help)
371
    {
372
        assert(!m_console);
373
        m_console = &cs;
374
        m_id = m_console->reg_cmd<A0>(name, function, help);
375
    }
376
 
377
    template <typename A0, typename A1>
378
    void reg(Console& cs,
379
        const std::string& name,
380
        const std::function<void (const A0&, const A1&)>& function,
381
        const std::string& help)
382
    {
383
        assert(!m_console);
384
        m_console = &cs;
385
        m_id = m_console->reg_cmd<A0,A1>(name, function, help);
386
    }
387
 
388
    template <typename A0, typename A1, typename A2>
389
    void reg(Console& cs,
390
        const std::string& name,
391
        const std::function<void (const A0&,
392
        const A1&, const A2&)>& function,
393
        const std::string& help)
394
    {
395
        assert(!m_console);
396
        m_console = &cs;
397
        m_id = m_console->reg_cmd<A0,A1,A2>(name, function, help);
398
    }
399
 
400
    inline ~command()
401
    {
402
        if (m_console)
403
            m_console->unreg_cmd(m_id);
404
    }
405
 
406
    inline const char* get_name() const
407
    {
408
        assert(m_console);
409
        return m_console->get_name(m_id);
410
    }
411
 
412
    inline const char* get_help() const
413
    {
414
        assert(m_console);
415
        return m_console->get_help(m_id);
416
    }
417
 
418
    inline Console* get_console() const { return m_console; }
419
    inline cmd_token get_id() const { assert(m_console); return m_id; }
420
 
421
private:
422
    command(command&);
423
    const command& operator=(const command&);
424
 
425
    Console* m_console;
426
    cmd_token m_id;
427
};
428
 
429
template <typename T>
430
class Console::variable
431
{
432
public:
433
    variable(const T& initial_value = T())
434
        : m_value(initial_value) {}
435
 
436
    void reg(Console& cs,
437
        const std::string& name,
438
        const std::string& help)
439
    {
440
        m_print_cmd.reg(cs, name,
441
            std::bind(&variable::print_value, this), help);
442
 
443
        m_set_cmd.reg<T>(cs, name,
444
            std::bind(&variable::set_value, this, std::placeholders::_1),
445
            help);
446
    }
447
 
448
    const variable& operator=(const T& value) { m_value = value; return *this; }
449
 
450
    operator const T&() const { return m_value; }
451
 
452
    const char* get_name() const { return m_print_cmd.get_name(); }
453
    const char* get_help() const { return m_print_cmd.get_help(); }
454
 
455
private:
456
    variable(const variable&);
457
    const variable& operator=(const variable&);
458
 
459
    void print_value()
460
    {
461
        m_print_cmd.get_console()->printf("%s = %s",
462
            m_print_cmd.get_name(),
463
            Console::to_string(m_value).c_str());
464
    }
465
 
466
    void set_value(const T& value)
467
    {
468
        m_value = value;
469
        m_print_cmd.get_console()->execute(m_print_cmd.get_name());
470
    }
471
 
472
    T m_value;
473
 
474
    command m_print_cmd;
475
    command m_set_cmd;
476
};
477
 
478
}
479
 
480
#endif //__GEL_GLGRAPHICS_CONSOLE_H__