Subversion Repositories gelsvn

Rev

Rev 601 | Rev 630 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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