Browse Source

* basic core design (Platform, Engine, Graphics classes)

* logger
* x11 platform implementation
Eduardo Bart 11 years ago
parent
commit
f58ce52be8
16 changed files with 1359 additions and 8 deletions
  1. 3
    0
      .gitignore
  2. 58
    1
      CMakeLists.txt
  3. 10
    0
      src/const.h
  4. 105
    0
      src/engine.cpp
  5. 40
    0
      src/engine.h
  6. 63
    0
      src/graphics.cpp
  7. 21
    0
      src/graphics.h
  8. 187
    0
      src/input.h
  9. 53
    0
      src/logger.cpp
  10. 22
    0
      src/logger.h
  11. 39
    0
      src/main.cpp
  12. 34
    0
      src/platform.h
  13. 30
    0
      src/util.cpp
  14. 10
    0
      src/util.h
  15. 684
    0
      src/x11platform.cpp
  16. 0
    7
      srcs/main.cpp

+ 3
- 0
.gitignore View File

@@ -4,4 +4,7 @@ CMakeCache.txt
4 4
 cmake_install.cmake
5 5
 Makefile
6 6
 otclient
7
+
8
+otclient.kdev4
9
+CMakeLists.txt.user
7 10
 !.gitignore

+ 58
- 1
CMakeLists.txt View File

@@ -1,4 +1,61 @@
1 1
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
2 2
 PROJECT(otclient)
3
-ADD_EXECUTABLE(otclient srcs/main.cpp)
3
+
4
+# find needed packages
5
+SET(Boost_USE_STATIC_LIBS ON)
6
+FIND_PACKAGE(Boost COMPONENTS thread filesystem REQUIRED)
7
+FIND_PACKAGE(OpenGL REQUIRED)
8
+FIND_PACKAGE(Lua51 REQUIRED)
9
+
10
+# choose a default build type if not specified
11
+IF(NOT CMAKE_BUILD_TYPE)
12
+    SET(CMAKE_BUILD_TYPE RelWithDebInfo)
13
+ENDIF(NOT CMAKE_BUILD_TYPE)
14
+MESSAGE(STATUS "BUILD TYPE: " ${CMAKE_BUILD_TYPE})
15
+
16
+# setup compiler options
17
+IF(CMAKE_COMPILER_IS_GNUCXX)
18
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wl,--as-needed")
19
+    SET(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -ggdb -fno-inline")
20
+    SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wl,-s")
21
+    SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
22
+ENDIF(CMAKE_COMPILER_IS_GNUCXX)
23
+
24
+INCLUDE_DIRECTORIES(
25
+${LUA_INCLUDE_DIRS}
26
+${Boost_INCLUDE_DIRS})
27
+
28
+LINK_DIRECTORIES(
29
+${Boost_LIBRARY_DIRS}
30
+${LUA_LIBRARY_DIRS})
31
+
32
+# setup definitions
33
+ADD_DEFINITIONS(-D_REENTRANT)
34
+
35
+IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
36
+    ADD_DEFINITIONS(-D_DEBUG)
37
+ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
38
+
39
+# find sources
40
+SET(SOURCES
41
+src/main.cpp
42
+src/engine.cpp
43
+src/graphics.cpp
44
+src/logger.cpp
45
+src/util.cpp)
46
+
47
+IF(WIN32)
48
+    SET(SOURCES ${SOURCES} src/win32platform.cpp)
49
+ELSE(WIN32)
50
+    SET(SOURCES ${SOURCES} src/x11platform.cpp)
51
+ENDIF(WIN32)
52
+
53
+# target executable
54
+ADD_EXECUTABLE(otclient ${SOURCES})
55
+
56
+# target link libraries
57
+TARGET_LINK_LIBRARIES(otclient
58
+${Boost_LIBRARIES}
59
+${OPENGL_LIBRARY}
60
+${LUA51_LIBRARY})
4 61
 

+ 10
- 0
src/const.h View File

@@ -0,0 +1,10 @@
1
+#ifndef VERSION_H
2
+#define VERSION_H
3
+
4
+#define APP_VERSION "0.1.0"
5
+#define APP_NAME "OTClient"
6
+#define APP_LONGNAME APP_NAME " " APP_VERSION
7
+#define APP_ICON "data/otclient.bmp"
8
+
9
+#endif
10
+

+ 105
- 0
src/engine.cpp View File

@@ -0,0 +1,105 @@
1
+#include "engine.h"
2
+#include "platform.h"
3
+#include "graphics.h"
4
+#include "const.h"
5
+#include "input.h"
6
+
7
+Engine g_engine;
8
+
9
+Engine::Engine() :
10
+    m_stopping(false),
11
+    m_running(false),
12
+    m_lastFrameTicks(0)
13
+{
14
+}
15
+
16
+Engine::~Engine()
17
+{
18
+}
19
+
20
+void Engine::init()
21
+{
22
+    Platform::init();
23
+
24
+    int width = 640;
25
+    int height = 480;
26
+
27
+    // create the window
28
+    Platform::createWindow(width, height, 550, 450);
29
+    Platform::setWindowTitle(APP_NAME);
30
+    Platform::setVsync();
31
+
32
+    // initialize graphics stuff
33
+    g_graphics.init();
34
+
35
+    // finally show the window
36
+    onResize(width, height);
37
+    Platform::showWindow();
38
+    Platform::hideMouseCursor();
39
+}
40
+
41
+void Engine::terminate()
42
+{
43
+    Platform::showMouseCursor();
44
+    Platform::terminate();
45
+    g_graphics.terminate();
46
+}
47
+
48
+void Engine::run()
49
+{
50
+    unsigned long ticks;
51
+
52
+    m_running = true;
53
+    m_lastFrameTicks = Platform::getTicks();
54
+
55
+    while(!m_stopping) {
56
+        // fire platform events
57
+        Platform::poll();
58
+
59
+        // update
60
+        ticks = Platform::getTicks();
61
+        update(ticks - m_lastFrameTicks);
62
+        m_lastFrameTicks = ticks;
63
+
64
+        // render
65
+        render();
66
+
67
+        // swap buffers
68
+        Platform::swapBuffers();
69
+    }
70
+
71
+    m_lastFrameTicks = 0;
72
+    m_stopping = false;
73
+    m_running = false;
74
+}
75
+
76
+void Engine::stop()
77
+{
78
+    m_stopping = true;
79
+}
80
+
81
+void Engine::render()
82
+{
83
+    g_graphics.beginRender();
84
+    g_graphics.endRender();
85
+}
86
+
87
+void Engine::update(int elapsedTicks)
88
+{
89
+
90
+}
91
+
92
+void Engine::onClose()
93
+{
94
+    stop();
95
+}
96
+
97
+void Engine::onResize(int width, int height)
98
+{
99
+
100
+}
101
+
102
+void Engine::onInputEvent(InputEvent *event)
103
+{
104
+
105
+}

+ 40
- 0
src/engine.h View File

@@ -0,0 +1,40 @@
1
+#ifndef ENGINE_H
2
+#define ENGINE_H
3
+
4
+struct InputEvent;
5
+
6
+class Engine
7
+{
8
+public:
9
+    Engine();
10
+    ~Engine();
11
+
12
+    void init();
13
+    void terminate();
14
+
15
+    void run();
16
+    void stop();
17
+
18
+    bool isRunning() const { return m_running; }
19
+    bool isStopping() const { return m_stopping; }
20
+    unsigned long getLastFrameTicks() const { return m_lastFrameTicks; }
21
+
22
+    // events fired by platform
23
+    void onClose();
24
+    void onResize(int width, int height);
25
+    void onInputEvent(InputEvent *event);
26
+
27
+private:
28
+    void render();
29
+    void update(int elapsedTicks);
30
+
31
+    bool m_stopping;
32
+    bool m_running;
33
+
34
+    unsigned long m_lastFrameTicks;
35
+};
36
+
37
+extern Engine g_engine;
38
+
39
+#endif // ENGINE_H
40
+

+ 63
- 0
src/graphics.cpp View File

@@ -0,0 +1,63 @@
1
+#include "graphics.h"
2
+
3
+#include <GL/gl.h>
4
+#include <GL/glu.h>
5
+
6
+Graphics g_graphics;
7
+
8
+Graphics::Graphics()
9
+{
10
+
11
+}
12
+
13
+Graphics::~Graphics()
14
+{
15
+
16
+}
17
+
18
+void Graphics::init()
19
+{
20
+    // setup opengl
21
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // black background
22
+    glEnable(GL_ALPHA_TEST); // enable alpha
23
+    glAlphaFunc(GL_GREATER, 0.0f); // default alpha mode
24
+    glDisable(GL_DEPTH_TEST); // we are rendering 2D only, we don't need it
25
+}
26
+
27
+void Graphics::terminate()
28
+{
29
+
30
+}
31
+
32
+void Graphics::resize(int width, int height)
33
+{
34
+    // resize gl viewport
35
+    glViewport(0, 0, width, height);
36
+
37
+    /*
38
+      0,0---------0,w
39
+       |           |
40
+       |           |
41
+       |           |
42
+      h,0---------h,w
43
+    */
44
+    // setup view region like above
45
+    glMatrixMode(GL_PROJECTION);
46
+    glLoadIdentity();
47
+    gluOrtho2D(0.0f, width, height, 0.0f);
48
+
49
+    // back to model view
50
+    glMatrixMode(GL_MODELVIEW);
51
+    glLoadIdentity();
52
+}
53
+
54
+void Graphics::beginRender()
55
+{
56
+    glClear(GL_COLOR_BUFFER_BIT);
57
+    glLoadIdentity();
58
+}
59
+
60
+void Graphics::endRender()
61
+{
62
+
63
+}

+ 21
- 0
src/graphics.h View File

@@ -0,0 +1,21 @@
1
+#ifndef GRAPHICS_H
2
+#define GRAPHICS_H
3
+
4
+class Graphics
5
+{
6
+public:
7
+    Graphics();
8
+    ~Graphics();
9
+
10
+    void init();
11
+    void terminate();
12
+
13
+    void resize(int width, int height);
14
+
15
+    void beginRender();
16
+    void endRender();
17
+};
18
+
19
+extern Graphics g_graphics;
20
+
21
+#endif // GRAPHICS_H

+ 187
- 0
src/input.h View File

@@ -0,0 +1,187 @@
1
+#ifndef INPUT_H
2
+#define INPUT_H
3
+
4
+enum EKeyCode {
5
+    KC_UNKNOWN     = 0x00,
6
+    KC_ESCAPE      = 0x01,
7
+    KC_1           = 0x02,
8
+    KC_2           = 0x03,
9
+    KC_3           = 0x04,
10
+    KC_4           = 0x05,
11
+    KC_5           = 0x06,
12
+    KC_6           = 0x07,
13
+    KC_7           = 0x08,
14
+    KC_8           = 0x09,
15
+    KC_9           = 0x0A,
16
+    KC_0           = 0x0B,
17
+    KC_MINUS       = 0x0C,    // - on main keyboard
18
+    KC_EQUALS      = 0x0D,
19
+    KC_BACK        = 0x0E,    // backspace
20
+    KC_TAB         = 0x0F,
21
+    KC_Q           = 0x10,
22
+    KC_W           = 0x11,
23
+    KC_E           = 0x12,
24
+    KC_R           = 0x13,
25
+    KC_T           = 0x14,
26
+    KC_Y           = 0x15,
27
+    KC_U           = 0x16,
28
+    KC_I           = 0x17,
29
+    KC_O           = 0x18,
30
+    KC_P           = 0x19,
31
+    KC_LBRACKET    = 0x1A,
32
+    KC_RBRACKET    = 0x1B,
33
+    KC_RETURN      = 0x1C,    // Enter on main keyboard
34
+    KC_LCONTROL    = 0x1D,
35
+    KC_A           = 0x1E,
36
+    KC_S           = 0x1F,
37
+    KC_D           = 0x20,
38
+    KC_F           = 0x21,
39
+    KC_G           = 0x22,
40
+    KC_H           = 0x23,
41
+    KC_J           = 0x24,
42
+    KC_K           = 0x25,
43
+    KC_L           = 0x26,
44
+    KC_SEMICOLON   = 0x27,
45
+    KC_APOSTROPHE  = 0x28,
46
+    KC_GRAVE       = 0x29,    // accent
47
+    KC_LSHIFT      = 0x2A,
48
+    KC_BACKSLASH   = 0x2B,
49
+    KC_Z           = 0x2C,
50
+    KC_X           = 0x2D,
51
+    KC_C           = 0x2E,
52
+    KC_V           = 0x2F,
53
+    KC_B           = 0x30,
54
+    KC_N           = 0x31,
55
+    KC_M           = 0x32,
56
+    KC_COMMA       = 0x33,
57
+    KC_PERIOD      = 0x34,    // . on main keyboard
58
+    KC_SLASH       = 0x35,    // / on main keyboard
59
+    KC_RSHIFT      = 0x36,
60
+    KC_MULTIPLY    = 0x37,    // * on numeric keypad
61
+    KC_LALT        = 0x38,    // left Alt
62
+    KC_SPACE       = 0x39,
63
+    KC_CAPITAL     = 0x3A,
64
+    KC_F1          = 0x3B,
65
+    KC_F2          = 0x3C,
66
+    KC_F3          = 0x3D,
67
+    KC_F4          = 0x3E,
68
+    KC_F5          = 0x3F,
69
+    KC_F6          = 0x40,
70
+    KC_F7          = 0x41,
71
+    KC_F8          = 0x42,
72
+    KC_F9          = 0x43,
73
+    KC_F10         = 0x44,
74
+    KC_NUMLOCK     = 0x45,
75
+    KC_SCROLL      = 0x46,    // Scroll Lock
76
+    KC_NUMPAD7     = 0x47,
77
+    KC_NUMPAD8     = 0x48,
78
+    KC_NUMPAD9     = 0x49,
79
+    KC_SUBTRACT    = 0x4A,    // - on numeric keypad
80
+    KC_NUMPAD4     = 0x4B,
81
+    KC_NUMPAD5     = 0x4C,
82
+    KC_NUMPAD6     = 0x4D,
83
+    KC_ADD         = 0x4E,    // + on numeric keypad
84
+    KC_NUMPAD1     = 0x4F,
85
+    KC_NUMPAD2     = 0x50,
86
+    KC_NUMPAD3     = 0x51,
87
+    KC_NUMPAD0     = 0x52,
88
+    KC_DECIMAL     = 0x53,    // . on numeric keypad
89
+    KC_OEM_102     = 0x56,    // < > | on UK/Germany keyboards
90
+    KC_F11         = 0x57,
91
+    KC_F12         = 0x58,
92
+    KC_F13         = 0x64,    //                     (NEC PC98)
93
+    KC_F14         = 0x65,    //                     (NEC PC98)
94
+    KC_F15         = 0x66,    //                     (NEC PC98)
95
+    KC_KANA        = 0x70,    // (Japanese keyboard)
96
+    KC_ABNT_C1     = 0x73,    // / ? on Portugese (Brazilian) keyboards
97
+    KC_CONVERT     = 0x79,    // (Japanese keyboard)
98
+    KC_NOCONVERT   = 0x7B,    // (Japanese keyboard)
99
+    KC_YEN         = 0x7D,    // (Japanese keyboard)
100
+    KC_ABNT_C2     = 0x7E,    // Numpad . on Portugese (Brazilian) keyboards
101
+    KC_NUMPADEQUALS= 0x8D,    // = on numeric keypad (NEC PC98)
102
+    KC_PREVTRACK   = 0x90,    // Previous Track (KC_CIRCUMFLEX on Japanese keyboard)
103
+    KC_AT          = 0x91,    //                     (NEC PC98)
104
+    KC_COLON       = 0x92,    //                     (NEC PC98)
105
+    KC_UNDERLINE   = 0x93,    //                     (NEC PC98)
106
+    KC_KANJI       = 0x94,    // (Japanese keyboard)
107
+    KC_STOP        = 0x95,    //                     (NEC PC98)
108
+    KC_AX          = 0x96,    //                     (Japan AX)
109
+    KC_UNLABELED   = 0x97,    //                        (J3100)
110
+    KC_NEXTTRACK   = 0x99,    // Next Track
111
+    KC_NUMPADENTER = 0x9C,    // Enter on numeric keypad
112
+    KC_RCONTROL    = 0x9D,
113
+    KC_MUTE        = 0xA0,    // Mute
114
+    KC_CALCULATOR  = 0xA1,    // Calculator
115
+    KC_PLAYPAUSE   = 0xA2,    // Play / Pause
116
+    KC_MEDIASTOP   = 0xA4,    // Media Stop
117
+    KC_VOLUMEDOWN  = 0xAE,    // Volume -
118
+    KC_VOLUMEUP    = 0xB0,    // Volume +
119
+    KC_WEBHOME     = 0xB2,    // Web home
120
+    KC_NUMPADCOMMA = 0xB3,    // , on numeric keypad (NEC PC98)
121
+    KC_DIVIDE      = 0xB5,    // / on numeric keypad
122
+    KC_SYSRQ       = 0xB7,
123
+    KC_RALT        = 0xB8,    // right Alt
124
+    KC_PAUSE       = 0xC5,    // Pause
125
+    KC_HOME        = 0xC7,    // Home on arrow keypad
126
+    KC_UP          = 0xC8,    // UpArrow on arrow keypad
127
+    KC_PGUP        = 0xC9,    // PgUp on arrow keypad
128
+    KC_LEFT        = 0xCB,    // LeftArrow on arrow keypad
129
+    KC_RIGHT       = 0xCD,    // RightArrow on arrow keypad
130
+    KC_END         = 0xCF,    // End on arrow keypad
131
+    KC_DOWN        = 0xD0,    // DownArrow on arrow keypad
132
+    KC_PGDOWN      = 0xD1,    // PgDn on arrow keypad
133
+    KC_INSERT      = 0xD2,    // Insert on arrow keypad
134
+    KC_DELETE      = 0xD3,    // Delete on arrow keypad
135
+    KC_LWIN        = 0xDB,    // Left Windows key
136
+    KC_RWIN        = 0xDC,    // Right Windows key
137
+    KC_APPS        = 0xDD,    // AppMenu key
138
+    KC_POWER       = 0xDE,    // System Power
139
+    KC_SLEEP       = 0xDF,    // System Sleep
140
+    KC_WAKE        = 0xE3,    // System Wake
141
+    KC_WEBSEARCH   = 0xE5,    // Web Search
142
+    KC_WEBFAVORITES= 0xE6,    // Web Favorites
143
+    KC_WEBREFRESH  = 0xE7,    // Web Refresh
144
+    KC_WEBSTOP     = 0xE8,    // Web Stop
145
+    KC_WEBFORWARD  = 0xE9,    // Web Forward
146
+    KC_WEBBACK     = 0xEA,    // Web Back
147
+    KC_MYCOMPUTER  = 0xEB,    // My Computer
148
+    KC_MAIL        = 0xEC,    // Mail
149
+    KC_MEDIASELECT = 0xED     // Media Select
150
+};
151
+
152
+enum EEvent {
153
+    EV_KEY_DOWN = 0,
154
+    EV_KEY_UP,
155
+    EV_TEXT_ENTER,
156
+    EV_MOUSE_LDOWN,
157
+    EV_MOUSE_LUP,
158
+    EV_MOUSE_MDOWN,
159
+    EV_MOUSE_MUP,
160
+    EV_MOUSE_RDOWN,
161
+    EV_MOUSE_RUP,
162
+    EV_MOUSE_WHEEL_UP,
163
+    EV_MOUSE_WHEEL_DOWN,
164
+    EV_MOUSE_MOVE
165
+};
166
+
167
+struct KeyEvent {
168
+    char keychar;
169
+    unsigned char keycode;
170
+    bool ctrl;
171
+    bool shift;
172
+    bool alt;
173
+};
174
+
175
+struct MouseEvent {
176
+    int x, y;
177
+};
178
+
179
+struct InputEvent {
180
+    EEvent type;
181
+    union {
182
+        KeyEvent key;
183
+        MouseEvent mouse;
184
+    };
185
+};
186
+
187
+#endif // INPUT_H

+ 53
- 0
src/logger.cpp View File

@@ -0,0 +1,53 @@
1
+#include "logger.h"
2
+#include "util.h"
3
+
4
+#include <iostream>
5
+#include <sstream>
6
+#include <cstdarg>
7
+#include <cstdlib>
8
+#include <boost/algorithm/string.hpp>
9
+
10
+void _log(int level, const char *trace, const char *format, ...)
11
+{
12
+    va_list args;
13
+    std::stringstream out;
14
+    std::string strace;
15
+
16
+    va_start(args, format);
17
+    std::string text = vformat(format, args);
18
+    va_end(args);
19
+
20
+    if(trace) {
21
+        strace = trace;
22
+        strace = strace.substr(0, strace.find_first_of('('));
23
+        if(strace.find_last_of(' ') != std::string::npos)
24
+            strace = strace.substr(strace.find_last_of(' ') + 1);
25
+    }
26
+
27
+#ifdef linux
28
+    static char const *colors[] = { "\033[01;31m ", "\033[01;31m", "\033[01;33m", "\033[0;32m", "\033[01;34m" };
29
+    static bool colored = getenv("COLORED_OUTPUT");
30
+    if(colored)
31
+        out << colors[level];
32
+#endif
33
+
34
+    if(!strace.empty())
35
+        out << "[" << strace << "] ";
36
+
37
+    static char const *prefixes[] = { "FATAL ERROR: ", "ERROR: ", "WARNING: ", "", "", "" };
38
+    out << prefixes[level];
39
+    out << text;
40
+
41
+#ifdef linux
42
+    if(colored)
43
+        out << "\033[0m";
44
+#endif
45
+
46
+    if(level <= LWARNING)
47
+        std::cerr << out.str() << std::endl;
48
+    else
49
+        std::cout << out.str() << std::endl;
50
+
51
+    if(level == LFATAL)
52
+        exit(-1);
53
+}

+ 22
- 0
src/logger.h View File

@@ -0,0 +1,22 @@
1
+#ifndef LOGGER_H
2
+#define LOGGER_H
3
+
4
+#include <string>
5
+
6
+enum ELogLevel {
7
+    LFATAL = 0,
8
+    LERROR,
9
+    LWARNING,
10
+    LNOTICE,
11
+    LDEBUG
12
+};
13
+
14
+void _log(int level, const char *trace, const char *format, ...);
15
+
16
+#define fatal(...) _log(LFATAL, NULL, ## __VA_ARGS__)
17
+#define error(...) _log(LERROR, NULL, ## __VA_ARGS__)
18
+#define warning(...) _log(LWARNING, NULL, ## __VA_ARGS__)
19
+#define debug(...) _log(LDEBUG, NULL, ## __VA_ARGS__)
20
+#define notice(...) _log(LNOTICE, NULL, ## __VA_ARGS__)
21
+
22
+#endif

+ 39
- 0
src/main.cpp View File

@@ -0,0 +1,39 @@
1
+#include "engine.h"
2
+#include "const.h"
3
+#include "logger.h"
4
+
5
+#include <csignal>
6
+
7
+// catches terminate signals to exit nicely
8
+void signal_handler(int sig)
9
+{
10
+    switch(sig) {
11
+        case SIGTERM:
12
+        case SIGINT:
13
+        case SIGQUIT:
14
+        {
15
+            static bool stopping = false;
16
+            if(!stopping) {
17
+                stopping = true;
18
+                g_engine.stop();
19
+            }
20
+            break;
21
+        }
22
+    }
23
+}
24
+
25
+int main(int argc, const char *argv[])
26
+{
27
+    // install our signal handler
28
+    signal(SIGTERM, signal_handler);
29
+    signal(SIGINT, signal_handler);
30
+    signal(SIGQUIT, signal_handler);
31
+
32
+    notice(APP_LONGNAME);
33
+
34
+    // setup the engine and run
35
+    g_engine.init();
36
+    g_engine.run();
37
+    g_engine.terminate();
38
+    return 0;
39
+}

+ 34
- 0
src/platform.h View File

@@ -0,0 +1,34 @@
1
+#ifndef PLATFORM_H
2
+#define PLATFORM_H
3
+
4
+namespace Platform
5
+{
6
+    void init();
7
+    void terminate();
8
+
9
+    void poll();
10
+
11
+    unsigned long getTicks();
12
+    void sleep(unsigned long miliseconds);
13
+
14
+    bool createWindow(int width, int height, int minWidth, int minHeight);
15
+    void destroyWindow();
16
+    void showWindow();
17
+    void setWindowTitle(const char *title);
18
+    bool isWindowFocused();
19
+    bool isWindowVisible();
20
+
21
+    void *getExtensionProcAddress(const char *ext);
22
+    bool isExtensionSupported(const char *ext);
23
+
24
+    const char *getTextFromClipboard();
25
+    void copyToClipboard(const char *text);
26
+
27
+    void hideMouseCursor();
28
+    void showMouseCursor();
29
+
30
+    void setVsync(bool enable = true);
31
+    void swapBuffers();
32
+};
33
+
34
+#endif // PLATFORM_H

+ 30
- 0
src/util.cpp View File

@@ -0,0 +1,30 @@
1
+#include "util.h"
2
+
3
+#include <cstdio>
4
+
5
+std::string vformat(const char *format, va_list args)
6
+{
7
+    if(!format)
8
+        return "";
9
+    int result = -1, length = 256;
10
+    char *buffer = 0;
11
+    while(result == -1) {
12
+        if(buffer)
13
+            delete [] buffer;
14
+        buffer = new char [length + 1];
15
+        result = vsnprintf(buffer, length, format, args);
16
+        length *= 2;
17
+    }
18
+    std::string s(buffer);
19
+    delete [] buffer;
20
+    return s;
21
+}
22
+
23
+std::string format(const char *format, ...)
24
+{
25
+    va_list args;
26
+    va_start(args, format);
27
+    std::string s = vformat(format, args);
28
+    va_end(args);
29
+    return s;
30
+}

+ 10
- 0
src/util.h View File

@@ -0,0 +1,10 @@
1
+#ifndef UTIL_H
2
+#define UTIL_H
3
+
4
+#include <string>
5
+#include <cstdarg>
6
+
7
+std::string vformat(const char *format, va_list args);
8
+std::string format(const char *format, ...);
9
+
10
+#endif

+ 684
- 0
src/x11platform.cpp View File

@@ -0,0 +1,684 @@
1
+#include "platform.h"
2
+#include "engine.h"
3
+#include "input.h"
4
+#include "logger.h"
5
+
6
+#include <cstring>
7
+#include <ctime>
8
+
9
+#include <string>
10
+#include <algorithm>
11
+#include <map>
12
+
13
+#include <sys/time.h>
14
+#include <X11/Xlib.h>
15
+#include <X11/Xatom.h>
16
+#include <GL/glx.h>
17
+
18
+struct X11PlatformPrivate {
19
+    Display *display;
20
+    XVisualInfo *visual;
21
+    GLXContext glxContext;
22
+    XIM xim;
23
+    XIC xic;
24
+    Colormap colormap;
25
+    Window window;
26
+    Cursor cursor;
27
+    Atom atomDeleteWindow;
28
+    Atom atomClipboard;
29
+    Atom atomTargets;
30
+    Atom atomText;
31
+    Atom atomCompoundText;
32
+    Atom atomUTF8String;
33
+    bool visible;
34
+    bool focused;
35
+    int width;
36
+    int height;
37
+    std::string clipboardText;
38
+    std::map<int, unsigned char> keyMap;
39
+} x11;
40
+
41
+void Platform::init()
42
+{
43
+    x11.display = NULL;
44
+    x11.visual = NULL;
45
+    x11.glxContext = NULL;
46
+    x11.xim = NULL;
47
+    x11.xic = NULL;
48
+    x11.colormap = None;
49
+    x11.window = None;
50
+    x11.cursor = None;
51
+    x11.visible = false;
52
+    x11.focused = false;
53
+    x11.width = 0;
54
+    x11.height = 0;
55
+
56
+    // setup keymap
57
+    x11.keyMap[XK_1] = KC_1;
58
+    x11.keyMap[XK_2] = KC_2;
59
+    x11.keyMap[XK_3] = KC_3;
60
+    x11.keyMap[XK_4] = KC_4;
61
+    x11.keyMap[XK_5] = KC_5;
62
+    x11.keyMap[XK_6] = KC_6;
63
+    x11.keyMap[XK_7] = KC_7;
64
+    x11.keyMap[XK_8] = KC_8;
65
+    x11.keyMap[XK_9] = KC_9;
66
+    x11.keyMap[XK_0] = KC_0;
67
+
68
+    x11.keyMap[XK_BackSpace] = KC_BACK;
69
+
70
+    x11.keyMap[XK_minus] = KC_MINUS;
71
+    x11.keyMap[XK_equal] = KC_EQUALS;
72
+    x11.keyMap[XK_space] = KC_SPACE;
73
+    x11.keyMap[XK_comma] = KC_COMMA;
74
+    x11.keyMap[XK_period] = KC_PERIOD;
75
+
76
+    x11.keyMap[XK_backslash] = KC_BACKSLASH;
77
+    x11.keyMap[XK_slash] = KC_SLASH;
78
+    x11.keyMap[XK_bracketleft] = KC_LBRACKET;
79
+    x11.keyMap[XK_bracketright] = KC_RBRACKET;
80
+
81
+    x11.keyMap[XK_Escape] = KC_ESCAPE;
82
+    x11.keyMap[XK_Caps_Lock] = KC_CAPITAL;
83
+
84
+    x11.keyMap[XK_Tab] = KC_TAB;
85
+    x11.keyMap[XK_Return] = KC_RETURN;
86
+    x11.keyMap[XK_Control_L] = KC_LCONTROL;
87
+    x11.keyMap[XK_Control_R] = KC_RCONTROL;
88
+
89
+    x11.keyMap[XK_colon] = KC_COLON;
90
+    x11.keyMap[XK_semicolon] = KC_SEMICOLON;
91
+    x11.keyMap[XK_apostrophe] = KC_APOSTROPHE;
92
+    x11.keyMap[XK_grave] = KC_GRAVE;
93
+
94
+    x11.keyMap[XK_b] = KC_B;
95
+    x11.keyMap[XK_a] = KC_A;
96
+    x11.keyMap[XK_c] = KC_C;
97
+    x11.keyMap[XK_d] = KC_D;
98
+    x11.keyMap[XK_e] = KC_E;
99
+    x11.keyMap[XK_f] = KC_F;
100
+    x11.keyMap[XK_g] = KC_G;
101
+    x11.keyMap[XK_h] = KC_H;
102
+    x11.keyMap[XK_i] = KC_I;
103
+    x11.keyMap[XK_j] = KC_J;
104
+    x11.keyMap[XK_k] = KC_K;
105
+    x11.keyMap[XK_l] = KC_L;
106
+    x11.keyMap[XK_m] = KC_M;
107
+    x11.keyMap[XK_n] = KC_N;
108
+    x11.keyMap[XK_o] = KC_O;
109
+    x11.keyMap[XK_p] = KC_P;
110
+    x11.keyMap[XK_q] = KC_Q;
111
+    x11.keyMap[XK_r] = KC_R;
112
+    x11.keyMap[XK_s] = KC_S;
113
+    x11.keyMap[XK_t] = KC_T;
114
+    x11.keyMap[XK_u] = KC_U;
115
+    x11.keyMap[XK_v] = KC_V;
116
+    x11.keyMap[XK_w] = KC_W;
117
+    x11.keyMap[XK_x] = KC_X;
118
+    x11.keyMap[XK_y] = KC_Y;
119
+    x11.keyMap[XK_z] = KC_Z;
120
+
121
+    x11.keyMap[XK_F1] = KC_F1;
122
+    x11.keyMap[XK_F2] = KC_F2;
123
+    x11.keyMap[XK_F3] = KC_F3;
124
+    x11.keyMap[XK_F4] = KC_F4;
125
+    x11.keyMap[XK_F5] = KC_F5;
126
+    x11.keyMap[XK_F6] = KC_F6;
127
+    x11.keyMap[XK_F7] = KC_F7;
128
+    x11.keyMap[XK_F8] = KC_F8;
129
+    x11.keyMap[XK_F9] = KC_F9;
130
+    x11.keyMap[XK_F10] = KC_F10;
131
+    x11.keyMap[XK_F11] = KC_F11;
132
+    x11.keyMap[XK_F12] = KC_F12;
133
+    x11.keyMap[XK_F13] = KC_F13;
134
+    x11.keyMap[XK_F14] = KC_F14;
135
+    x11.keyMap[XK_F15] = KC_F15;
136
+
137
+    // keypad
138
+    x11.keyMap[XK_KP_0] = KC_NUMPAD0;
139
+    x11.keyMap[XK_KP_1] = KC_NUMPAD1;
140
+    x11.keyMap[XK_KP_2] = KC_NUMPAD2;
141
+    x11.keyMap[XK_KP_3] = KC_NUMPAD3;
142
+    x11.keyMap[XK_KP_4] = KC_NUMPAD4;
143
+    x11.keyMap[XK_KP_5] = KC_NUMPAD5;
144
+    x11.keyMap[XK_KP_6] = KC_NUMPAD6;
145
+    x11.keyMap[XK_KP_7] = KC_NUMPAD7;
146
+    x11.keyMap[XK_KP_8] = KC_NUMPAD8;
147
+    x11.keyMap[XK_KP_9] = KC_NUMPAD9;
148
+    x11.keyMap[XK_KP_Add] = KC_ADD;
149
+    x11.keyMap[XK_KP_Subtract] = KC_SUBTRACT;
150
+    x11.keyMap[XK_KP_Decimal] = KC_DECIMAL;
151
+    x11.keyMap[XK_KP_Equal] = KC_NUMPADEQUALS;
152
+    x11.keyMap[XK_KP_Divide] = KC_DIVIDE;
153
+    x11.keyMap[XK_KP_Multiply] = KC_MULTIPLY;
154
+    x11.keyMap[XK_KP_Enter] = KC_NUMPADENTER;
155
+
156
+    // keypad with numlock off
157
+    x11.keyMap[XK_KP_Home] = KC_NUMPAD7;
158
+    x11.keyMap[XK_KP_Up] = KC_NUMPAD8;
159
+    x11.keyMap[XK_KP_Page_Up] = KC_NUMPAD9;
160
+    x11.keyMap[XK_KP_Left] = KC_NUMPAD4;
161
+    x11.keyMap[XK_KP_Begin] = KC_NUMPAD5;
162
+    x11.keyMap[XK_KP_Right] = KC_NUMPAD6;
163
+    x11.keyMap[XK_KP_End] = KC_NUMPAD1;
164
+    x11.keyMap[XK_KP_Down] = KC_NUMPAD2;
165
+    x11.keyMap[XK_KP_Page_Down] = KC_NUMPAD3;
166
+    x11.keyMap[XK_KP_Insert] = KC_NUMPAD0;
167
+    x11.keyMap[XK_KP_Delete] = KC_DECIMAL;
168
+
169
+    x11.keyMap[XK_Up] = KC_UP;
170
+    x11.keyMap[XK_Down] = KC_DOWN;
171
+    x11.keyMap[XK_Left] = KC_LEFT;
172
+    x11.keyMap[XK_Right] = KC_RIGHT;
173
+
174
+    x11.keyMap[XK_Page_Up] = KC_PGUP;
175
+    x11.keyMap[XK_Page_Down] = KC_PGDOWN;
176
+    x11.keyMap[XK_Home] = KC_HOME;
177
+    x11.keyMap[XK_End] = KC_END;
178
+
179
+    x11.keyMap[XK_Num_Lock] = KC_NUMLOCK;
180
+    x11.keyMap[XK_Print] = KC_SYSRQ;
181
+    x11.keyMap[XK_Scroll_Lock] = KC_SCROLL;
182
+    x11.keyMap[XK_Pause] = KC_PAUSE;
183
+
184
+    x11.keyMap[XK_Shift_R] = KC_RSHIFT;
185
+    x11.keyMap[XK_Shift_L] = KC_LSHIFT;
186
+    x11.keyMap[XK_Alt_R] = KC_RALT;
187
+    x11.keyMap[XK_Alt_L] = KC_LALT;
188
+
189
+    x11.keyMap[XK_Insert] = KC_INSERT;
190
+    x11.keyMap[XK_Delete] = KC_DELETE;
191
+
192
+    x11.keyMap[XK_Super_L] = KC_LWIN;
193
+    x11.keyMap[XK_Super_R] = KC_RWIN;
194
+    x11.keyMap[XK_Menu] = KC_APPS;
195
+
196
+    // open display
197
+    x11.display = XOpenDisplay(0);
198
+    if(!x11.display)
199
+        fatal("Failed to open X display");
200
+
201
+    // check if GLX is supported on this display
202
+    if(!glXQueryExtension(x11.display, 0, 0))
203
+        fatal("GLX not supported");
204
+
205
+    // retrieve GLX version
206
+    int glxMajor;
207
+    int glxMinor;
208
+    if(!glXQueryVersion(x11.display, &glxMajor, &glxMinor))
209
+        fatal("Unable to query GLX version");
210
+    notice("GLX version %d.%d", glxMajor, glxMinor);
211
+
212
+    // clipboard related atoms
213
+    x11.atomClipboard = XInternAtom(x11.display, "CLIPBOARD", False);
214
+    x11.atomTargets = XInternAtom(x11.display, "TARGETS", False);
215
+    x11.atomUTF8String = XInternAtom(x11.display, "UTF8_STRING", False);
216
+    x11.atomText = XInternAtom(x11.display, "TEXT", False);
217
+    x11.atomCompoundText = XInternAtom(x11.display, "COMPOUND_TEXT", False);
218
+}
219
+
220
+void Platform::terminate()
221
+{
222
+    if(x11.window) {
223
+        destroyWindow();
224
+        x11.window = None;
225
+    }
226
+
227
+    // close display
228
+    if(x11.display) {
229
+        XCloseDisplay(x11.display);
230
+        x11.display = NULL;
231
+    }
232
+}
233
+
234
+void Platform::poll()
235
+{
236
+    XEvent event, peekevent;
237
+    static InputEvent inputEvent;
238
+    while(XPending(x11.display) > 0) {
239
+        XNextEvent(x11.display, &event);
240
+
241
+        // call filter because xim will discard KeyPress events when keys still composing
242
+        if(XFilterEvent(&event, x11.window))
243
+            continue;
244
+
245
+        // discard events of repeated key releases
246
+        if(event.type == KeyRelease && XPending(x11.display)) {
247
+            XPeekEvent(x11.display, &peekevent);
248
+            if((peekevent.type == KeyPress) &&
249
+              (peekevent.xkey.keycode == event.xkey.keycode) &&
250
+              ((peekevent.xkey.time-event.xkey.time) < 2))
251
+                continue;
252
+        }
253
+
254
+        switch(event.type) {
255
+            case ConfigureNotify:
256
+                // window resize
257
+                if(x11.width != event.xconfigure.width || x11.height != event.xconfigure.height) {
258
+                    x11.width = event.xconfigure.width;
259
+                    x11.height = event.xconfigure.height;
260
+                    g_engine.onResize(x11.width, x11.height);
261
+                }
262
+                break;
263
+
264
+            case KeyPress:
265
+            case KeyRelease: {
266
+                KeySym keysym;
267
+                char buf[32];
268
+                int len;
269
+
270
+                inputEvent.key.ctrl = (event.xkey.state & ControlMask);
271
+                inputEvent.key.shift = (event.xkey.state & ShiftMask);
272
+                inputEvent.key.alt = (event.xkey.state & Mod1Mask);
273
+
274
+                // fire enter text event
275
+                if(event.type == KeyPress && !inputEvent.key.ctrl && !inputEvent.key.alt) {
276
+                    if(x11.xic) { // with xim we can get latin1 input correctly
277
+                        Status status;
278
+                        len = XmbLookupString(x11.xic, &event.xkey, buf, sizeof(buf), &keysym, &status);
279
+                    } else { // otherwise use XLookupString, but it doesn't work right with dead keys often
280
+                        static XComposeStatus compose = {NULL, 0};
281
+                        len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
282
+                    }
283
+                    if(len > 0 &&
284
+                       // for some reason these keys produces characters and we don't want that
285
+                       keysym != XK_BackSpace &&
286
+                       keysym != XK_Return &&
287
+                       keysym != XK_Delete &&
288
+                       keysym != XK_Escape
289
+                    ) {
290
+                        inputEvent.type = EV_TEXT_ENTER;
291
+                        inputEvent.key.keychar = buf[0];
292
+                        inputEvent.key.keycode = KC_UNKNOWN;
293
+                        g_engine.onInputEvent(&inputEvent);
294
+                    }
295
+                }
296
+
297
+                // unmask Shift/Lock to get expected results
298
+                event.xkey.state &= ~(ShiftMask | LockMask);
299
+                len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
300
+
301
+                // fire key up/down event
302
+                if(x11.keyMap.find(keysym) != x11.keyMap.end()) {
303
+                    inputEvent.key.keycode = x11.keyMap[keysym];
304
+                    inputEvent.type = (event.type == KeyPress) ? EV_KEY_DOWN : EV_KEY_UP;
305
+                    inputEvent.key.keychar = (len > 0) ? buf[0] : 0;
306
+                    g_engine.onInputEvent(&inputEvent);
307
+                }
308
+                break;
309
+            }
310
+            case ButtonPress:
311
+            case ButtonRelease:
312
+                switch(event.xbutton.button) {
313
+                    case Button1:
314
+                        inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_LDOWN : EV_MOUSE_LUP;
315
+                        break;
316
+                    case Button3:
317
+                        inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_RDOWN : EV_MOUSE_RUP;
318
+                        break;
319
+                    case Button2:
320
+                        inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_MDOWN : EV_MOUSE_MUP;
321
+                        break;
322
+                    case Button4:
323
+                        inputEvent.type = EV_MOUSE_WHEEL_UP;
324
+                        break;
325
+                    case Button5:
326
+                        inputEvent.type = EV_MOUSE_WHEEL_DOWN;
327
+                        break;
328
+                }
329
+                g_engine.onInputEvent(&inputEvent);
330
+                break;
331
+
332
+            case MotionNotify:
333
+                inputEvent.type = EV_MOUSE_MOVE;
334
+                inputEvent.mouse.x = event.xbutton.x;
335
+                inputEvent.mouse.y = event.xbutton.y;
336
+                g_engine.onInputEvent(&inputEvent);
337
+                break;
338
+
339
+            case MapNotify:
340
+                x11.visible = true;
341
+                break;
342
+
343
+            case UnmapNotify:
344
+                x11.visible = false;
345
+                break;
346
+
347
+            case FocusIn:
348
+                x11.focused = true;
349
+                break;
350
+
351
+            case FocusOut:
352
+                x11.focused = false;
353
+                break;
354
+
355
+            // clipboard data request
356
+            case SelectionRequest:
357
+            {
358
+                XEvent respond;
359
+                XSelectionRequestEvent *req = &(event.xselectionrequest);
360
+
361
+                if(req->target == x11.atomTargets ) {
362
+                    Atom typeList[] = {x11.atomText, x11.atomCompoundText, x11.atomUTF8String, XA_STRING};
363
+
364
+                    XChangeProperty(x11.display, req->requestor,
365
+                                    req->property, req->target,
366
+                                    8, PropModeReplace,
367
+                                    (unsigned char *) &typeList,
368
+                                    sizeof(typeList));
369
+                    respond.xselection.property = req->property;
370
+                } else {
371
+                    XChangeProperty(x11.display,
372
+                                    req->requestor,
373
+                                    req->property, req->target,
374
+                                    8,
375
+                                    PropModeReplace,
376
+                                    (unsigned char*) x11.clipboardText.c_str(),
377
+                                    x11.clipboardText.size());
378
+                    respond.xselection.property = req->property;
379
+                }
380
+
381
+                respond.xselection.type = SelectionNotify;
382
+                respond.xselection.display = req->display;
383
+                respond.xselection.requestor = req->requestor;
384
+                respond.xselection.selection = req->selection;
385
+                respond.xselection.target = req->target;
386
+                respond.xselection.time = req->time;
387
+                XSendEvent(x11.display, req->requestor, 0, 0, &respond);
388
+                XFlush(x11.display);
389
+                break;
390
+            }
391
+
392
+            case ClientMessage:
393
+            {
394
+                if((Atom)event.xclient.data.l[0] == x11.atomDeleteWindow)
395
+                    g_engine.onClose();
396
+                break;
397
+            }
398
+        }
399
+    }
400
+}
401
+
402
+unsigned long Platform::getTicks()
403
+{
404
+    static timeval tv;
405
+    static unsigned long firstTick = 0;
406
+
407
+    gettimeofday(&tv, 0);
408
+    if(!firstTick)
409
+        firstTick = tv.tv_sec;
410
+
411
+    return ((tv.tv_sec - firstTick) * 1000) + (tv.tv_usec / 1000);
412
+}
413
+
414
+void Platform::sleep(unsigned long miliseconds)
415
+{
416
+    timespec tv;
417
+    tv.tv_sec  = miliseconds / 1000;
418
+    tv.tv_nsec = (miliseconds % 1000) * 1000000;
419
+    nanosleep(&tv, NULL);
420
+}
421
+
422
+bool Platform::createWindow(int width, int height, int minWidth, int minHeight)
423
+{
424
+    static int attrList[] = {
425
+        GLX_USE_GL,
426
+        GLX_RGBA,
427
+        GLX_DOUBLEBUFFER,
428
+        None
429
+    };
430
+
431
+    // choose OpenGL, RGBA, double buffered, visual
432
+    x11.visual = glXChooseVisual(x11.display, DefaultScreen(x11.display), attrList);
433
+    if(!x11.visual)
434
+        fatal("RGBA/Double buffered visual not supported");
435
+
436
+    // create GLX context
437
+    x11.glxContext = glXCreateContext(x11.display, x11.visual, 0, GL_TRUE);
438
+    if(!x11.glxContext)
439
+        fatal("Unable to create GLX context");
440
+
441
+    // color map
442
+    x11.colormap  = XCreateColormap(x11.display,
443
+                                  RootWindow(x11.display, x11.visual->screen),
444
+                                  x11.visual->visual,
445
+                                  AllocNone);
446
+
447
+    // setup window attributes
448
+    XSetWindowAttributes wa;
449
+    wa.colormap = x11.colormap;
450
+    wa.border_pixel = 0;
451
+    wa.event_mask = KeyPressMask | KeyReleaseMask |
452
+                         ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
453
+                         ExposureMask | VisibilityChangeMask |
454
+                         StructureNotifyMask | FocusChangeMask;
455
+
456
+    // calculate center position
457
+    int x = (XDisplayHeight(x11.display, DefaultScreen(x11.display)) - width) / 2;
458
+    int y = (XDisplayHeight(x11.display, DefaultScreen(x11.display)) - height) / 2;
459
+
460
+    // create the window
461
+    x11.window = XCreateWindow(x11.display,
462
+                             RootWindow(x11.display, x11.visual->screen),
463
+                             x, y,
464
+                             width, height,
465
+                             0,
466
+                             x11.visual->depth,
467
+                             InputOutput,
468
+                             x11.visual->visual,
469
+                             CWBorderPixel | CWColormap | CWEventMask,
470
+                             &wa);
471
+
472
+    if(!x11.window)
473
+        fatal("Unable to create X window");
474
+
475
+    // setup locale to en_US.ISO-8859-1 characters
476
+    // and create input context (to get special characters from input)
477
+    if(setlocale(LC_ALL, "en_US.ISO-8859-1")) {
478
+        if(XSupportsLocale()) {
479
+            XSetLocaleModifiers("");
480
+            x11.xim = XOpenIM(x11.display, NULL, NULL, NULL);
481
+            if(x11.xim) {
482
+                x11.xic = XCreateIC(x11.xim,
483
+                                        XNInputStyle,
484
+                                        XIMPreeditNothing | XIMStatusNothing,
485
+                                        XNClientWindow, x11.window, NULL);
486
+                if(!x11.xic)
487
+                    error("Unable to create the input context");
488
+            } else
489
+                error("Failed to open an input method");
490
+        } else
491
+            error("X11 does not support the current locale");
492
+    }
493
+    else
494
+        error("Failed setting locale to latin1");
495
+
496
+    if(!x11.xic)
497
+        warning("Input of special keys maybe messed up because we couldn't create an input context");
498
+
499
+
500
+    // set window minimum size
501
+    XSizeHints xsizehints;
502
+    xsizehints.flags = PMinSize;
503
+    xsizehints.min_width = minWidth;
504
+    xsizehints.min_height= minHeight;
505
+    XSetWMSizeHints(x11.display, x11.window, &xsizehints, XA_WM_NORMAL_HINTS);
506
+
507
+    // handle delete window event
508
+    x11.atomDeleteWindow = XInternAtom(x11.display, "WM_DELETE_WINDOW", True);
509
+    XSetWMProtocols(x11.display, x11.window, &x11.atomDeleteWindow , 1);
510
+
511
+    // connect the GLX-context to the window
512
+    glXMakeCurrent(x11.display, x11.window, x11.glxContext);
513
+
514
+    x11.width = width;
515
+    x11.height = height;
516
+    return true;
517
+}
518
+
519
+void Platform::destroyWindow()
520
+{
521
+    if(x11.glxContext) {
522
+        glXMakeCurrent(x11.display, None, NULL);
523
+        glXDestroyContext(x11.display, x11.glxContext);
524
+        x11.glxContext = NULL;
525
+    }
526
+
527
+    if(x11.visual) {
528
+        XFree(x11.visual);
529
+        x11.visual = NULL;
530
+    }
531
+
532
+    if(x11.colormap != None) {
533
+        XFreeColormap(x11.display, x11.colormap);
534
+        x11.colormap = 0;
535
+    }
536
+
537
+    if(x11.window != None) {
538
+        XUnmapWindow(x11.display, x11.window);
539
+        XDestroyWindow(x11.display, x11.window);
540
+        x11.window = None;
541
+    }
542
+
543
+    if(x11.xic) {
544
+        XDestroyIC(x11.xic);
545
+        x11.xic = NULL;
546
+    }
547
+
548
+    if(x11.xim) {
549
+        XCloseIM(x11.xim);
550
+        x11.xim = NULL;
551
+    }
552
+}
553
+
554
+void Platform::showWindow()
555
+{
556
+    XMapWindow(x11.display, x11.window);
557
+}
558
+
559
+void Platform::setWindowTitle(const char *title)
560
+{
561
+    XStoreName(x11.display, x11.window, title);
562
+    XSetIconName(x11.display, x11.window, title);
563
+}
564
+
565
+void *Platform::getExtensionProcAddress(const char *ext)
566
+{
567
+    return (void*)glXGetProcAddressARB((const GLubyte*)ext);
568
+}
569
+
570
+bool Platform::isExtensionSupported(const char *ext)
571
+{
572
+    const char *exts = glXQueryExtensionsString(x11.display, DefaultScreen(x11.display));
573
+    if(strstr(exts, ext))
574
+        return true;
575
+    return true;
576
+}
577
+
578
+const char *Platform::getTextFromClipboard()
579
+{
580
+    Window ownerWindow = XGetSelectionOwner(x11.display, x11.atomClipboard);
581
+    if(ownerWindow ==  x11.window)
582
+        return x11.clipboardText.c_str();
583
+
584
+    std::string clipboard = "";
585
+    if(ownerWindow != None) {
586
+        XConvertSelection(x11.display, x11.atomClipboard, XA_STRING, 0, ownerWindow, CurrentTime);
587
+        XFlush(x11.display);
588
+
589
+        // hack to wait SelectioNotify event, otherwise we will get wrong clipboard pastes
590
+        sleep(100);
591
+
592
+        // check for data
593
+        Atom type;
594
+        int format;
595
+        unsigned long numItems, bytesLeft, dummy;
596
+        unsigned char *data;
597
+        XGetWindowProperty(x11.display, ownerWindow,
598
+                            XA_STRING,
599
+                            0, 0, 0,
600
+                            AnyPropertyType,
601
+                            &type,
602
+                            &format,
603
+                            &numItems,
604
+                            &bytesLeft,
605
+                            &data);
606
+        if(bytesLeft > 0)  {
607
+            // get the data get
608
+            int result = XGetWindowProperty(x11.display, ownerWindow,
609
+                                            XA_STRING,
610
+                                            0,
611
+                                            bytesLeft,
612
+                                            0,
613
+                                            AnyPropertyType,
614
+                                            &type,
615
+                                            &format,
616
+                                            &numItems,
617
+                                            &dummy,
618
+                                            &data);
619
+            if(result == Success)
620
+                clipboard = (const char*)data;
621
+            XFree(data);
622
+        }
623
+    }
624
+    return clipboard.c_str();
625
+}
626
+
627
+void Platform::copyToClipboard(const char *text)
628
+{
629
+    x11.clipboardText = text;
630
+    XSetSelectionOwner(x11.display, x11.atomClipboard, x11.window, CurrentTime);
631
+    XFlush(x11.display);
632
+}
633
+
634
+void Platform::hideMouseCursor()
635
+{
636
+    if(x11.cursor == None) {
637
+        char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
638
+        Pixmap pix = XCreateBitmapFromData(x11.display, x11.window, bm, 8, 8);
639
+        XColor black;
640
+        memset(&black, 0, sizeof(XColor));
641
+        black.flags = DoRed | DoGreen | DoBlue;
642
+        x11.cursor = XCreatePixmapCursor(x11.display, pix, pix, &black, &black, 0, 0);
643
+        XFreePixmap(x11.display, pix);
644
+    }
645
+    XDefineCursor(x11.display, x11.window, x11.cursor);
646
+}
647
+
648
+void Platform::showMouseCursor()
649
+{
650
+    XUndefineCursor(x11.display, x11.window);
651
+    if(x11.cursor != None) {
652
+        XFreeCursor(x11.display, x11.cursor);
653
+        x11.cursor = None;
654
+    }
655
+}
656
+
657
+void Platform::setVsync(bool enable)
658
+{
659
+    typedef GLint (*glSwapIntervalProc)(GLint);
660
+    glSwapIntervalProc glSwapInterval = NULL;
661
+
662
+    if(isExtensionSupported("GLX_MESA_swap_control"))
663
+        glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
664
+    else if(isExtensionSupported("GLX_SGI_swap_control"))
665
+        glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
666
+
667
+    if(glSwapInterval)
668
+        glSwapInterval(enable ? 1 : 0);
669
+}
670
+
671
+void Platform::swapBuffers()
672
+{
673
+    glXSwapBuffers(x11.display, x11.window);
674
+}
675
+
676
+bool Platform::isWindowFocused()
677
+{
678
+    return x11.focused;
679
+}
680
+
681
+bool Platform::isWindowVisible()
682
+{
683
+    return x11.visible;
684
+}

+ 0
- 7
srcs/main.cpp View File

@@ -1,7 +0,0 @@
1
-#include <iostream>
2
-
3
-int main(int argc, const char *argv[])
4
-{
5
-    std::cout << "Hello World!" << std::endl;
6
-    return 0;
7
-}

Loading…
Cancel
Save