File: Application.cpp

package info (click to toggle)
freeorion 0.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 194,940 kB
  • sloc: cpp: 186,508; python: 40,969; ansic: 1,164; xml: 719; makefile: 32; sh: 7
file content (262 lines) | stat: -rw-r--r-- 8,710 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#include "Application.h"

#include <GG/Texture.h>
#include <GG/Cursor.h>

#include "../../../UI/SDLGUI.h"

#include <boost/format.hpp>


extern const unsigned char cursor_data[16 * 16 * 4];

class Application::Impl {
    public:
        Impl(int argc, char** argv, unsigned width, unsigned height);

        virtual ~Impl();

        /// The given window will be made visible.
        /// Then the event pump is started.
        /// This method only returns once the application quits
        void Run(std::shared_ptr<GG::Wnd> wnd);

    private:
        std::unique_ptr<class MinimalGGApp> m_app;
};


class MinimalGGApp : public SDLGUI {
    public:
        MinimalGGApp(int width, int height, bool calculate_FPS, std::string name,
                     int x, int y, bool fullscreen, bool fake_mode_change);

        virtual ~MinimalGGApp();

        void Enter2DMode() override;
        void Exit2DMode() override;
        virtual void GLInit();

        void Initialize() override
        {}

    protected:
        void Render() override;
};

MinimalGGApp::MinimalGGApp(int width, int height, bool calculate_FPS, std::string name,
                           int x, int y, bool fullscreen, bool fake_mode_change) :
    SDLGUI(width, height, calculate_FPS, std::move(name), x, y, fullscreen, fake_mode_change)
{
    auto cursor_texture = std::make_shared<GG::Texture>();

    cursor_texture->Init(GG::X(16), GG::Y(16), cursor_data, GL_RGBA, GL_UNSIGNED_BYTE, 1);

    GG::GetTextureManager().StoreTexture(cursor_texture, "test_cursor");
    SetCursor(std::make_shared<GG::TextureCursor>(cursor_texture, GG::Pt(GG::X(1), GG::Y(1))));
    RenderCursor(true);

    GLInit();
}

MinimalGGApp::~MinimalGGApp() = default;

// The application is assumed to be in "3D mode" (non-orthographic) whenever
// GG is not rendering "in 2D" (orthographic, with coordinates mapped 1-1 onto
// the pixels of the display).  To move into "2D" mode, GG calls Enter2DMode()
// at the beginning of each GG rendering iteration.  This method is
// responsible for preserving any state it alters, then altering the necessary
// state to match what GG requires.  GG requires GL_TEXTURE_2D to be on,
// GL_LIGHTING off, and requires a viewport and orthographic projection as
// shown below.  The other code you see here is usually convenient to working
// with GG, but not required.
void MinimalGGApp::Enter2DMode() {
    glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_TEXTURE_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glViewport(0, 0, Value(AppWidth()), Value(AppHeight()));

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    // This sets up the world coordinate space with the origin in the
    // upper-left corner and +x and +y directions right and down,
    // respectively.  Note that this call leaves the depth of the viewing
    // volume is only 1 (from 0.0 to 1.0), which is fine for GG's purposes.
    glOrtho(0.0, Value(AppWidth()), Value(AppHeight()), 0.0, 0.0, Value(AppWidth()));

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}

// At the end of a single iteration of the GG rendering cycle, GG attempts to
// return GL state to what it was before the call to Enter2DMode() at the
// beginning of the iteration.  That is accomplished by calling Exit2DMode().
// Note that Enter- and Exit2DMode() depend entirely on the details of your
// application; there is no default implementation for either of these methods
// in SDLGUI.
void MinimalGGApp::Exit2DMode() {
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glPopAttrib();
}


// This gets called once per frame, and should call GG::GUI::Render() at its
// end.  Before this call to GG::GUI::Render(), all "3D" (non-GG,
// non-orthographic) rendering should be done.  If you don't plan on doing
// anything but using GG's windows and controls, you won't need to override
// this method at all.  Note that GG::GUI::Render() calls Enter2DMode() at tis
// beginning and Exit2DMode() at its end.
void MinimalGGApp::Render() {
    const double RPM = 4;
    const double DEGREES_PER_MS = 360.0 * RPM / 60000.0;

    glPushMatrix();

    glRotated ( (Ticks() % 60000) * DEGREES_PER_MS, 0.0, 1.0, 0.0);

    glBegin (GL_LINES);

    glColor3d (0.0, 0.5, 0.0);

    glVertex3d (1.0, 1.0, 1.0);
    glVertex3d (1.0, -1.0, 1.0);

    glVertex3d (1.0, -1.0, 1.0);
    glVertex3d (1.0, -1.0, -1.0);

    glVertex3d (1.0, -1.0, -1.0);
    glVertex3d (1.0, 1.0, -1.0);

    glVertex3d (1.0, 1.0, -1.0);
    glVertex3d (1.0, 1.0, 1.0);

    glVertex3d (1.0, 1.0, 1.0);
    glVertex3d (-1.0, 1.0, 1.0);

    glVertex3d (1.0, -1.0, 1.0);
    glVertex3d (-1.0, -1.0, 1.0);

    glVertex3d (1.0, -1.0, -1.0);
    glVertex3d (-1.0, -1.0, -1.0);

    glVertex3d (1.0, 1.0, -1.0);
    glVertex3d (-1.0, 1.0, -1.0);

    glEnd();

    glPopMatrix();

    GG::GUI::Render();
}

// This is where you put any OpenGL initialization code you need to execute at
// the start of the application.  This should set up the initial "3D"
// environment, the one that exists before Enter2DMode() and after
// Exit2DMode().  As with Enter- and Exit2DMode(), the needed code is entirely
// application-dependent.  Note that this method is called before Render() is
// ever called.
void MinimalGGApp::GLInit() {
    glEnable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glClearColor(0, 0, 0, 0);
    glViewport(0, 0, Value(AppWidth()), Value(AppHeight()));
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // set up perspective with vertical FOV of 50°. 1:1 application
    // window ratio, near plane of 1.0 and far plane of 10.0
    float ratio = AppWidth() / static_cast<float>(Value(AppHeight()));
    float radians = 50.0f * M_PI / 180.f;
    float near = 1.0f;
    float far = 10.0f;
    float cotangent = std::cos(radians) / std::sin(radians);

    float projection[4][4] = {{0.0f}};
    projection[0][0] = cotangent / ratio;
    projection[1][1] = cotangent;
    projection[2][2] = -((far + near) / (far - near));
    projection[2][3] = -1.0f;
    projection[3][2] = -((2.0f * far * near) / (far - near));
    projection[3][3] = 0.0f;

    glMultMatrixf(&projection[0][0]);

    // set up camera in -5.0 z offset from origin looking at origin
    GLfloat view[4][4] = {{0.0}};
    view[0][0] = -1.0;
    view[1][1] = -1.0;
    view[2][2] = 1.0;
    view[3][3] = 1.0;

    glMultMatrixf(&view[0][0]);
    glTranslated(-0.0, -0.0, -5.0);
    glMatrixMode(GL_MODELVIEW);
}


Application::Application(int argc, char** argv, unsigned width, unsigned height)
{ self = std::make_unique<Application::Impl>(argc, argv, width, height); }

Application::~Application() = default;

void Application::Run(std::shared_ptr<GG::Wnd> wnd)
{ self->Run(std::forward<std::shared_ptr<GG::Wnd>>(wnd)); }

Application::Impl::Impl(int argc, char** argv, unsigned width, unsigned height) {
    //std::vector<std::string> args;
    //for (int i = 0; i < argc; ++i)
    //    args.push_back(argv[i]);

    try {
        bool fullscreen = false;
        int left = 200;
        int top = 100;

        m_app = std::make_unique<MinimalGGApp>(800, 600, true, "Test", left, top, fullscreen, false);

    } catch (const std::exception& e) {
        std::cerr << "main() caught exception(std::exception): " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "main() caught unknown exception." << std::endl;
    }
}

Application::Impl::~Impl() = default;

void Application::Impl::Run(std::shared_ptr<GG::Wnd> window) {
    try {

        m_app->Register(std::forward<std::shared_ptr<GG::Wnd>>(window));
        m_app->Run();

    } catch (const std::invalid_argument& e) {
        std::cerr << "main() caught exception(std::invalid_arg): " << e.what() << std::endl;
    } catch (const std::runtime_error& e) {
        std::cerr << "main() caught exception(std::runtime_error): " << e.what() << std::endl;
    } catch (const  boost::io::format_error& e) {
        std::cerr << "main() caught exception(boost::io::format_error): " << e.what() << std::endl;
    } catch (const GG::ExceptionBase& e) {
        std::cerr << "main() caught exception(" << e.type() << "): " << e.what() << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "main() caught exception(std::exception): " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "main() caught unknown exception." << std::endl;
    }
}