Files
gronod 6aaf73d70c
Build macOS app / Build DOOM.app (push) Canceled after 0s
macOS port: add app build workflow
2026-09-18 20:01:16 +01:00

425 lines
9.6 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// DOOM graphics stuff for macOS, SDL2.
// Replaces the X11/MIT-SHM implementation.
//
//-----------------------------------------------------------------------------
static const char
rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include "doomstat.h"
#include "i_system.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
#include "m_argv.h"
#include "m_misc.h"
#include "d_main.h"
#include "doomdef.h"
static SDL_Window* sdl_window;
static SDL_Renderer* sdl_renderer;
static SDL_Texture* sdl_texture;
// Framebuffer: screens[0] converted to 32bpp before upload.
static Uint32 framebuffer[SCREENWIDTH * SCREENHEIGHT];
// 8-bit palette (with gamma applied) expanded to ARGB8888.
static Uint32 argb_palette[256];
// Fake mouse handling.
boolean grabMouse;
#define MIN_WINDOW_WIDTH 640
#define MIN_WINDOW_HEIGHT 480
//
// Translates an SDL_Keycode to a DOOM key value.
//
int xlatekey(SDL_Keycode sym)
{
int rc = sym;
switch (sym)
{
case SDLK_LEFT: rc = KEY_LEFTARROW; break;
case SDLK_RIGHT: rc = KEY_RIGHTARROW; break;
case SDLK_DOWN: rc = KEY_DOWNARROW; break;
case SDLK_UP: rc = KEY_UPARROW; break;
case SDLK_ESCAPE: rc = KEY_ESCAPE; break;
case SDLK_RETURN: rc = KEY_ENTER; break;
case SDLK_TAB: rc = KEY_TAB; break;
case SDLK_F1: rc = KEY_F1; break;
case SDLK_F2: rc = KEY_F2; break;
case SDLK_F3: rc = KEY_F3; break;
case SDLK_F4: rc = KEY_F4; break;
case SDLK_F5: rc = KEY_F5; break;
case SDLK_F6: rc = KEY_F6; break;
case SDLK_F7: rc = KEY_F7; break;
case SDLK_F8: rc = KEY_F8; break;
case SDLK_F9: rc = KEY_F9; break;
case SDLK_F10: rc = KEY_F10; break;
case SDLK_F11: rc = KEY_F11; break;
case SDLK_F12: rc = KEY_F12; break;
case SDLK_BACKSPACE:
case SDLK_DELETE: rc = KEY_BACKSPACE; break;
case SDLK_PAUSE: rc = KEY_PAUSE; break;
case SDLK_KP_EQUALS:
case SDLK_EQUALS: rc = KEY_EQUALS; break;
case SDLK_KP_MINUS:
case SDLK_MINUS: rc = KEY_MINUS; break;
case SDLK_LSHIFT:
case SDLK_RSHIFT: rc = KEY_RSHIFT; break;
case SDLK_LCTRL:
case SDLK_RCTRL: rc = KEY_RCTRL; break;
case SDLK_LALT:
case SDLK_RALT: rc = KEY_RALT; break;
default:
// SDL_Keycode values for printable keys are ASCII.
if (rc >= 'A' && rc <= 'Z')
rc = rc - 'A' + 'a';
break;
}
return rc;
}
void I_ShutdownGraphics(void)
{
if (sdl_texture)
SDL_DestroyTexture(sdl_texture);
if (sdl_renderer)
SDL_DestroyRenderer(sdl_renderer);
if (sdl_window)
SDL_DestroyWindow(sdl_window);
sdl_texture = NULL;
sdl_renderer = NULL;
sdl_window = NULL;
}
//
// I_StartFrame
//
void I_StartFrame (void)
{
// er?
}
//
// Mouse button bitmask in DOOM order:
// bit0 = left, bit1 = middle, bit2 = right.
//
static int mousebuttons(void)
{
Uint32 state = SDL_GetMouseState(NULL, NULL);
int bits = 0;
if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) bits |= 1;
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) bits |= 2;
if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) bits |= 4;
return bits;
}
void I_GetEvent(void)
{
SDL_Event sdl_event;
event_t event;
while (SDL_PollEvent(&sdl_event))
{
switch (sdl_event.type)
{
case SDL_KEYDOWN:
event.type = ev_keydown;
event.data1 = xlatekey(sdl_event.key.keysym.sym);
D_PostEvent(&event);
break;
case SDL_KEYUP:
event.type = ev_keyup;
event.data1 = xlatekey(sdl_event.key.keysym.sym);
D_PostEvent(&event);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
event.type = ev_mouse;
event.data1 = mousebuttons();
event.data2 = event.data3 = 0;
D_PostEvent(&event);
break;
case SDL_MOUSEMOTION:
event.type = ev_mouse;
event.data1 = mousebuttons();
event.data2 = sdl_event.motion.xrel << 2;
event.data3 = -sdl_event.motion.yrel << 2;
if (event.data2 || event.data3 || grabMouse)
D_PostEvent(&event);
break;
case SDL_WINDOWEVENT:
if (sdl_event.window.event == SDL_WINDOWEVENT_RESIZED
&& !(SDL_GetWindowFlags(sdl_window) & SDL_WINDOW_FULLSCREEN))
{
window_width = sdl_event.window.data1;
window_height = sdl_event.window.data2;
}
break;
case SDL_QUIT:
I_Quit();
break;
default:
break;
}
}
}
//
// I_StartTic
//
void I_StartTic (void)
{
I_GetEvent();
}
//
// I_UpdateNoBlit
//
void I_UpdateNoBlit (void)
{
// what is this?
}
//
// I_FinishUpdate
//
void I_FinishUpdate (void)
{
static int lasttic;
int tics;
int i;
int output_width;
int output_height;
SDL_Rect dest;
// draws little dots on the bottom of the screen
if (devparm)
{
i = I_GetTime();
tics = i - lasttic;
lasttic = i;
if (tics > 20) tics = 20;
for (i=0 ; i<tics*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
for ( ; i<20*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
}
// expand the 8-bit palettized screen to the 32-bit framebuffer
{
const byte* src = screens[0];
Uint32* dst = framebuffer;
int count = SCREENWIDTH * SCREENHEIGHT;
while (count--)
*dst++ = argb_palette[*src++];
}
SDL_UpdateTexture(sdl_texture, NULL, framebuffer, SCREENWIDTH * sizeof(Uint32));
if (SDL_GetRendererOutputSize(sdl_renderer, &output_width, &output_height) != 0)
SDL_GetWindowSize(sdl_window, &output_width, &output_height);
if (output_width * 3 > output_height * 4)
{
dest.h = output_height;
dest.w = output_height * 4 / 3;
}
else
{
dest.w = output_width;
dest.h = output_width * 3 / 4;
}
dest.x = (output_width - dest.w) / 2;
dest.y = (output_height - dest.h) / 2;
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, &dest);
SDL_RenderPresent(sdl_renderer);
}
//
// I_ReadScreen
//
void I_ReadScreen (byte* scr)
{
memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
}
//
// I_SetPalette
//
void I_SetPalette (byte* palette)
{
int i;
int c;
for (i=0 ; i<256 ; i++)
{
c = gammatable[usegamma][*palette++];
argb_palette[i] = 0xff000000 | (c<<16);
c = gammatable[usegamma][*palette++];
argb_palette[i] |= (c<<8);
c = gammatable[usegamma][*palette++];
argb_palette[i] |= c;
}
}
void I_InitGraphics(void)
{
Uint32 flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
SDL_Rect usable_bounds;
int start_width;
int start_height;
static int firsttime = 1;
if (!firsttime)
return;
firsttime = 0;
signal(SIGINT, (void (*)(int)) I_Quit);
if (M_CheckParm("-fullscreen"))
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
// check if the user wants to grab the mouse
grabMouse = !!M_CheckParm("-grabmouse");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) != 0)
I_Error("SDL_Init() failed: %s", SDL_GetError());
// Normalize saved dimensions before applying temporary command-line presets.
if (window_width < MIN_WINDOW_WIDTH)
window_width = MIN_WINDOW_WIDTH;
if (window_height < MIN_WINDOW_HEIGHT)
window_height = MIN_WINDOW_HEIGHT;
if (SDL_GetDisplayUsableBounds(0, &usable_bounds) == 0)
{
if (window_width > usable_bounds.w)
window_width = usable_bounds.w;
if (window_height > usable_bounds.h)
window_height = usable_bounds.h;
}
start_width = window_width;
start_height = window_height;
if (M_CheckParm("-2"))
{
start_width = 640;
start_height = 480;
}
if (M_CheckParm("-3"))
{
start_width = 960;
start_height = 720;
}
if (M_CheckParm("-4"))
{
start_width = 1280;
start_height = 960;
}
sdl_window = SDL_CreateWindow("DOOM",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
start_width,
start_height,
flags);
if (!sdl_window)
I_Error("SDL_CreateWindow() failed: %s", SDL_GetError());
SDL_SetWindowMinimumSize(sdl_window, MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1,
SDL_RENDERER_ACCELERATED);
if (!sdl_renderer)
I_Error("SDL_CreateRenderer() failed: %s", SDL_GetError());
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
sdl_texture = SDL_CreateTexture(sdl_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
SCREENWIDTH,
SCREENHEIGHT);
if (!sdl_texture)
I_Error("SDL_CreateTexture() failed: %s", SDL_GetError());
if (SDL_SetTextureScaleMode(sdl_texture, SDL_ScaleModeNearest) != 0)
I_Error("SDL_SetTextureScaleMode() failed: %s", SDL_GetError());
if (grabMouse)
SDL_SetRelativeMouseMode(SDL_TRUE);
// screens[0] was already allocated by V_Init.
// Fill the palette with something sane until I_SetPalette is called.
I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE));
}