Native resolution fullscreen with F11 toggle

This commit is contained in:
MrBruh committed 2026-09-27 20:42:09 +13:00
1 parent fef8a582dd
commit 50eae19bac
16 files changed
+333 -86

No files matched your search

+1 -1
View File
@@ -95,7 +95,7 @@ viewport's shape with a fixed vertical one, so the 3D view simply widens
("Hor+"). The HUD anchors to the title-safe frame, which widens with the
screen; the menus, the loading bar and the post-game screens are laid out
for 640 columns and are drawn centered (the vertex shaders shift them,
`halo_android_ui_offset`); chapter titles keep their place relative to the
`halo_screen_ui_offset`); chapter titles keep their place relative to the
screen's sides; letterbox bars and fades cover the whole width. The
changes are in `rasterizer_xbox.c`, `render.c`, `ui_widget.c`,
`cinematics.c`, `main.c` and `rasterizer_xbox_screen_effect.c`, under
+3 -1
View File
@@ -71,13 +71,15 @@ further gamepads become controllers 2-4.
| F1 | back |
| \` | opens the developer console (typing then goes to the console) |
| F12 | releases or recaptures the mouse |
| F11 | switches between fullscreen and the window |
### Settings
| Variable | Effect |
| --- | --- |
| `HALO_DATA_ROOT`, `HALO_SAVE_ROOT` | see above |
| `HALO_WINDOW_SCALE` | initial window size as a multiple of 640x480 (default 2); the window is resizable and the picture is letterboxed |
| `HALO_FULLSCREEN` | `0` opens the game in a window instead of fullscreen (F11 switches between the two). Fullscreen draws at the display's resolution and shape: 480 of the game's lines, as wide as the display (the view widens, the HUD keeps to the screen's edges, menus stay centered), each drawn at as many pixels as the display has; a window draws the Xbox's 640x480 |
| `HALO_WINDOW_SCALE` | window size as a multiple of 640x480 (default 2); the window is resizable and the picture is letterboxed |
| `HALO_MOUSE_SENSITIVITY` | mouse aim multiplier (default 1.0) |
| `HALO_MOUSE_INVERT` | set to invert vertical mouse aim |
| `HALO_VOLUME` | master volume (default 1.0) |
@@ -35,11 +35,12 @@ void render_interpolation_first_person(short local_player_index, struct real_mat
short node_count, struct render_camera const *camera);
float render_interpolation_game_time_sec(long ticks);
#ifdef HALO_ANDROID
/* the screen at the device's aspect ratio (port/linux/src/d3d8_gl.c) */
long halo_android_screen_width(void);
/* the width of the screen the game draws, 480 lines tall: the device's or
the display's shape, or 640 (port/linux/src/d3d8_gl.c) */
long halo_screen_width(void);
/* takes up a new width between frames (F11); returns the width */
long halo_screen_commit(void);
/* while TRUE, drawing shifts right to center 640-column layouts */
void halo_android_ui_offset(unsigned char centered);
#endif
void halo_screen_ui_offset(unsigned char centered);
#endif
+166 -45
View File
@@ -31,6 +31,7 @@ Conventions carried over from the Xbox:
#include <time.h>
void d3d8_surface_initialize(D3DSurface *surface, D3DFORMAT format, unsigned long width, unsigned long height);
void d3d8_surface_resize(D3DSurface *surface, D3DFORMAT format, unsigned long width, unsigned long height);
#ifdef HALO_ANDROID
/* OpenGL ES 3 (port/android/README.md): the desktop formats, enumerants
@@ -54,43 +55,78 @@ struct xgpu_capabilities xgpu_capabilities;
/* ---------- the screen's width
The Xbox screen is 640x480. On Android the game renders at the device's
aspect ratio instead: 480 lines, and as many columns as the display's shape
gives (HALO_SCREEN_WIDTH, set by the host; 640 keeps 4:3). The game's
camera derives its horizontal field of view from the viewport, so the 3D
view simply widens. The menus and full-screen overlays are laid out for 640
columns; while they draw (halo_android_ui_offset), everything shifts right
to center them. */
The Xbox screen is 640x480. The native ports can draw a wider one: 480
lines, and as many columns as the display's shape gives. On Android that is
HALO_SCREEN_WIDTH, set by the host (640 keeps 4:3); on the desktop, the
display's shape while the game is fullscreen, and 640 in a window. The
game's camera derives its horizontal field of view from the viewport, so the
3D view simply widens. The menus and full-screen overlays are laid out for
640 columns; while they draw (halo_screen_ui_offset), everything shifts right
to center them.
#ifdef HALO_ANDROID
Fullscreen on the desktop also draws at the display's resolution: render
targets the size of the screen get that many pixels (screen_scale), and
viewports, clears and visibility counts are scaled to match, so the game
still works in its 480 lines. The width and the scale change only between
frames, after one is presented (halo_screen_commit). */
#define SCREEN_HEIGHT 480
#define SCREEN_MAXIMUM_WIDTH 1920
/* the width the game draws, 0 until first asked, and how many pixels a
render target the size of the screen has per unit of it */
static long screen_width;
static float screen_scale[2] = { 1.0f, 1.0f };
static long ui_offset;
#define UI_OFFSET ((GLint)ui_offset)
long halo_android_screen_width(void)
static void screen_mode_choose(long *width, float scale[2])
{
static long width;
#ifdef HALO_ANDROID
const char *text = getenv("HALO_SCREEN_WIDTH");
if (!width)
{
const char *text = getenv("HALO_SCREEN_WIDTH");
width = text ? atol(text) : 640;
if (width < 640)
width = 640;
if (width > 1600)
width = 1600;
width &= ~1L;
}
return width;
}
void halo_android_ui_offset(unsigned char centered)
{
ui_offset = centered ? (halo_android_screen_width() - 640) / 2 : 0;
}
*width = text ? atol(text) : 640;
if (*width < 640)
*width = 640;
if (*width > 1600)
*width = 1600;
*width &= ~1L;
scale[0] = scale[1] = 1.0f;
#else
#define UI_OFFSET 0
long display_width, display_height;
*width = 640;
scale[0] = scale[1] = 1.0f;
if (platform_screen_mode(&display_width, &display_height) && display_width > 0 && display_height > 0)
{
long wanted = (SCREEN_HEIGHT * display_width + display_height / 2) / display_height;
*width = wanted < 640 ? 640 : wanted > SCREEN_MAXIMUM_WIDTH ? SCREEN_MAXIMUM_WIDTH : wanted & ~1L;
scale[0] = (float)display_width / (float)*width;
scale[1] = (float)display_height / (float)SCREEN_HEIGHT;
/* a display narrower or wider than the game can be: the picture
keeps its shape and the display blit letterboxes it */
if (*width != wanted && *width != (wanted & ~1L))
scale[0] = scale[1] = scale[0] < scale[1] ? scale[0] : scale[1];
}
#endif
}
long halo_screen_width(void)
{
if (!screen_width)
{
screen_mode_choose(&screen_width, screen_scale);
platform_log("screen: %ldx%d drawn at %.0fx%.0f", screen_width, SCREEN_HEIGHT,
screen_width * screen_scale[0], SCREEN_HEIGHT * screen_scale[1]);
}
return screen_width;
}
void halo_screen_ui_offset(unsigned char centered)
{
ui_offset = centered ? (halo_screen_width() - 640) / 2 : 0;
}
/* ---------- state the XDK header's inline functions read and write */
@@ -295,6 +331,9 @@ struct gl_device
GLuint queries[VISIBILITY_TEST_SLOTS];
BOOL query_pending[VISIBILITY_TEST_SLOTS];
/* the pixels each of the game's pixels covered in the test's target
(render_target_get), which its count is divided by */
float query_area[VISIBILITY_TEST_SLOTS];
GLuint active_query;
BOOL visibility_test_active;
#ifdef HALO_ANDROID
@@ -702,11 +741,20 @@ static struct render_target_entry *render_target_get(const D3DSurface *surface)
if (!surface || !surface->Data)
return NULL;
float scale[2] = { 1.0f, 1.0f };
surface_dimensions(surface, &width, &height, &depth);
/* the screen's targets are drawn at the screen's scale */
if (width == (unsigned long)halo_screen_width() && height == SCREEN_HEIGHT)
{
scale[0] = screen_scale[0];
scale[1] = screen_scale[1];
}
for (entry = *render_target_bucket(surface->Data); entry; entry = entry->next_in_bucket)
{
if (entry->target.data == surface->Data && entry->target.width == width &&
entry->target.height == height && entry->target.depth == depth)
entry->target.height == height && entry->target.depth == depth &&
entry->target.scale[0] == scale[0] && entry->target.scale[1] == scale[1])
{
return entry;
}
@@ -716,14 +764,19 @@ static struct render_target_entry *render_target_get(const D3DSurface *surface)
entry->target.width = width;
entry->target.height = height;
entry->target.depth = depth;
entry->target.scale[0] = scale[0];
entry->target.scale[1] = scale[1];
entry->target.gl_width = (unsigned long)(width * scale[0] + 0.5f);
entry->target.gl_height = (unsigned long)(height * scale[1] + 0.5f);
glGenTextures(1, &entry->target.texture);
glBindTexture(GL_TEXTURE_2D, entry->target.texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
if (depth)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, (GLsizei)width, (GLsizei)height, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, (GLsizei)entry->target.gl_width,
(GLsizei)entry->target.gl_height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)entry->target.gl_width, (GLsizei)entry->target.gl_height,
0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
xgpu_gl_state_invalidate();
entry->next = render_targets;
render_targets = entry;
@@ -772,6 +825,15 @@ static GLuint framebuffer_get(GLuint color, GLuint depth)
return entry->framebuffer;
}
/* the pixels per unit of the bound targets (render_target_get) */
static float target_scale[2] = { 1.0f, 1.0f };
/* the pixel edge of a coordinate in the bound targets' units */
static GLint target_pixel(float coordinate, int axis)
{
return (GLint)floorf(coordinate * target_scale[axis] + 0.5f);
}
/* binds the framebuffer for the current targets; returns FALSE if there is
nothing to draw into */
static BOOL bind_targets(BOOL *has_depth)
@@ -785,6 +847,9 @@ static BOOL bind_targets(BOOL *has_depth)
return FALSE;
if (color)
color->last_rendered = device.frame + 1;
/* viewports and clears are in the targets' units (render_target_get) */
target_scale[0] = color ? color->target.scale[0] : depth->target.scale[0];
target_scale[1] = color ? color->target.scale[1] : depth->target.scale[1];
state_framebuffer(framebuffer_get(color ? color->target.texture : 0, depth ? depth->target.texture : 0));
*has_depth = depth != NULL;
return TRUE;
@@ -987,8 +1052,17 @@ HRESULT WINAPI Direct3D_CreateDevice(UINT adapter, D3DDEVTYPE device_type, void
device.presentation = *presentation_parameters;
width = device.presentation.BackBufferWidth ? device.presentation.BackBufferWidth : 640;
height = device.presentation.BackBufferHeight ? device.presentation.BackBufferHeight : 480;
#ifdef HALO_ANDROID
d3d8_surface_initialize(&device.back_buffer, D3DFMT_LIN_A8R8G8B8, width, height);
d3d8_surface_initialize(&device.depth_buffer, D3DFMT_LIN_D24S8, width, height);
#else
/* room for the widest screen, which F11 can switch to (the screen's
width, above) */
d3d8_surface_initialize(&device.back_buffer, D3DFMT_LIN_A8R8G8B8, SCREEN_MAXIMUM_WIDTH, height);
d3d8_surface_initialize(&device.depth_buffer, D3DFMT_LIN_D24S8, SCREEN_MAXIMUM_WIDTH, height);
d3d8_surface_resize(&device.back_buffer, D3DFMT_LIN_A8R8G8B8, width, height);
d3d8_surface_resize(&device.depth_buffer, D3DFMT_LIN_D24S8, width, height);
#endif
device.render_target = &device.back_buffer;
device.depth_stencil = &device.depth_buffer;
for (index = 0; index < D3DTS_MAX; index++)
@@ -1040,6 +1114,36 @@ HRESULT WINAPI Direct3D_CreateDevice(UINT adapter, D3DDEVTYPE device_type, void
return S_OK;
}
/* takes up the display's shape and resolution, or the window's, if they
have changed; between frames, since the game's layout and the targets must
agree for a whole frame. Returns the width the game draws. */
long halo_screen_commit(void)
{
long width;
float scale[2];
if (!screen_width)
return halo_screen_width();
screen_mode_choose(&width, scale);
if (width != screen_width || scale[0] != screen_scale[0] || scale[1] != screen_scale[1])
{
platform_log("screen: %ldx%d drawn at %.0fx%.0f", width, SCREEN_HEIGHT,
width * scale[0], SCREEN_HEIGHT * scale[1]);
screen_width = width;
screen_scale[0] = scale[0];
screen_scale[1] = scale[1];
#ifndef HALO_ANDROID
if (device.created)
{
device.presentation.BackBufferWidth = (UINT)width;
d3d8_surface_resize(&device.back_buffer, D3DFMT_LIN_A8R8G8B8, (unsigned long)width, SCREEN_HEIGHT);
d3d8_surface_resize(&device.depth_buffer, D3DFMT_LIN_D24S8, (unsigned long)width, SCREEN_HEIGHT);
}
#endif
}
return screen_width;
}
ULONG WINAPI D3DDevice_Release(void)
{
return 1;
@@ -1208,6 +1312,7 @@ HRESULT WINAPI D3DDevice_EndVisibilityTest(DWORD index)
}
#endif
glEndQuery(VISIBILITY_QUERY);
device.query_area[index] = target_scale[0] * target_scale[1];
/* swap the scratch query into the requested slot */
scratch = device.queries[0];
device.queries[0] = device.queries[index];
@@ -1225,6 +1330,16 @@ HRESULT WINAPI D3DDevice_EndVisibilityTest(DWORD index)
return S_OK;
}
#ifndef HALO_ANDROID
/* a count of pixels in the game's pixels */
static GLuint visibility_unscaled(GLuint samples, DWORD index)
{
float area = device.query_area[index];
return area > 1.0f ? (GLuint)(samples / area + 0.5f) : samples;
}
#endif
HRESULT WINAPI D3DDevice_GetVisibilityTestResult(DWORD index, UINT *result, ULONGLONG *time_stamp)
{
GLuint available = 0, samples = 0;
@@ -1257,7 +1372,7 @@ HRESULT WINAPI D3DDevice_GetVisibilityTestResult(DWORD index, UINT *result, ULON
/* the latest count the GPU has written: from this test, or while
the GPU is still behind, from the slot's earlier ones */
if (result)
*result = device.visibility_results[index];
*result = visibility_unscaled(device.visibility_results[index], index);
return S_OK;
}
#endif
@@ -1271,6 +1386,8 @@ HRESULT WINAPI D3DDevice_GetVisibilityTestResult(DWORD index, UINT *result, ULON
more than any test covers, well below what would overflow there. */
if (samples)
samples = VISIBILITY_ALL_SAMPLES;
#else
samples = visibility_unscaled(samples, index);
#endif
if (result)
*result = samples;
@@ -1933,7 +2050,8 @@ static GLuint mip_composite_get(const struct xgpu_texture_description *descripti
struct xgpu_render_target *target =
xgpu_render_target_find(data + xgpu_texture_level_offset(description, level));
if (!target || target->width != width || target->height != height)
if (!target || target->width != width || target->height != height ||
target->gl_width != width || target->gl_height != height)
break;
#ifdef HALO_ANDROID
if (!xgpu_capabilities.copy_image)
@@ -2046,10 +2164,10 @@ static void apply_raster_state(BOOL has_depth)
unsigned char color_mask;
BOOL depth_test = has_depth && rs[D3DRS_ZENABLE];
viewport[0] = (GLint)device.viewport.X;
viewport[1] = (GLint)device.viewport.Y;
viewport[2] = (GLint)device.viewport.Width;
viewport[3] = (GLint)device.viewport.Height;
viewport[0] = target_pixel((float)device.viewport.X, 0);
viewport[1] = target_pixel((float)device.viewport.Y, 1);
viewport[2] = target_pixel((float)(device.viewport.X + device.viewport.Width), 0) - viewport[0];
viewport[3] = target_pixel((float)(device.viewport.Y + device.viewport.Height), 1) - viewport[1];
if (memcmp(gl_state.viewport, viewport, sizeof(viewport)))
{
memcpy(gl_state.viewport, viewport, sizeof(viewport));
@@ -3313,8 +3431,11 @@ void WINAPI D3DDevice_Clear(DWORD count, CONST D3DRECT *rectangles, DWORD flags,
glEnable(GL_SCISSOR_TEST);
for (index = 0; index < count; index++)
{
glScissor(rectangles[index].x1 + UI_OFFSET, rectangles[index].y1,
rectangles[index].x2 - rectangles[index].x1, rectangles[index].y2 - rectangles[index].y1);
GLint x0 = target_pixel((float)(rectangles[index].x1 + UI_OFFSET), 0);
GLint y0 = target_pixel((float)rectangles[index].y1, 1);
glScissor(x0, y0, target_pixel((float)(rectangles[index].x2 + UI_OFFSET), 0) - x0,
target_pixel((float)rectangles[index].y2, 1) - y0);
glClear(mask);
}
glDisable(GL_SCISSOR_TEST);
@@ -3326,7 +3447,7 @@ void WINAPI D3DDevice_Clear(DWORD count, CONST D3DRECT *rectangles, DWORD flags,
static void write_screenshot(struct render_target_entry *target)
{
const char *directory = getenv("HALO_SCREENSHOT_DIR");
unsigned long width = target->target.width, height = target->target.height;
unsigned long width = target->target.gl_width, height = target->target.gl_height;
unsigned char *pixels;
char path[512];
FILE *file;
@@ -3397,11 +3518,11 @@ void WINAPI D3DDevice_Present(CONST RECT *source_rectangle, CONST RECT *destinat
platform_video_drawable_size(&window_width, &window_height);
/* letterbox to the back buffer's aspect ratio */
width = window_width;
height = (int)((long)window_width * back_buffer->target.height / back_buffer->target.width);
height = (int)((long)window_width * back_buffer->target.gl_height / back_buffer->target.gl_width);
if (height > window_height)
{
height = window_height;
width = (int)((long)window_height * back_buffer->target.width / back_buffer->target.height);
width = (int)((long)window_height * back_buffer->target.gl_width / back_buffer->target.gl_height);
}
x = (window_width - width) / 2;
y = (window_height - height) / 2;
@@ -3412,7 +3533,7 @@ void WINAPI D3DDevice_Present(CONST RECT *source_rectangle, CONST RECT *destinat
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_get(back_buffer->target.texture, 0));
/* row 0 of the render target is the top of the picture */
glBlitFramebuffer(0, 0, (GLint)back_buffer->target.width, (GLint)back_buffer->target.height,
glBlitFramebuffer(0, 0, (GLint)back_buffer->target.gl_width, (GLint)back_buffer->target.gl_height,
x, y + height, x + width, y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
platform_video_swap();
xgpu_gl_state_invalidate();
+11
View File
@@ -83,6 +83,17 @@ void d3d8_surface_initialize(D3DSurface *surface, D3DFORMAT format, unsigned lon
((height - 1) << D3DSIZE_HEIGHT_SHIFT) | (width - 1);
}
/* changes the size a surface describes, keeping its memory, which must
hold the new size (the back buffer, when the screen's width changes) */
void d3d8_surface_resize(D3DSurface *surface, D3DFORMAT format, unsigned long width, unsigned long height)
{
unsigned long pitch = (width * bytes_per_texel(format) + D3DTEXTURE_PITCH_ALIGNMENT - 1) &
~(unsigned long)(D3DTEXTURE_PITCH_ALIGNMENT - 1);
surface->Size = ((pitch / D3DTEXTURE_PITCH_ALIGNMENT - 1) << D3DSIZE_PITCH_SHIFT) |
((height - 1) << D3DSIZE_HEIGHT_SHIFT) | (width - 1);
}
/* ---------- registration and release */
void WINAPI D3DResource_Register(D3DResource *resource, void *base)
+1 -3
View File
@@ -151,10 +151,8 @@ static const char shader_prologue[] =
"uniform vec4 viewport_scale;\n"
"uniform vec4 viewport_offset;\n"
"uniform float point_size;\n"
#ifdef HALO_ANDROID
/* columns the menus shift by to center on a wide screen (d3d8_gl.c) */
"uniform float screen_offset;\n"
#endif
"out vec4 xD0;\n"
"out vec4 xD1;\n"
"out vec4 xB0;\n"
@@ -354,7 +352,7 @@ char *nv2a_vertex_shader_to_glsl(const DWORD *instructions, unsigned long instru
"\telse\n"
"\t\tgl_Position = vec4((vec3(oPos.xy + vec2(0.5 + screen_offset, 0.5), oPos.z) - viewport_offset.xyz) / scale * oPos.w, oPos.w);\n"
#else
"\tvec3 ndc = (vec3(oPos.xy + 0.5, oPos.z) - viewport_offset.xyz) / scale;\n"
"\tvec3 ndc = (vec3(oPos.xy + vec2(0.5 + screen_offset, 0.5), oPos.z) - viewport_offset.xyz) / scale;\n"
"\tgl_Position = vec4(ndc * oPos.w, oPos.w);\n"
#endif
#ifdef HALO_ANDROID
+48 -1
View File
@@ -69,6 +69,38 @@ int halo_interpolation_enabled(void)
return enabled;
}
#ifndef HALO_ANDROID
/* whether the window opens fullscreen: yes unless HALO_FULLSCREEN=0, and
never when it is hidden */
static BOOL platform_fullscreen_setting(void)
{
const char *setting = getenv("HALO_FULLSCREEN");
return !getenv("HALO_HIDDEN_WINDOW") && !(setting && !strcmp(setting, "0"));
}
/* whether the game is, or is to be, fullscreen, and if so the size in
pixels of the display it fills (d3d8_gl.c draws at that resolution) */
BOOL platform_screen_mode(long *width, long *height)
{
SDL_DisplayID display;
const SDL_DisplayMode *mode;
if (platform_window ? !(SDL_GetWindowFlags(platform_window) & SDL_WINDOW_FULLSCREEN) :
!platform_fullscreen_setting() || !platform_sdl_initialize())
{
return FALSE;
}
display = platform_window ? SDL_GetDisplayForWindow(platform_window) : SDL_GetPrimaryDisplay();
mode = display ? SDL_GetDesktopDisplayMode(display) : NULL;
if (!mode)
return FALSE;
*width = (long)(mode->w * mode->pixel_density + 0.5f);
*height = (long)(mode->h * mode->pixel_density + 0.5f);
return TRUE;
}
#endif
BOOL platform_video_initialize(unsigned long width, unsigned long height)
{
const char *scale_text = getenv("HALO_WINDOW_SCALE");
@@ -108,8 +140,14 @@ BOOL platform_video_initialize(unsigned long width, unsigned long height)
platform_window = SDL_CreateWindow("Halo", (int)(width * scale), (int)(height * scale),
SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
#else
/* fullscreen at the desktop's resolution unless HALO_FULLSCREEN=0, where
the game draws the display's shape at its resolution (d3d8_gl.c); the
window size is the windowed mode F11 switches to and from, where it
draws 640x480 */
platform_window = SDL_CreateWindow("Halo", (int)(width * scale), (int)(height * scale),
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (getenv("HALO_HIDDEN_WINDOW") ? SDL_WINDOW_HIDDEN : 0));
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY |
(getenv("HALO_HIDDEN_WINDOW") ? SDL_WINDOW_HIDDEN : 0) |
(platform_fullscreen_setting() ? SDL_WINDOW_FULLSCREEN : 0));
#endif
if (!platform_window)
{
@@ -350,6 +388,15 @@ void platform_pump_events(void)
input_state.mouse_released = !input_state.mouse_released;
platform_mouse_capture(!input_state.mouse_released);
}
#ifndef HALO_ANDROID
/* F11 switches between fullscreen and the window (SDL keeps the
window's size and place while fullscreen) */
if (event.key.down && !event.key.repeat && event.key.scancode == SDL_SCANCODE_F11)
{
SDL_SetWindowFullscreen(platform_window,
(SDL_GetWindowFlags(platform_window) & SDL_WINDOW_FULLSCREEN) ? false : true);
}
#endif
break;
case SDL_EVENT_MOUSE_MOTION:
input_state.mouse_dx += event.motion.xrel;
+3
View File
@@ -32,6 +32,9 @@ struct platform_keystroke
BOOL platform_sdl_initialize(void);
/* creates the window and makes its OpenGL context current on this thread */
BOOL platform_video_initialize(unsigned long width, unsigned long height);
#ifndef HALO_ANDROID
BOOL platform_screen_mode(long *width, long *height);
#endif
void platform_video_drawable_size(int *width, int *height);
void platform_video_swap(void);
/* frames between the 30 Hz ticks at the display's refresh rate, unless
+4
View File
@@ -159,6 +159,10 @@ struct xgpu_render_target
unsigned long width, height;
BOOL depth;
GLuint texture;
/* pixels per unit of width and height: more than 1 for the screen's
targets when the game draws at the display's resolution (d3d8_gl.c) */
float scale[2];
unsigned long gl_width, gl_height;
};
/* the GL texture holding a render target with this physical address, or 0 */
+2 -2
View File
@@ -470,13 +470,13 @@ void cinematic_render(
((pixel32)shadow_alpha << 24) |
(title->shadow_color & 0x00FFFFFF));
#ifdef HALO_ANDROID
#ifdef HALO_LINUX
{
/* the bounds are for 640 columns: on a wider screen move
them so they keep their place relative to its sides */
static rectangle2d wide_bounds;
short shift = (short)(((title_bounds->x0 + title_bounds->x1) / 2) *
(halo_android_screen_width() - 640) / 640);
(halo_screen_width() - 640) / 640);
wide_bounds = *title_bounds;
wide_bounds.x0 += shift;
+3 -3
View File
@@ -5535,10 +5535,10 @@ void render_ui_widgets(
{
real alpha;
#ifdef HALO_ANDROID
#ifdef HALO_LINUX
/* the whole screen, around the centered 640 columns */
bounds.x0 = (short)(-(halo_android_screen_width() - 640) / 2);
bounds.x1 = (short)(640 + (halo_android_screen_width() - 640) / 2);
bounds.x0 = (short)(-(halo_screen_width() - 640) / 2);
bounds.x1 = (short)(640 + (halo_screen_width() - 640) / 2);
#else
bounds.x0 = 0;
bounds.x1 = 640;
+2 -2
View File
@@ -2904,8 +2904,8 @@ void halt_and_catch_fire(
1.0f);
window_parameters.camera.z_near = rasterizer_globals.near_clip_distance;
window_parameters.camera.viewport_bounds.x0 = 0;
#ifdef HALO_ANDROID
window_parameters.camera.viewport_bounds.x1 = (short)halo_android_screen_width();
#ifdef HALO_LINUX
window_parameters.camera.viewport_bounds.x1 = (short)halo_screen_width();
#else
window_parameters.camera.viewport_bounds.x1 = 640;
#endif
+65 -6
View File
@@ -1432,7 +1432,12 @@ void rasterizer_set_target_as_texture(
render_primary->Common = RASTERIZER_TARGET_RENDER_PRIMARY_COMMON;
render_primary->Data = d3d_backbuffer->Data;
render_primary->Lock = 0;
#ifdef HALO_LINUX
/* the back buffer's width (rasterizer_screen_width_update) */
render_primary->Size = d3d_backbuffer->Size;
#else
render_primary->Size = RASTERIZER_TARGET_RENDER_PRIMARY_SIZE;
#endif
render_primary->Format = RASTERIZER_TARGET_RENDER_PRIMARY_FORMAT;
result = IDirect3DSurface8_Release(d3d_backbuffer);
if (result >= 0)
@@ -1852,8 +1857,8 @@ boolean rasterizer_preinitialize__fill_you_up_with_the_devils_cock(
d3d_present_parameters.EnableAutoDepthStencil = TRUE;
d3d_present_parameters.AutoDepthStencilFormat = D3DFMT_D24S8;
d3d_present_parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
#ifdef HALO_ANDROID
d3d_present_parameters.BackBufferWidth = halo_android_screen_width();
#ifdef HALO_LINUX
d3d_present_parameters.BackBufferWidth = halo_screen_width();
#else
d3d_present_parameters.BackBufferWidth = RASTERIZER_SCREEN_WIDTH;
#endif
@@ -2408,6 +2413,48 @@ void _rasterizer_frame_end(
return;
}
#ifdef HALO_LINUX
/* The native ports can change the width of the screen between frames (F11
switches the desktop builds between fullscreen at the display's shape and a
640x480 window: halo_screen_commit, port/linux/src/d3d8_gl.c, which resizes
the back buffer). The screen and the title-safe frame follow, as set up in
rasterizer_initialize, and so do the textures the game made of the back
buffer and its copy. */
static void rasterizer_screen_width_update(
void)
{
long width = halo_screen_commit();
if (width != rasterizer_globals.reserved04.screen_bounds.x1 - rasterizer_globals.reserved04.screen_bounds.x0)
{
short frame_index;
rasterizer_globals.reserved04.screen_bounds.x0 = 0;
rasterizer_globals.reserved04.screen_bounds.x1 = (short)width;
rasterizer_globals.reserved04.frame_bounds.x0 =
(short)(RASTERIZER_FRAME_BOUNDS_X0 * width / RASTERIZER_SCREEN_WIDTH);
rasterizer_globals.reserved04.frame_bounds.x1 =
(short)(width - rasterizer_globals.reserved04.frame_bounds.x0);
if (global_d3d_surface_render_primary)
{
DWORD size = global_d3d_surface_render_primary->Size;
for (frame_index = 0; frame_index < 2; frame_index++)
{
if (global_d3d_texture_render_primary[frame_index])
global_d3d_texture_render_primary[frame_index]->Size = size;
}
if (global_d3d_texture_render_primary_copy)
global_d3d_texture_render_primary_copy->Size = size;
if (global_d3d_surface_render_primary_copy)
global_d3d_surface_render_primary_copy->Size = size;
}
}
return;
}
#endif
void _rasterizer_present(
struct bitmap_data *screenshot_bitmap,
point2d const *screenshot_index)
@@ -2524,6 +2571,9 @@ void _rasterizer_present(
"IDirect3DDevice8_Present(global_d3d_device, NULL, NULL, window_globals.hWndPresentTarget, NULL)");
}
rasterizer_globals.fps_accumulation_frame_index++;
#ifdef HALO_LINUX
rasterizer_screen_width_update();
#endif
if (!success)
error(_error_silent, "### ERROR rasterizer_present failed");
return;
@@ -2880,15 +2930,15 @@ boolean _rasterizer_initialize(
rasterizer_globals.reserved04.screen_bounds.y0 = 0;
rasterizer_globals.reserved04.screen_bounds.x0 = 0;
#ifdef HALO_ANDROID
#ifdef HALO_LINUX
/* the device's aspect ratio, with the title-safe frame (the HUD)
widened in proportion */
rasterizer_globals.reserved04.screen_bounds.x1 = (short)halo_android_screen_width();
rasterizer_globals.reserved04.screen_bounds.x1 = (short)halo_screen_width();
rasterizer_globals.reserved04.screen_bounds.y1 = RASTERIZER_SCREEN_HEIGHT;
rasterizer_globals.reserved04.frame_bounds.x0 =
(short)(RASTERIZER_FRAME_BOUNDS_X0 * halo_android_screen_width() / RASTERIZER_SCREEN_WIDTH);
(short)(RASTERIZER_FRAME_BOUNDS_X0 * halo_screen_width() / RASTERIZER_SCREEN_WIDTH);
rasterizer_globals.reserved04.frame_bounds.x1 =
(short)(halo_android_screen_width() - rasterizer_globals.reserved04.frame_bounds.x0);
(short)(halo_screen_width() - rasterizer_globals.reserved04.frame_bounds.x0);
#else
rasterizer_globals.reserved04.screen_bounds.x1 = RASTERIZER_SCREEN_WIDTH;
rasterizer_globals.reserved04.screen_bounds.y1 = RASTERIZER_SCREEN_HEIGHT;
@@ -3101,7 +3151,12 @@ boolean _rasterizer_initialize(
d3d_texture->Common = RASTERIZER_TARGET_RENDER_PRIMARY_COMMON;
d3d_texture->Data = (frame_index == 1) ? global_d3d_surface_render_primary->Data : 0;
d3d_texture->Lock = 0;
#ifdef HALO_LINUX
/* the back buffer's width (rasterizer_screen_width_update) */
d3d_texture->Size = global_d3d_surface_render_primary->Size;
#else
d3d_texture->Size = RASTERIZER_TARGET_RENDER_PRIMARY_SIZE;
#endif
d3d_texture->Format = RASTERIZER_TARGET_RENDER_PRIMARY_FORMAT;
}
}
@@ -3133,7 +3188,11 @@ boolean _rasterizer_initialize(
d3d_texture->Common = RASTERIZER_TARGET_RENDER_PRIMARY_COMMON;
d3d_texture->Data = global_d3d_surface_render_primary_z->Data;
d3d_texture->Lock = 0;
#ifdef HALO_LINUX
d3d_texture->Size = global_d3d_surface_render_primary->Size;
#else
d3d_texture->Size = RASTERIZER_TARGET_RENDER_PRIMARY_SIZE;
#endif
d3d_texture->Format = RASTERIZER_TARGET_RENDER_PRIMARY_FORMAT;
}
else
@@ -994,11 +994,11 @@ void _rasterizer_screen_effect(
if (pass == 0 && main_get_window_count() > 1 && pass_count != 1)
{
#ifdef HALO_ANDROID
#ifdef HALO_LINUX
vertex_bounds.x0 = 2 * global_window_parameters.camera.viewport_bounds.x0 *
(1.0f / (real)halo_android_screen_width()) - 1.0f;
(1.0f / (real)halo_screen_width()) - 1.0f;
vertex_bounds.x1 = 2 * global_window_parameters.camera.viewport_bounds.x1 *
(1.0f / (real)halo_android_screen_width()) - 1.0f;
(1.0f / (real)halo_screen_width()) - 1.0f;
#else
vertex_bounds.x0 = 2 * global_window_parameters.camera.viewport_bounds.x0 *
(1.0f / 640.0f) - 1.0f;
+14 -14
View File
@@ -106,8 +106,8 @@ enum
/* ---------- macros */
#ifdef HALO_ANDROID
#define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH halo_android_screen_width()
#ifdef HALO_LINUX
#define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH halo_screen_width()
#else
#define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH 640
#endif
@@ -238,10 +238,10 @@ static void render_nonplayer_frame(
break;
case 1:
#ifdef HALO_ANDROID
halo_android_ui_offset(TRUE);
#ifdef HALO_LINUX
halo_screen_ui_offset(TRUE);
game_engine_nonplayer_post_rasterize();
halo_android_ui_offset(FALSE);
halo_screen_ui_offset(FALSE);
#else
game_engine_nonplayer_post_rasterize();
#endif
@@ -282,10 +282,10 @@ void render_frame_pregame(
rasterizer_parameters.rasterizer_target = 0;
rasterizer_window_begin(&rasterizer_parameters);
#ifdef HALO_ANDROID
halo_android_ui_offset(TRUE);
#ifdef HALO_LINUX
halo_screen_ui_offset(TRUE);
render_ui_widgets(0, &window->rasterizer_camera.viewport_bounds);
halo_android_ui_offset(FALSE);
halo_screen_ui_offset(FALSE);
#else
render_ui_widgets(0, &window->rasterizer_camera.viewport_bounds);
#endif
@@ -441,10 +441,10 @@ static void render_window(
rasterizer_lens_flares_draw();
interface_draw_screen();
rasterizer_screen_flash();
#ifdef HALO_ANDROID
halo_android_ui_offset(TRUE);
#ifdef HALO_LINUX
halo_screen_ui_offset(TRUE);
render_ui_widgets(local_player_index, &rasterizer_camera->viewport_bounds);
halo_android_ui_offset(FALSE);
halo_screen_ui_offset(FALSE);
#else
render_ui_widgets(local_player_index, &rasterizer_camera->viewport_bounds);
#endif
@@ -670,10 +670,10 @@ void render_frame(
render_nonplayer_frame(window, window_type);
}
#ifdef HALO_ANDROID
halo_android_ui_offset(TRUE);
#ifdef HALO_LINUX
halo_screen_ui_offset(TRUE);
progress_bar_eachframe();
halo_android_ui_offset(FALSE);
halo_screen_ui_offset(FALSE);
#else
progress_bar_eachframe();
#endif
+1
View File
@@ -177,6 +177,7 @@ def main() -> None:
"HALO_SAVE_ROOT": str(saves.resolve()),
"HALO_EXIT_AFTER": str(seconds),
"HALO_NO_VSYNC": "1",
"HALO_FULLSCREEN": "0",
"HALO_VOLUME": "0",
"LLVM_PROFILE_FILE": str((raw / f"{name}-%p.profraw").resolve()),
}