Preserve current legacy presentation and options improvements
This commit is contained in:
1 parent
214789fe87
commit
eee082f2ad
15 files changed
+1090
-73
No files matched your search
@@ -183,6 +183,9 @@ ANIMS_Init(
|
||||
|
||||
// SUPER SHIELD
|
||||
ANIMS_Register(FILE149_SHIPGLOW_BLK, 4, HIGH_AIR, 1, 1, A_NORM);
|
||||
|
||||
// MACHINE-GUN EJECTA (world-space casing streaks, GUNSTR art)
|
||||
ANIMS_Register(FILE1c7_GUNSTR_BLK, 4, GROUND, 0, 0, A_NORM);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -70,6 +70,11 @@ typedef struct ANIMS_S
|
||||
#define A_ENERGY_GRAB 19
|
||||
#define A_SUPER_SHIELD 20
|
||||
|
||||
// Machine-gun ejecta: same GUNSTR streak art dropped into world space at
|
||||
// the wingtips (ground layer, drifts with the map scroll) so casings stay
|
||||
// behind the plane instead of flicking in place at the gun.
|
||||
#define A_PLAYER_EJECTA 21
|
||||
|
||||
void ANIMS_Clear(void);
|
||||
ANIMS *ANIMS_Remove(ANIMS *anim);
|
||||
void ANIMS_Init(void);
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// AdvMAME scale2x/scale3x filters by Andrea Mazzoleni, reimplemented
|
||||
// in-repo (GPLv2+, same license as the project). Each source pixel E
|
||||
// with its neighbors
|
||||
//
|
||||
// A B C
|
||||
// D E F
|
||||
// G H I
|
||||
//
|
||||
// expands to a 2x2 (scale2x) or 3x3 (scale3x) block of output pixels.
|
||||
// Factor 4 is scale2x applied twice, the reference composition.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "i_upscale.h"
|
||||
|
||||
// Exact per-byte average of two packed RGBA pixels: the common bits plus
|
||||
// half the differing bits. The mask keeps the halving inside each byte
|
||||
// lane, so no carry crosses channels and no unpacking is needed.
|
||||
|
||||
static uint32_t pixel_blend(uint32_t x, uint32_t y)
|
||||
{
|
||||
return (x & y) + (((x ^ y) >> 1) & 0x7f7f7f7f);
|
||||
}
|
||||
|
||||
static void scale2x_pass(const uint32_t *src, int spitch, int w, int h,
|
||||
uint32_t *dst, int dpitch)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < h; ++y)
|
||||
{
|
||||
const uint32_t *row = src + y * spitch;
|
||||
const uint32_t *above = y > 0 ? row - spitch : row;
|
||||
const uint32_t *below = y < h - 1 ? row + spitch : row;
|
||||
uint32_t *out0 = dst + (y * 2) * dpitch;
|
||||
uint32_t *out1 = dst + (y * 2 + 1) * dpitch;
|
||||
|
||||
for (x = 0; x < w; ++x)
|
||||
{
|
||||
// Out-of-bounds neighbors are treated as E (edges of the
|
||||
// above/below row aliases and of the x clamp do exactly that).
|
||||
|
||||
uint32_t E = row[x];
|
||||
uint32_t B = above[x];
|
||||
uint32_t H = below[x];
|
||||
uint32_t D = x > 0 ? row[x - 1] : E;
|
||||
uint32_t F = x < w - 1 ? row[x + 1] : E;
|
||||
uint32_t a, b, c, d;
|
||||
|
||||
a = (D == B && D != H && B != F) ? D : E;
|
||||
b = (B == F && B != D && F != H) ? B : E;
|
||||
c = (D == H && D != B && H != F) ? D : E;
|
||||
d = (H == F && H != D && F != B) ? F : E;
|
||||
|
||||
out0[x * 2] = a;
|
||||
out0[x * 2 + 1] = b;
|
||||
out1[x * 2] = c;
|
||||
out1[x * 2 + 1] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scale3x_pass(const uint32_t *src, int spitch, int w, int h,
|
||||
uint32_t *dst, int dpitch)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < h; ++y)
|
||||
{
|
||||
const uint32_t *row = src + y * spitch;
|
||||
const uint32_t *above = y > 0 ? row - spitch : row;
|
||||
const uint32_t *below = y < h - 1 ? row + spitch : row;
|
||||
uint32_t *out0 = dst + (y * 3) * dpitch;
|
||||
uint32_t *out1 = dst + (y * 3 + 1) * dpitch;
|
||||
uint32_t *out2 = dst + (y * 3 + 2) * dpitch;
|
||||
|
||||
for (x = 0; x < w; ++x)
|
||||
{
|
||||
uint32_t E = row[x];
|
||||
uint32_t B = above[x];
|
||||
uint32_t H = below[x];
|
||||
uint32_t D = x > 0 ? row[x - 1] : E;
|
||||
uint32_t F = x < w - 1 ? row[x + 1] : E;
|
||||
uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8;
|
||||
|
||||
a4 = E;
|
||||
a1 = (B == D) ? D : E;
|
||||
a5 = (B == F) ? F : E;
|
||||
a7 = (H == F) ? F : E;
|
||||
a3 = (H == D) ? D : E;
|
||||
|
||||
a0 = (B == D && B != F && D != H) ? D
|
||||
: ((D == B && D == H && F != H && B != F) ? pixel_blend(D, B) : E);
|
||||
a2 = (B == F && B != D && F != H) ? F
|
||||
: ((B == F && H == F && D != H && B != D) ? pixel_blend(B, F) : E);
|
||||
a6 = (D == H && D != B && H != F) ? D
|
||||
: ((D == H && H == F && B != F && D != B) ? pixel_blend(D, H) : E);
|
||||
a8 = (H == F && H != D && F != B) ? F
|
||||
: ((H == F && F == B && D != B && H != D) ? pixel_blend(H, F) : E);
|
||||
|
||||
out0[x * 3] = a0;
|
||||
out0[x * 3 + 1] = a1;
|
||||
out0[x * 3 + 2] = a2;
|
||||
out1[x * 3] = a3;
|
||||
out1[x * 3 + 1] = a4;
|
||||
out1[x * 3 + 2] = a5;
|
||||
out2[x * 3] = a6;
|
||||
out2[x * 3 + 1] = a7;
|
||||
out2[x * 3 + 2] = a8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I_UpscaleFrame(const uint32_t *src, int srcpitch_px, int w, int h,
|
||||
uint32_t *dst, int dstpitch_px, int factor)
|
||||
{
|
||||
if (factor == 2)
|
||||
{
|
||||
scale2x_pass(src, srcpitch_px, w, h, dst, dstpitch_px);
|
||||
}
|
||||
else if (factor == 3)
|
||||
{
|
||||
scale3x_pass(src, srcpitch_px, w, h, dst, dstpitch_px);
|
||||
}
|
||||
else if (factor == 4)
|
||||
{
|
||||
// scale2x applied twice (640x400x4 = 1 MB temporary).
|
||||
|
||||
uint32_t *tmp = (uint32_t *) malloc(sizeof(uint32_t)
|
||||
* w * 2 * h * 2);
|
||||
|
||||
if (tmp == NULL)
|
||||
{
|
||||
EXIT_Error("I_UpscaleFrame: memory");
|
||||
}
|
||||
|
||||
scale2x_pass(src, srcpitch_px, w, h, tmp, w * 2);
|
||||
scale2x_pass(tmp, w * 2, w * 2, h * 2, dst, dstpitch_px);
|
||||
free(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
EXIT_Error("I_UpscaleFrame: bad factor %d", factor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Presentation-level pixel-art upscaler (AdvMAME scale2x/scale3x).
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Upscale a w x h 32-bit RGBA frame by factor (2, 3 or 4) into dst, which
|
||||
// must be w*factor x h*factor pixels. Pitches are in pixels, not bytes;
|
||||
// the caller converts surface pitches. No SDL dependency, no global state.
|
||||
|
||||
void I_UpscaleFrame(const uint32_t *src, int srcpitch_px, int w, int h,
|
||||
uint32_t *dst, int dstpitch_px, int factor);
|
||||
+181
-12
@@ -38,6 +38,7 @@
|
||||
#include "musapi.h"
|
||||
#include "prefapi.h"
|
||||
#include "joyapi.h"
|
||||
#include "i_upscale.h"
|
||||
|
||||
// These are (1) the window (or the full screen) that our game is rendered to
|
||||
// and (2) the renderer that scales the texture (see below) into this window.
|
||||
@@ -61,6 +62,12 @@ static SDL_Surface *argbbuffer = NULL;
|
||||
static SDL_Texture *texture = NULL;
|
||||
static SDL_Texture *texture_upscaled = NULL;
|
||||
|
||||
// HD remaster: when the presentation upscaler is active, the filtered
|
||||
// factor-sized RGBA frame lands here before going into the streaming
|
||||
// texture.
|
||||
|
||||
static SDL_Surface *argbbuffer_scaled = NULL;
|
||||
|
||||
static SDL_Rect blit_rect = {
|
||||
0,
|
||||
0,
|
||||
@@ -117,6 +124,13 @@ int fullscreen_width = 0, fullscreen_height = 0;
|
||||
|
||||
static int max_scaling_buffer_pixels = 16000000;
|
||||
|
||||
// HD remaster: presentation-level pixel-art upscaler (0 = off, else 2/3/4)
|
||||
// and scanline overlay (0 = off, 1 = on). Read from [Video] upscaler /
|
||||
// [Video] scanlines in SETUP.INI at boot only; changing them needs a restart.
|
||||
|
||||
static int upscale_factor = 3;
|
||||
static int scanlines = 0;
|
||||
|
||||
// Run in full screen mode? (int type for config code)
|
||||
|
||||
// int fullscreen = true;
|
||||
@@ -218,6 +232,14 @@ void VIDEO_LoadPrefs(void)
|
||||
aspect_ratio_correct = INI_GetPreferenceLong("Video", "aspect_ratio_correct", 1);
|
||||
txt_fullscreen = INI_GetPreferenceLong("Video", "txt_fullscreen", 0);
|
||||
borderless = INI_GetPreferenceLong("Video", "borderless", 0);
|
||||
upscale_factor = INI_GetPreferenceLong("Video", "upscaler", 3);
|
||||
scanlines = INI_GetPreferenceLong("Video", "scanlines", 0);
|
||||
|
||||
if (upscale_factor != 0 && upscale_factor != 2 && upscale_factor != 3
|
||||
&& upscale_factor != 4)
|
||||
{
|
||||
upscale_factor = 3;
|
||||
}
|
||||
}
|
||||
|
||||
static bool MouseShouldBeGrabbed()
|
||||
@@ -854,24 +876,64 @@ void I_FinishUpdate (void)
|
||||
|
||||
SDL_LowerBlit(screenbuffer, &blit_rect, argbbuffer, &blit_rect);
|
||||
|
||||
// Update the intermediate texture with the contents of the RGBA buffer.
|
||||
if (upscale_factor > 1)
|
||||
{
|
||||
// HD remaster path: filter the RGBA frame into the factor-sized
|
||||
// surface and stream it directly to screen. The source is already
|
||||
// integer-scaled by the filter, so the nearest-integer intermediate
|
||||
// (which exists to sharpen sub-integer fits of a 1x source) is not
|
||||
// used here.
|
||||
|
||||
SDL_UpdateTexture(texture, NULL, argbbuffer->pixels, argbbuffer->pitch);
|
||||
I_UpscaleFrame((uint32_t *) argbbuffer->pixels,
|
||||
argbbuffer->pitch / 4,
|
||||
SCREENWIDTH, SCREENHEIGHT,
|
||||
(uint32_t *) argbbuffer_scaled->pixels,
|
||||
argbbuffer_scaled->pitch / 4,
|
||||
upscale_factor);
|
||||
|
||||
// Make sure the pillarboxes are kept clear each frame.
|
||||
SDL_UpdateTexture(texture, NULL, argbbuffer_scaled->pixels,
|
||||
argbbuffer_scaled->pitch);
|
||||
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the intermediate texture with the contents of the RGBA buffer.
|
||||
|
||||
// Render this intermediate texture into the upscaled texture
|
||||
// using "nearest" integer scaling.
|
||||
SDL_UpdateTexture(texture, NULL, argbbuffer->pixels, argbbuffer->pitch);
|
||||
|
||||
SDL_SetRenderTarget(renderer, texture_upscaled);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
// Make sure the pillarboxes are kept clear each frame.
|
||||
|
||||
// Finally, render this upscaled texture to screen using linear scaling.
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_RenderCopy(renderer, texture_upscaled, NULL, NULL);
|
||||
// Render this intermediate texture into the upscaled texture
|
||||
// using "nearest" integer scaling.
|
||||
|
||||
SDL_SetRenderTarget(renderer, texture_upscaled);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
|
||||
// Finally, render this upscaled texture to screen using linear scaling.
|
||||
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_RenderCopy(renderer, texture_upscaled, NULL, NULL);
|
||||
}
|
||||
|
||||
if (scanlines)
|
||||
{
|
||||
// Scanline overlay: every third logical row darkened. Logical size
|
||||
// is 320xactualheight, so the lines stay evenly spaced physical rows
|
||||
// under any window size.
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 70);
|
||||
|
||||
for (int y = 1; y < actualheight; y += 3)
|
||||
{
|
||||
SDL_RenderDrawLine(renderer, 0, y, SCREENWIDTH, y);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw!
|
||||
|
||||
@@ -1242,6 +1304,7 @@ void I_GetWindowPosition(int *x, int *y, int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
static void RebuildStreamTextures(void);
|
||||
static void SetVideoMode(void)
|
||||
{
|
||||
int w, h;
|
||||
@@ -1452,6 +1515,33 @@ static void SetVideoMode(void)
|
||||
SDL_FillRect(argbbuffer, NULL, 0);
|
||||
}
|
||||
|
||||
// HD remaster: with the upscaler active, a factor-sized RGBA surface
|
||||
// feeds the (factor-sized) streaming texture. Freed alongside
|
||||
// argbbuffer above on every re-init.
|
||||
|
||||
RebuildStreamTextures();
|
||||
}
|
||||
|
||||
// Rebuild the factor-sized RGBA surface and the streaming texture that
|
||||
// carry the frame at the current upscale_factor. Shared by SetVideoMode
|
||||
// (full re-init) and the runtime filter setter (I_SetVideoFilter).
|
||||
static void RebuildStreamTextures(void)
|
||||
{
|
||||
if (argbbuffer_scaled != NULL)
|
||||
{
|
||||
SDL_FreeSurface(argbbuffer_scaled);
|
||||
argbbuffer_scaled = NULL;
|
||||
}
|
||||
|
||||
if (upscale_factor > 1)
|
||||
{
|
||||
argbbuffer_scaled = SDL_CreateRGBSurfaceWithFormat(0,
|
||||
SCREENWIDTH * upscale_factor,
|
||||
SCREENHEIGHT * upscale_factor,
|
||||
32, pixel_format);
|
||||
SDL_FillRect(argbbuffer_scaled, NULL, 0);
|
||||
}
|
||||
|
||||
if (texture != NULL)
|
||||
{
|
||||
SDL_DestroyTexture(texture);
|
||||
@@ -1470,13 +1560,92 @@ static void SetVideoMode(void)
|
||||
texture = SDL_CreateTexture(renderer,
|
||||
pixel_format,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
SCREENWIDTH, SCREENHEIGHT);
|
||||
upscale_factor > 1
|
||||
? SCREENWIDTH * upscale_factor
|
||||
: SCREENWIDTH,
|
||||
upscale_factor > 1
|
||||
? SCREENHEIGHT * upscale_factor
|
||||
: SCREENHEIGHT);
|
||||
|
||||
// Initially create the upscaled texture for rendering to screen
|
||||
|
||||
CreateUpscaledTexture(true);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// Runtime video option setters (in-game Options dialog)
|
||||
//
|
||||
// These only touch presentation resources. Never call SetVideoMode() from
|
||||
// here: it frees and recreates screenbuffer without re-pointing
|
||||
// I_VideoBuffer, so the game would keep drawing into freed memory.
|
||||
//**************************************************************************
|
||||
|
||||
void I_SetVideoFilter(int factor)
|
||||
{
|
||||
if (factor != 0 && factor != 2 && factor != 3 && factor != 4)
|
||||
return;
|
||||
|
||||
if (factor == upscale_factor)
|
||||
return;
|
||||
|
||||
upscale_factor = factor;
|
||||
RebuildStreamTextures();
|
||||
}
|
||||
|
||||
void I_SetScanlines(int on)
|
||||
{
|
||||
scanlines = on ? 1 : 0;
|
||||
}
|
||||
|
||||
void I_SetVideoResolution(int w, int h)
|
||||
{
|
||||
if (fullscreen)
|
||||
I_SetFullscreen(0);
|
||||
|
||||
window_width = w;
|
||||
window_height = h;
|
||||
AdjustWindowSize();
|
||||
SDL_SetWindowSize(screen, window_width, window_height);
|
||||
|
||||
// The RESIZED event path in I_FinishUpdate adapts the textures.
|
||||
}
|
||||
|
||||
void I_SetFullscreen(int on)
|
||||
{
|
||||
fullscreen = on ? 1 : 0;
|
||||
|
||||
SDL_SetWindowFullscreen(screen,
|
||||
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
|
||||
if (!fullscreen)
|
||||
{
|
||||
AdjustWindowSize();
|
||||
SDL_SetWindowSize(screen, window_width, window_height);
|
||||
}
|
||||
}
|
||||
|
||||
void I_SetAspectCorrect(int on)
|
||||
{
|
||||
aspect_ratio_correct = on ? 1 : 0;
|
||||
actualheight = aspect_ratio_correct ? SCREENHEIGHT_4_3 : SCREENHEIGHT;
|
||||
|
||||
SDL_RenderSetLogicalSize(renderer, SCREENWIDTH, actualheight);
|
||||
AdjustWindowSize();
|
||||
SDL_SetWindowSize(screen, window_width, window_height);
|
||||
CreateUpscaledTexture(false);
|
||||
palette_to_set = true;
|
||||
}
|
||||
|
||||
int I_GetVideoFilter(void)
|
||||
{
|
||||
return upscale_factor;
|
||||
}
|
||||
|
||||
int I_GetScanlines(void)
|
||||
{
|
||||
return scanlines;
|
||||
}
|
||||
|
||||
void I_InitGraphics(uint8_t *pal)
|
||||
{
|
||||
SDL_Event dummy;
|
||||
|
||||
@@ -37,6 +37,7 @@ extern int window_width;
|
||||
extern int window_height;
|
||||
extern int fullscreen;
|
||||
extern int txt_fullscreen;
|
||||
extern int aspect_ratio_correct;
|
||||
|
||||
extern pixel_t *I_VideoBuffer;
|
||||
|
||||
@@ -50,6 +51,15 @@ void I_GetMousePos(int *x, int *y);
|
||||
void I_SetMousePos(int x, int y);
|
||||
void I_SetGrabMouseCallback(grabmouse_callback_t func);
|
||||
void VIDEO_LoadPrefs(void);
|
||||
|
||||
// Runtime video option setters (in-game Options dialog)
|
||||
void I_SetVideoFilter(int factor); // 0/2/3/4, anything else is ignored
|
||||
void I_SetScanlines(int on);
|
||||
void I_SetVideoResolution(int w, int h);
|
||||
void I_SetFullscreen(int on);
|
||||
void I_SetAspectCorrect(int on);
|
||||
int I_GetVideoFilter(void);
|
||||
int I_GetScanlines(void);
|
||||
void closewindow(void);
|
||||
bool I_GetNeedResize(bool setonlypos);
|
||||
int I_VsyncActive(void);
|
||||
|
||||
+16
-1
@@ -922,7 +922,22 @@ Do_Game(
|
||||
b3_flag = 0;
|
||||
}
|
||||
|
||||
if (KBD_IsKey(SC_P) || JOY_IsKeyInGameStart(Start))
|
||||
if (KBD_IsKey(SC_O))
|
||||
{
|
||||
SWD_SetClearFlag(0);
|
||||
IPT_End();
|
||||
WIN_Opts();
|
||||
IPT_Start();
|
||||
RAP_ClearSides();
|
||||
RAP_DisplayStats();
|
||||
SWD_SetClearFlag(1);
|
||||
IMS_StartAck();
|
||||
BUT_1 = BUT_2 = BUT_3 = BUT_4 = 0;
|
||||
b2_flag = 0;
|
||||
b3_flag = 0;
|
||||
}
|
||||
|
||||
if (KBD_IsKey(SC_P) || JOY_IsKeyInGameStart(Start))
|
||||
{
|
||||
while (IMS_IsAck())
|
||||
{
|
||||
|
||||
@@ -633,7 +633,10 @@ SHOTS_PlayerShoot(
|
||||
cur->move.y2 = 0;
|
||||
cur->startx = player_cx;
|
||||
cur->starty = player_cy;
|
||||
ANIMS_StartAnim(A_PLAYER_SHOOT, o_gun1[playerpic], 0);
|
||||
// Casing streaks drop into world space (StartGAnim takes the
|
||||
// top-left; the 8x8 GUNSTR art is centered on the muzzle by hand).
|
||||
ANIMS_StartGAnim(A_PLAYER_EJECTA,
|
||||
player_cx + o_gun1[playerpic] - 4, player_cy - 4);
|
||||
|
||||
cur = SHOTS_Get();
|
||||
if (!cur)
|
||||
@@ -651,7 +654,8 @@ SHOTS_PlayerShoot(
|
||||
cur->move.y2 = 0;
|
||||
cur->startx = player_cx;
|
||||
cur->starty = player_cy;
|
||||
ANIMS_StartAnim(A_PLAYER_SHOOT, -o_gun1[playerpic] - 1, 0);
|
||||
ANIMS_StartGAnim(A_PLAYER_EJECTA,
|
||||
player_cx - o_gun1[playerpic] - 1 - 4, player_cy - 4);
|
||||
break;
|
||||
|
||||
case S_PLASMA_GUNS:
|
||||
|
||||
+254
-58
@@ -1,5 +1,6 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "SDL.h"
|
||||
#include "common.h"
|
||||
#include "glbapi.h"
|
||||
#include "gfxapi.h"
|
||||
@@ -182,6 +183,178 @@ WIN_OptDraw(
|
||||
GFX_PutSprite((char*)GLB_GetItem(FILE127_SLIDE_PIC), x + opt_vol[FX_VOL] - 2, y);
|
||||
}
|
||||
|
||||
// WIN_Opts value rows: field + selection icon, keyboard order (matches the
|
||||
// dialog, top to bottom). The last two are the volume slider rows.
|
||||
|
||||
#define OPT_ROWS 8
|
||||
#define OPT_VALUE_ROWS 6
|
||||
#define FILTER_COUNT 4
|
||||
|
||||
static const int opt_filter_list[FILTER_COUNT] = { 0, 2, 3, 4 };
|
||||
|
||||
static const struct
|
||||
{
|
||||
int field;
|
||||
int icon;
|
||||
} opt_rows[OPT_ROWS] = {
|
||||
{OPTS_DETAIL, OPTS_PIC1},
|
||||
{OPTS_FILTER, OPTS_PIC4},
|
||||
{OPTS_SCANLINES, OPTS_PIC5},
|
||||
{OPTS_RES, OPTS_PIC6},
|
||||
{OPTS_FULLSCR, OPTS_PIC7},
|
||||
{OPTS_ASPECT, OPTS_PIC8},
|
||||
{OPTS_VMUSIC, OPTS_PIC2},
|
||||
{OPTS_VFX, OPTS_PIC3}
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
int w, h;
|
||||
} res_list[] = {
|
||||
{640, 480}, {800, 600}, {960, 720}, {1280, 960},
|
||||
{1600, 1200}, {1920, 1440}
|
||||
};
|
||||
|
||||
#define RES_COUNT ((int)(sizeof(res_list) / sizeof(res_list[0])))
|
||||
|
||||
static const char opt_detail_txt[2][16] = {
|
||||
"LOW DETAIL",
|
||||
"HIGH DETAIL"
|
||||
};
|
||||
|
||||
static int opt_curd;
|
||||
static int opt_filter_idx;
|
||||
static int opt_scan;
|
||||
static int opt_res_idx;
|
||||
static int opt_avail[RES_COUNT];
|
||||
static int opt_fullscr;
|
||||
static int opt_aspect;
|
||||
|
||||
static const char *OPTS_FilterText(char *buf)
|
||||
{
|
||||
if (opt_filter_list[opt_filter_idx] == 0)
|
||||
strcpy(buf, "FILTER OFF");
|
||||
else
|
||||
sprintf(buf, "FILTER SCALE %dX", opt_filter_list[opt_filter_idx]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *OPTS_ScanText(char *buf)
|
||||
{
|
||||
strcpy(buf, opt_scan ? "SCANLINES ON" : "SCANLINES OFF");
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *OPTS_ResText(char *buf)
|
||||
{
|
||||
sprintf(buf, "RESOLUTION %dX%d", res_list[opt_res_idx].w,
|
||||
res_list[opt_res_idx].h);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *OPTS_FullscrText(char *buf)
|
||||
{
|
||||
strcpy(buf, opt_fullscr ? "FULLSCREEN ON" : "FULLSCREEN OFF");
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *OPTS_AspectText(char *buf)
|
||||
{
|
||||
strcpy(buf, opt_aspect ? "ASPECT 4:3 ON" : "ASPECT 4:3 OFF");
|
||||
return buf;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
OPTS_ShowRow() - Moves the selection arrow icon to a row
|
||||
***************************************************************************/
|
||||
static void
|
||||
OPTS_ShowRow(
|
||||
int row
|
||||
)
|
||||
{
|
||||
int loop;
|
||||
|
||||
for (loop = 0; loop < OPT_ROWS; loop++)
|
||||
SWD_SetFieldItem(opt_window, opt_rows[loop].icon, -1);
|
||||
|
||||
SWD_SetFieldItem(opt_window, opt_rows[row].icon, FILE128_POINT_PIC);
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
OPTS_StepRow() - Apply one LEFT(-1)/RIGHT(+1) step to an options row:
|
||||
updates the row state, live-applies the video setting and refreshes the
|
||||
field text. Returns 1 when the caller should play the slider patch sound.
|
||||
***************************************************************************/
|
||||
static int
|
||||
OPTS_StepRow(
|
||||
int field,
|
||||
int dir
|
||||
)
|
||||
{
|
||||
char buf[24];
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case OPTS_VMUSIC:
|
||||
opt_vol[MUSIC_VOL] += dir * 8;
|
||||
if (opt_vol[MUSIC_VOL] < 0)
|
||||
opt_vol[MUSIC_VOL] = 0;
|
||||
if (opt_vol[MUSIC_VOL] > 127)
|
||||
opt_vol[MUSIC_VOL] = 127;
|
||||
return 0;
|
||||
|
||||
case OPTS_VFX:
|
||||
opt_vol[FX_VOL] += dir * 8;
|
||||
if (opt_vol[FX_VOL] < 0)
|
||||
opt_vol[FX_VOL] = 0;
|
||||
if (opt_vol[FX_VOL] > 127)
|
||||
opt_vol[FX_VOL] = 127;
|
||||
return 1;
|
||||
|
||||
case OPTS_DETAIL:
|
||||
opt_curd ^= 1;
|
||||
SWD_SetFieldText(opt_window, OPTS_DETAIL, opt_detail_txt[opt_curd]);
|
||||
return 0;
|
||||
|
||||
case OPTS_FILTER:
|
||||
opt_filter_idx = (opt_filter_idx + dir + FILTER_COUNT) % FILTER_COUNT;
|
||||
I_SetVideoFilter(opt_filter_list[opt_filter_idx]);
|
||||
SWD_SetFieldText(opt_window, OPTS_FILTER, OPTS_FilterText(buf));
|
||||
return 0;
|
||||
|
||||
case OPTS_SCANLINES:
|
||||
opt_scan ^= 1;
|
||||
I_SetScanlines(opt_scan);
|
||||
SWD_SetFieldText(opt_window, OPTS_SCANLINES, OPTS_ScanText(buf));
|
||||
return 0;
|
||||
|
||||
case OPTS_RES:
|
||||
do
|
||||
{
|
||||
opt_res_idx = (opt_res_idx + dir + RES_COUNT) % RES_COUNT;
|
||||
} while (!opt_avail[opt_res_idx]);
|
||||
I_SetVideoResolution(res_list[opt_res_idx].w, res_list[opt_res_idx].h);
|
||||
SWD_SetFieldText(opt_window, OPTS_RES, OPTS_ResText(buf));
|
||||
return 0;
|
||||
|
||||
case OPTS_FULLSCR:
|
||||
opt_fullscr ^= 1;
|
||||
I_SetFullscreen(opt_fullscr);
|
||||
SWD_SetFieldText(opt_window, OPTS_FULLSCR, OPTS_FullscrText(buf));
|
||||
return 0;
|
||||
|
||||
case OPTS_ASPECT:
|
||||
opt_aspect ^= 1;
|
||||
I_SetAspectCorrect(opt_aspect);
|
||||
SWD_SetFieldText(opt_window, OPTS_ASPECT, OPTS_AspectText(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
WIN_Opts() - Sets Game Options
|
||||
***************************************************************************/
|
||||
@@ -192,35 +365,79 @@ WIN_Opts(
|
||||
{
|
||||
SWD_DLG dlg;
|
||||
int x, y, lx, ly;
|
||||
int kbactive, patchflag, curd, cur_field;
|
||||
int kbactive, patchflag, cur_field;
|
||||
int new_vol;
|
||||
int fpics[3] = {
|
||||
OPTS_PIC1, OPTS_PIC2, OPTS_PIC3
|
||||
};
|
||||
char detail[2][16] = {
|
||||
"LOW DETAIL",
|
||||
"HIGH DETAIL"
|
||||
};
|
||||
int loop, diff, best;
|
||||
SDL_DisplayMode desktop;
|
||||
char buf[24];
|
||||
|
||||
kbactive = 0;
|
||||
patchflag = 0;
|
||||
curd = opt_detail;
|
||||
cur_field = 0;
|
||||
|
||||
opt_vol[MUSIC_VOL] = music_volume;
|
||||
opt_vol[FX_VOL] = fx_volume;
|
||||
|
||||
// Video row state from the live settings
|
||||
|
||||
opt_curd = opt_detail;
|
||||
opt_filter_idx = 0;
|
||||
|
||||
for (loop = 0; loop < FILTER_COUNT; loop++)
|
||||
{
|
||||
if (opt_filter_list[loop] == I_GetVideoFilter())
|
||||
opt_filter_idx = loop;
|
||||
}
|
||||
|
||||
opt_scan = I_GetScanlines();
|
||||
opt_fullscr = fullscreen;
|
||||
opt_aspect = aspect_ratio_correct;
|
||||
|
||||
// Resolution presets: skip anything larger than the desktop, start on
|
||||
// the preset closest in area to the current window size
|
||||
|
||||
if (SDL_GetDesktopDisplayMode(0, &desktop) != 0)
|
||||
desktop.w = desktop.h = 0;
|
||||
|
||||
best = 0x7fffffff;
|
||||
opt_res_idx = 0;
|
||||
|
||||
for (loop = 0; loop < RES_COUNT; loop++)
|
||||
{
|
||||
opt_avail[loop] = 1;
|
||||
|
||||
if (desktop.w && (res_list[loop].w > desktop.w
|
||||
|| res_list[loop].h > desktop.h))
|
||||
{
|
||||
opt_avail[loop] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
diff = res_list[loop].w * res_list[loop].h
|
||||
- window_width * window_height;
|
||||
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
|
||||
if (diff < best)
|
||||
{
|
||||
best = diff;
|
||||
opt_res_idx = loop;
|
||||
}
|
||||
}
|
||||
|
||||
opt_window = SWD_InitWindow(FILE13f_OPTS_SWD);
|
||||
|
||||
SWD_SetFieldText(opt_window, OPTS_DETAIL, detail[curd]);
|
||||
SWD_SetFieldText(opt_window, OPTS_DETAIL, opt_detail_txt[opt_curd]);
|
||||
SWD_SetFieldText(opt_window, OPTS_FILTER, OPTS_FilterText(buf));
|
||||
SWD_SetFieldText(opt_window, OPTS_SCANLINES, OPTS_ScanText(buf));
|
||||
SWD_SetFieldText(opt_window, OPTS_RES, OPTS_ResText(buf));
|
||||
SWD_SetFieldText(opt_window, OPTS_FULLSCR, OPTS_FullscrText(buf));
|
||||
SWD_SetFieldText(opt_window, OPTS_ASPECT, OPTS_AspectText(buf));
|
||||
SWD_SetWinDrawFunc(opt_window, WIN_OptDraw);
|
||||
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC1, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC2, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC3, -1);
|
||||
|
||||
SWD_ShowAllWindows();
|
||||
|
||||
OPTS_ShowRow(0);
|
||||
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
GFX_DisplayUpdate();
|
||||
|
||||
@@ -284,29 +501,11 @@ WIN_Opts(
|
||||
break;
|
||||
|
||||
case SC_LEFT:
|
||||
if (cur_field)
|
||||
{
|
||||
if (cur_field == 2)
|
||||
patchflag = 1;
|
||||
opt_vol[cur_field - 1] -= 8;
|
||||
if (opt_vol[cur_field - 1] < 0)
|
||||
opt_vol[cur_field - 1] = 0;
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_RIGHT:
|
||||
if (cur_field)
|
||||
{
|
||||
if (cur_field == 2)
|
||||
patchflag = 1;
|
||||
opt_vol[cur_field - 1] += 8;
|
||||
if (opt_vol[cur_field - 1] > 127)
|
||||
opt_vol[cur_field - 1] = 127;
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
}
|
||||
patchflag = OPTS_StepRow(opt_rows[cur_field].field,
|
||||
dlg.keypress == SC_RIGHT ? 1 : -1);
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
break;
|
||||
|
||||
case SC_UP:
|
||||
@@ -314,33 +513,23 @@ WIN_Opts(
|
||||
cur_field--;
|
||||
kbactive = 1;
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC1, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC2, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC3, -1);
|
||||
SWD_SetFieldItem(opt_window, fpics[cur_field], FILE128_POINT_PIC);
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
OPTS_ShowRow(cur_field);
|
||||
break;
|
||||
|
||||
case SC_DOWN:
|
||||
if (kbactive && cur_field < 2)
|
||||
if (kbactive && cur_field < OPT_ROWS - 1)
|
||||
cur_field++;
|
||||
kbactive = 1;
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC1, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC2, -1);
|
||||
SWD_SetFieldItem(opt_window, OPTS_PIC3, -1);
|
||||
SWD_SetFieldItem(opt_window, fpics[cur_field], FILE128_POINT_PIC);
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
OPTS_ShowRow(cur_field);
|
||||
break;
|
||||
|
||||
case SC_ENTER:
|
||||
if (!cur_field)
|
||||
if (cur_field < OPT_VALUE_ROWS)
|
||||
{
|
||||
dlg.cur_act = S_FLD_COMMAND;
|
||||
dlg.cur_cmd = F_SELECT;
|
||||
dlg.field = OPTS_DETAIL;
|
||||
dlg.field = opt_rows[cur_field].field;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -387,7 +576,7 @@ WIN_Opts(
|
||||
}
|
||||
}
|
||||
|
||||
opt_detail = curd;
|
||||
opt_detail = opt_curd;
|
||||
|
||||
if (fx_volume != opt_vol[FX_VOL])
|
||||
fx_volume = opt_vol[FX_VOL];
|
||||
@@ -414,13 +603,22 @@ WIN_Opts(
|
||||
INI_PutPreferenceLong("SoundFX", "Volume", fx_volume);
|
||||
}
|
||||
INI_PutPreferenceLong("Setup", "Detail", opt_detail);
|
||||
INI_PutPreferenceLong("Video", "upscaler", I_GetVideoFilter());
|
||||
INI_PutPreferenceLong("Video", "scanlines", I_GetScanlines());
|
||||
INI_PutPreferenceLong("Video", "fullscreen", fullscreen);
|
||||
INI_PutPreferenceLong("Video", "aspect_ratio_correct",
|
||||
aspect_ratio_correct);
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
goto exit_opts;
|
||||
|
||||
case OPTS_DETAIL:
|
||||
case OPTS_FILTER:
|
||||
case OPTS_SCANLINES:
|
||||
case OPTS_RES:
|
||||
case OPTS_FULLSCR:
|
||||
case OPTS_ASPECT:
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
curd ^= 1;
|
||||
SWD_SetFieldText(opt_window, OPTS_DETAIL, detail[curd]);
|
||||
OPTS_StepRow(dlg.field, 1);
|
||||
SWD_ShowAllWindows();
|
||||
GFX_DisplayUpdate();
|
||||
break;
|
||||
@@ -431,8 +629,6 @@ WIN_Opts(
|
||||
SND_Patch(FX_SWEP, 127);
|
||||
}
|
||||
|
||||
exit_opts:
|
||||
|
||||
SWD_SetWinDrawFunc(opt_window, NULL);
|
||||
|
||||
SWD_DestroyWindow(opt_window);
|
||||
|
||||
@@ -25,6 +25,7 @@ void WIN_AskExit(void);
|
||||
void WIN_MainMenu(void);
|
||||
void WIN_MainLoop(void);
|
||||
void WIN_Pause(void);
|
||||
void WIN_Opts(void);
|
||||
int WIN_AskBool(const char *question);
|
||||
void WIN_WinGame(int game);
|
||||
void WIN_Msg(const char *msg);
|
||||
|
||||
@@ -194,3 +194,13 @@
|
||||
#define OPTS_000A 0x000a // TEXT FIELD
|
||||
#define OPTS_VMUSIC 0x000b // VIEW AREA
|
||||
#define OPTS_VFX 0x000c // VIEW AREA
|
||||
#define OPTS_FILTER 0x000d // BUTTON FIELD
|
||||
#define OPTS_SCANLINES 0x000e // BUTTON FIELD
|
||||
#define OPTS_RES 0x000f // BUTTON FIELD
|
||||
#define OPTS_FULLSCR 0x0010 // BUTTON FIELD
|
||||
#define OPTS_ASPECT 0x0011 // BUTTON FIELD
|
||||
#define OPTS_PIC4 0x0012 // ICON
|
||||
#define OPTS_PIC5 0x0013 // ICON
|
||||
#define OPTS_PIC6 0x0014 // ICON
|
||||
#define OPTS_PIC7 0x0015 // ICON
|
||||
#define OPTS_PIC8 0x0016 // ICON
|
||||
Reference in new issue
Block a user