1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Window.Internal.Init;
25 
26 private:
27 
28 import derelict.sdl2.sdl;
29 import derelict.opengl3.gl;
30 import derelict.sdl2.ttf;
31 import derelict.sdl2.image;
32 import derelict.sdl2.mixer;
33 
34 import Dgame.Window.GLContextSettings;
35 import Dgame.Internal.Error;
36 
37 shared static this() {
38     DerelictSDL2.load();
39     DerelictSDL2Image.load();
40     DerelictSDL2ttf.load();
41     DerelictSDL2Mixer.load();
42     DerelictGL.load();
43 }
44 
45 shared static ~this() {
46     if (SDL_WasInit(SDL_INIT_JOYSTICK) != 0)
47         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
48     if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) != 0)
49         SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
50 
51     // quit SDL_image
52     IMG_Quit();
53     // quit SDL_ttf
54     TTF_Quit();
55     // quit SDL_mixer
56     Mix_ReserveChannels(0);
57     Mix_CloseAudio();
58     Mix_Quit();
59     // quit SDL
60     SDL_Quit();
61 
62     DerelictSDL2Image.unload();
63     DerelictSDL2ttf.unload();
64     DerelictSDL2Mixer.unload();
65     DerelictSDL2.unload();
66     DerelictGL.unload();
67 }
68 
69 bool _isGLInited = false;
70 bool _isSDLInited = false;
71 
72 package(Dgame):
73 
74 void _initSDL() {
75     if (_isSDLInited)
76         return;
77 
78     debug {
79         SDL_version sdlver = void;
80         SDL_GetVersion(&sdlver);
81 
82         print_fmt("SDL version: %d.%d.%d\n", sdlver.major, sdlver.minor, sdlver.patch);
83     }
84 
85     scope(exit) _isSDLInited = true;
86 
87     // Initialize SDL2
88     int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
89     assert_fmt(result == 0, "Error: SDL could not be initialized: %s\n", SDL_GetError());
90 
91     if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0)
92         print_fmt("Warning: No Joystick support\n");
93     if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0)
94         print_fmt("Warning: No GameController support\n");
95 
96     // Initialize SDL_image
97     result = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
98     assert_fmt(result != 0, "Error: Failed to init the required jpg and png support: %s\n", IMG_GetError());
99     
100     if ((result & IMG_INIT_JPG) == 0)
101         print_fmt("Warning: No jpg support: %s\n", IMG_GetError());
102     else if ((result & IMG_INIT_PNG) == 0)
103         print_fmt("Warning: No png support: %s\n", IMG_GetError());
104 
105     // Initialize SDL_ttf
106     result = TTF_Init();
107     assert_fmt(result == 0, "Error: SDL_TTF could not be initialized: %s\n", Mix_GetError());
108 
109     // Initialize SDL_mixer
110     result = Mix_Init(MIX_INIT_OGG | MIX_INIT_MP3);
111     assert_fmt(result != 0, "Error: Failed to init the required ogg and mp3 support: %s\n", Mix_GetError());
112     
113     if ((result & MIX_INIT_OGG) == 0)
114         print_fmt("Warning: No ogg support: %s\n", Mix_GetError());
115     else if ((result & MIX_INIT_MP3) == 0)
116         print_fmt("Warning: No mp3 support: %s\n", Mix_GetError());
117 
118     result = Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096);
119     assert_fmt(result == 0, "Warning: Could not open Mix_OpenAudio: %s\n", Mix_GetError());
120 
121     SDL_ClearError(); // Ignore XAudio2 error: http://redmine.audacious-media-player.org/issues/346
122     
123     immutable int channels = Mix_AllocateChannels(256);
124     if (channels < 256)
125         print_fmt("Warning: Could not reserve 256 channels, only %d. %s\n", channels, Mix_GetError());
126 }
127 
128 @nogc
129 void _initGLAttr(const GLContextSettings gl) {
130     ubyte majorVersion, minorVersion;
131 
132     if (gl.vers == GLContextSettings.Version.Default) {
133         version (OSX) {
134             majorVersion = 2;
135             minorVersion = 1;
136         }
137     } else {
138         majorVersion = gl.vers / 10;
139         minorVersion = gl.vers % 10;
140     }
141 
142     if (majorVersion != 0) {
143         int result = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
144         assert_fmt(result == 0, "Error by initializing OpenGL: %s\n", SDL_GetError());
145 
146         result = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
147         assert_fmt(result == 0, "Error by initializing OpenGL: %s\n", SDL_GetError());
148 
149         debug print_fmt("OpenGL Context created in OpenGL version %d.%d\n", majorVersion, minorVersion);
150     }
151 
152     final switch (gl.profile) {
153         case GLContextSettings.Profile.Default:
154             break;
155         case GLContextSettings.Profile.Core:
156             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
157             SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
158             break;
159         case GLContextSettings.Profile.Compatibility:
160             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
161             break;
162         case GLContextSettings.Profile.ES:
163             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
164             break;
165     }
166 
167     if (gl.antiAlias > 0) {
168         debug print_fmt("Set %d as anti alias level\n", gl.antiAlias);
169 
170         int result = SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
171         if (result != 0)
172             print_fmt("Could not enable Anti-Alias: %s\n", SDL_GetError());
173 
174         result = SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, gl.antiAlias);
175         if (result != 0)
176             print_fmt("Could not enable Anti-Alias Level %d: %s\n", gl.antiAlias, SDL_GetError());
177     }
178 
179     int result = SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
180     assert_fmt(result == 0, "Error by initializing OpenGL: %s\n", SDL_GetError());
181 
182     result = SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
183     assert_fmt(result == 0, "Error by initializing OpenGL: %s\n", SDL_GetError());
184 }
185 
186 void _initGL() {
187     if (_isGLInited)
188         return;
189 
190     scope(exit) _isGLInited = true;
191 
192     immutable GLVersion glver = DerelictGL.reload();
193     const char* glverstr = glGetString(GL_VERSION);
194     debug print_fmt("Derelict loaded GL version: %d (%d), available GL version: %s\n", DerelictGL.loadedVersion, glver, glverstr);
195     
196     version (OSX)
197         enum GLVersion NEEDED_GL_VERSION = GLVersion.GL21;
198     else
199         enum GLVersion NEEDED_GL_VERSION = GLVersion.GL30;
200 
201     assert_fmt(glver >= NEEDED_GL_VERSION, "Your OpenGL version (%d) is too low. Need at least OpenGL 3.0.", glver);
202 
203     glDisable(GL_DITHER);
204     glDisable(GL_LIGHTING);
205     glDisable(GL_DEPTH_TEST);
206     glDisable(GL_ALPHA_TEST);
207 
208     glEnable(GL_TEXTURE_2D);
209 
210     glEnable(GL_BLEND);
211     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
212 
213     glEnable(GL_CULL_FACE);
214     glCullFace(GL_FRONT);
215 
216     glEnable(GL_MULTISAMPLE);
217 
218     //glShadeModel(GL_SMOOTH);
219     //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
220 
221     glEnableClientState(GL_VERTEX_ARRAY);
222     glEnableClientState(GL_COLOR_ARRAY);
223     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
224 }