-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
305 lines (264 loc) · 11.5 KB
/
Program.cs
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
using System.Text;
using System.Runtime.InteropServices;
using SDL2;
namespace SDL2Example;
internal class Program
{
static void Main(string[] args)
{
// avoid 0x406D1388 exception. See https://wiki.libsdl.org/SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING
SDL.SDL_SetHint(SDL.SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1");
// init video
ConOut.Write("Init SDL2 video: ");
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) < 0)
{
ConOut.WriteLine($"Error: {SDL.SDL_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// init audio
ConOut.Write("Init SDL2 audio: ");
if (SDL.SDL_Init(SDL.SDL_INIT_AUDIO) < 0)
{
ConOut.WriteLine($"Error: {SDL.SDL_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// init mixer
ConOut.Write("Init SDL2 mixer: ");
if (SDL_mixer.Mix_OpenAudio(44100, SDL_mixer.MIX_DEFAULT_FORMAT, 2, 2048) == -1)
{
ConOut.WriteLine($"Error: {SDL_mixer.Mix_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// init ttf
ConOut.Write("Init SDL2_ttf: ");
if (SDL_ttf.TTF_Init() < 0)
{
ConOut.WriteLine($"Error: {SDL_ttf.TTF_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// spawn window
ConOut.Write("Spawn window: ");
IntPtr Window = IntPtr.Zero;
Window = SDL.SDL_CreateWindow(
"SDL2Example",
SDL.SDL_WINDOWPOS_CENTERED,
SDL.SDL_WINDOWPOS_CENTERED,
800,
600,
SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE
);
if (Window == IntPtr.Zero)
{
ConOut.WriteLine($"Error: {SDL.SDL_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// set icon
IntPtr ico = SDL_image.IMG_Load("Resources\\Icon.png");
SDL.SDL_SetWindowIcon(Window, ico);
SDL.SDL_FreeSurface(ico);
// create renderer
ConOut.Write("Creating renderer: ");
IntPtr Renderer = IntPtr.Zero;
bool vSync = true;
Renderer = SDL.SDL_CreateRenderer(
Window,
-1,
SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED | (vSync ? SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC : 0x0)
);
if (Renderer == IntPtr.Zero)
{
ConOut.WriteLine($"Error: {SDL.SDL_GetError()}", ConsoleColor.Red);
return;
}
else
{
ConOut.WriteLine("Success", ConsoleColor.Green);
}
// log some renderer information
SDL.SDL_RendererInfo rendererInfo;
SDL.SDL_GetRendererInfo(Renderer, out rendererInfo);
string? currentVideoDriver = Marshal.PtrToStringAnsi(rendererInfo.name);
if (currentVideoDriver != null && currentVideoDriver != "")
{
ConOut.Write("Rendering using ");
ConOut.Write(currentVideoDriver, ConsoleColor.Blue);
ConOut.Write(" (");
ConOut.Write(SDL.SDL_GetCurrentVideoDriver(), ConsoleColor.Blue);
ConOut.WriteLine(")");
}
// load audio
IntPtr Music = SDL_mixer.Mix_LoadMUS("Resources\\loop.wav");
IntPtr Pew = SDL_mixer.Mix_LoadWAV("Resources\\laserpew.ogg");
// play music
SDL_mixer.Mix_VolumeMusic(64); // 0..128
SDL_mixer.Mix_FadeInMusic(Music, -1, 200); // fadein period under 200ms won't work
//SDL_mixer.Mix_PlayMusic(Music, -1); // for no fadein
// common texture size rect(s) for easy reuse
SDL.SDL_Rect TextureSize32 = new SDL.SDL_Rect() { w = 32, h = 32 };
// load texture(s)
IntPtr DeerTex = SDL_image.IMG_LoadTexture(Renderer, "Resources\\deer.png");
SDL.SDL_Rect DeerTexDrawPosition = TextureSize32; // initialize from texture size, to keep W and H in sync
DeerTexDrawPosition.x = 128;
DeerTexDrawPosition.y = 128;
// load font
IntPtr VCRFont = SDL_ttf.TTF_OpenFont("Resources\\VCR_OSD_MONO_1.001.ttf", 32); // filename, fontsize
SDL.SDL_Color FontColor = new SDL.SDL_Color() { r = 255, g = 127, b = 31 }; // r g b
// prerender font to texture
IntPtr FontSurface = SDL_ttf.TTF_RenderText_Solid(VCRFont, "This is a deer!", FontColor);
IntPtr FontTexture = SDL.SDL_CreateTextureFromSurface(Renderer, FontSurface);
// get font texture dimensions
SDL.SDL_QueryTexture(FontTexture, out _, out _, out int FontTexW, out int FontTexH);
SDL.SDL_Rect FontRect = new SDL.SDL_Rect() { w = FontTexW, h = FontTexH };
SDL.SDL_Rect FontTarget = FontRect; // initialize from texture size, to keep W and H in sync
FontTarget.x = 64;
FontTarget.y = 64;
// prepare a color for SDL2_gfx
UInt32 SolidRed = 0xFF0000FF; // Warning, this is in reverse but basically HTML color codes: A B G R
// main loop
SDL.SDL_Event e;
Boolean stop = false;
while (!stop)
{
ulong start = SDL.SDL_GetPerformanceCounter();
// start render batch
SDL.SDL_SetRenderDrawColor(Renderer, 32, 32, 64, 255); // R G B A background color
SDL.SDL_RenderClear(Renderer);
// draw texture
SDL.SDL_RenderCopy(Renderer, DeerTex, ref TextureSize32, ref DeerTexDrawPosition);
// draw font texture
SDL.SDL_RenderCopy(Renderer, FontTexture, ref FontRect, ref FontTarget);
// underline the font with SDL_gfx
SDL_gfx.lineColor(Renderer, (short)FontTarget.x, (short)(FontTarget.y + FontTarget.h + 10), (short)(FontTarget.x + FontTarget.w), (short)(FontTarget.y + FontTarget.h + 10), SolidRed);
// end render batch
SDL.SDL_RenderPresent(Renderer);
// handle events
while (SDL.SDL_PollEvent(out e) != 0)
{
switch (e.type)
{
case SDL.SDL_EventType.SDL_QUIT:
//quit on window closed
ConOut.WriteLine("Exiting: Caught SDL_QUIT", ConsoleColor.Blue);
stop = true;
break;
case SDL.SDL_EventType.SDL_KEYDOWN:
//quit on escape
if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_ESCAPE)
{
ConOut.WriteLine("Exiting: Caught SDLK_ESCAPE", ConsoleColor.Blue);
stop = true;
}
break;
case SDL.SDL_EventType.SDL_KEYUP:
// example to catch actual key name:
ConOut.WriteLine($"KeyUp: {Enum.GetName(typeof(SDL.SDL_Keycode), e.key.keysym.sym)}");
// play sound effect on RETURN (enter)
if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_RETURN)
{
SDL_mixer.Mix_PlayChannel(-1, Pew, 0); //play Pew effect once
}
break;
case SDL.SDL_EventType.SDL_MOUSEMOTION:
// catching this separately to avoid mouse movement spam as unhandled events in console
break;
case SDL.SDL_EventType.SDL_WINDOWEVENT:
switch (e.window.windowEvent)
{
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED:
//minimum size: 640x480
bool setRes = false;
int xSize = 640;
int ySize = 480;
if (e.window.data1 < 640)
{
setRes = true;
}
else
{
xSize = e.window.data1;
}
if (e.window.data2 < 480)
{
setRes = true;
}
else
{
ySize = e.window.data2;
}
if (setRes)
{
SDL.SDL_SetWindowSize(Window, xSize, ySize);
}
break;
default:
ConOut.WriteLine($"Unhandled window event: {Enum.GetName(typeof(SDL.SDL_WindowEventID), e.window.windowEvent)}", ConsoleColor.Yellow);
break;
}
break;
case SDL.SDL_EventType.SDL_TEXTINPUT:
// example to catch TextInput event. This supports IME so will work for compound characters like ë â ç and so on.
// use this to handle text input (like username/password)
byte[] rawBytes = new byte[SDL2.SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE];
unsafe
{
Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL2.SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE);
}
int length = Array.IndexOf(rawBytes, (byte)0);
string text = Encoding.UTF8.GetString(rawBytes, 0, length);
ConOut.WriteLine($"Caught TextInput event: {text}", ConsoleColor.Yellow);
break;
default:
ConOut.WriteLine($"Unhandled event: {Enum.GetName(typeof(SDL.SDL_EventType), e.type)}", ConsoleColor.Yellow);
break;
}
}
// limit framerate to ~120 fps when vSync is disabled
if (!vSync)
{
ulong end = SDL.SDL_GetPerformanceCounter();
float elapsed = (end - start) / (float)SDL.SDL_GetPerformanceFrequency() * 1000.0f;
uint delay = (uint)Math.Floor(8.333f - elapsed);
// this check avoids a huge delay when the window can't be drawn during for example moving it
if (delay < 32)
{
SDL.SDL_Delay(delay);
}
}
} // end of main loop
// handle shutdown
ConOut.WriteLine("Cleaning up...", ConsoleColor.White);
SDL.SDL_DestroyTexture(FontTexture);
SDL.SDL_FreeSurface(FontSurface);
SDL_ttf.TTF_CloseFont(VCRFont);
SDL_mixer.Mix_FreeChunk(Pew);
SDL_mixer.Mix_FreeMusic(Music);
SDL.SDL_DestroyTexture(DeerTex);
SDL.SDL_DestroyRenderer(Renderer);
SDL.SDL_DestroyWindow(Window);
SDL_mixer.Mix_CloseAudio();
SDL_ttf.TTF_Quit();
SDL.SDL_Quit();
ConOut.WriteLine("Bye!", ConsoleColor.Green);
Console.ResetColor();
}
}