mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 13:00:25 +02:00
Native resolution fullscreen with F11 toggle
This commit is contained in:
1 parent
fef8a582dd
commit
50eae19bac
16 files changed
+333
-86
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user