blob: c16c8fb25c3b1c39003f1cfa56f058e0f61f6a0d [file] [log] [blame]
Franklin Weia855d622017-01-21 15:18:31 -05001/*
2 * An SDL replacement for BUILD's VESA code.
3 *
4 * Written by Ryan C. Gordon. (icculus@clutteredmind.org)
5 *
6 * Please do NOT harrass Ken Silverman about any code modifications
7 * (including this file) to BUILD.
8 */
9
10/*
11 * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
12 * Ken Silverman's official web site: "http://www.advsys.net/ken"
13 * See the included license file "BUILDLIC.TXT" for license info.
14 * This file IS NOT A PART OF Ken Silverman's original release
15 */
16#include <stdio.h>
17#include <stdlib.h>
18#include <stdarg.h>
19#include <assert.h>
20#include <string.h>
21#include "platform.h"
22
23#include "lib/pluginlib_bmp.h"
24#include "SDL_config.h"
25
26#if (!defined PLATFORM_SUPPORTS_SDL)
27#error This platform apparently does not use SDL. Do not compile this.
28#endif
29
30
31#define BUILD_NOMOUSEGRAB "BUILD_NOMOUSEGRAB"
32#define BUILD_WINDOWED "BUILD_WINDOWED"
33#define BUILD_SDLDEBUG "BUILD_SDLDEBUG"
34#define BUILD_RENDERER "BUILD_RENDERER"
35#define BUILD_GLLIBRARY "BUILD_GLLIBRARY"
36#define BUILD_USERSCREENRES "BUILD_USERSCREENRES"
37#define BUILD_MAXSCREENRES "BUILD_MAXSCREENRES"
38#define BUILD_HALLOFMIRRORS "BUILD_HALLOFMIRRORS"
39#define BUILD_GLDUMP "BUILD_GLDUMP"
40#define BUILD_SDLJOYSTICK "BUILD_SDLJOYSTICK"
41
42#include "SDL.h"
43#include "build.h"
44#include "display.h"
45#include "fixedPoint_math.h"
46#include "engine.h"
47#include "network.h"
48
49#include "mmulti_unstable.h"
50#include "mmulti_stable.h"
51#include "network.h"
52#include "icon.h"
53
54// NATIVE TIMER FUNCTION DECLARATION
55/*
56 FCS: The timer section sadly uses Native high precision calls to implement timer functions.
57 QueryPerformanceFrequency and QueryPerformanceCounter
58 it seems SDL precision was not good enough (or rather using unaccurate OS functions) to replicate
59 a DOS timer.
60 */
61
62int TIMER_GetPlatformTicksInOneSecond(int64_t* t);
63void TIMER_GetPlatformTicks(int64_t* t);
64
65//END // NATIVE TIMER FUNCTION DECLARATION
66
67
68
69
70
71
Franklin Weia855d622017-01-21 15:18:31 -050072#include "draw.h"
73#include "cache.h"
74
75
76/*
77 * !!! remove the surface_end checks, for speed's sake. They are a
78 * !!! needed safety right now. --ryan.
79 */
80
81
82#define DEFAULT_MAXRESWIDTH 1600
83#define DEFAULT_MAXRESHEIGHT 1200
84
85
86#define UNLOCK_SURFACE_AND_RETURN if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); return;
87
88
89 /* !!! move these elsewhere? */
90int32_t xres, yres, bytesperline, imageSize, maxpages;
91uint8_t* frameplace;
92
93//The frambuffer address
94uint8_t* frameoffset;
95uint8_t *screen, vesachecked;
96int32_t buffermode, origbuffermode, linearmode;
97uint8_t permanentupdate = 0, vgacompatible;
98
99SDL_Surface *surface = NULL; /* This isn't static so that we can use it elsewhere AH */
100
101static uint32_t sdl_flags = SDL_HWPALETTE;
102static int32_t mouse_relative_x = 0;
103static int32_t mouse_relative_y = 0;
104static short mouse_buttons = 0;
105static unsigned int lastkey = 0;
106/* so we can make use of setcolor16()... - DDOI */
107static uint8_t drawpixel_color=0;
108
109static uint32_t scancodes[SDLK_LAST];
110
111static int32_t last_render_ticks = 0;
112int32_t total_render_time = 1;
113int32_t total_rendered_frames = 0;
114
115static char *titleNameLong = NULL;
116static char *titleNameShort = NULL;
117
118void restore256_palette (void);
119void set16color_palette (void);
120
121
122
123static void __append_sdl_surface_flag(SDL_Surface *_surface, char *str,
124 size_t strsize, Uint32 flag,
125 const char *flagstr)
126{
127 if (_surface->flags & flag)
128 {
129 if ( (strlen(str) + strlen(flagstr)) >= (strsize - 1) )
130 strcpy(str + (strsize - 5), " ...");
131 else
132 strcat(str, flagstr);
133 } /* if */
134}
135
136
137#define append_sdl_surface_flag(a, b, c, fl) __append_sdl_surface_flag(a, b, c, fl, " " #fl)
138#define print_tf_state(str, val) printf("%s: {%s}\n", str, (val) ? "true" : "false" )
139
140static void output_surface_info(SDL_Surface *_surface)
141{
142 const SDL_VideoInfo *info;
143 char f[256];
144
145
146 if (_surface == NULL)
147 {
148 printf("-WARNING- You've got a NULL screen surface!");
149 }
150 else
151 {
152 f[0] = '\0';
153 printf("screen surface is (%dx%dx%dbpp).\n",_surface->w, _surface->h, _surface->format->BitsPerPixel);
154
155 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SWSURFACE);
156 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWSURFACE);
157 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_ASYNCBLIT);
158 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_ANYFORMAT);
159 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWPALETTE);
160 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_DOUBLEBUF);
161 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_FULLSCREEN);
162 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_OPENGL);
163 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_OPENGLBLIT);
164 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RESIZABLE);
165 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_NOFRAME);
166 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWACCEL);
167 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SRCCOLORKEY);
168 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RLEACCELOK);
169 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RLEACCEL);
170 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SRCALPHA);
171 append_sdl_surface_flag(_surface, f, sizeof (f), SDL_PREALLOC);
172
173 if (f[0] == '\0')
174 strcpy(f, " (none)");
175
176 printf("New vidmode flags:%s.\n", f);
177
178 info = SDL_GetVideoInfo();
179 assert(info != NULL);
180/*
181 print_tf_state("hardware surface available", info->hw_available);
182 print_tf_state("window manager available", info->wm_available);
183 print_tf_state("accelerated hardware->hardware blits", info->blit_hw);
184 print_tf_state("accelerated hardware->hardware colorkey blits", info->blit_hw_CC);
185 print_tf_state("accelerated hardware->hardware alpha blits", info->blit_hw_A);
186 print_tf_state("accelerated software->hardware blits", info->blit_sw);
187 print_tf_state("accelerated software->hardware colorkey blits", info->blit_sw_CC);
188 print_tf_state("accelerated software->hardware alpha blits", info->blit_sw_A);
189 print_tf_state("accelerated color fills", info->blit_fill);
190
191 printf("video memory: (%d),\n", info->video_mem);
192 */
193 }
194}
195
196
197static void output_driver_info(void)
198{
199 char buffer[256];
200
201 if (SDL_VideoDriverName(buffer, sizeof (buffer)) == NULL){
202 printf("-WARNING- SDL_VideoDriverName() returned NULL!");
203 } /* if */
204 else
205 {
206 printf("Using SDL video driver \"%s\".", buffer);
207 } /* else */
208} /* output_driver_info */
209
210
211void* get_framebuffer(void){
212 return((Uint8 *) surface->pixels);
213}
214
215
216
217/*
218 * !!! This is almost an entire copy of the original setgamemode().
219 * !!! Figure out what is needed for just 2D mode, and separate that
220 * !!! out. Then, place the original setgamemode() back into engine.c,
221 * !!! and remove our simple implementation (and this function.)
222 * !!! Just be sure to keep the non-DOS things, like the window's
223 * !!! titlebar caption. --ryan.
224 */
225static uint8_t screenalloctype = 255;
226static void init_new_res_vars(int32_t davidoption)
227{
228 int i = 0;
229 int j = 0;
230
231 setupmouse();
232
233 SDL_WM_SetCaption(titleNameLong, titleNameShort);
234
235 xdim = xres = surface->w;
236 ydim = yres = surface->h;
237
238 printf("init_new_res_vars %d %d\n",xdim,ydim);
239
240 bytesperline = surface->w;
241 vesachecked = 1;
242 vgacompatible = 1;
243 linearmode = 1;
244 qsetmode = surface->h;
245 activepage = visualpage = 0;
246
247
248 frameoffset = frameplace = (uint8_t*)surface->pixels;
249
250 if (screen != NULL)
251 {
252 if (screenalloctype == 0) kkfree((void *)screen);
253 if (screenalloctype == 1) suckcache((int32_t *)screen);
254 screen = NULL;
255 } /* if */
256
257
258 switch(vidoption)
259 {
260 case 1:i = xdim*ydim; break;
261 case 2: xdim = 320; ydim = 200; i = xdim*ydim; break;
262
263 default: assert(0);
264 }
265 j = ydim*4*sizeof(int32_t); /* Leave room for horizlookup&horizlookup2 */
266
267 if(horizlookup)
268 free(horizlookup);
269
270 if(horizlookup2)
271 free(horizlookup2);
272
273 horizlookup = (int32_t*)malloc(j);
274 horizlookup2 = (int32_t*)malloc(j);
275
276 j = 0;
277
278 //Build lookup table (X screespace -> frambuffer offset.
279 for(i = 0; i <= ydim; i++)
280 {
281 ylookup[i] = j;
282 j += bytesperline;
283 }
284
285 horizycent = ((ydim*4)>>1);
286
287 /* Force drawrooms to call dosetaspect & recalculate stuff */
288 oxyaspect = oxdimen = oviewingrange = -1;
289
290 //Let the Assembly module how many pixels to skip when drawing a column
291 setBytesPerLine(bytesperline);
292
293
294 setview(0L,0L,xdim-1,ydim-1);
295
296 setbrightness(curbrightness, palette);
297
298 if (searchx < 0) {
299 searchx = halfxdimen;
300 searchy = (ydimen>>1);
301 }
302
303}
304
305
306
307static void go_to_new_vid_mode(int davidoption, int w, int h)
308{
309 getvalidvesamodes();
310 SDL_ClearError();
311 // don't do SDL_SetVideoMode if SDL_WM_SetIcon not called. See sdl doc for SDL_WM_SetIcon
312 surface = SDL_SetVideoMode(w, h, 8, sdl_flags);
313 if (surface == NULL)
314 {
315 Error(EXIT_FAILURE, "BUILDSDL: Failed to set %dx%d video mode!\n"
316 "BUILDSDL: SDL_Error() says [%s].\n",
317 w, h, SDL_GetError());
318 } /* if */
319
320 output_surface_info(surface);
321 init_new_res_vars(davidoption); // dont be confused between vidoption (global) and davidoption
322}
323
324static __inline int sdl_mouse_button_filter(SDL_MouseButtonEvent const *event)
325{
326 /*
327 * What bits BUILD expects:
328 * 0 left button pressed if 1
329 * 1 right button pressed if 1
330 * 2 middle button pressed if 1
331 *
332 * (That is, this is what Int 33h (AX=0x05) returns...)
333 *
334 * additionally bits 3&4 are set for the mouse wheel
335 */
336 Uint8 button = event->button;
337 if (button >= sizeof (mouse_buttons) * 8)
338 return(0);
339
340 if (button == SDL_BUTTON_RIGHT)
341 button = SDL_BUTTON_MIDDLE;
342 else if (button == SDL_BUTTON_MIDDLE)
343 button = SDL_BUTTON_RIGHT;
344
345 if (((const SDL_MouseButtonEvent*)event)->state)
346 mouse_buttons |= 1<<(button-1);
347 else if (button != 4 && button != 5)
348 mouse_buttons ^= 1<<(button-1);
349#if 0
350 Uint8 bmask = SDL_GetMouseState(NULL, NULL);
351 mouse_buttons = 0;
352 if (bmask & SDL_BUTTON_LMASK) mouse_buttons |= 1;
353 if (bmask & SDL_BUTTON_RMASK) mouse_buttons |= 2;
354 if (bmask & SDL_BUTTON_MMASK) mouse_buttons |= 4;
355#endif
356
357 return(0);
358} /* sdl_mouse_up_filter */
359
360
361static int sdl_mouse_motion_filter(SDL_Event const *event)
362{
363 if (surface == NULL)
364 return(0);
365
366 if (event->type == SDL_JOYBALLMOTION)
367 {
368 mouse_relative_x = event->jball.xrel/100;
369 mouse_relative_y = event->jball.yrel/100;
370 }
371 else
372 {
373 if (SDL_WM_GrabInput(SDL_GRAB_QUERY)==SDL_GRAB_ON)
374 {
375 mouse_relative_x += event->motion.xrel;
376 mouse_relative_y += event->motion.yrel;
377 //printf("sdl_mouse_motion_filter: mrx=%d, mry=%d, mx=%d, my=%d\n",
378 // mouse_relative_x, mouse_relative_y, event->motion.xrel, event->motion.yrel);
379
380 // mouse_relative_* is already reset in
381 // readmousexy(). It must not be
382 // reset here because calling this function does not mean
383 // we always handle the mouse.
384 // FIX_00001: Mouse speed is uneven and slower in windowed mode vs fullscreen mode.
385 }
386 else
387 mouse_relative_x = mouse_relative_y = 0;
388 }
389
390 return(0);
391} /* sdl_mouse_motion_filter */
392
393
394 /*
395 * The windib driver can't alert us to the keypad enter key, which
396 * Ken's code depends on heavily. It sends it as the same key as the
397 * regular return key. These users will have to hit SHIFT-ENTER,
398 * which we check for explicitly, and give the engine a keypad enter
399 * enter event.
400 */
401static __inline int handle_keypad_enter_hack(const SDL_Event *event)
402{
403 static int kp_enter_hack = 0;
404 int retval = 0;
405
406 if (event->key.keysym.sym == SDLK_RETURN)
407 {
408 if (event->key.state == SDL_PRESSED)
409 {
410 if (event->key.keysym.mod & KMOD_SHIFT)
411 {
412 kp_enter_hack = 1;
413 lastkey = scancodes[SDLK_KP_ENTER];
414 retval = 1;
415 } /* if */
416 } /* if */
417
418 else /* key released */
419 {
420 if (kp_enter_hack)
421 {
422 kp_enter_hack = 0;
423 lastkey = scancodes[SDLK_KP_ENTER];
424 retval = 1;
425 } /* if */
426 } /* if */
427 } /* if */
428
429 return(retval);
430} /* handle_keypad_enter_hack */
431
432void fullscreen_toggle_and_change_driver(void)
433{
434
435// FIX_00002: New Toggle Windowed/FullScreen system now simpler and will
436// dynamically change for Windib or Directx driver. Windowed/Fullscreen
437// toggle also made available from menu.
438// Replace attempt_fullscreen_toggle(SDL_Surface **surface, Uint32 *flags)
439
440 int32_t x,y;
441 x = surface->w;
442 y = surface->h;
443
444 BFullScreen =!BFullScreen;
445 SDL_QuitSubSystem(SDL_INIT_VIDEO);
446 _platform_init(0, NULL, "Duke Nukem 3D", "Duke3D");
447 _setgamemode(ScreenMode,x,y);
448 //vscrn();
449
450 return;
451}
452
453static int sdl_key_filter(const SDL_Event *event)
454{
455 int extended;
456
457 if ( (event->key.keysym.sym == SDLK_m) &&
458 (event->key.state == SDL_PRESSED) &&
459 (event->key.keysym.mod & KMOD_CTRL) )
460 {
461
462
463 // FIX_00005: Mouse pointer can be toggled on/off (see mouse menu or use CTRL-M)
464 // This is usefull to move the duke window when playing in window mode.
465
466 if (SDL_WM_GrabInput(SDL_GRAB_QUERY)==SDL_GRAB_ON)
467 {
468 SDL_WM_GrabInput(SDL_GRAB_OFF);
469 SDL_ShowCursor(1);
470 }
471 else
472 {
473 SDL_WM_GrabInput(SDL_GRAB_ON);
474 SDL_ShowCursor(0);
475 }
476
477 return(0);
478 } /* if */
479
480 else if ( ( (event->key.keysym.sym == SDLK_RETURN) ||
481 (event->key.keysym.sym == SDLK_KP_ENTER) ) &&
482 (event->key.state == SDL_PRESSED) &&
483 (event->key.keysym.mod & KMOD_ALT) )
484 { fullscreen_toggle_and_change_driver();
485
486 // hack to discard the ALT key...
487 lastkey=scancodes[SDLK_RALT]>>8; // extended
488 keyhandler();
489 lastkey=(scancodes[SDLK_RALT]&0xff)+0x80; // Simulating Key up
490 keyhandler();
491 lastkey=(scancodes[SDLK_LALT]&0xff)+0x80; // Simulating Key up (not extended)
492 keyhandler();
493 SDL_SetModState(KMOD_NONE); // SDL doesnt see we are releasing the ALT-ENTER keys
494
495 return(0);
496 }
497
498 if (!handle_keypad_enter_hack(event))
499 lastkey = scancodes[event->key.keysym.sym];
500
501// printf("key.keysym.sym=%d\n", event->key.keysym.sym);
502
503 if (lastkey == 0x0000) /* No DOS equivalent defined. */
504 return(0);
505
506 extended = ((lastkey & 0xFF00) >> 8);
507 if (extended != 0)
508 {
509 lastkey = extended;
510 keyhandler();
511 lastkey = (scancodes[event->key.keysym.sym] & 0xFF);
512 } /* if */
513
514 if (event->key.state == SDL_RELEASED)
515 lastkey += 128; /* +128 signifies that the key is released in DOS. */
516
517 keyhandler();
518 return(0);
519} /* sdl_key_filter */
520
521
522static int root_sdl_event_filter(const SDL_Event *event)
523{
524 switch (event->type)
525 {
526 case SDL_KEYUP:
527 // FIX_00003: Pause mode is now fully responsive - (Thx to Jonathon Fowler tips)
528 if(event->key.keysym.sym == SDLK_PAUSE)
529 break;
530 case SDL_KEYDOWN:
531 return(sdl_key_filter(event));
532 case SDL_JOYBUTTONDOWN:
533 case SDL_JOYBUTTONUP:
534 {
535 //Do Nothing
536
537 //printf("Joybutton UP/DOWN\n");
538 //return(sdl_joystick_button_filter((const SDL_MouseButtonEvent*)event));
539 return 0;
540 }
541 case SDL_JOYBALLMOTION:
542 case SDL_MOUSEMOTION:
543 return(sdl_mouse_motion_filter(event));
544 case SDL_MOUSEBUTTONUP:
545 case SDL_MOUSEBUTTONDOWN:
546 return(sdl_mouse_button_filter((const SDL_MouseButtonEvent*)event));
547 case SDL_QUIT:
548 /* !!! rcg TEMP */
549 Error(EXIT_SUCCESS, "Exit through SDL\n");
550 default:
551 //printf("This event is not handled: %d\n",event->type);
552 break;
553 } /* switch */
554
555 return(1);
556} /* root_sdl_event_filter */
557
558
559static void handle_events(void)
560{
561 SDL_Event event;
562
563 while(SDL_PollEvent(&event))
564 root_sdl_event_filter(&event);
565} /* handle_events */
566
567
568/* bleh...public version... */
569void _handle_events(void)
570{
571 handle_events();
572} /* _handle_events */
573
574
575static SDL_Joystick *joystick = NULL;
576void _joystick_init(void)
577{
578 const char *envr = getenv(BUILD_SDLJOYSTICK);
579 int favored = 0;
580 int numsticks;
581 int i;
582
583 if (joystick != NULL)
584 {
585 printf("Joystick appears to be already initialized.\n");
586 printf("...deinitializing for stick redetection...\n");
587 _joystick_deinit();
588 } /* if */
589
590 if ((envr != NULL) && (strcmp(envr, "none") == 0))
591 {
592 printf("Skipping joystick detection/initialization at user request\n");
593 return;
594 } /* if */
595
596 printf("Initializing SDL joystick subsystem...");
597 printf(" (export environment variable BUILD_SDLJOYSTICK=none to skip)\n");
598
599 if (SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE) != 0)
600 {
601 printf("SDL_Init(SDL_INIT_JOYSTICK) failed: [%s].\n", SDL_GetError());
602 return;
603 } /* if */
604
605 numsticks = SDL_NumJoysticks();
606 printf("SDL sees %d joystick%s.\n", numsticks, numsticks == 1 ? "" : "s");
607 if (numsticks == 0)
608 return;
609
610 for (i = 0; i < numsticks; i++)
611 {
612 const char *stickname = SDL_JoystickName(i);
613 if ((envr != NULL) && (strcmp(envr, stickname) == 0))
614 favored = i;
615
616 printf("Stick #%d: [%s]\n", i, stickname);
617 } /* for */
618
619 printf("Using Stick #%d.", favored);
620 if ((envr == NULL) && (numsticks > 1))
621 printf("Set BUILD_SDLJOYSTICK to one of the above names to change.\n");
622
623 joystick = SDL_JoystickOpen(favored);
624 if (joystick == NULL)
625 {
626 printf("Joystick #%d failed to init: %s\n", favored, SDL_GetError());
627 return;
628 } /* if */
629
630 printf("Joystick initialized. %d axes, %d buttons, %d hats, %d balls.\n",
631 SDL_JoystickNumAxes(joystick), SDL_JoystickNumButtons(joystick),
632 SDL_JoystickNumHats(joystick), SDL_JoystickNumBalls(joystick));
633
634 SDL_JoystickEventState(SDL_QUERY);
635} /* _joystick_init */
636
637
638void _joystick_deinit(void)
639{
640 if (joystick != NULL)
641 {
642 printf("Closing joystick device...\n");
643 SDL_JoystickClose(joystick);
644 printf("Joystick device closed. Deinitializing SDL subsystem...\n");
645 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
646 printf("SDL joystick subsystem deinitialized.\n");
647 joystick = NULL;
648 } /* if */
649} /* _joystick_deinit */
650
651
652int _joystick_update(void)
653{
654 if (joystick == NULL)
655 return(0);
656
657 SDL_JoystickUpdate();
658 return(1);
659} /* _joystick_update */
660
661
662int _joystick_axis(int axis)
663{
664 if (joystick == NULL)
665 {
666 return(0);
667 }
668
669 return(SDL_JoystickGetAxis(joystick, axis));
670} /* _joystick_axis */
671
672int _joystick_hat(int hat)
673{
674 if (joystick == NULL)
675 {
676 return(-1);
677 }
678
679 return(SDL_JoystickGetHat(joystick, hat));
680} /* _joystick_axis */
681
682int _joystick_button(int button)
683{
684 if (joystick == NULL)
685 return(0);
686
687 return(SDL_JoystickGetButton(joystick, button) != 0);
688} /* _joystick_button */
689
690
691uint8_t _readlastkeyhit(void)
692{
693 return(lastkey);
694} /* _readlastkeyhit */
695
696
697
698#if (!defined __DATE__)
699#define __DATE__ "a long, int32_t time ago"
700#endif
701
702static void output_sdl_versions(void)
703{
704 const SDL_version *linked_ver = SDL_Linked_Version();
705 SDL_version compiled_ver;
706
707 SDL_VERSION(&compiled_ver);
708
709 printf("SDL display driver for the BUILD engine initializing.\n");
710 printf(" sdl_driver.c by Ryan C. Gordon (icculus@clutteredmind.org).\n");
711 printf("Compiled %s against SDL version %d.%d.%d ...\n", __DATE__,
712 compiled_ver.major, compiled_ver.minor, compiled_ver.patch);
713 printf("Linked SDL version is %d.%d.%d ...\n",
714 linked_ver->major, linked_ver->minor, linked_ver->patch);
715} /* output_sdl_versions */
716
717
718/* lousy -ansi flag. :) */
719static char *string_dupe(const char *str)
720{
721 char *retval = malloc(strlen(str) + 1);
722 if (retval != NULL)
723 strcpy(retval, str);
724 return(retval);
725} /* string_dupe */
726
727
728
729
730
731
732
733void _platform_init(int argc, char **argv, const char *title, const char *iconName)
734{
735 int i;
736 int64_t timeElapsed;
737 char dummyString[4096];
738
739 // FIX_00061: "ERROR: Two players have the same random ID" too frequent cuz of internet windows times
740 TIMER_GetPlatformTicks(&timeElapsed);
741 srand(timeElapsed&0xFFFFFFFF);
742
743 Setup_UnstableNetworking();
744
745 // Look through the command line args
746 for(i = 0; i < argc; i++)
747 {
748 if(argv[i][0] == '-' )
749 {
750 if(strcmpi(argv[i], "-netmode_stable") == 0)
751 {
752 //fullscreen = 1;
753 //TODO:
754//TODO ( "[Todo: handle -netmode <int>]" )
755 Setup_StableNetworking();
756
757 }
758 }
759 }
760
761
Franklin Weia855d622017-01-21 15:18:31 -0500762 if (SDL_Init(SDL_INIT_VIDEO) == -1){
763 Error(EXIT_FAILURE, "BUILDSDL: SDL_Init() failed!\nBUILDSDL: SDL_GetError() says \"%s\".\n", SDL_GetError());
764 }
765
766
767 // Set up the correct renderer
768 // Becarfull setenv can't reach dll in VC++
769 // A way to proceed is to integrate the SDL libs
770 // in the exe instead.
771
772 // FIX_00004: SDL.dll and SDL_Mixer.dll are now integrated within the exe
773 // (this also makes the Windib/Directx driver switching easier with SDL)
774
775 // This requires to recompile the whole sdl and sdl mixer with the lib
776 // switch instead of the default dll switch.
777
778 putenv("SDL_VIDEO_CENTERED=1");
779
780 if (title == NULL)
781 title = "BUILD";
782
783 if (iconName == NULL)
784 iconName = "BUILD";
785
786 titleNameLong = string_dupe(title);
787 titleNameShort = string_dupe(iconName);
788
789 sdl_flags = BFullScreen ? SDL_FULLSCREEN : 0;
790
791 sdl_flags |= SDL_HWPALETTE;
792
793
794 memset(scancodes, '\0', sizeof (scancodes));
795 scancodes[SDLK_ESCAPE] = 0x01;
796 scancodes[SDLK_1] = 0x02;
797 scancodes[SDLK_2] = 0x03;
798 scancodes[SDLK_3] = 0x04;
799 scancodes[SDLK_4] = 0x05;
800 scancodes[SDLK_5] = 0x06;
801 scancodes[SDLK_6] = 0x07;
802 scancodes[SDLK_7] = 0x08;
803 scancodes[SDLK_8] = 0x09;
804 scancodes[SDLK_9] = 0x0A;
805 scancodes[SDLK_0] = 0x0B;
806 scancodes[SDLK_MINUS] = 0x0C; /* was 0x4A */
807 scancodes[SDLK_EQUALS] = 0x0D; /* was 0x4E */
808 scancodes[SDLK_BACKSPACE] = 0x0E;
809 scancodes[SDLK_TAB] = 0x0F;
810 scancodes[SDLK_q] = 0x10;
811 scancodes[SDLK_w] = 0x11;
812 scancodes[SDLK_e] = 0x12;
813 scancodes[SDLK_r] = 0x13;
814 scancodes[SDLK_t] = 0x14;
815 scancodes[SDLK_y] = 0x15;
816 scancodes[SDLK_u] = 0x16;
817 scancodes[SDLK_i] = 0x17;
818 scancodes[SDLK_o] = 0x18;
819 scancodes[SDLK_p] = 0x19;
820 scancodes[SDLK_LEFTBRACKET] = 0x1A;
821 scancodes[SDLK_RIGHTBRACKET] = 0x1B;
822 scancodes[SDLK_RETURN] = 0x1C;
823 scancodes[SDLK_LCTRL] = 0x1D;
824 scancodes[SDLK_a] = 0x1E;
825 scancodes[SDLK_s] = 0x1F;
826 scancodes[SDLK_d] = 0x20;
827 scancodes[SDLK_f] = 0x21;
828 scancodes[SDLK_g] = 0x22;
829 scancodes[SDLK_h] = 0x23;
830 scancodes[SDLK_j] = 0x24;
831 scancodes[SDLK_k] = 0x25;
832 scancodes[SDLK_l] = 0x26;
833 scancodes[SDLK_SEMICOLON] = 0x27;
834 scancodes[SDLK_QUOTE] = 0x28;
835 scancodes[SDLK_BACKQUOTE] = 0x29;
836 scancodes[SDLK_LSHIFT] = 0x2A;
837 scancodes[SDLK_BACKSLASH] = 0x2B;
838 scancodes[SDLK_z] = 0x2C;
839 scancodes[SDLK_x] = 0x2D;
840 scancodes[SDLK_c] = 0x2E;
841 scancodes[SDLK_v] = 0x2F;
842 scancodes[SDLK_b] = 0x30;
843 scancodes[SDLK_n] = 0x31;
844 scancodes[SDLK_m] = 0x32;
845 scancodes[SDLK_COMMA] = 0x33;
846 scancodes[SDLK_PERIOD] = 0x34;
847 scancodes[SDLK_SLASH] = 0x35;
848 scancodes[SDLK_RSHIFT] = 0x36;
849 scancodes[SDLK_KP_MULTIPLY] = 0x37;
850 scancodes[SDLK_LALT] = 0x38;
851 scancodes[SDLK_SPACE] = 0x39;
852 scancodes[SDLK_CAPSLOCK] = 0x3A;
853 scancodes[SDLK_F1] = 0x3B;
854 scancodes[SDLK_F2] = 0x3C;
855 scancodes[SDLK_F3] = 0x3D;
856 scancodes[SDLK_F4] = 0x3E;
857 scancodes[SDLK_F5] = 0x3F;
858 scancodes[SDLK_F6] = 0x40;
859 scancodes[SDLK_F7] = 0x41;
860 scancodes[SDLK_F8] = 0x42;
861 scancodes[SDLK_F9] = 0x43;
862 scancodes[SDLK_F10] = 0x44;
863 scancodes[SDLK_NUMLOCK] = 0x45;
864 scancodes[SDLK_SCROLLOCK] = 0x46;
865 scancodes[SDLK_KP7] = 0x47;
866 scancodes[SDLK_KP8] = 0x48;
867 scancodes[SDLK_KP9] = 0x49;
868 scancodes[SDLK_KP_MINUS] = 0x4A;
869 scancodes[SDLK_KP4] = 0x4B;
870 scancodes[SDLK_KP5] = 0x4C;
871 scancodes[SDLK_KP6] = 0x4D;
872 scancodes[SDLK_KP_PLUS] = 0x4E;
873 scancodes[SDLK_KP1] = 0x4F;
874 scancodes[SDLK_KP2] = 0x50;
875 scancodes[SDLK_KP3] = 0x51;
876 scancodes[SDLK_KP0] = 0x52;
877 scancodes[SDLK_KP_PERIOD] = 0x53;
878 scancodes[SDLK_F11] = 0x57;
879 scancodes[SDLK_F12] = 0x58;
880 scancodes[SDLK_PAUSE] = 0x59; /* SBF - technically incorrect */
881
882 scancodes[SDLK_KP_ENTER] = 0xE01C;
883 scancodes[SDLK_RCTRL] = 0xE01D;
884 scancodes[SDLK_KP_DIVIDE] = 0xE035;
885 scancodes[SDLK_PRINT] = 0xE037; /* SBF - technically incorrect */
886 scancodes[SDLK_SYSREQ] = 0xE037; /* SBF - for windows... */
887 scancodes[SDLK_RALT] = 0xE038;
888 scancodes[SDLK_HOME] = 0xE047;
889 scancodes[SDLK_UP] = 0xE048;
890 scancodes[SDLK_PAGEUP] = 0xE049;
891 scancodes[SDLK_LEFT] = 0xE04B;
892 scancodes[SDLK_RIGHT] = 0xE04D;
893 scancodes[SDLK_END] = 0xE04F;
894 scancodes[SDLK_DOWN] = 0xE050;
895 scancodes[SDLK_PAGEDOWN] = 0xE051;
896 scancodes[SDLK_INSERT] = 0xE052;
897 scancodes[SDLK_DELETE] = 0xE053;
898
899
900
901 output_sdl_versions();
902 output_driver_info();
903
904
905 printf("Video Driver: '%s'.\n", SDL_VideoDriverName(dummyString, 20));
906
907}
908
909// Capture BMP of the current frame
910int screencapture(char *filename, uint8_t inverseit)
911{
912// FIX_00006: better naming system for screenshots + message when pic is taken.
913// Use ./screenshots folder. Screenshot code rerwritten. Faster and
914// makes smaller files. Doesn't freeze or lag the game anymore.
915
916 SDL_SaveBMP(surface, filename);
917 return 0;
918} /* screencapture */
919
920
921void setvmode(int mode)
922{
923
924 if (mode == 0x3) /* text mode. */
925 {
926 SDL_QuitSubSystem(SDL_INIT_VIDEO);
927 return;
928 } else
929 printf("setvmode(0x%x) is unsupported in SDL driver.\n", mode);
930
931}
932
933int32_t _setgamemode(uint8_t davidoption, int32_t daxdim, int32_t daydim)
934{
935 int validated, i;
936 SDL_Surface *image;
937 Uint32 colorkey;
938
Franklin Weia855d622017-01-21 15:18:31 -0500939 // Install icon
940 image = SDL_LoadBMP_RW(SDL_RWFromMem(iconBMP, iconBMP_size), 1);
941 colorkey = 0; // index in this image to be transparent
942 SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
943 SDL_WM_SetIcon(image,NULL);
Franklin Weia855d622017-01-21 15:18:31 -0500944
945 if (daxdim > MAXXDIM || daydim > MAXYDIM)
946 {
947 printf("Resolution %dx%d is too high. Changed to %dx%d\n", daxdim, daydim, MAXXDIM,MAXYDIM);
948 daxdim = MAXXDIM;
949 daydim = MAXYDIM;
950 }
951
952 getvalidvesamodes();
953
954 validated = 0;
955 for(i=0; i<validmodecnt; i++){
956 if(validmodexdim[i] == daxdim && validmodeydim[i] == daydim)
957 validated = 1;
958 }
959
960 if(!validated){
961 printf("Resolution %dx%d unsupported. Changed to 640x480\n", daxdim, daydim);
962 daxdim = LCD_WIDTH;
963 daydim = LCD_HEIGHT;
964 }
965
966 go_to_new_vid_mode((int) davidoption, daxdim, daydim);
967
968 qsetmode = 200;
969 last_render_ticks = getticks();
970
971 return(0);
972} /* setgamemode */
973
974
975static int get_dimensions_from_str(const char *str, int32_t *_w, int32_t *_h)
976{
977 char *xptr = NULL;
978 char *ptr = NULL;
979 int32_t w = -1;
980 int32_t h = -1;
981
982 if (str == NULL)
983 return(0);
984
985 xptr = strchr(str, 'x');
986 if (xptr == NULL)
987 return(0);
988
989 w = strtol(str, &ptr, 10);
990 if (ptr != xptr)
991 return(0);
992
993 xptr++;
994 h = strtol(xptr, &ptr, 10);
995 if ( (*xptr == '\0') || (*ptr != '\0') )
996 return(0);
997
998 if ((w <= 1) || (h <= 1))
999 return(0);
1000
1001 if (_w != NULL)
1002 *_w = w;
1003
1004 if (_h != NULL)
1005 *_h = h;
1006
1007 return(1);
1008} /* get_dimensions_from_str */
1009
1010
1011static __inline void get_max_screen_res(int32_t *max_w, int32_t *max_h)
1012{
1013 int32_t w = DEFAULT_MAXRESWIDTH;
1014 int32_t h = DEFAULT_MAXRESHEIGHT;
1015 const char *envr = getenv(BUILD_MAXSCREENRES);
1016
1017 if (envr != NULL)
1018 {
1019 if (!get_dimensions_from_str(envr, &w, &h))
1020 {
1021 printf("User's resolution ceiling [%s] is bogus!\n", envr);
1022 w = DEFAULT_MAXRESWIDTH;
1023 h = DEFAULT_MAXRESHEIGHT;
1024 } /* if */
1025 } /* if */
1026
1027 if (max_w != NULL)
1028 *max_w = w;
1029
1030 if (max_h != NULL)
1031 *max_h = h;
1032}
1033
1034
1035static void add_vesa_mode(const char *typestr, int w, int h)
1036{
1037 //printf("Adding %s resolution (%dx%d).\n", typestr, w, h);
1038 validmode[validmodecnt] = validmodecnt;
1039 validmodexdim[validmodecnt] = w;
1040 validmodeydim[validmodecnt] = h;
1041 validmodecnt++;
1042} /* add_vesa_mode */
1043
1044
1045/* Let the user specify a specific mode via environment variable. */
1046static __inline void add_user_defined_resolution(void)
1047{
1048 int32_t w;
1049 int32_t h;
1050 const char *envr = getenv(BUILD_USERSCREENRES);
1051
1052 /* rockbox hack */
1053 add_vesa_mode("rockbox", LCD_WIDTH, LCD_HEIGHT);
1054 add_vesa_mode("rockbox", LCD_HEIGHT, LCD_WIDTH);
1055
1056
1057 if (envr == NULL)
1058 return;
1059
1060 if (get_dimensions_from_str(envr, &w, &h))
1061 add_vesa_mode("user defined", w, h);
1062 else
1063 printf("User defined resolution [%s] is bogus!\n", envr);
1064} /* add_user_defined_resolution */
1065
1066
1067static __inline SDL_Rect **get_physical_resolutions(void)
1068{
1069 const SDL_VideoInfo *vidInfo = SDL_GetVideoInfo();
1070 SDL_Rect **modes = SDL_ListModes(vidInfo->vfmt, sdl_flags | SDL_FULLSCREEN);
1071 if (modes == NULL)
1072 {
1073 sdl_flags &= ~SDL_FULLSCREEN;
1074 modes = SDL_ListModes(vidInfo->vfmt, sdl_flags); /* try without fullscreen. */
1075 if (modes == NULL)
1076 modes = (SDL_Rect **) -1; /* fuck it. */
1077 } /* if */
1078
1079 if (modes == (SDL_Rect **) -1)
1080 printf("Couldn't get any physical resolutions.\n");
1081 else
1082 {
1083 printf("Highest physical resolution is (%dx%d).\n",
1084 modes[0]->w, modes[0]->h);
1085 } /* else */
1086
1087 return(modes);
1088} /* get_physical_resolutions */
1089
1090
1091static void remove_vesa_mode(int index, const char *reason)
1092{
1093 int i;
1094
1095 assert(index < validmodecnt);
1096 //printf("Removing resolution #%d, %dx%d [%s].\n",index, validmodexdim[index], validmodeydim[index], reason);
1097
1098 for (i = index; i < validmodecnt - 1; i++)
1099 {
1100 validmode[i] = validmode[i + 1];
1101 validmodexdim[i] = validmodexdim[i + 1];
1102 validmodeydim[i] = validmodeydim[i + 1];
1103 } /* for */
1104
1105 validmodecnt--;
1106} /* remove_vesa_mode */
1107
1108
1109static __inline void cull_large_vesa_modes(void)
1110{
1111 int32_t max_w;
1112 int32_t max_h;
1113 int i;
1114
1115 get_max_screen_res(&max_w, &max_h);
1116 printf("Setting resolution ceiling to (%dx%d).\n", max_w, max_h);
1117
1118 for (i = 0; i < validmodecnt; i++)
1119 {
1120 if ((validmodexdim[i] > max_w) || (validmodeydim[i] > max_h))
1121 {
1122 remove_vesa_mode(i, "above resolution ceiling");
1123 i--; /* list shrinks. */
1124 } /* if */
1125 } /* for */
1126} /* cull_large_vesa_modes */
1127
1128
1129static __inline void cull_duplicate_vesa_modes(void)
1130{
1131 int i;
1132 int j;
1133
1134 for (i = 0; i < validmodecnt; i++){
1135 for (j = i + 1; j < validmodecnt; j++){
1136 if ( (validmodexdim[i] == validmodexdim[j]) &&(validmodeydim[i] == validmodeydim[j]) ){
1137 remove_vesa_mode(j, "duplicate");
1138 j--; /* list shrinks. */
1139 }
1140 }
1141 }
1142}
1143
1144
1145#define swap_macro(tmp, x, y) { tmp = x; x = y; y = tmp; }
1146
1147/* be sure to call cull_duplicate_vesa_modes() before calling this. */
1148static __inline void sort_vesa_modelist(void)
1149{
1150 int i;
1151 int sorted;
1152 int32_t tmp;
1153
1154 do
1155 {
1156 sorted = 1;
1157 for (i = 0; i < validmodecnt - 1; i++)
1158 {
1159 if ( (validmodexdim[i] >= validmodexdim[i+1]) &&
1160 (validmodeydim[i] >= validmodeydim[i+1]) )
1161 {
1162 sorted = 0;
1163 swap_macro(tmp, validmode[i], validmode[i+1]);
1164 swap_macro(tmp, validmodexdim[i], validmodexdim[i+1]);
1165 swap_macro(tmp, validmodeydim[i], validmodeydim[i+1]);
1166 } /* if */
1167 } /* for */
1168 } while (!sorted);
1169} /* sort_vesa_modelist */
1170
1171
1172static __inline void cleanup_vesa_modelist(void)
1173{
1174 cull_large_vesa_modes();
1175 cull_duplicate_vesa_modes();
1176 sort_vesa_modelist();
1177} /* cleanup_vesa_modelist */
1178
1179
1180static __inline void output_vesa_modelist(void)
1181{
1182 char buffer[256];
1183 char numbuf[20];
1184 int i;
1185
1186 buffer[0] = '\0';
1187
1188 for (i = 0; i < validmodecnt; i++)
1189 {
1190 sprintf(numbuf, " (%dx%d)",(int32_t) validmodexdim[i], (int32_t) validmodeydim[i]);
1191
1192 if ( (strlen(buffer) + strlen(numbuf)) >= (sizeof (buffer) - 1) )
1193 strcpy(buffer + (sizeof (buffer) - 5), " ...");
1194 else
1195 strcat(buffer, numbuf);
1196 } /* for */
1197
1198 printf("Final sorted modelist:%s", buffer);
1199}
1200
1201
1202void getvalidvesamodes(void)
1203{
1204 static int already_checked = 0;
1205 int i;
1206 SDL_Rect **modes = NULL;
1207 int stdres[][2] = {
1208 {320, 200}, {640, 350}, {640, 480},
1209 {800, 600}, {1024, 768}
1210 };
1211
1212 if (already_checked)
1213 return;
1214
1215 already_checked = 1;
1216 validmodecnt = 0;
1217 vidoption = 1; /* !!! tmp */
1218
1219 /* fill in the standard resolutions... */
1220 for (i = 0; i < sizeof (stdres) / sizeof (stdres[0]); i++)
1221 add_vesa_mode("standard", stdres[i][0], stdres[i][1]);
1222
1223 /* Anything the hardware can specifically do is added now... */
1224 modes = get_physical_resolutions();
1225 for (i = 0; (modes != (SDL_Rect **) -1) && (modes[i] != NULL); i++)
1226 add_vesa_mode("physical", modes[i]->w, modes[i]->h);
1227
1228 /* Now add specific resolutions that the user wants... */
1229 add_user_defined_resolution();
1230
1231 /* get rid of dupes and bogus resolutions... */
1232 cleanup_vesa_modelist();
1233
1234 /* print it out for debugging purposes... */
1235 output_vesa_modelist();
1236}
1237
1238uint8_t lastPalette[768];
1239void WriteTranslucToFile(void){
1240
1241 uint8_t buffer[65535*4];
1242 uint8_t tga_header[18];
1243 uint8_t* transPointer = transluc;
1244 uint8_t* bufferPointer = buffer;
1245 int i;
1246 FILE* file;
1247
1248 for (i=0; i < 65535; i++) {
1249
1250 bufferPointer[0] = (lastPalette[(*transPointer)*3+0]) / 63.0 * 255;
1251 bufferPointer[1] = (lastPalette[(*transPointer)*3+1]) / 63.0 * 255;
1252 bufferPointer[2] = (lastPalette[(*transPointer)*3+2]) / 63.0 * 255;
1253 bufferPointer[3] = 255;
1254
1255 printf("%d,",*transPointer);
1256 if (i%255 ==0)
1257 printf("\n");
1258
1259 transPointer +=1;
1260 bufferPointer+=4;
1261 }
1262
1263
1264
1265 file = fopen("/transluc.tga", "w");
1266
1267 memset(tga_header, 0, 18);
1268 tga_header[2] = 2;
1269 tga_header[12] = (256 & 0x00FF);
1270 tga_header[13] = (256 & 0xFF00) / 256;
1271 tga_header[14] = (256 & 0x00FF) ;
1272 tga_header[15] =(256 & 0xFF00) / 256;
1273 tga_header[16] = 32 ;
1274
1275 fwrite(&tga_header, 18, sizeof(uint8_t), file);
1276 fwrite(buffer, 65535, 4, file);
1277 fclose(file);
1278}
1279
1280void WritePaletteToFile(uint8_t* palette,const char* filename,int width, int height){
1281
1282 uint8_t tga_header[18];
1283 uint8_t* buffer;
1284 uint8_t* palettePointer = palette;
1285 uint8_t* bufferPointer ;
1286 int i;
1287
1288 FILE* file = fopen(filename, "w");
1289
1290
1291 memset(tga_header, 0, 18);
1292 tga_header[2] = 2;
1293 tga_header[12] = (width & 0x00FF);
1294 tga_header[13] = (width & 0xFF00) / 256;
1295 tga_header[14] = (height & 0x00FF) ;
1296 tga_header[15] =(height & 0xFF00) / 256;
1297 tga_header[16] = 32 ;
1298
1299 fwrite(&tga_header, 18, sizeof(uint8_t), file);
1300
1301 bufferPointer = buffer = malloc(width*height*4);
1302
1303 for (i = 0 ; i < width*height ; i++)
1304 {
1305 bufferPointer[0] = palettePointer[0] / 63.0 * 255;
1306 bufferPointer[1] = palettePointer[1] / 63.0 * 255;
1307 bufferPointer[2] = palettePointer[2] / 63.0 * 255;
1308 bufferPointer[3] = 255;
1309
1310 bufferPointer += 4;
1311 palettePointer+= 3;
1312 }
1313
1314 fwrite(buffer, width*height, 4, file);
1315 fclose(file);
1316
1317 free(buffer);
1318}
1319
1320
1321void WriteLastPaletteToFile(){
1322 WritePaletteToFile(lastPalette,"lastPalette.tga",16,16);
1323}
1324
1325int VBE_setPalette(uint8_t *palettebuffer)
1326/*
1327 * (From Ken's docs:)
1328 * Set (num) palette palette entries starting at (start)
1329 * palette entries are in a 4-byte format in this order:
1330 * 0: Blue (0-63)
1331 * 1: Green (0-63)
1332 * 2: Red (0-63)
1333 * 3: Reserved
1334 *
1335 * Naturally, the bytes are in the reverse order that SDL wants them...
1336 * More importantly, SDL wants the color elements in a range from 0-255,
1337 * so we do a conversion.
1338 */
1339{
1340 SDL_Color fmt_swap[256];
1341 SDL_Color *sdlp = fmt_swap;
1342 uint8_t *p = palettebuffer;
1343 int i;
1344 //static updated=0;
1345
1346 //if (updated >=1 )
1347 // return ;
1348
1349 //WritePaletteToFile(palettebuffer,"lastPalette.tga",16,16);
1350 //updated++;
1351
1352
1353 //CODE EXPLORATION
1354 //Used only to write the last palette to file.
1355 memcpy(lastPalette, palettebuffer, 768);
1356
1357 for (i = 0; i < 256; i++){
Franklin Weicf07bb32018-01-05 17:25:03 -05001358 /* doesn't map perfectly */
1359 sdlp->b = (Uint8) (*p << 2) | (*p >> 4);
1360 p++;
1361 sdlp->g = (Uint8) (*p << 2) | (*p >> 4);
1362 p++;
1363 sdlp->r = (Uint8) (*p << 2) | (*p >> 4);
1364 p++;
Franklin Weia855d622017-01-21 15:18:31 -05001365 sdlp->unused = *p++; /* This byte is unused in BUILD, too. */
1366 sdlp++;
1367 }
1368
1369 return(SDL_SetColors(surface, fmt_swap, 0, 256));
1370}
1371
1372
1373int VBE_getPalette(int32_t start, int32_t num, uint8_t *palettebuffer)
1374{
1375 SDL_Color *sdlp = surface->format->palette->colors + start;
1376 uint8_t *p = palettebuffer + (start * 4);
1377 int i;
1378
1379 for (i = 0; i < num; i++)
1380 {
1381 *p++ = (Uint8) ((((float) sdlp->b) / 255.0) * 63.0);
1382 *p++ = (Uint8) ((((float) sdlp->g) / 255.0) * 63.0);
1383 *p++ = (Uint8) ((((float) sdlp->r) / 255.0) * 63.0);
1384 *p++ = sdlp->unused; /* This byte is unused in both SDL and BUILD. */
1385 sdlp++;
1386 }
1387
1388 return(1);
1389}
1390
1391
1392void _uninitengine(void)
1393{
1394 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1395} /* _uninitengine */
1396
1397
1398
1399
1400int setupmouse(void)
1401{
1402
1403 SDL_Event event;
1404
1405 if (surface == NULL)
1406 return(0);
1407
1408 SDL_WM_GrabInput(SDL_GRAB_ON);
1409 SDL_ShowCursor(0);
1410
1411 mouse_relative_x = mouse_relative_y = 0;
1412
1413 /*
1414 * this global usually gets set by BUILD, but it's a one-shot
1415 * deal, and we may not have an SDL surface at that point. --ryan.
1416 */
1417 moustat = 1;
1418
1419 // FIX_00063: Duke's angle changing or incorrect when using toggle fullscreen/window mode
1420 while(SDL_PollEvent(&event)); // Empying the various pending events (especially the mouse one)
1421
1422 //SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
1423
1424 return(1);
1425} /* setupmouse */
1426
1427
1428void readmousexy(short *x, short *y)
1429{
1430 if (x)
1431 *x = mouse_relative_x << 2;
1432 if (y)
1433 *y = mouse_relative_y << 2;
1434
1435 mouse_relative_x = mouse_relative_y = 0;
1436} /* readmousexy */
1437
1438
1439void readmousebstatus(short *bstatus)
1440{
1441 if (bstatus)
1442 *bstatus = mouse_buttons;
1443
1444 // special wheel treatment: make it like a button click
1445 if(mouse_buttons&8)
1446 mouse_buttons ^= 8;
1447 if(mouse_buttons&16)
1448 mouse_buttons ^= 16;
1449
1450} /* readmousebstatus */
1451
1452
1453void _updateScreenRect(int32_t x, int32_t y, int32_t w, int32_t h)
1454{
1455 SDL_UpdateRect(surface, x, y, w, h);
1456}
1457
1458//int counter= 0 ;
1459//char bmpName[256];
1460void _nextpage(void)
1461
1462{
1463 Uint32 ticks;
1464
1465 _handle_events();
1466
1467
1468 SDL_UpdateRect(surface, 0, 0, 0, 0);
1469
1470 //sprintf(bmpName,"%d.bmp",counter++);
1471 //SDL_SaveBMP(surface,bmpName);
1472
1473
1474 //if (CLEAR_FRAMEBUFFER)
1475 // SDL_FillRect(surface,NULL,0);
1476
1477 ticks = getticks();
1478 total_render_time = (ticks - last_render_ticks);
1479 if (total_render_time > 1000){
1480 total_rendered_frames = 0;
1481 total_render_time = 1;
1482 last_render_ticks = ticks;
1483 }
1484 total_rendered_frames++;
1485}
1486
1487
1488uint8_t readpixel(uint8_t * offset)
1489{
1490 return *offset;
1491}
1492
1493void drawpixel(uint8_t * location, uint8_t pixel)
1494{
1495 *location = pixel;
1496}
1497
1498/* Fix this up The Right Way (TM) - DDOI */
1499void setcolor16(uint8_t col)
1500{
1501 drawpixel_color = col;
1502}
1503
1504void drawpixel16(int32_t offset)
1505{
1506 drawpixel((uint8_t*)surface->pixels + offset, drawpixel_color);
1507} /* drawpixel16 */
1508
1509
1510void fillscreen16(int32_t offset, int32_t color, int32_t blocksize)
1511{
1512 Uint8 *surface_end;
1513 Uint8 *wanted_end;
1514 Uint8 *pixels;
1515
1516 if (SDL_MUSTLOCK(surface))
1517 SDL_LockSurface(surface);
1518
1519 pixels = get_framebuffer();
1520
1521 /* Make this function pageoffset aware - DDOI */
1522 if (!pageoffset) {
1523 offset = offset << 3;
1524 offset += 640*336;
1525 }
1526
1527 surface_end = (pixels + (surface->w * surface->h)) - 1;
1528 wanted_end = (pixels + offset) + blocksize;
1529
1530 if (offset < 0)
1531 offset = 0;
1532
1533 if (wanted_end > surface_end)
1534 blocksize = ((uint32_t) surface_end) - ((uint32_t) pixels + offset);
1535
1536 memset(pixels + offset, (int) color, blocksize);
1537
1538 if (SDL_MUSTLOCK(surface))
1539 SDL_UnlockSurface(surface);
1540
1541 _nextpage();
1542} /* fillscreen16 */
1543
1544
1545/* Most of this line code is taken from Abrash's "Graphics Programming Blackbook".
1546Remember, sharing code is A Good Thing. AH */
1547static __inline void DrawHorizontalRun (uint8_t **ScreenPtr, int XAdvance, int RunLength, uint8_t Color)
1548{
1549 int i;
1550 uint8_t *WorkingScreenPtr = *ScreenPtr;
1551
1552 for (i=0; i<RunLength; i++)
1553 {
1554 *WorkingScreenPtr = Color;
1555 WorkingScreenPtr += XAdvance;
1556 }
1557 WorkingScreenPtr += surface->w;
1558 *ScreenPtr = WorkingScreenPtr;
1559}
1560
1561static __inline void DrawVerticalRun (uint8_t **ScreenPtr, int XAdvance, int RunLength, uint8_t Color)
1562{
1563 int i;
1564 uint8_t *WorkingScreenPtr = *ScreenPtr;
1565
1566 for (i=0; i<RunLength; i++)
1567 {
1568 *WorkingScreenPtr = Color;
1569 WorkingScreenPtr += surface->w;
1570 }
1571 WorkingScreenPtr += XAdvance;
1572 *ScreenPtr = WorkingScreenPtr;
1573}
1574
1575void drawline16(int32_t XStart, int32_t YStart, int32_t XEnd, int32_t YEnd, uint8_t Color)
1576{
1577 int Temp, AdjUp, AdjDown, ErrorTerm, XAdvance, XDelta, YDelta;
1578 int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength;
1579 uint8_t *ScreenPtr;
1580 int32_t dx, dy;
1581
1582 if (SDL_MUSTLOCK(surface))
1583 SDL_LockSurface(surface);
1584
1585 dx = XEnd-XStart;
1586 dy = YEnd-YStart;
1587
1588 //Analyse the slope
1589 if (dx >= 0)
1590 {
1591 if ((XStart > 639) || (XEnd < 0)) return;
1592 if (XStart < 0) { if (dy) YStart += scale(0-XStart,dy,dx); XStart = 0; }
1593 if (XEnd > 639) { if (dy) YEnd += scale(639-XEnd,dy,dx); XEnd = 639; }
1594 }
1595 else
1596 {
1597 if ((XEnd > 639) || (XStart < 0)) return;
1598 if (XEnd < 0) { if (dy) YEnd += scale(0-XEnd,dy,dx); XEnd = 0; }
1599 if (XStart > 639) { if (dy) YStart += scale(639-XStart,dy,dx); XStart = 639; }
1600 }
1601 if (dy >= 0)
1602 {
1603 if ((YStart >= ydim16) || (YEnd < 0)) return;
1604 if (YStart < 0) { if (dx) XStart += scale(0-YStart,dx,dy); YStart = 0; }
1605 if (YEnd >= ydim16) { if (dx) XEnd += scale(ydim16-1-YEnd,dx,dy); YEnd = ydim16-1; }
1606 }
1607 else
1608 {
1609 if ((YEnd >= ydim16) || (YStart < 0)) return;
1610 if (YEnd < 0) { if (dx) XEnd += scale(0-YEnd,dx,dy); YEnd = 0; }
1611 if (YStart >= ydim16) { if (dx) XStart += scale(ydim16-1-YStart,dx,dy); YStart = ydim16-1; }
1612 }
1613
1614 /* Make sure the status bar border draws correctly - DDOI */
1615 if (!pageoffset) { YStart += 336; YEnd += 336; }
1616
1617 /* We'll always draw top to bottom */
1618 if (YStart > YEnd) {
1619 Temp = YStart;
1620 YStart = YEnd;
1621 YEnd = Temp;
1622 Temp = XStart;
1623 XStart = XEnd;
1624 XEnd = Temp;
1625 }
1626
1627 /* Point to the bitmap address first pixel to draw */
1628 ScreenPtr = (uint8_t *) (get_framebuffer()) + XStart + (surface->w * YStart);
1629
1630 /* Figure out whether we're going left or right, and how far we're going horizontally */
1631 if ((XDelta = XEnd - XStart) < 0)
1632 {
1633 XAdvance = (-1);
1634 XDelta = -XDelta;
1635 } else {
1636 XAdvance = 1;
1637 }
1638
1639 /* Figure out how far we're going vertically */
1640 YDelta = YEnd - YStart;
1641
1642 /* Special cases: Horizontal, vertical, and diagonal lines */
1643 if (XDelta == 0)
1644 {
1645 for (i=0; i <= YDelta; i++)
1646 {
1647 *ScreenPtr = Color;
1648 ScreenPtr += surface->w;
1649 }
1650
1651 UNLOCK_SURFACE_AND_RETURN;
1652 }
1653 if (YDelta == 0)
1654 {
1655 for (i=0; i <= XDelta; i++)
1656 {
1657 *ScreenPtr = Color;
1658 ScreenPtr += XAdvance;
1659 }
1660 UNLOCK_SURFACE_AND_RETURN;
1661 }
1662 if (XDelta == YDelta)
1663 {
1664 for (i=0; i <= XDelta; i++)
1665 {
1666 *ScreenPtr = Color;
1667 ScreenPtr += XAdvance + surface->w;
1668 }
1669 UNLOCK_SURFACE_AND_RETURN;
1670 }
1671
1672 /* Determine whether the line is X or Y major, and handle accordingly */
1673 if (XDelta >= YDelta) /* X major line */
1674 {
1675 WholeStep = XDelta / YDelta;
1676 AdjUp = (XDelta % YDelta) * 2;
1677 AdjDown = YDelta * 2;
1678 ErrorTerm = (XDelta % YDelta) - (YDelta * 2);
1679
1680 InitialPixelCount = (WholeStep / 2) + 1;
1681 FinalPixelCount = InitialPixelCount;
1682
1683 if ((AdjUp == 0) && ((WholeStep & 0x01) == 0)) InitialPixelCount--;
1684 if ((WholeStep & 0x01) != 0) ErrorTerm += YDelta;
1685
1686 DrawHorizontalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color);
1687
1688 for (i=0; i<(YDelta-1); i++)
1689 {
1690 RunLength = WholeStep;
1691 if ((ErrorTerm += AdjUp) > 0)
1692 {
1693 RunLength ++;
1694 ErrorTerm -= AdjDown;
1695 }
1696
1697 DrawHorizontalRun(&ScreenPtr, XAdvance, RunLength, Color);
1698 }
1699
1700 DrawHorizontalRun(&ScreenPtr, XAdvance, FinalPixelCount, Color);
1701
1702 UNLOCK_SURFACE_AND_RETURN;
1703 } else { /* Y major line */
1704 WholeStep = YDelta / XDelta;
1705 AdjUp = (YDelta % XDelta) * 2;
1706 AdjDown = XDelta * 2;
1707 ErrorTerm = (YDelta % XDelta) - (XDelta * 2);
1708 InitialPixelCount = (WholeStep / 2) + 1;
1709 FinalPixelCount = InitialPixelCount;
1710
1711 if ((AdjUp == 0) && ((WholeStep & 0x01) == 0)) InitialPixelCount --;
1712 if ((WholeStep & 0x01) != 0) ErrorTerm += XDelta;
1713
1714 DrawVerticalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color);
1715
1716 for (i=0; i<(XDelta-1); i++)
1717 {
1718 RunLength = WholeStep;
1719 if ((ErrorTerm += AdjUp) > 0)
1720 {
1721 RunLength ++;
1722 ErrorTerm -= AdjDown;
1723 }
1724
1725 DrawVerticalRun(&ScreenPtr, XAdvance, RunLength, Color);
1726 }
1727
1728 DrawVerticalRun(&ScreenPtr, XAdvance, FinalPixelCount, Color);
1729 UNLOCK_SURFACE_AND_RETURN;
1730 }
1731} /* drawline16 */
1732
1733
1734void clear2dscreen(void)
1735{
1736 SDL_Rect rect;
1737
1738 rect.x = rect.y = 0;
1739 rect.w = surface->w;
1740
1741 if (qsetmode == 350)
1742 rect.h = 350;
1743 else if (qsetmode == 480)
1744 {
1745 if (ydim16 <= 336)
1746 rect.h = 336;
1747 else
1748 rect.h = 480;
1749 } /* else if */
1750
1751 SDL_FillRect(surface, &rect, 0);
1752} /* clear2dscreen */
1753
1754
1755void _idle(void)
1756{
1757 if (surface != NULL)
1758 _handle_events();
1759 SDL_Delay(1);
1760} /* _idle */
1761
1762void *_getVideoBase(void)
1763{
1764 return((void *) surface->pixels);
1765}
1766
1767
1768//-------------------------------------------------------------------------------------------------
1769// TIMER
1770//=================================================================================================
1771
1772
1773
1774
1775// FIX_00007: game speed corrected. The game speed is now as the real
1776// DOS duke3d. Unloading a full 200 bullet pistol must take 45.1 sec.
1777// SDL timer was not fast/accurate enough and was slowing down the gameplay,
1778// so bad
1779
1780
1781static int64_t timerfreq=0;
1782static int32_t timerlastsample=0;
1783static int timerticspersec=0;
1784static void (*usertimercallback)(void) = NULL;
1785
1786// This timer stuff is all Ken's idea.
1787
1788//
1789// installusertimercallback() -- set up a callback function to be called when the timer is fired
1790//
1791void (*installusertimercallback(void (*callback)(void)))(void)
1792{
1793 void (*oldtimercallback)(void);
1794
1795 oldtimercallback = usertimercallback;
1796 usertimercallback = callback;
1797
1798 return oldtimercallback;
1799}
1800
1801
1802/*
1803 inittimer() -- initialise timer
1804 FCS: The tickspersecond parameter is a ratio value that helps replicating
1805 oldschool DOS tick per seconds.
1806
1807 The way the timer work is:
1808 float newSystemTickPerSecond = [0,1]
1809 tickPerSecond on a DOS system = tickspersecond * newSystemTickPerSecond ;
1810*/
1811
1812int inittimer(int tickspersecond)
1813{
1814 int64_t t;
1815
1816
1817 if (timerfreq) return 0; // already installed
1818
1819 //printf("Initialising timer, with tickPerSecond=%d\n",tickspersecond);
1820
1821 // OpenWatcom seems to want us to query the value into a local variable
1822 // instead of the global 'timerfreq' or else it gets pissed with an
1823 // access violation
1824 if (!TIMER_GetPlatformTicksInOneSecond(&t)) {
1825 printf("Failed fetching timer frequency\n");
1826 return -1;
1827 }
1828 timerfreq = t;
1829 timerticspersec = tickspersecond;
1830 TIMER_GetPlatformTicks(&t);
1831 timerlastsample = (int32_t)(t*timerticspersec / timerfreq);
1832
1833 usertimercallback = NULL;
1834
1835 return 0;
1836}
1837
1838//
1839// uninittimer() -- shut down timer
1840//
1841void uninittimer(void)
1842{
1843 if (!timerfreq) return;
1844
1845 timerfreq=0;
1846 timerticspersec = 0;
1847}
1848
1849//
1850// sampletimer() -- update totalclock
1851//
1852void sampletimer(void)
1853{
1854 int64_t i;
1855 int32_t n;
1856
1857 if (!timerfreq) return;
1858
1859 TIMER_GetPlatformTicks(&i);
1860
1861
1862 n = (int32_t)(i*timerticspersec / timerfreq) - timerlastsample;
1863 if (n>0) {
1864 totalclock += n;
1865 timerlastsample += n;
1866 }
1867
1868 if (usertimercallback) for (; n>0; n--) usertimercallback();
1869}
1870
1871
1872/*
1873 getticks() -- returns the windows ticks count
1874 FCS: This seeems to be only used in the multiplayer code
1875*/
1876uint32_t getticks(void)
1877{
1878 int64_t i;
1879 TIMER_GetPlatformTicks(&i);
1880 return (uint32_t)(i*(int32_t)(1000)/timerfreq);
1881}
1882
1883
1884//
1885// gettimerfreq() -- returns the number of ticks per second the timer is configured to generate
1886//
1887int gettimerfreq(void)
1888{
1889 return timerticspersec;
1890}
1891
1892
1893
1894void initkeys(void)
1895{
1896 /* does nothing in SDL. Key input handling is set up elsewhere. */
1897 /* !!! why not here? */
1898}
1899
1900void uninitkeys(void)
1901{
1902 /* does nothing in SDL. Key input handling is set up elsewhere. */
1903}
1904
Franklin Weia855d622017-01-21 15:18:31 -05001905int TIMER_GetPlatformTicksInOneSecond(int64_t* t)
1906{
1907 *t = 1000;
1908 return 1;
1909}
1910
1911void TIMER_GetPlatformTicks(int64_t* t)
1912{
1913 *t = SDL_GetTicks();
1914}
Franklin Weia855d622017-01-21 15:18:31 -05001915/* end of sdl_driver.c ... */
1916