Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

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