1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 *
31 *-----------------------------------------------------------------------------
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 #ifdef _WIN32
38 #define WIN32_LEAN_AND_MEAN
39 #include <windows.h>
40 #include <direct.h>
41 #include <winreg.h>
42 #endif
43 #ifdef GL_DOOM
44 #include <SDL_opengl.h>
45 #endif
46 #include <string.h>
47 #include <math.h>
48
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52
53 #include "SDL.h"
54 #ifdef _WIN32
55 #include <SDL_syswm.h>
56 #endif
57
58 #include "hu_lib.h"
59
60 #include "doomtype.h"
61 #include "doomstat.h"
62 #include "d_main.h"
63 #include "s_sound.h"
64 #include "i_system.h"
65 #include "i_main.h"
66 #include "i_sound.h"
67 #include "m_menu.h"
68 #include "lprintf.h"
69 #include "m_argv.h"
70 #include "m_misc.h"
71 #include "i_system.h"
72 #include "p_maputl.h"
73 #include "p_map.h"
74 #include "i_video.h"
75 #include "info.h"
76 #include "r_screenmultiply.h"
77 #include "r_main.h"
78 #include "r_things.h"
79 #include "am_map.h"
80 #include "hu_tracers.h"
81 #ifdef GL_DOOM
82 #include "gl_struct.h"
83 #include "gl_intern.h"
84 #endif
85 #include "g_game.h"
86 #include "r_demo.h"
87 #include "e6y.h"
88
89 dboolean wasWiped = false;
90
91 int secretfound;
92 int messagecenter_counter;
93 int demo_skiptics;
94 int demo_playerscount;
95 int demo_tics_count;
96 int demo_curr_tic;
97 char demo_len_st[80];
98
99 int avi_shot_time;
100 int avi_shot_num;
101 const char *avi_shot_fname;
102 char avi_shot_curr_fname[PATH_MAX];
103
104 dboolean doSkip;
105 dboolean demo_stoponnext;
106 dboolean demo_stoponend;
107 dboolean demo_warp;
108
109 int key_speed_up;
110 int key_speed_down;
111 int key_speed_default;
112 int speed_step;
113 int key_level_restart;
114 int key_nextlevel;
115 int key_demo_jointogame;
116 int key_demo_endlevel;
117 int key_demo_skip;
118 int key_walkcamera;
119 int key_showalive;
120
121 int hudadd_gamespeed;
122 int hudadd_leveltime;
123 int hudadd_demotime;
124 int hudadd_secretarea;
125 int hudadd_smarttotals;
126 int hudadd_demoprogressbar;
127 int movement_strafe50;
128 int movement_shorttics;
129 int movement_strafe50onturns;
130 int movement_mouselook;
131 int movement_mouseinvert;
132 int movement_maxviewpitch;
133 int mouse_handler;
134 int mouse_doubleclick_as_use;
135 int render_fov;
136 int render_multisampling;
137 int render_paperitems;
138 int render_wipescreen;
139 int mouse_acceleration;
140 int demo_overwriteexisting;
141
142 int showendoom;
143
144 int palette_ondamage;
145 int palette_onbonus;
146 int palette_onpowers;
147
148 float mouse_accelfactor;
149
150 camera_t walkcamera;
151
152 hu_textline_t w_hudadd;
153 hu_textline_t w_centermsg;
154 hu_textline_t w_precache;
155 char hud_add[80];
156 char hud_centermsg[80];
157
158 fixed_t sidemove_normal[2] = {0x18, 0x28};
159 fixed_t sidemove_strafe50[2] = {0x19, 0x32};
160
161 int mouseSensitivity_mlook;
162 angle_t viewpitch;
163 float skyscale;
164 float screen_skybox_zplane;
165 float tan_pitch;
166 float skyUpAngle;
167 float skyUpShift;
168 float skyXShift;
169 float skyYShift;
170 dboolean mlook_or_fov;
171
172 int maxViewPitch;
173 int minViewPitch;
174
175 #ifdef _WIN32
WINError(void)176 const char* WINError(void)
177 {
178 static char *WinEBuff = NULL;
179 DWORD err = GetLastError();
180 char *ch;
181
182 if (WinEBuff)
183 {
184 LocalFree(WinEBuff);
185 }
186
187 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
188 NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
189 (LPTSTR) &WinEBuff, 0, NULL) == 0)
190 {
191 return "Unknown error";
192 }
193
194 if ((ch = strchr(WinEBuff, '\n')) != 0)
195 *ch = 0;
196 if ((ch = strchr(WinEBuff, '\r')) != 0)
197 *ch = 0;
198
199 return WinEBuff;
200 }
201 #endif
202
203 //--------------------------------------------------
204 #ifdef _WIN32
205 HWND WIN32_GetHWND(void);
206 #endif
207 //--------------------------------------------------
208
e6y_assert(const char * format,...)209 void e6y_assert(const char *format, ...)
210 {
211 static FILE *f = NULL;
212 va_list argptr;
213 va_start(argptr,format);
214 //if (!f)
215 f = fopen("d:\\a.txt", "ab+");
216 vfprintf(f, format, argptr);
217 fclose(f);
218 va_end(argptr);
219 }
220
221 /* ParamsMatchingCheck
222 * Conflicting command-line parameters could cause the engine to be confused
223 * in some cases. Added checks to prevent this.
224 * Example: glboom.exe -record mydemo -playdemo demoname
225 */
ParamsMatchingCheck()226 void ParamsMatchingCheck()
227 {
228 dboolean recording_attempt =
229 M_CheckParm("-record") ||
230 M_CheckParm("-recordfrom") ||
231 M_CheckParm("-recordfromto");
232
233 dboolean playbacking_attempt =
234 M_CheckParm("-playdemo") ||
235 M_CheckParm("-timedemo") ||
236 M_CheckParm("-fastdemo");
237
238 if (recording_attempt && playbacking_attempt)
239 I_Error("Params are not matching: Can not being played back and recorded at the same time.");
240 }
241
242 prboom_comp_t prboom_comp[PC_MAX] = {
243 {0xffffffff, 0x02020615, 0, "-force_monster_avoid_hazards"},
244 {0x00000000, 0x02040601, 0, "-force_remove_slime_trails"},
245 {0x02020200, 0x02040801, 0, "-force_no_dropoff"},
246 {0x00000000, 0x02040801, 0, "-force_truncated_sector_specials"},
247 {0x00000000, 0x02040802, 0, "-force_boom_brainawake"},
248 {0x00000000, 0x02040802, 0, "-force_prboom_friction"},
249 {0x02020500, 0x02040000, 0, "-reject_pad_with_ff"},
250 {0xffffffff, 0x02040802, 0, "-force_lxdoom_demo_compatibility"},
251 {0x00000000, 0x0202061b, 0, "-allow_ssg_direct"},
252 {0x00000000, 0x02040601, 0, "-treat_no_clipping_things_as_not_blocking"},
253 {0x00000000, 0x02040803, 0, "-force_incorrect_processing_of_respawn_frame_entry"},
254 {0x00000000, 0x02040601, 0, "-force_correct_code_for_3_keys_doors_in_mbf"},
255 {0x00000000, 0x02040601, 0, "-uninitialize_crush_field_for_stairs"},
256 {0x00000000, 0x02040802, 0, "-force_boom_findnexthighestfloor"},
257 {0x00000000, 0x02040802, 0, "-allow_sky_transfer_in_boom"},
258 {0x00000000, 0x02040803, 0, "-apply_green_armor_class_to_armor_bonuses"},
259 {0x00000000, 0x02040803, 0, "-apply_blue_armor_class_to_megasphere"},
260 {0x02050001, 0x02050003, 0, "-wrong_fixeddiv"},
261 {0x02020200, 0x02050003, 0, "-force_incorrect_bobbing_in_boom"},
262 {0xffffffff, 0x00000000, 0, "-boom_deh_parser"},
263 {0x00000000, 0x02050007, 0, "-mbf_remove_thinker_in_killmobj"},
264 {0x00000000, 0x02050007, 0, "-do_not_inherit_friendlyness_flag_on_spawn"},
265 {0x00000000, 0x02050007, 0, "-do_not_use_misc12_frame_parameters_in_a_mushroom"},
266 {0x00000000, 0x02050102, 0, "-apply_mbf_codepointers_to_any_complevel"},
267 };
268
269 dboolean *use_wrong_fixeddiv;
e6y_InitCommandLine(void)270 void e6y_InitCommandLine(void)
271 {
272 int p;
273
274 if ((p = M_CheckParm("-skipsec")) && (p < myargc-1))
275 demo_skiptics = (int)(atof(myargv[p + 1]) * 35);
276 if ((IsDemoPlayback() || IsDemoContinue()) && (startmap > 1 || demo_skiptics))
277 G_SkipDemoStart();
278 if ((p = M_CheckParm("-avidemo")) && (p < myargc-1))
279 avi_shot_fname = myargv[p + 1];
280 stats_level = M_CheckParm("-levelstat");
281
282 // TAS-tracers
283 InitTracers();
284
285 shorttics = movement_shorttics || M_CheckParm("-shorttics");
286
287 // What hacked exe are we emulating?
288 game_exe = EXE_NONE;
289 if ((p = M_CheckParm("-exe")) && (p < myargc-1))
290 {
291 if (!strcasecmp(myargv[p + 1], "chex") || !strcasecmp(myargv[p + 1], "chex.exe"))
292 {
293 game_exe = EXE_CHEX;
294 }
295 }
296 }
297
298 static dboolean saved_fastdemo;
299 static dboolean saved_nodrawers;
300 static dboolean saved_nosfxparm;
301 static dboolean saved_nomusicparm;
302 static int saved_render_precise;
303
G_SkipDemoStart(void)304 void G_SkipDemoStart(void)
305 {
306 saved_fastdemo = fastdemo;
307 saved_nodrawers = nodrawers;
308 saved_nosfxparm = nosfxparm;
309 saved_nomusicparm = nomusicparm;
310 saved_render_precise = render_precise;
311
312 paused = false;
313
314 doSkip = true;
315
316 S_StopMusic();
317 fastdemo = true;
318 nodrawers = true;
319 nosfxparm = true;
320 nomusicparm = true;
321
322 render_precise = false;
323 M_ChangeRenderPrecise();
324
325 I_Init2();
326 }
327
328 dboolean sound_inited_once = false;
329
G_SkipDemoStop(void)330 void G_SkipDemoStop(void)
331 {
332 fastdemo = saved_fastdemo;
333 nodrawers = saved_nodrawers;
334 nosfxparm = saved_nosfxparm;
335 nomusicparm = saved_nomusicparm;
336
337 render_precise = saved_render_precise;
338 M_ChangeRenderPrecise();
339
340 demo_stoponnext = false;
341 demo_stoponend = false;
342 demo_warp = false;
343 doSkip = false;
344 demo_skiptics = 0;
345 startmap = 0;
346
347 I_Init2();
348 if (!sound_inited_once && !(nomusicparm && nosfxparm))
349 {
350 I_InitSound();
351 }
352 S_Init(snd_SfxVolume, snd_MusicVolume);
353 S_Stop();
354 S_RestartMusic();
355
356 #ifdef GL_DOOM
357 if (V_GetMode() == VID_MODEGL) {
358 gld_PreprocessLevel();
359 }
360 #endif
361 }
362
G_SkipDemoCheck(void)363 void G_SkipDemoCheck(void)
364 {
365 if (doSkip && gametic > 0)
366 {
367 if (((startmap <= 1) &&
368 (gametic > demo_skiptics + (demo_skiptics > 0 ? 0 : demo_tics_count))) ||
369 (demo_warp && gametic - levelstarttic > demo_skiptics))
370 {
371 G_SkipDemoStop();
372 }
373 }
374 }
375
G_ReloadLevel(void)376 int G_ReloadLevel(void)
377 {
378 int result = false;
379
380 if ((gamestate == GS_LEVEL) &&
381 !deathmatch && !netgame &&
382 !demorecording && !demoplayback &&
383 !menuactive)
384 {
385 G_DeferedInitNew(gameskill, gameepisode, gamemap);
386 result = true;
387 }
388
389 return result;
390 }
391
G_GotoNextLevel(void)392 int G_GotoNextLevel(void)
393 {
394 static byte doom2_next[32] = {
395 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
396 12, 13, 14, 15, 31, 17, 18, 19, 20, 21,
397 22, 23, 24, 25, 26, 27, 28, 29, 30, 1,
398 32, 16
399 };
400 static byte doom_next[4][9] = {
401 {12, 13, 19, 15, 16, 17, 18, 21, 14},
402 {22, 23, 24, 25, 29, 27, 28, 31, 26},
403 {32, 33, 34, 35, 36, 39, 38, 41, 37},
404 {42, 49, 44, 45, 46, 47, 48, 11, 43}
405 };
406
407 int changed = false;
408
409 // secret level
410 doom2_next[14] = (haswolflevels ? 31 : 16);
411
412 // shareware doom has only episode 1
413 doom_next[0][7] = (gamemode == shareware ? 11 : 21);
414
415 doom_next[2][7] = ((gamemode == registered) ||
416 // the fourth episode for pre-ultimate complevels is not allowed.
417 (compatibility_level < ultdoom_compatibility) ?
418 11 : 41);
419
420 if ((gamestate == GS_LEVEL) &&
421 !deathmatch && !netgame &&
422 !demorecording && !demoplayback &&
423 !menuactive)
424 {
425 //doom2_next and doom_next are 0 biased, unlike gameepisode and gamemap
426 int epsd = gameepisode - 1;
427 int map = gamemap - 1;
428
429 if (gamemode == commercial)
430 {
431 epsd = 1;
432 map = doom2_next[BETWEEN(0, 31, map)];
433 }
434 else
435 {
436 int next = doom_next[BETWEEN(0, 3, epsd)][BETWEEN(0, 9, map)];
437 epsd = next / 10;
438 map = next % 10;
439 }
440
441 G_DeferedInitNew(gameskill, epsd, map);
442 changed = true;
443 }
444
445 return changed;
446 }
447
M_ChangeSpeed(void)448 void M_ChangeSpeed(void)
449 {
450 extern int sidemove[2];
451
452 if(movement_strafe50)
453 {
454 sidemove[0] = sidemove_strafe50[0];
455 sidemove[1] = sidemove_strafe50[1];
456 }
457 else
458 {
459 movement_strafe50onturns = false;
460 sidemove[0] = sidemove_normal[0];
461 sidemove[1] = sidemove_normal[1];
462 }
463 }
464
465 #ifdef GL_DOOM
M_ChangeMouseLook(void)466 void M_ChangeMouseLook(void)
467 {
468 viewpitch = 0;
469
470 if (gl_skymode == skytype_auto)
471 gl_drawskys = (movement_mouselook ? skytype_skydome : skytype_standard);
472 else
473 gl_drawskys = gl_skymode;
474 }
475
M_ChangeMouseInvert(void)476 void M_ChangeMouseInvert(void)
477 {
478 }
479
M_ChangeMaxViewPitch(void)480 void M_ChangeMaxViewPitch(void)
481 {
482 int angle = (int)((float)movement_maxviewpitch / 45.0f * ANG45);
483 maxViewPitch = (angle - (1<<ANGLETOFINESHIFT));
484 minViewPitch = (-angle + (1<<ANGLETOFINESHIFT));
485
486 viewpitch = 0;
487 }
488 #endif // GL_DOOM
489
M_ChangeRenderPrecise(void)490 void M_ChangeRenderPrecise(void)
491 {
492 #ifdef GL_DOOM
493 if (V_GetMode() != VID_MODEGL)
494 {
495 gl_seamless = false;
496 return;
497 }
498 else
499 {
500 if (render_precise)
501 {
502 gl_seamless = true;
503 gld_InitVertexData();
504 }
505 else
506 {
507 gl_seamless = false;
508 gld_CleanVertexData();
509 }
510 }
511 #endif // GL_DOOM
512
513 AM_SetRenderPrecise();
514 }
515
M_ChangeScreenMultipleFactor(void)516 void M_ChangeScreenMultipleFactor(void)
517 {
518 V_ChangeScreenResolution();
519 }
520
M_ChangeInterlacedScanning(void)521 void M_ChangeInterlacedScanning(void)
522 {
523 if (render_interlaced_scanning)
524 interlaced_scanning_requires_clearing = 1;
525 }
526
527 #ifdef GL_DOOM
GetMouseLook(void)528 dboolean GetMouseLook(void)
529 {
530 return movement_mouselook;
531 }
HaveMouseLook(void)532 dboolean HaveMouseLook(void)
533 {
534 return (viewpitch != 0);
535 }
536 #endif
537
CheckPitch(signed int * pitch)538 void CheckPitch(signed int *pitch)
539 {
540 if (V_GetMode() == VID_MODEGL)
541 {
542 if(*pitch > maxViewPitch)
543 *pitch = maxViewPitch;
544 if(*pitch < minViewPitch)
545 *pitch = minViewPitch;
546
547 (*pitch) >>= 16;
548 (*pitch) <<= 16;
549 }
550 }
551
552 int render_aspect;
553 float render_ratio;
554 float render_fovratio;
555 float render_fovy = FOV90;
556 float render_multiplier;
557
M_ChangeAspectRatio(void)558 void M_ChangeAspectRatio(void)
559 {
560 extern int screenblocks;
561
562 #ifdef GL_DOOM
563 M_ChangeFOV();
564 #endif
565
566 R_SetViewSize(screenblocks);
567 }
568
M_ChangeStretch(void)569 void M_ChangeStretch(void)
570 {
571 extern int screenblocks;
572
573 render_stretch_hud = render_stretch_hud_default;
574
575 R_SetViewSize(screenblocks);
576 }
577
578 #ifdef GL_DOOM
M_ChangeMultiSample(void)579 void M_ChangeMultiSample(void)
580 {
581 }
582
M_ChangeFOV(void)583 void M_ChangeFOV(void)
584 {
585 float f1, f2;
586 int p;
587 int render_aspect_width, render_aspect_height;
588
589 if ((p = M_CheckParm("-aspect")) && (p+1 < myargc) && (strlen(myargv[p+1]) <= 21) &&
590 (2 == sscanf(myargv[p+1], "%dx%d", &render_aspect_width, &render_aspect_height)))
591 {
592 CheckRatio(SCREENWIDTH, SCREENHEIGHT);
593 render_fovratio = (float)render_aspect_width / (float)render_aspect_height;
594 render_ratio = RMUL * render_fovratio;
595 render_multiplier = 64.0f / render_fovratio / RMUL;
596 }
597 else
598 {
599 CheckRatio(SCREENWIDTH, SCREENHEIGHT);
600 render_ratio = BaseRatioSizes[wide_ratio].gl_ratio;
601 render_multiplier = (float)BaseRatioSizes[wide_ratio].multiplier;
602 if (!(wide_ratio & 4))
603 {
604 render_fovratio = 1.6f;
605 }
606 else
607 {
608 render_fovratio = render_ratio;
609 }
610 }
611
612 render_fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(render_fov) / 2) / render_fovratio)));
613
614 screen_skybox_zplane = 320.0f/2.0f/(float)tan(DEG2RAD(render_fov/2));
615
616 f1 = (float)(320.0f / 200.0f * (float)render_fov / (float)FOV90 - 0.2f);
617 f2 = (float)tan(DEG2RAD(render_fovy)/2.0f);
618 if (f1-f2<1)
619 skyUpAngle = (float)-RAD2DEG(asin(f1-f2));
620 else
621 skyUpAngle = -90.0f;
622
623 skyUpShift = (float)tan(DEG2RAD(render_fovy)/2.0f);
624
625 skyscale = 1.0f / (float)tan(DEG2RAD(render_fov / 2));
626 }
627
M_ChangeSpriteClip(void)628 void M_ChangeSpriteClip(void)
629 {
630 gl_sprite_offset = (gl_spriteclip != spriteclip_const ? 0 : (.01f * (float)gl_sprite_offset_default));
631 gl_spriteclip_threshold_f = (float)gl_spriteclip_threshold / MAP_COEFF;
632 }
633
ResolveColormapsHiresConflict(dboolean prefer_colormap)634 void ResolveColormapsHiresConflict(dboolean prefer_colormap)
635 {
636 gl_boom_colormaps = !r_have_internal_hires && !gl_texture_external_hires;
637 #if 0
638 if (prefer_colormap)
639 {
640 if (gl_boom_colormaps_default)
641 {
642 gl_texture_external_hires = false;
643 }
644 else if (gl_texture_external_hires)
645 {
646 gl_boom_colormaps = false;
647 gl_boom_colormaps_default = false;
648 }
649 }
650 else
651 {
652 if (gl_texture_external_hires)
653 {
654 gl_boom_colormaps = false;
655 gl_boom_colormaps_default = false;
656 }
657 else if (gl_boom_colormaps_default)
658 {
659 gl_texture_external_hires = false;
660 }
661 }
662 #endif
663 }
664
M_ChangeAllowBoomColormaps(void)665 void M_ChangeAllowBoomColormaps(void)
666 {
667 if (gl_boom_colormaps == -1)
668 {
669 gl_boom_colormaps = gl_boom_colormaps_default;
670 ResolveColormapsHiresConflict(true);
671 }
672 else
673 {
674 gl_boom_colormaps = gl_boom_colormaps_default;
675 ResolveColormapsHiresConflict(true);
676 gld_FlushTextures();
677 gld_Precache();
678 }
679 }
680
M_ChangeTextureUseHires(void)681 void M_ChangeTextureUseHires(void)
682 {
683 ResolveColormapsHiresConflict(false);
684
685 gld_FlushTextures();
686 gld_Precache();
687 }
688
M_ChangeTextureHQResize(void)689 void M_ChangeTextureHQResize(void)
690 {
691 gld_FlushTextures();
692 }
693 #endif //GL_DOOM
694
695 void M_Mouse(int choice, int *sens);
M_MouseMLook(int choice)696 void M_MouseMLook(int choice)
697 {
698 M_Mouse(choice, &mouseSensitivity_mlook);
699 }
700
M_MouseAccel(int choice)701 void M_MouseAccel(int choice)
702 {
703 M_Mouse(choice, &mouse_acceleration);
704 MouseAccelChanging();
705 }
706
MouseAccelChanging(void)707 void MouseAccelChanging(void)
708 {
709 mouse_accelfactor = (float)mouse_acceleration/100.0f+1.0f;
710 }
711
M_DemosBrowse(void)712 void M_DemosBrowse(void)
713 {
714 }
715
716 float viewPitch;
717 dboolean transparentpresent;
718
StepwiseSum(int value,int direction,int step,int minval,int maxval,int defval)719 int StepwiseSum(int value, int direction, int step, int minval, int maxval, int defval)
720 {
721 static int prev_value = 0;
722 static int prev_direction = 0;
723
724 int newvalue;
725 int val = (direction > 0 ? value : value - 1);
726
727 if (direction == 0)
728 return defval;
729
730 direction = (direction > 0 ? 1 : -1);
731
732 if (step != 0)
733 newvalue = (prev_direction * direction < 0 ? prev_value : value + direction * step);
734 else
735 {
736 int exp = 1;
737 while (exp * 10 <= val)
738 exp *= 10;
739 newvalue = direction * (val < exp * 5 && exp > 1 ? exp / 2 : exp);
740 newvalue = (value + newvalue) / newvalue * newvalue;
741 }
742
743 if (newvalue > maxval) newvalue = maxval;
744 if (newvalue < minval) newvalue = minval;
745
746 if ((value < defval && newvalue > defval) || (value > defval && newvalue < defval))
747 newvalue = defval;
748
749 if (newvalue != value)
750 {
751 prev_value = value;
752 prev_direction = direction;
753 }
754
755 return newvalue;
756 }
757
I_vWarning(const char * message,va_list argList)758 void I_vWarning(const char *message, va_list argList)
759 {
760 char msg[1024];
761 #ifdef HAVE_VSNPRINTF
762 vsnprintf(msg,sizeof(msg),message,argList);
763 #else
764 vsprintf(msg,message,argList);
765 #endif
766 lprintf(LO_ERROR, "%s\n", msg);
767 #ifdef _MSC_VER
768 I_MessageBox(msg, PRB_MB_OK);
769 #endif
770 }
771
I_Warning(const char * message,...)772 void I_Warning(const char *message, ...)
773 {
774 va_list argptr;
775 va_start(argptr,message);
776 I_vWarning(message, argptr);
777 va_end(argptr);
778 }
779
I_MessageBox(const char * text,unsigned int type)780 int I_MessageBox(const char* text, unsigned int type)
781 {
782 int result = PRB_IDCANCEL;
783
784 #ifdef _WIN32
785 {
786 HWND current_hwnd = GetForegroundWindow();
787 result = MessageBox(GetDesktopWindow(), text, PACKAGE_NAME, type|MB_TASKMODAL|MB_TOPMOST);
788 I_SwitchToWindow(current_hwnd);
789 return result;
790 }
791 #endif
792
793 #if 0
794 {
795 typedef struct mb_hotkeys_s
796 {
797 int type;
798 char *hotkeys_str;
799 } mb_hotkeys_t;
800
801 mb_hotkeys_t mb_hotkeys[] = {
802 {PRB_MB_OK , "(press <enter> to continue)"},
803 {PRB_MB_OKCANCEL , "(press <enter> to continue or <esc> to cancel)"},
804 {PRB_MB_ABORTRETRYIGNORE , "(a - abort, r - retry, i - ignore)"},
805 {PRB_MB_YESNOCANCEL , "(y - yes, n - no, esc - cancel"},
806 {PRB_MB_YESNO , "(y - yes, n - no)"},
807 {PRB_MB_RETRYCANCEL , "(r - retry, <esc> - cancel)"},
808 {0, NULL}
809 };
810
811 int i, c;
812 char* hotkeys_str = NULL;
813
814 type &= 0x000000ff;
815
816 i = 0;
817 while (mb_hotkeys[i].hotkeys_str)
818 {
819 if (mb_hotkeys[i].type == type)
820 {
821 hotkeys_str = mb_hotkeys[i].hotkeys_str;
822 break;
823 }
824 i++;
825 }
826
827 if (hotkeys_str)
828 {
829 lprintf(LO_CONFIRM, "%s\n%s\n", text, hotkeys_str);
830
831 result = -1;
832 do
833 {
834 I_uSleep(1000);
835
836 c = tolower(getchar());
837
838 if (c == 'y') result = PRB_IDYES;
839 else if (c == 'n') result = PRB_IDNO;
840 else if (c == 'a') result = PRB_IDABORT;
841 else if (c == 'r') result = PRB_IDRETRY;
842 else if (c == 'i') result = PRB_IDIGNORE;
843 else if (c == 'o' || c == 13) result = PRB_IDOK;
844 else if (c == 'c' || c == 27) result = PRB_IDCANCEL;
845 }
846 while (result == EOF);
847
848 return result;
849 }
850
851 return result;
852 }
853 #else
854 return PRB_IDCANCEL;
855 #endif
856 }
857
858 int stats_level;
859 int numlevels = 0;
860 int levels_max = 0;
861 timetable_t *stats = NULL;
862
e6y_G_DoCompleted(void)863 void e6y_G_DoCompleted(void)
864 {
865 int i;
866
867 if (doSkip && (demo_stoponend || demo_warp))
868 G_SkipDemoStop();
869
870 if(!stats_level)
871 return;
872
873 if (numlevels >= levels_max)
874 {
875 levels_max = levels_max ? levels_max*2 : 32;
876 stats = realloc(stats,sizeof(*stats)*levels_max);
877 }
878
879 memset(&stats[numlevels], 0, sizeof(timetable_t));
880
881 if (gamemode==commercial)
882 sprintf(stats[numlevels].map,"MAP%02i",gamemap);
883 else
884 sprintf(stats[numlevels].map,"E%iM%i",gameepisode,gamemap);
885
886 stats[numlevels].stat[TT_TIME] = leveltime;
887 stats[numlevels].stat[TT_TOTALTIME] = totalleveltimes;
888 stats[numlevels].stat[TT_TOTALKILL] = totalkills;
889 stats[numlevels].stat[TT_TOTALITEM] = totalitems;
890 stats[numlevels].stat[TT_TOTALSECRET] = totalsecret;
891
892 for (i=0 ; i<MAXPLAYERS ; i++)
893 {
894 if (playeringame[i])
895 {
896 stats[numlevels].kill[i] = players[i].killcount - players[i].resurectedkillcount;
897 stats[numlevels].item[i] = players[i].itemcount;
898 stats[numlevels].secret[i] = players[i].secretcount;
899
900 stats[numlevels].stat[TT_ALLKILL] += stats[numlevels].kill[i];
901 stats[numlevels].stat[TT_ALLITEM] += stats[numlevels].item[i];
902 stats[numlevels].stat[TT_ALLSECRET] += stats[numlevels].secret[i];
903 }
904 }
905
906 numlevels++;
907
908 e6y_WriteStats();
909 }
910
911 typedef struct tmpdata_s
912 {
913 char kill[200];
914 char item[200];
915 char secret[200];
916 } tmpdata_t;
917
e6y_WriteStats(void)918 void e6y_WriteStats(void)
919 {
920 FILE *f;
921 char str[200];
922 int i, level, playerscount;
923 timetable_t max;
924 tmpdata_t tmp;
925 tmpdata_t all[32];
926 size_t allkills_len=0, allitems_len=0, allsecrets_len=0;
927
928 f = fopen("levelstat.txt", "wb");
929
930 memset(&max, 0, sizeof(timetable_t));
931
932 playerscount = 0;
933 for (i=0; i<MAXPLAYERS; i++)
934 if (playeringame[i])
935 playerscount++;
936
937 for (level=0;level<numlevels;level++)
938 {
939 memset(&tmp, 0, sizeof(tmpdata_t));
940 for (i=0 ; i<MAXPLAYERS ; i++)
941 {
942 if (playeringame[i])
943 {
944 strcpy(str, strlen(tmp.kill)==0?"%s%d":"%s+%d");
945
946 sprintf(tmp.kill, str, tmp.kill, stats[level].kill[i] );
947 sprintf(tmp.item, str, tmp.item, stats[level].item[i] );
948 sprintf(tmp.secret, str, tmp.secret, stats[level].secret[i]);
949 }
950 }
951 if (playerscount<2)
952 memset(&all[level], 0, sizeof(tmpdata_t));
953 else
954 {
955 sprintf(all[level].kill, " (%s)", tmp.kill );
956 sprintf(all[level].item, " (%s)", tmp.item );
957 sprintf(all[level].secret, " (%s)", tmp.secret);
958 }
959
960 if (strlen(all[level].kill) > allkills_len)
961 allkills_len = strlen(all[level].kill);
962 if (strlen(all[level].item) > allitems_len)
963 allitems_len = strlen(all[level].item);
964 if (strlen(all[level].secret) > allsecrets_len)
965 allsecrets_len = strlen(all[level].secret);
966
967 for(i=0; i<TT_MAX; i++)
968 if (stats[level].stat[i] > max.stat[i])
969 max.stat[i] = stats[level].stat[i];
970 }
971 max.stat[TT_TIME] = max.stat[TT_TIME]/TICRATE/60;
972 max.stat[TT_TOTALTIME] = max.stat[TT_TOTALTIME]/TICRATE/60;
973
974 for(i=0; i<TT_MAX; i++) {
975 SNPRINTF(str, 200, "%d", max.stat[i]);
976 max.stat[i] = strlen(str);
977 }
978
979 for (level=0;level<numlevels;level++)
980 {
981 sprintf(str,
982 "%%s - %%%dd:%%05.2f (%%%dd:%%02d) K: %%%dd/%%-%dd%%%ds I: %%%dd/%%-%dd%%%ds S: %%%dd/%%-%dd %%%ds\r\n",
983 max.stat[TT_TIME], max.stat[TT_TOTALTIME],
984 max.stat[TT_ALLKILL], max.stat[TT_TOTALKILL], allkills_len,
985 max.stat[TT_ALLITEM], max.stat[TT_TOTALITEM], allitems_len,
986 max.stat[TT_ALLSECRET], max.stat[TT_TOTALSECRET], allsecrets_len);
987
988 fprintf(f, str, stats[level].map,
989 stats[level].stat[TT_TIME]/TICRATE/60,
990 (float)(stats[level].stat[TT_TIME]%(60*TICRATE))/TICRATE,
991 (stats[level].stat[TT_TOTALTIME])/TICRATE/60,
992 (stats[level].stat[TT_TOTALTIME]%(60*TICRATE))/TICRATE,
993 stats[level].stat[TT_ALLKILL], stats[level].stat[TT_TOTALKILL], all[level].kill,
994 stats[level].stat[TT_ALLITEM], stats[level].stat[TT_TOTALITEM], all[level].item,
995 stats[level].stat[TT_ALLSECRET],stats[level].stat[TT_TOTALSECRET], all[level].secret
996 );
997
998 }
999
1000 fclose(f);
1001 }
1002
e6y_G_DoWorldDone(void)1003 void e6y_G_DoWorldDone(void)
1004 {
1005 if (doSkip)
1006 {
1007 static int firstmap = 1;
1008 int episode = 0;
1009 int map = 0;
1010 int p;
1011
1012 if ((p = M_CheckParm ("-warp")))
1013 {
1014 if (gamemode == commercial)
1015 {
1016 if (p < myargc - 1)
1017 map = atoi(myargv[p + 1]);
1018 }
1019 else
1020 {
1021 if (p < myargc - 2)
1022 {
1023 episode = atoi(myargv[++p]);
1024 map = atoi(myargv[p + 1]);
1025 }
1026 }
1027 }
1028
1029 demo_warp = demo_stoponnext ||
1030 (gamemode == commercial ? (map == gamemap) : (episode == gameepisode && map == gamemap));
1031
1032 if (demo_warp && demo_skiptics == 0 && !firstmap)
1033 G_SkipDemoStop();
1034
1035 firstmap = 0;
1036 }
1037 }
1038
1039 //--------------------------------------------------
1040
1041 #ifdef _WIN32
WIN32_GetHWND(void)1042 HWND WIN32_GetHWND(void)
1043 {
1044 static HWND Window = NULL;
1045 if(!Window)
1046 {
1047 SDL_SysWMinfo wminfo;
1048 SDL_VERSION(&wminfo.version);
1049 SDL_GetWMInfo(&wminfo);
1050 #if SDL_VERSION_ATLEAST(1, 3, 0)
1051 Window = wminfo.info.win.window;
1052 #else
1053 Window = wminfo.window;
1054 #endif
1055 }
1056 return Window;
1057 }
1058 #endif
1059
AccelerateMouse(int val)1060 int AccelerateMouse(int val)
1061 {
1062 if (!mouse_acceleration)
1063 return val;
1064
1065 if (val < 0)
1066 return -AccelerateMouse(-val);
1067
1068 return M_DoubleToInt(pow((double)val, (double)mouse_accelfactor));
1069 }
1070
1071 int mlooky = 0;
1072
1073 dboolean IsDehMaxHealth = false;
1074 dboolean IsDehMaxSoul = false;
1075 dboolean IsDehMegaHealth = false;
1076 dboolean DEH_mobjinfo_bits[NUMMOBJTYPES] = {0};
1077
1078 int deh_maxhealth;
1079 int deh_max_soul;
1080 int deh_mega_health;
1081
1082 int maxhealthbonus;
1083
M_ChangeCompTranslucency(void)1084 void M_ChangeCompTranslucency(void)
1085 {
1086 int i;
1087 int predefined_translucency[] = {
1088 MT_FIRE, MT_SMOKE, MT_FATSHOT, MT_BRUISERSHOT, MT_SPAWNFIRE,
1089 MT_TROOPSHOT, MT_HEADSHOT, MT_PLASMA, MT_BFG, MT_ARACHPLAZ, MT_PUFF,
1090 MT_TFOG, MT_IFOG, MT_MISC12, MT_INV, MT_INS, MT_MEGA
1091 };
1092
1093 for(i = 0; (size_t)i < sizeof(predefined_translucency)/sizeof(predefined_translucency[0]); i++)
1094 {
1095 if (!DEH_mobjinfo_bits[predefined_translucency[i]])
1096 {
1097 // Transparent sprites are not visible behind transparent walls in OpenGL.
1098 // It needs much work.
1099 #ifdef GL_DOOM
1100 if (V_GetMode() == VID_MODEGL)
1101 {
1102 // Disabling transparency in OpenGL for original sprites
1103 // which are not changed by dehacked, because it's buggy for now.
1104 // Global sorting of transparent sprites and walls is needed
1105 mobjinfo[predefined_translucency[i]].flags &= ~MF_TRANSLUCENT;
1106 }
1107 else
1108 #endif
1109 if (comp[comp_translucency])
1110 mobjinfo[predefined_translucency[i]].flags &= ~MF_TRANSLUCENT;
1111 else
1112 mobjinfo[predefined_translucency[i]].flags |= MF_TRANSLUCENT;
1113 }
1114 }
1115 }
1116
e6y_G_Compatibility(void)1117 void e6y_G_Compatibility(void)
1118 {
1119 extern int maxhealth;
1120 extern int max_soul;
1121 extern int mega_health;
1122
1123 int comp_max = (compatibility_level == doom_12_compatibility ? 199 : 200);
1124
1125 max_soul = (IsDehMaxSoul ? deh_max_soul : comp_max);
1126 mega_health = (IsDehMegaHealth ? deh_mega_health : comp_max);
1127
1128 if (comp[comp_maxhealth])
1129 {
1130 maxhealth = 100;
1131 maxhealthbonus = (IsDehMaxHealth ? deh_maxhealth : comp_max);
1132 }
1133 else
1134 {
1135 maxhealth = (IsDehMaxHealth ? deh_maxhealth : 100);
1136 maxhealthbonus = maxhealth * 2;
1137 }
1138
1139 if (!DEH_mobjinfo_bits[MT_SKULL])
1140 {
1141 if (compatibility_level == doom_12_compatibility)
1142 mobjinfo[MT_SKULL].flags |= (MF_COUNTKILL);
1143 else
1144 mobjinfo[MT_SKULL].flags &= ~(MF_COUNTKILL);
1145 }
1146
1147 M_ChangeCompTranslucency();
1148
1149 if (IsDemoPlayback())
1150 {
1151 int i, p;
1152
1153 //"2.4.8.2" -> 0x02040802
1154 if ((p = M_CheckParm("-emulate")) && (p < myargc - 1))
1155 {
1156 unsigned int emulated_version = 0;
1157 int b[4], k = 1;
1158 memset(b, 0, sizeof(b));
1159 sscanf(myargv[p + 1], "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]);
1160 for (i = 3; i >= 0; i--, k *= 256)
1161 {
1162 #ifdef RANGECHECK
1163 if (b[i] >= 256)
1164 I_Error("Wrong version number of package: %s", VERSION);
1165 #endif
1166 emulated_version += b[i] * k;
1167 }
1168
1169 for (i = 0; i < PC_MAX; i++)
1170 {
1171 prboom_comp[i].state =
1172 (emulated_version >= prboom_comp[i].minver &&
1173 emulated_version < prboom_comp[i].maxver);
1174 }
1175 }
1176
1177 for (i = 0; i < PC_MAX; i++)
1178 {
1179 if (M_CheckParm(prboom_comp[i].cmd))
1180 prboom_comp[i].state = true;
1181 }
1182 }
1183 use_wrong_fixeddiv = &(prboom_comp[PC_WRONG_FIXEDDIV].state);
1184
1185 P_CrossSubsector = P_CrossSubsector_PrBoom;
1186 if (!prboom_comp[PC_FORCE_LXDOOM_DEMO_COMPATIBILITY].state)
1187 {
1188 if (demo_compatibility)
1189 P_CrossSubsector = P_CrossSubsector_Doom;
1190
1191 switch (compatibility_level)
1192 {
1193 case boom_compatibility_compatibility:
1194 case boom_201_compatibility:
1195 case boom_202_compatibility:
1196 case mbf_compatibility:
1197 P_CrossSubsector = P_CrossSubsector_Boom;
1198 break;
1199 }
1200 }
1201 }
1202
1203 dboolean zerotag_manual;
1204 int comperr_zerotag;
1205 int comperr_passuse;
1206 int comperr_hangsolid;
1207
ProcessNoTagLines(line_t * line,sector_t ** sec,int * secnum)1208 dboolean ProcessNoTagLines(line_t* line, sector_t **sec, int *secnum)
1209 {
1210 zerotag_manual = false;
1211 if (line->tag == 0 && COMPBAD(comperr_zerotag))
1212 {
1213 if (!(*sec=line->backsector))
1214 return true;
1215 *secnum = (*sec)->iSectorID;
1216 zerotag_manual = true;
1217 return true;
1218 }
1219 return false;
1220 }
1221
PathFindFileName(const char * pPath)1222 char* PathFindFileName(const char* pPath)
1223 {
1224 const char* pT = pPath;
1225
1226 if (pPath)
1227 {
1228 for ( ; *pPath; pPath++)
1229 {
1230 if ((pPath[0] == '\\' || pPath[0] == ':' || pPath[0] == '/')
1231 && pPath[1] && pPath[1] != '\\' && pPath[1] != '/')
1232 pT = pPath + 1;
1233 }
1234 }
1235
1236 return (char*)pT;
1237 }
1238
NormalizeSlashes2(char * str)1239 void NormalizeSlashes2(char *str)
1240 {
1241 size_t l;
1242
1243 if (!str || !(l = strlen(str)))
1244 return;
1245 if (str[--l]=='\\' || str[l]=='/')
1246 str[l]=0;
1247 while (l--)
1248 if (str[l]=='/')
1249 str[l]='\\';
1250 }
1251
AfxGetFileName(const char * lpszPathName,char * lpszTitle,unsigned int nMax)1252 unsigned int AfxGetFileName(const char* lpszPathName, char* lpszTitle, unsigned int nMax)
1253 {
1254 char* lpszTemp = PathFindFileName(lpszPathName);
1255
1256 if (lpszTitle == NULL)
1257 return strlen(lpszTemp)+1;
1258
1259 strncpy(lpszTitle, lpszTemp, nMax-1);
1260 return 0;
1261 }
1262
AbbreviateName(char * lpszCanon,int cchMax,int bAtLeastName)1263 void AbbreviateName(char* lpszCanon, int cchMax, int bAtLeastName)
1264 {
1265 int cchFullPath, cchFileName, cchVolName;
1266 const char* lpszCur;
1267 const char* lpszBase;
1268 const char* lpszFileName;
1269
1270 lpszBase = lpszCanon;
1271 cchFullPath = strlen(lpszCanon);
1272
1273 cchFileName = AfxGetFileName(lpszCanon, NULL, 0) - 1;
1274 lpszFileName = lpszBase + (cchFullPath-cchFileName);
1275
1276 if (cchMax >= cchFullPath)
1277 return;
1278
1279 if (cchMax < cchFileName)
1280 {
1281 strcpy(lpszCanon, (bAtLeastName) ? lpszFileName : "");
1282 return;
1283 }
1284
1285 lpszCur = lpszBase + 2;
1286
1287 if (lpszBase[0] == '\\' && lpszBase[1] == '\\')
1288 {
1289 while (*lpszCur != '\\')
1290 lpszCur++;
1291 }
1292
1293 if (cchFullPath - cchFileName > 3)
1294 {
1295 lpszCur++;
1296 while (*lpszCur != '\\')
1297 lpszCur++;
1298 }
1299
1300 cchVolName = (int)(lpszCur - lpszBase);
1301 if (cchMax < cchVolName + 5 + cchFileName)
1302 {
1303 strcpy(lpszCanon, lpszFileName);
1304 return;
1305 }
1306
1307 while (cchVolName + 4 + (int)strlen(lpszCur) > cchMax)
1308 {
1309 do
1310 {
1311 lpszCur++;
1312 }
1313 while (*lpszCur != '\\');
1314 }
1315
1316 lpszCanon[cchVolName] = '\0';
1317 strcat(lpszCanon, "\\...");
1318 strcat(lpszCanon, lpszCur);
1319 }
1320
1321 int levelstarttic;
1322
1323 int force_singletics_to = 0;
1324
HU_DrawDemoProgress(int force)1325 int HU_DrawDemoProgress(int force)
1326 {
1327 static unsigned int last_update = 0;
1328 static int prev_len = -1;
1329
1330 int len, tics_count, diff;
1331 unsigned int tick, max_period;
1332
1333 if (gamestate == GS_DEMOSCREEN || (!demoplayback && !democontinue) || !hudadd_demoprogressbar)
1334 return false;
1335
1336 tics_count = ((doSkip && demo_skiptics > 0) ? MIN(demo_skiptics, demo_tics_count) : demo_tics_count) * demo_playerscount;
1337 len = MIN(SCREENWIDTH, (int)((int_64_t)SCREENWIDTH * demo_curr_tic / tics_count));
1338
1339 if (!force)
1340 {
1341 max_period = ((tics_count - demo_curr_tic > 35 * demo_playerscount) ? 500 : 15);
1342
1343 // Unnecessary updates of progress bar
1344 // can slow down demo skipping and playback
1345 tick = SDL_GetTicks();
1346 if (tick - last_update < max_period)
1347 return false;
1348 last_update = tick;
1349
1350 // Do not update progress bar if difference is small
1351 diff = len - prev_len;
1352 if (diff == 0 || diff == 1) // because of static prev_len
1353 return false;
1354 }
1355
1356 prev_len = len;
1357
1358 V_FillRect(0, 0, SCREENHEIGHT - 4, len - 0, 4, 4);
1359 if (len > 4)
1360 V_FillRect(0, 2, SCREENHEIGHT - 3, len - 4, 2, 0);
1361
1362 return true;
1363 }
1364
1365 #ifdef ALL_IN_ONE
GetAllInOneLumpHandle(void)1366 unsigned char* GetAllInOneLumpHandle(void)
1367 {
1368 static unsigned char* AllInOneLumpHandle = NULL;
1369
1370 if (!AllInOneLumpHandle)
1371 {
1372 HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_ALL_IN_ONE_LUMP), RT_RCDATA);
1373 if (hrsrc)
1374 {
1375 HGLOBAL hglobal = LoadResource(NULL, hrsrc);
1376 if (hglobal)
1377 {
1378 AllInOneLumpHandle = LockResource(hglobal);
1379 }
1380 }
1381 }
1382
1383 if (!AllInOneLumpHandle)
1384 I_Error("Can't load internal data.");
1385
1386 return AllInOneLumpHandle;
1387 }
1388 #endif
1389
1390 #ifdef _MSC_VER
GetFullPath(const char * FileName,const char * ext,char * Buffer,size_t BufferLength)1391 int GetFullPath(const char* FileName, const char* ext, char *Buffer, size_t BufferLength)
1392 {
1393 int i, Result;
1394 char *p;
1395 char dir[PATH_MAX];
1396
1397 for (i=0; i<3; i++)
1398 {
1399 switch(i)
1400 {
1401 case 0:
1402 getcwd(dir, sizeof(dir));
1403 break;
1404 case 1:
1405 if (!getenv("DOOMWADDIR"))
1406 continue;
1407 strcpy(dir, getenv("DOOMWADDIR"));
1408 break;
1409 case 2:
1410 strcpy(dir, I_DoomExeDir());
1411 break;
1412 }
1413
1414 Result = SearchPath(dir,FileName,ext,BufferLength,Buffer,&p);
1415 if (Result)
1416 return Result;
1417 }
1418
1419 return false;
1420 }
1421 #endif
1422
1423 #ifdef _WIN32
1424 #include <Mmsystem.h>
1425 #pragma comment( lib, "winmm.lib" )
1426 int mus_extend_volume;
I_midiOutSetVolumes(int volume)1427 void I_midiOutSetVolumes(int volume)
1428 {
1429 // NSM changed to work on the 0-15 volume scale,
1430 // and to check mus_extend_volume itself.
1431
1432 MMRESULT result;
1433 int calcVolume;
1434 MIDIOUTCAPS capabilities;
1435 unsigned int i;
1436
1437 if (volume > 15)
1438 volume = 15;
1439 if (volume < 0)
1440 volume = 0;
1441 calcVolume = (65535 * volume / 15);
1442
1443 //SDL_LockAudio(); // this function doesn't touch anything the audio callback touches
1444
1445 //Device loop
1446 for (i = 0; i < midiOutGetNumDevs(); i++)
1447 {
1448 //Get device capabilities
1449 result = midiOutGetDevCaps(i, &capabilities, sizeof(capabilities));
1450 if (result == MMSYSERR_NOERROR)
1451 {
1452 //Adjust volume on this candidate
1453 if ((capabilities.dwSupport & MIDICAPS_VOLUME))
1454 {
1455 midiOutSetVolume((HMIDIOUT)i, MAKELONG(calcVolume, calcVolume));
1456 }
1457 }
1458 }
1459
1460 //SDL_UnlockAudio();
1461 }
1462 #endif
1463
1464 //Begin of GZDoom code
1465 /*
1466 **---------------------------------------------------------------------------
1467 ** Copyright 2004-2005 Christoph Oelckers
1468 ** All rights reserved.
1469 **
1470 ** Redistribution and use in source and binary forms, with or without
1471 ** modification, are permitted provided that the following conditions
1472 ** are met:
1473 **
1474 ** 1. Redistributions of source code must retain the above copyright
1475 ** notice, this list of conditions and the following disclaimer.
1476 ** 2. Redistributions in binary form must reproduce the above copyright
1477 ** notice, this list of conditions and the following disclaimer in the
1478 ** documentation and/or other materials provided with the distribution.
1479 ** 3. The name of the author may not be used to endorse or promote products
1480 ** derived from this software without specific prior written permission.
1481 ** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
1482 ** covered by the terms of the GNU Lesser General Public License as published
1483 ** by the Free Software Foundation; either version 2.1 of the License, or (at
1484 ** your option) any later version.
1485 */
1486
1487 //===========================================================================
1488 //
1489 // smooth the edges of transparent fields in the texture
1490 // returns false when nothing is manipulated to save the work on further
1491 // levels
1492
1493 // 28/10/2003: major optimization: This function was far too pedantic.
1494 // taking the value of one of the neighboring pixels is fully sufficient
1495 //
1496 //===========================================================================
1497
1498 #ifdef WORDS_BIGENDIAN
1499 #define MSB 0
1500 #define SOME_MASK 0xffffff00
1501 #else
1502 #define MSB 3
1503 #define SOME_MASK 0x00ffffff
1504 #endif
1505
1506 #define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((unsigned int*)l1)[0] = ((unsigned int*)l1)[ofs]&SOME_MASK), trans=true ) : false)
1507
SmoothEdges(unsigned char * buffer,int w,int h)1508 dboolean SmoothEdges(unsigned char * buffer,int w, int h)
1509 {
1510 int x,y;
1511 dboolean trans=buffer[MSB]==0; // If I set this to false here the code won't detect textures
1512 // that only contain transparent pixels.
1513 unsigned char * l1;
1514
1515 // makes (a) no sense and (b) doesn't work with this code!
1516 // if (h<=1 || w<=1)
1517 // e6y: Do not smooth small patches.
1518 // Makes sense for HUD small digits
1519 // 2 and 7 still look ugly
1520 if (h<=8 || w<=8)
1521 return false;
1522
1523 l1=buffer;
1524
1525 if (l1[MSB]==0 && !CHKPIX(1)) CHKPIX(w);
1526 l1+=4;
1527 for(x=1;x<w-1;x++, l1+=4)
1528 {
1529 if (l1[MSB]==0 && !CHKPIX(-1) && !CHKPIX(1)) CHKPIX(w);
1530 }
1531 if (l1[MSB]==0 && !CHKPIX(-1)) CHKPIX(w);
1532 l1+=4;
1533
1534 for(y=1;y<h-1;y++)
1535 {
1536 if (l1[MSB]==0 && !CHKPIX(-w) && !CHKPIX(1)) CHKPIX(w);
1537 l1+=4;
1538 for(x=1;x<w-1;x++, l1+=4)
1539 {
1540 if (l1[MSB]==0 && !CHKPIX(-w) && !CHKPIX(-1) && !CHKPIX(1)) CHKPIX(w);
1541 }
1542 if (l1[MSB]==0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(w);
1543 l1+=4;
1544 }
1545
1546 if (l1[MSB]==0 && !CHKPIX(-w)) CHKPIX(1);
1547 l1+=4;
1548 for(x=1;x<w-1;x++, l1+=4)
1549 {
1550 if (l1[MSB]==0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(1);
1551 }
1552 if (l1[MSB]==0 && !CHKPIX(-w)) CHKPIX(-1);
1553
1554 return trans;
1555 }
1556
1557 #undef MSB
1558 #undef SOME_MASK
1559 //End of GZDoom code
1560