mirror of
https://github.com/izzy2lost/shipdev.git
synced 2026-07-05 15:19:25 -07:00
Merge branch 'develop' into 3DProjectiles
This commit is contained in:
@@ -96,7 +96,6 @@ static struct {
|
||||
uint32_t msaa_num_quality_levels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT];
|
||||
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
ComPtr<ID3D11RasterizerState> rasterizer_state;
|
||||
ComPtr<ID3D11DepthStencilState> depth_stencil_state;
|
||||
@@ -252,7 +251,24 @@ static void gfx_d3d11_init(void) {
|
||||
});
|
||||
|
||||
// Create the swap chain
|
||||
d3d.swap_chain = gfx_dxgi_create_swap_chain(d3d.device.Get());
|
||||
gfx_dxgi_create_swap_chain(d3d.device.Get(), []() {
|
||||
d3d.framebuffers[0].render_target_view.Reset();
|
||||
d3d.textures[d3d.framebuffers[0].texture_id].texture.Reset();
|
||||
d3d.context->ClearState();
|
||||
d3d.context->Flush();
|
||||
|
||||
d3d.last_shader_program = nullptr;
|
||||
d3d.last_vertex_buffer_stride = 0;
|
||||
d3d.last_blend_state.Reset();
|
||||
d3d.last_resource_views[0].Reset();
|
||||
d3d.last_resource_views[1].Reset();
|
||||
d3d.last_sampler_states[0].Reset();
|
||||
d3d.last_sampler_states[1].Reset();
|
||||
d3d.last_depth_test = -1;
|
||||
d3d.last_depth_mask = -1;
|
||||
d3d.last_zmode_decal = -1;
|
||||
d3d.last_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
});
|
||||
|
||||
// Create D3D Debug device if in debug mode
|
||||
|
||||
@@ -266,7 +282,7 @@ static void gfx_d3d11_init(void) {
|
||||
|
||||
// Check the size of the window
|
||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&swap_chain_desc));
|
||||
ThrowIfFailed(gfx_dxgi_get_swap_chain()->GetDesc1(&swap_chain_desc));
|
||||
d3d.textures[fb.texture_id].width = swap_chain_desc.Width;
|
||||
d3d.textures[fb.texture_id].height = swap_chain_desc.Height;
|
||||
fb.msaa_level = 1;
|
||||
@@ -303,8 +319,6 @@ static void gfx_d3d11_init(void) {
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&constant_buffer_desc, nullptr, d3d.per_frame_cb.GetAddressOf()),
|
||||
gfx_dxgi_get_h_wnd(), "Failed to create per-frame constant buffer.");
|
||||
|
||||
d3d.context->PSSetConstantBuffers(0, 1, d3d.per_frame_cb.GetAddressOf());
|
||||
|
||||
// Create per-draw constant buffer
|
||||
|
||||
constant_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
@@ -316,8 +330,6 @@ static void gfx_d3d11_init(void) {
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&constant_buffer_desc, nullptr, d3d.per_draw_cb.GetAddressOf()),
|
||||
gfx_dxgi_get_h_wnd(), "Failed to create per-draw constant buffer.");
|
||||
|
||||
d3d.context->PSSetConstantBuffers(1, 1, d3d.per_draw_cb.GetAddressOf());
|
||||
|
||||
// Create compute shader that can be used to retrieve depth buffer values
|
||||
|
||||
const char* shader_source = R"(
|
||||
@@ -737,6 +749,8 @@ static void gfx_d3d11_on_resize(void) {
|
||||
|
||||
static void gfx_d3d11_start_frame(void) {
|
||||
// Set per-frame constant buffer
|
||||
ID3D11Buffer* buffers[2] = { d3d.per_frame_cb.Get(), d3d.per_draw_cb.Get() };
|
||||
d3d.context->PSSetConstantBuffers(0, 2, buffers);
|
||||
|
||||
d3d.per_frame_cb_data.noise_frame++;
|
||||
if (d3d.per_frame_cb_data.noise_frame > 150) {
|
||||
@@ -803,15 +817,16 @@ static void gfx_d3d11_update_framebuffer_parameters(int fb_id, uint32_t width, u
|
||||
if (msaa_level <= 1) {
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(tex.texture.Get(), nullptr, tex.resource_view.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
} else if (diff) {
|
||||
} else if (diff || (render_target && tex.texture.Get() == nullptr)) {
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1;
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
|
||||
IDXGISwapChain1* swap_chain = gfx_dxgi_get_swap_chain();
|
||||
ThrowIfFailed(swap_chain->GetDesc1(&desc1));
|
||||
if (desc1.Width != width || desc1.Height != height) {
|
||||
fb.render_target_view.Reset();
|
||||
tex.texture.Reset();
|
||||
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags));
|
||||
ThrowIfFailed(swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags));
|
||||
}
|
||||
ThrowIfFailed(d3d.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)tex.texture.ReleaseAndGetAddressOf()));
|
||||
ThrowIfFailed(swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)tex.texture.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
if (render_target) {
|
||||
ThrowIfFailed(d3d.device->CreateRenderTargetView(tex.texture.Get(), nullptr, fb.render_target_view.ReleaseAndGetAddressOf()));
|
||||
|
||||
@@ -34,15 +34,8 @@
|
||||
#define WINCLASS_NAME L"N64GAME"
|
||||
#define GFX_API_NAME "DirectX"
|
||||
|
||||
#ifdef VERSION_EU
|
||||
#define FRAME_INTERVAL_US_NUMERATOR_ 60000
|
||||
#define FRAME_INTERVAL_US_DENOMINATOR 3
|
||||
#else
|
||||
#define FRAME_INTERVAL_US_NUMERATOR_ 50000
|
||||
#define FRAME_INTERVAL_US_DENOMINATOR 3
|
||||
#endif
|
||||
|
||||
#define FRAME_INTERVAL_US_NUMERATOR (FRAME_INTERVAL_US_NUMERATOR_ * dxgi.frame_divisor)
|
||||
#define FRAME_INTERVAL_NS_NUMERATOR 1000000000
|
||||
#define FRAME_INTERVAL_NS_DENOMINATOR (dxgi.target_fps)
|
||||
|
||||
using namespace Microsoft::WRL; // For ComPtr
|
||||
|
||||
@@ -66,14 +59,19 @@ static struct {
|
||||
ComPtr<IDXGIFactory2> factory;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
HANDLE waitable_object;
|
||||
ComPtr<IUnknown> swap_chain_device; // D3D11 Device or D3D12 Command Queue
|
||||
std::function<void()> before_destroy_swap_chain_fn;
|
||||
uint64_t qpc_init, qpc_freq;
|
||||
uint64_t frame_timestamp; // in units of 1/FRAME_INTERVAL_US_DENOMINATOR microseconds
|
||||
uint64_t frame_timestamp; // in units of 1/FRAME_INTERVAL_NS_DENOMINATOR nanoseconds
|
||||
std::map<UINT, DXGI_FRAME_STATISTICS> frame_stats;
|
||||
std::set<std::pair<UINT, UINT>> pending_frame_stats;
|
||||
bool dropped_frame;
|
||||
bool zero_latency;
|
||||
float detected_hz;
|
||||
UINT length_in_vsync_frames;
|
||||
uint32_t frame_divisor;
|
||||
uint32_t target_fps;
|
||||
uint32_t maximum_frame_latency;
|
||||
uint32_t applied_maximum_frame_latency;
|
||||
HANDLE timer;
|
||||
bool use_timer;
|
||||
LARGE_INTEGER previous_present_time;
|
||||
@@ -143,6 +141,22 @@ static void run_as_dpi_aware(Fun f) {
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_maximum_frame_latency(bool first) {
|
||||
ComPtr<IDXGISwapChain2> swap_chain2;
|
||||
if (dxgi.swap_chain->QueryInterface(__uuidof(IDXGISwapChain2), &swap_chain2) == S_OK) {
|
||||
ThrowIfFailed(swap_chain2->SetMaximumFrameLatency(dxgi.maximum_frame_latency));
|
||||
if (first) {
|
||||
dxgi.waitable_object = swap_chain2->GetFrameLatencyWaitableObject();
|
||||
WaitForSingleObject(dxgi.waitable_object, INFINITE);
|
||||
}
|
||||
} else {
|
||||
ComPtr<IDXGIDevice1> device1;
|
||||
ThrowIfFailed(dxgi.swap_chain->GetDevice(__uuidof(IDXGIDevice1), &device1));
|
||||
ThrowIfFailed(device1->SetMaximumFrameLatency(dxgi.maximum_frame_latency));
|
||||
}
|
||||
dxgi.applied_maximum_frame_latency = dxgi.maximum_frame_latency;
|
||||
}
|
||||
|
||||
static void toggle_borderless_window_full_screen(bool enable, bool call_callback) {
|
||||
// Windows 7 + flip mode + waitable object can't go to exclusive fullscreen,
|
||||
// so do borderless instead. If DWM is enabled, this means we get one monitor
|
||||
@@ -271,7 +285,8 @@ void gfx_dxgi_init(const char *game_name, bool start_in_fullscreen) {
|
||||
dxgi.qpc_init = qpc_init.QuadPart;
|
||||
dxgi.qpc_freq = qpc_freq.QuadPart;
|
||||
|
||||
dxgi.frame_divisor = 1;
|
||||
dxgi.target_fps = 60;
|
||||
dxgi.maximum_frame_latency = 1;
|
||||
dxgi.timer = CreateWaitableTimer(nullptr, false, nullptr);
|
||||
|
||||
// Prepare window title
|
||||
@@ -367,8 +382,8 @@ static void gfx_dxgi_handle_events(void) {
|
||||
}*/
|
||||
}
|
||||
|
||||
static uint64_t qpc_to_us(uint64_t qpc) {
|
||||
return qpc / dxgi.qpc_freq * 1000000 + qpc % dxgi.qpc_freq * 1000000 / dxgi.qpc_freq;
|
||||
static uint64_t qpc_to_ns(uint64_t qpc) {
|
||||
return qpc / dxgi.qpc_freq * 1000000000 + qpc % dxgi.qpc_freq * 1000000000 / dxgi.qpc_freq;
|
||||
}
|
||||
|
||||
static uint64_t qpc_to_100ns(uint64_t qpc) {
|
||||
@@ -406,7 +421,7 @@ static bool gfx_dxgi_start_frame(void) {
|
||||
|
||||
dxgi.use_timer = false;
|
||||
|
||||
dxgi.frame_timestamp += FRAME_INTERVAL_US_NUMERATOR;
|
||||
dxgi.frame_timestamp += FRAME_INTERVAL_NS_NUMERATOR;
|
||||
|
||||
if (dxgi.frame_stats.size() >= 2) {
|
||||
DXGI_FRAME_STATISTICS *first = &dxgi.frame_stats.begin()->second;
|
||||
@@ -421,14 +436,16 @@ static bool gfx_dxgi_start_frame(void) {
|
||||
}
|
||||
|
||||
double estimated_vsync_interval = (double)sync_qpc_diff / (double)sync_vsync_diff;
|
||||
uint64_t estimated_vsync_interval_us = qpc_to_us(estimated_vsync_interval);
|
||||
//printf("Estimated vsync_interval: %d\n", (int)estimated_vsync_interval_us);
|
||||
if (estimated_vsync_interval_us < 2 || estimated_vsync_interval_us > 1000000) {
|
||||
uint64_t estimated_vsync_interval_ns = qpc_to_ns(estimated_vsync_interval);
|
||||
//printf("Estimated vsync_interval: %d\n", (int)estimated_vsync_interval_ns);
|
||||
if (estimated_vsync_interval_ns < 2000 || estimated_vsync_interval_ns > 1000000000) {
|
||||
// Unreasonable, maybe a monitor change
|
||||
estimated_vsync_interval_us = 16666;
|
||||
estimated_vsync_interval = estimated_vsync_interval_us * dxgi.qpc_freq / 1000000;
|
||||
estimated_vsync_interval_ns = 16666666;
|
||||
estimated_vsync_interval = estimated_vsync_interval_ns * dxgi.qpc_freq / 1000000000;
|
||||
}
|
||||
|
||||
dxgi.detected_hz = (float)((double)1000000000 / (double)estimated_vsync_interval_ns);
|
||||
|
||||
UINT queued_vsyncs = 0;
|
||||
bool is_first = true;
|
||||
for (const std::pair<UINT, UINT>& p : dxgi.pending_frame_stats) {
|
||||
@@ -440,21 +457,21 @@ static bool gfx_dxgi_start_frame(void) {
|
||||
}
|
||||
|
||||
uint64_t last_frame_present_end_qpc = (last->SyncQPCTime.QuadPart - dxgi.qpc_init) + estimated_vsync_interval * queued_vsyncs;
|
||||
uint64_t last_end_us = qpc_to_us(last_frame_present_end_qpc);
|
||||
uint64_t last_end_ns = qpc_to_ns(last_frame_present_end_qpc);
|
||||
|
||||
double vsyncs_to_wait = (double)(int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR - last_end_us) / estimated_vsync_interval_us;
|
||||
//printf("ts: %llu, last_end_us: %llu, Init v: %f\n", dxgi.frame_timestamp / 3, last_end_us, vsyncs_to_wait);
|
||||
double vsyncs_to_wait = (double)(int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_NS_DENOMINATOR - last_end_ns) / estimated_vsync_interval_ns;
|
||||
//printf("ts: %llu, last_end_ns: %llu, Init v: %f\n", dxgi.frame_timestamp / 3, last_end_ns, vsyncs_to_wait);
|
||||
|
||||
if (vsyncs_to_wait <= 0) {
|
||||
// Too late
|
||||
|
||||
if ((int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR - last_end_us) < -66666) {
|
||||
if ((int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_NS_DENOMINATOR - last_end_ns) < -66666666) {
|
||||
// The application must have been paused or similar
|
||||
vsyncs_to_wait = round(((double)FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR) / estimated_vsync_interval_us);
|
||||
vsyncs_to_wait = round(((double)FRAME_INTERVAL_NS_NUMERATOR / FRAME_INTERVAL_NS_DENOMINATOR) / estimated_vsync_interval_ns);
|
||||
if (vsyncs_to_wait < 1) {
|
||||
vsyncs_to_wait = 1;
|
||||
}
|
||||
dxgi.frame_timestamp = FRAME_INTERVAL_US_DENOMINATOR * (last_end_us + vsyncs_to_wait * estimated_vsync_interval_us);
|
||||
dxgi.frame_timestamp = FRAME_INTERVAL_NS_DENOMINATOR * (last_end_ns + vsyncs_to_wait * estimated_vsync_interval_ns);
|
||||
} else {
|
||||
// Drop frame
|
||||
//printf("Dropping frame\n");
|
||||
@@ -464,9 +481,9 @@ static bool gfx_dxgi_start_frame(void) {
|
||||
}
|
||||
double orig_wait = vsyncs_to_wait;
|
||||
if (floor(vsyncs_to_wait) != vsyncs_to_wait) {
|
||||
uint64_t left = last_end_us + floor(vsyncs_to_wait) * estimated_vsync_interval_us;
|
||||
uint64_t right = last_end_us + ceil(vsyncs_to_wait) * estimated_vsync_interval_us;
|
||||
uint64_t adjusted_desired_time = dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR + (last_end_us + (FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR) > dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR ? 2000 : -2000);
|
||||
uint64_t left = last_end_ns + floor(vsyncs_to_wait) * estimated_vsync_interval_ns;
|
||||
uint64_t right = last_end_ns + ceil(vsyncs_to_wait) * estimated_vsync_interval_ns;
|
||||
uint64_t adjusted_desired_time = dxgi.frame_timestamp / FRAME_INTERVAL_NS_DENOMINATOR + (last_end_ns + (FRAME_INTERVAL_NS_NUMERATOR / FRAME_INTERVAL_NS_DENOMINATOR) > dxgi.frame_timestamp / FRAME_INTERVAL_NS_DENOMINATOR ? 2000000 : -2000000);
|
||||
int64_t diff_left = adjusted_desired_time - left;
|
||||
int64_t diff_right = right - adjusted_desired_time;
|
||||
if (diff_left < 0) {
|
||||
@@ -506,7 +523,7 @@ static void gfx_dxgi_swap_buffers_begin(void) {
|
||||
LARGE_INTEGER t;
|
||||
if (dxgi.use_timer) {
|
||||
QueryPerformanceCounter(&t);
|
||||
int64_t next = qpc_to_100ns(dxgi.previous_present_time.QuadPart) + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
int64_t next = qpc_to_100ns(dxgi.previous_present_time.QuadPart) + FRAME_INTERVAL_NS_NUMERATOR / (FRAME_INTERVAL_NS_DENOMINATOR * 100);
|
||||
int64_t left = next - qpc_to_100ns(t.QuadPart);
|
||||
if (left > 0) {
|
||||
LARGE_INTEGER li;
|
||||
@@ -531,6 +548,32 @@ static void gfx_dxgi_swap_buffers_end(void) {
|
||||
QueryPerformanceCounter(&t0);
|
||||
QueryPerformanceCounter(&t1);
|
||||
|
||||
if (dxgi.applied_maximum_frame_latency > dxgi.maximum_frame_latency) {
|
||||
// There seems to be a bug that if latency is decreased, there is no effect of that operation, so recreate swap chain
|
||||
if (dxgi.waitable_object != nullptr) {
|
||||
if (!dxgi.dropped_frame) {
|
||||
// Wait the last time on this swap chain
|
||||
WaitForSingleObject(dxgi.waitable_object, INFINITE);
|
||||
}
|
||||
CloseHandle(dxgi.waitable_object);
|
||||
dxgi.waitable_object = nullptr;
|
||||
}
|
||||
|
||||
dxgi.before_destroy_swap_chain_fn();
|
||||
|
||||
dxgi.swap_chain.Reset();
|
||||
|
||||
gfx_dxgi_create_swap_chain(dxgi.swap_chain_device.Get(), move(dxgi.before_destroy_swap_chain_fn));
|
||||
|
||||
dxgi.frame_timestamp = 0;
|
||||
dxgi.frame_stats.clear();
|
||||
dxgi.pending_frame_stats.clear();
|
||||
|
||||
return; // Make sure we don't wait a second time on the waitable object, since that would hang the program
|
||||
} else if (dxgi.applied_maximum_frame_latency != dxgi.maximum_frame_latency) {
|
||||
apply_maximum_frame_latency(false);
|
||||
}
|
||||
|
||||
if (!dxgi.dropped_frame) {
|
||||
if (dxgi.waitable_object != nullptr) {
|
||||
WaitForSingleObject(dxgi.waitable_object, INFINITE);
|
||||
@@ -554,8 +597,20 @@ static double gfx_dxgi_get_time(void) {
|
||||
return (double)(t.QuadPart - dxgi.qpc_init) / dxgi.qpc_freq;
|
||||
}
|
||||
|
||||
static void gfx_dxgi_set_frame_divisor(int divisor) {
|
||||
dxgi.frame_divisor = divisor;
|
||||
static void gfx_dxgi_set_target_fps(int fps) {
|
||||
uint32_t old_fps = dxgi.target_fps;
|
||||
uint64_t t0 = dxgi.frame_timestamp / old_fps;
|
||||
uint32_t t1 = dxgi.frame_timestamp % old_fps;
|
||||
dxgi.target_fps = fps;
|
||||
dxgi.frame_timestamp = t0 * dxgi.target_fps + t1 * dxgi.target_fps / old_fps;
|
||||
}
|
||||
|
||||
static void gfx_dxgi_set_maximum_frame_latency(int latency) {
|
||||
dxgi.maximum_frame_latency = latency;
|
||||
}
|
||||
|
||||
static float gfx_dxgi_get_detected_hz() {
|
||||
return dxgi.detected_hz;
|
||||
}
|
||||
|
||||
void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*create_device_fn)(IDXGIAdapter1 *adapter, bool test_only)) {
|
||||
@@ -592,12 +647,12 @@ void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*crea
|
||||
SetWindowTextW(dxgi.h_wnd, w_title);
|
||||
}
|
||||
|
||||
ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device) {
|
||||
void gfx_dxgi_create_swap_chain(IUnknown *device, std::function<void()>&& before_destroy_fn) {
|
||||
bool win8 = IsWindows8OrGreater(); // DXGI_SCALING_NONE is only supported on Win8 and beyond
|
||||
bool dxgi_13 = dxgi.CreateDXGIFactory2 != nullptr; // DXGI 1.3 introduced waitable object
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
|
||||
swap_chain_desc.BufferCount = 2;
|
||||
swap_chain_desc.BufferCount = 3;
|
||||
swap_chain_desc.Width = 0;
|
||||
swap_chain_desc.Height = 0;
|
||||
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -617,28 +672,24 @@ ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device) {
|
||||
});
|
||||
ThrowIfFailed(dxgi.factory->MakeWindowAssociation(dxgi.h_wnd, DXGI_MWA_NO_ALT_ENTER));
|
||||
|
||||
ComPtr<IDXGISwapChain2> swap_chain2;
|
||||
if (dxgi.swap_chain->QueryInterface(__uuidof(IDXGISwapChain2), &swap_chain2) == S_OK) {
|
||||
ThrowIfFailed(swap_chain2->SetMaximumFrameLatency(1));
|
||||
dxgi.waitable_object = swap_chain2->GetFrameLatencyWaitableObject();
|
||||
WaitForSingleObject(dxgi.waitable_object, INFINITE);
|
||||
} else {
|
||||
ComPtr<IDXGIDevice1> device1;
|
||||
ThrowIfFailed(device->QueryInterface(IID_PPV_ARGS(&device1)));
|
||||
ThrowIfFailed(device1->SetMaximumFrameLatency(1));
|
||||
}
|
||||
apply_maximum_frame_latency(true);
|
||||
|
||||
ThrowIfFailed(dxgi.swap_chain->GetDesc1(&swap_chain_desc));
|
||||
dxgi.current_width = swap_chain_desc.Width;
|
||||
dxgi.current_height = swap_chain_desc.Height;
|
||||
|
||||
return dxgi.swap_chain;
|
||||
dxgi.swap_chain_device = device;
|
||||
dxgi.before_destroy_swap_chain_fn = std::move(before_destroy_fn);
|
||||
}
|
||||
|
||||
HWND gfx_dxgi_get_h_wnd(void) {
|
||||
return dxgi.h_wnd;
|
||||
}
|
||||
|
||||
IDXGISwapChain1* gfx_dxgi_get_swap_chain() {
|
||||
return dxgi.swap_chain.Get();
|
||||
}
|
||||
|
||||
void ThrowIfFailed(HRESULT res) {
|
||||
if (FAILED(res)) {
|
||||
fprintf(stderr, "Error: 0x%08X\n", res);
|
||||
@@ -668,7 +719,9 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
|
||||
gfx_dxgi_swap_buffers_begin,
|
||||
gfx_dxgi_swap_buffers_end,
|
||||
gfx_dxgi_get_time,
|
||||
gfx_dxgi_set_frame_divisor,
|
||||
gfx_dxgi_set_target_fps,
|
||||
gfx_dxgi_set_maximum_frame_latency,
|
||||
gfx_dxgi_get_detected_hz,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
#include "gfx_rendering_api.h"
|
||||
|
||||
#ifdef DECLARE_GFX_DXGI_FUNCTIONS
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*create_device_fn)(IDXGIAdapter1 *adapter, bool test_only));
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device);
|
||||
void gfx_dxgi_create_swap_chain(IUnknown *device, std::function<void()>&& before_destroy_fn);
|
||||
HWND gfx_dxgi_get_h_wnd(void);
|
||||
IDXGISwapChain1* gfx_dxgi_get_swap_chain();
|
||||
void ThrowIfFailed(HRESULT res);
|
||||
void ThrowIfFailed(HRESULT res, HWND h_wnd, const char *message);
|
||||
#endif
|
||||
|
||||
@@ -2789,6 +2789,9 @@ void gfx_run(Gfx *commands, const std::unordered_map<Mtx *, MtxF>& mtx_replaceme
|
||||
gfx_rapi->start_frame();
|
||||
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
rendering_state.viewport = {};
|
||||
rendering_state.scissor = {};
|
||||
gfx_run_dl(commands);
|
||||
gfx_flush();
|
||||
SohUtils::saveEnvironmentVar("framebuffer", string());
|
||||
@@ -2825,8 +2828,16 @@ void gfx_end_frame(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_framedivisor(int divisor) {
|
||||
gfx_wapi->set_frame_divisor(divisor);
|
||||
void gfx_set_target_fps(int fps) {
|
||||
gfx_wapi->set_target_fps(fps);
|
||||
}
|
||||
|
||||
void gfx_set_maximum_frame_latency(int latency) {
|
||||
gfx_wapi->set_maximum_frame_latency(latency);
|
||||
}
|
||||
|
||||
float gfx_get_detected_hz(void) {
|
||||
return gfx_wapi->get_detected_hz();
|
||||
}
|
||||
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
|
||||
@@ -67,7 +67,9 @@ struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
|
||||
void gfx_start_frame(void);
|
||||
void gfx_run(Gfx* commands, const std::unordered_map<Mtx*, MtxF>& mtx_replacements);
|
||||
void gfx_end_frame(void);
|
||||
void gfx_set_framedivisor(int);
|
||||
void gfx_set_target_fps(int);
|
||||
void gfx_set_maximum_frame_latency(int latency);
|
||||
float gfx_get_detected_hz(void);
|
||||
void gfx_texture_cache_clear();
|
||||
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height);
|
||||
void gfx_get_pixel_depth_prepare(float x, float y);
|
||||
|
||||
@@ -123,11 +123,10 @@ static uint64_t previous_time;
|
||||
static HANDLE timer;
|
||||
#endif
|
||||
|
||||
static int frameDivisor = 1;
|
||||
static int target_fps = 60;
|
||||
|
||||
#define FRAME_INTERVAL_US_NUMERATOR_ 50000
|
||||
#define FRAME_INTERVAL_US_DENOMINATOR 3
|
||||
#define FRAME_INTERVAL_US_NUMERATOR (FRAME_INTERVAL_US_NUMERATOR_ * frameDivisor)
|
||||
#define FRAME_INTERVAL_US_NUMERATOR 1000000
|
||||
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
|
||||
|
||||
static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) {
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
@@ -250,6 +249,7 @@ static void gfx_sdl_handle_events(void) {
|
||||
}
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
SDL_Quit(); // bandaid fix for linux window closing issue
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
@@ -266,15 +266,16 @@ static uint64_t qpc_to_100ns(uint64_t qpc) {
|
||||
|
||||
static inline void sync_framerate_with_timer(void) {
|
||||
uint64_t t;
|
||||
t = SDL_GetPerformanceCounter();
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
|
||||
const int64_t next = qpc_to_100ns(previous_time) + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
const int64_t left = next - qpc_to_100ns(t);
|
||||
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
const int64_t left = next - t;
|
||||
if (left > 0) {
|
||||
#ifdef __linux__
|
||||
const timespec spec = { 0, left * 100 };
|
||||
nanosleep(&spec, nullptr);
|
||||
#else
|
||||
// The accuracy of this timer seems to usually be within +- 1.0 ms
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = -left;
|
||||
SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false);
|
||||
@@ -282,7 +283,13 @@ static inline void sync_framerate_with_timer(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
t = SDL_GetPerformanceCounter();
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
if (left > 0 && t - next < 10000) {
|
||||
// In case it takes some time for the application to wake up after sleep,
|
||||
// or inaccurate timer,
|
||||
// don't let that slow down the framerate.
|
||||
t = next;
|
||||
}
|
||||
previous_time = t;
|
||||
}
|
||||
|
||||
@@ -299,9 +306,16 @@ static double gfx_sdl_get_time(void) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_framedivisor(int divisor)
|
||||
{
|
||||
frameDivisor = divisor;
|
||||
static void gfx_sdl_set_target_fps(int fps) {
|
||||
target_fps = fps;
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_maximum_frame_latency(int latency) {
|
||||
// Not supported by SDL :(
|
||||
}
|
||||
|
||||
static float gfx_sdl_get_detected_hz(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
@@ -317,7 +331,9 @@ struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_swap_buffers_begin,
|
||||
gfx_sdl_swap_buffers_end,
|
||||
gfx_sdl_get_time,
|
||||
gfx_sdl_set_framedivisor
|
||||
gfx_sdl_set_target_fps,
|
||||
gfx_sdl_set_maximum_frame_latency,
|
||||
gfx_sdl_get_detected_hz
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,9 @@ struct GfxWindowManagerAPI {
|
||||
void (*swap_buffers_begin)(void);
|
||||
void (*swap_buffers_end)(void);
|
||||
double (*get_time)(void); // For debug
|
||||
void (*set_frame_divisor)(int);
|
||||
void (*set_target_fps)(int fps);
|
||||
void (*set_maximum_frame_latency)(int latency);
|
||||
float (*get_detected_hz)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -63,12 +63,14 @@ namespace SohImGui {
|
||||
extern bool needs_save;
|
||||
void Init(WindowImpl window_impl);
|
||||
void Update(EventImpl event);
|
||||
|
||||
void EnhancementRadioButton(std::string text, std::string cvarName, int value);
|
||||
void EnhancementCheckbox(std::string text, std::string cvarName);
|
||||
void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format);
|
||||
void EnhancementSliderFloat(std::string text, std::string id, std::string cvarName, float min, float max, std::string format, float defaultValue);
|
||||
void EnhancementColor3(std::string text, std::string cvarName, float ColorRGB[3], bool TitleSameLine);
|
||||
void Tooltip(const char* text);
|
||||
|
||||
void EnhancementRadioButton(const char* text, const char* cvarName, int id);
|
||||
void EnhancementCheckbox(const char* text, const char* cvarName);
|
||||
void EnhancementButton(const char* text, const char* cvarName);
|
||||
void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format);
|
||||
void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage);
|
||||
void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false);
|
||||
|
||||
void DrawMainMenuAndCalculateGameSize(void);
|
||||
|
||||
@@ -79,7 +81,10 @@ namespace SohImGui {
|
||||
void BindCmd(const std::string& cmd, CommandEntry entry);
|
||||
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);
|
||||
void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1));
|
||||
void LoadInterfaceEditor();
|
||||
void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha=false);
|
||||
void RandomizeColor(const char* cvarName, ImVec4* colors);
|
||||
void RainbowColor(const char* cvarName, ImVec4* colors);
|
||||
void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha);
|
||||
ImTextureID GetTextureByID(int id);
|
||||
ImTextureID GetTextureByName(const std::string& name);
|
||||
}
|
||||
|
||||
@@ -272,13 +272,14 @@ namespace Ship {
|
||||
gfx_run(Commands, m);
|
||||
gfx_end_frame();
|
||||
}
|
||||
gfx_run(Commands, {});
|
||||
gfx_end_frame();
|
||||
}
|
||||
|
||||
void Window::SetFrameDivisor(int divisor) {
|
||||
gfx_set_framedivisor(divisor);
|
||||
//gfx_set_framedivisor(0);
|
||||
void Window::SetTargetFps(int fps) {
|
||||
gfx_set_target_fps(fps);
|
||||
}
|
||||
|
||||
void Window::SetMaximumFrameLatency(int latency) {
|
||||
gfx_set_maximum_frame_latency(latency);
|
||||
}
|
||||
|
||||
void Window::GetPixelDepthPrepare(float x, float y) {
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace Ship {
|
||||
void Init();
|
||||
void StartFrame();
|
||||
void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements);
|
||||
void SetFrameDivisor(int divisor);
|
||||
void SetTargetFps(int fps);
|
||||
void SetMaximumFrameLatency(int latency);
|
||||
void GetPixelDepthPrepare(float x, float y);
|
||||
uint16_t GetPixelDepth(float x, float y);
|
||||
void ToggleFullscreen();
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ WARN := \
|
||||
-funsigned-char \
|
||||
-m32 -mhard-float -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \
|
||||
|
||||
CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib -march=i386
|
||||
CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib -march=i386
|
||||
CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib -march=i386 -msse2 -mfpmath=sse
|
||||
CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib -march=i386 -msse2 -mfpmath=sse
|
||||
LDFLAGS := -m32
|
||||
CPPFLAGS := -MMD
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Root>
|
||||
<File Name="object_triforce_spot" Segment="6">
|
||||
<Array Name="gTriforceVtx" Count="32" Offset="0x0000">
|
||||
<Array Name="gTriforceVtx" Count="96" Offset="0x0000">
|
||||
<Vtx/>
|
||||
</Array>
|
||||
|
||||
|
||||
+34
-6
@@ -175,8 +175,6 @@ extern "C" void Graph_StartFrame() {
|
||||
|
||||
// C->C++ Bridge
|
||||
extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
|
||||
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(CVar_GetS32("g60FPS", 0) == 0 ? R_UPDATE_RATE : 1);
|
||||
|
||||
if (!audio.initialized) {
|
||||
audio.initialized = true;
|
||||
std::thread([]() {
|
||||
@@ -226,15 +224,45 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
|
||||
audio.cv_to_thread.notify_one();
|
||||
|
||||
std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
|
||||
if (CVar_GetS32("g60FPS", 0) != 0) {
|
||||
int to = R_UPDATE_RATE;
|
||||
for (int i = 1; i < to; i++) {
|
||||
mtx_replacements.push_back(FrameInterpolation_Interpolate(i / (float)to));
|
||||
int target_fps = CVar_GetS32("gInterpolationFPS", 20);
|
||||
static int last_fps;
|
||||
static int last_update_rate;
|
||||
static int time;
|
||||
int fps = target_fps;
|
||||
int original_fps = 60 / R_UPDATE_RATE;
|
||||
|
||||
if (target_fps == 20 || original_fps > target_fps) {
|
||||
fps = original_fps;
|
||||
}
|
||||
|
||||
if (last_fps != fps || last_update_rate != R_UPDATE_RATE) {
|
||||
time = 0;
|
||||
}
|
||||
|
||||
// time_base = fps * original_fps (one second)
|
||||
int next_original_frame = fps;
|
||||
|
||||
while (time + original_fps <= next_original_frame) {
|
||||
time += original_fps;
|
||||
if (time != next_original_frame) {
|
||||
mtx_replacements.push_back(FrameInterpolation_Interpolate((float)time / next_original_frame));
|
||||
} else {
|
||||
mtx_replacements.emplace_back();
|
||||
}
|
||||
}
|
||||
|
||||
time -= fps;
|
||||
|
||||
OTRGlobals::Instance->context->GetWindow()->SetTargetFps(fps);
|
||||
|
||||
int threshold = CVar_GetS32("gExtraLatencyThreshold", 80);
|
||||
OTRGlobals::Instance->context->GetWindow()->SetMaximumFrameLatency(threshold > 0 && target_fps >= threshold ? 2 : 1);
|
||||
|
||||
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands, mtx_replacements);
|
||||
|
||||
last_fps = fps;
|
||||
last_update_rate = R_UPDATE_RATE;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(audio.mutex);
|
||||
while (audio.processing) {
|
||||
|
||||
@@ -451,7 +451,7 @@ void FrameInterpolation_StartRecord(void) {
|
||||
current_recording = {};
|
||||
current_path.clear();
|
||||
current_path.push_back(¤t_recording.root_path);
|
||||
if (CVar_GetS32("g60FPS", 0) != 0) {
|
||||
if (CVar_GetS32("gInterpolationFPS", 20) != 20) {
|
||||
is_recording = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,50 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) {
|
||||
if (file == nullptr)
|
||||
return nullptr;
|
||||
|
||||
MessageTableEntry* table = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * file->messages.size());
|
||||
// Allocate room for an additional message
|
||||
MessageTableEntry* table = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * (file->messages.size() + 1));
|
||||
|
||||
for (int i = 0; i < file->messages.size(); i++) {
|
||||
// Look for Owl Text
|
||||
if (file->messages[i].id == 0x2066) {
|
||||
// Create a new message based on the Owl Text
|
||||
char* kaeporaPatch = (char*)malloc(sizeof(char) * file->messages[i].msg.size());
|
||||
file->messages[i].msg.copy(kaeporaPatch, file->messages[i].msg.size(), 0);
|
||||
|
||||
// Swap the order of yes and no in this new message
|
||||
if (filePath == "text/nes_message_data_static/nes_message_data_static") {
|
||||
kaeporaPatch[26] = 'Y';
|
||||
kaeporaPatch[27] = 'e';
|
||||
kaeporaPatch[28] = 's';
|
||||
kaeporaPatch[29] = 1;
|
||||
kaeporaPatch[30] = 'N';
|
||||
kaeporaPatch[31] = 'o';
|
||||
} else if (filePath == "text/ger_message_data_static/ger_message_data_static") {
|
||||
kaeporaPatch[30] = 'J';
|
||||
kaeporaPatch[31] = 'a';
|
||||
kaeporaPatch[32] = '!';
|
||||
kaeporaPatch[33] = 1;
|
||||
kaeporaPatch[34] = 'N';
|
||||
kaeporaPatch[35] = 'e';
|
||||
kaeporaPatch[36] = 'i';
|
||||
kaeporaPatch[37] = 'n';
|
||||
} else {
|
||||
kaeporaPatch[26] = 'O';
|
||||
kaeporaPatch[27] = 'u';
|
||||
kaeporaPatch[28] = 'i';
|
||||
kaeporaPatch[29] = 1;
|
||||
kaeporaPatch[30] = 'N';
|
||||
kaeporaPatch[31] = 'o';
|
||||
kaeporaPatch[32] = 'n';
|
||||
}
|
||||
|
||||
// load data into message
|
||||
table[file->messages.size()].textId = 0x71B3;
|
||||
table[file->messages.size()].typePos = (file->messages[i].textboxType << 4) | file->messages[i].textboxYPos;
|
||||
table[file->messages.size()].segment = kaeporaPatch;
|
||||
table[file->messages.size()].msgSize = file->messages[i].msg.size();
|
||||
}
|
||||
|
||||
table[i].textId = file->messages[i].id;
|
||||
table[i].typePos = (file->messages[i].textboxType << 4) | file->messages[i].textboxYPos;
|
||||
table[i].segment = file->messages[i].msg.c_str();
|
||||
|
||||
@@ -2290,8 +2290,8 @@ void Actor_DrawFaroresWindPointer(GlobalContext* globalCtx) {
|
||||
((void)0, gSaveContext.respawn[RESPAWN_MODE_TOP].pos.y) + yOffset,
|
||||
((void)0, gSaveContext.respawn[RESPAWN_MODE_TOP].pos.z), 255, 255, 255, lightRadius);
|
||||
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 5474);
|
||||
}
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 5474);
|
||||
}
|
||||
|
||||
void func_80030488(GlobalContext* globalCtx) {
|
||||
|
||||
+28
-21
@@ -128,6 +128,13 @@ void HealthMeter_Init(GlobalContext* globalCtx) {
|
||||
HeartDDOutline[0] = CVar_GetS32("gDDCCHeartsPrimR", 90);
|
||||
HeartDDOutline[1] = CVar_GetS32("gDDCCHeartsPrimG", 90);
|
||||
HeartDDOutline[2] = CVar_GetS32("gDDCCHeartsPrimB", 90);
|
||||
} else {
|
||||
HeartInner[0] = HEARTS_PRIM_R;
|
||||
HeartInner[1] = HEARTS_PRIM_G;
|
||||
HeartInner[2] = HEARTS_PRIM_B;
|
||||
HeartDDOutline[0] = HEARTS_DD_PRIM_R;
|
||||
HeartDDOutline[1] = HEARTS_DD_PRIM_G;
|
||||
HeartDDOutline[2] = HEARTS_DD_PRIM_B;
|
||||
}
|
||||
|
||||
interfaceCtx->unk_228 = 0x140;
|
||||
@@ -194,12 +201,12 @@ void HealthMeter_Update(GlobalContext* globalCtx) {
|
||||
HeartDDOutline[1] = CVar_GetS32("gDDCCHeartsPrimG", sHeartsDDPrim[0][1]);
|
||||
HeartDDOutline[2] = CVar_GetS32("gDDCCHeartsPrimB", sHeartsDDPrim[0][2]);
|
||||
} else {
|
||||
HeartInner[0] = sHeartsPrimColors[0][0];
|
||||
HeartInner[1] = sHeartsPrimColors[0][1];
|
||||
HeartInner[2] = sHeartsPrimColors[0][2];
|
||||
HeartDDOutline[0] = sHeartsDDPrim[0][0];
|
||||
HeartDDOutline[1] = sHeartsDDPrim[0][1];
|
||||
HeartDDOutline[2] = sHeartsDDPrim[0][2];
|
||||
HeartInner[0] = HEARTS_PRIM_R;
|
||||
HeartInner[1] = HEARTS_PRIM_G;
|
||||
HeartInner[2] = HEARTS_PRIM_B;
|
||||
HeartDDOutline[0] = HEARTS_DD_PRIM_R;
|
||||
HeartDDOutline[1] = HEARTS_DD_PRIM_G;
|
||||
HeartDDOutline[2] = HEARTS_DD_PRIM_B;
|
||||
}
|
||||
|
||||
if (interfaceCtx->unk_200 != 0) {
|
||||
@@ -299,33 +306,33 @@ void HealthMeter_Update(GlobalContext* globalCtx) {
|
||||
sBeatingHeartsDDEnv[1] = (u8)(gFactor + HeartDDInner[1]) & 0xFF;
|
||||
sBeatingHeartsDDEnv[2] = (u8)(bFactor + HeartDDInner[2]) & 0xFF;
|
||||
} else {
|
||||
sHeartsDDPrim[2][0] = HeartInner[0];
|
||||
sHeartsDDPrim[2][1] = HeartInner[1];
|
||||
sHeartsDDPrim[2][2] = HeartInner[2];
|
||||
sHeartsDDPrim[2][0] = HEARTS_PRIM_R;
|
||||
sHeartsDDPrim[2][1] = HEARTS_PRIM_G;
|
||||
sHeartsDDPrim[2][2] = HEARTS_PRIM_B;
|
||||
|
||||
sHeartsDDPrim[1][0] = sHeartsDDPrimColors[ddType][0];
|
||||
sHeartsDDPrim[1][1] = sHeartsDDPrimColors[ddType][1];
|
||||
sHeartsDDPrim[1][2] = sHeartsDDPrimColors[ddType][2];
|
||||
sHeartsDDPrim[1][0] = HEARTS_DD_PRIM_R;
|
||||
sHeartsDDPrim[1][1] = HEARTS_DD_PRIM_G;
|
||||
sHeartsDDPrim[1][2] = HEARTS_DD_PRIM_B;
|
||||
|
||||
sHeartsDDEnv[1][0] = sHeartsDDEnvColors[ddType][0];
|
||||
sHeartsDDEnv[1][1] = sHeartsDDEnvColors[ddType][1];
|
||||
sHeartsDDEnv[1][2] = sHeartsDDEnvColors[ddType][2];
|
||||
sHeartsDDEnv[1][0] = HEARTS_PRIM_R;
|
||||
sHeartsDDEnv[1][1] = HEARTS_PRIM_G;
|
||||
sHeartsDDEnv[1][2] = HEARTS_PRIM_B;
|
||||
|
||||
rFactor = sHeartsDDPrimFactors[ddType][0] * ddFactor;
|
||||
gFactor = sHeartsDDPrimFactors[ddType][1] * ddFactor;
|
||||
bFactor = sHeartsDDPrimFactors[ddType][2] * ddFactor;
|
||||
|
||||
sBeatingHeartsDDPrim[0] = (u8)(rFactor + HeartDDOutline[0]) & 0xFF;
|
||||
sBeatingHeartsDDPrim[1] = (u8)(gFactor + HeartDDOutline[1]) & 0xFF;
|
||||
sBeatingHeartsDDPrim[2] = (u8)(bFactor + HeartDDOutline[2]) & 0xFF;
|
||||
sBeatingHeartsDDPrim[0] = (u8)(rFactor + HEARTS_DD_PRIM_R) & 0xFF;
|
||||
sBeatingHeartsDDPrim[1] = (u8)(gFactor + HEARTS_DD_PRIM_G) & 0xFF;
|
||||
sBeatingHeartsDDPrim[2] = (u8)(bFactor + HEARTS_DD_PRIM_B) & 0xFF;
|
||||
|
||||
rFactor = sHeartsDDEnvFactors[ddType][0] * ddFactor;
|
||||
gFactor = sHeartsDDEnvFactors[ddType][1] * ddFactor;
|
||||
bFactor = sHeartsDDEnvFactors[ddType][2] * ddFactor;
|
||||
|
||||
sBeatingHeartsDDEnv[0] = (u8)(rFactor + HeartDDInner[0]) & 0xFF;
|
||||
sBeatingHeartsDDEnv[1] = (u8)(gFactor + HeartDDInner[1]) & 0xFF;
|
||||
sBeatingHeartsDDEnv[2] = (u8)(bFactor + HeartDDInner[2]) & 0xFF;
|
||||
sBeatingHeartsDDEnv[0] = (u8)(rFactor + HEARTS_PRIM_R) & 0xFF;
|
||||
sBeatingHeartsDDEnv[1] = (u8)(gFactor + HEARTS_PRIM_G) & 0xFF;
|
||||
sBeatingHeartsDDEnv[2] = (u8)(bFactor + HEARTS_PRIM_B) & 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -272,6 +272,13 @@ void Message_FindMessage(GlobalContext* globalCtx, u16 textId) {
|
||||
const char** languageSegmentTable;
|
||||
Font* font;
|
||||
const char* seg;
|
||||
u16 bufferId = textId;
|
||||
// Use the better owl message if better owl is enabled
|
||||
if (CVar_GetS32("gBetterOwl", 0) != 0 && (bufferId == 0x2066 || bufferId == 0x607B ||
|
||||
bufferId == 0x10C2 || bufferId == 0x10C6 || bufferId == 0x206A))
|
||||
{
|
||||
bufferId = 0x71B3;
|
||||
}
|
||||
|
||||
if (gSaveContext.language == LANGUAGE_GER)
|
||||
messageTableEntry = sGerMessageEntryTablePtr;
|
||||
@@ -287,7 +294,7 @@ void Message_FindMessage(GlobalContext* globalCtx, u16 textId) {
|
||||
while (messageTableEntry->textId != 0xFFFF) {
|
||||
font = &globalCtx->msgCtx.font;
|
||||
|
||||
if (messageTableEntry->textId == textId) {
|
||||
if (messageTableEntry->textId == bufferId) {
|
||||
foundSeg = messageTableEntry->segment;
|
||||
font->charTexBuf[0] = messageTableEntry->typePos;
|
||||
|
||||
@@ -298,14 +305,14 @@ void Message_FindMessage(GlobalContext* globalCtx, u16 textId) {
|
||||
// "Message found!!!"
|
||||
osSyncPrintf(" メッセージが,見つかった!!! = %x "
|
||||
"(data=%x) (data0=%x) (data1=%x) (data2=%x) (data3=%x)\n",
|
||||
textId, font->msgOffset, font->msgLength, foundSeg, seg, nextSeg);
|
||||
bufferId, font->msgOffset, font->msgLength, foundSeg, seg, nextSeg);
|
||||
return;
|
||||
}
|
||||
messageTableEntry++;
|
||||
}
|
||||
|
||||
// "Message not found!!!"
|
||||
osSyncPrintf(" メッセージが,見つからなかった!!! = %x\n", textId);
|
||||
osSyncPrintf(" メッセージが,見つからなかった!!! = %x\n", bufferId);
|
||||
font = &globalCtx->msgCtx.font;
|
||||
messageTableEntry = sNesMessageEntryTablePtr;
|
||||
|
||||
|
||||
@@ -2884,7 +2884,26 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) {
|
||||
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0);
|
||||
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
|
||||
PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
|
||||
|
||||
|
||||
//There is probably a more elegant way to do it.
|
||||
char* doAction = actionsTbl[3];
|
||||
char newName[512];
|
||||
if (gSaveContext.language != LANGUAGE_ENG) {
|
||||
size_t length = strlen(doAction);
|
||||
strcpy(newName, doAction);
|
||||
if (gSaveContext.language == LANGUAGE_FRA) {
|
||||
newName[length - 6] = 'F';
|
||||
newName[length - 5] = 'R';
|
||||
newName[length - 4] = 'A';
|
||||
} else if (gSaveContext.language == LANGUAGE_GER) {
|
||||
newName[length - 6] = 'G';
|
||||
newName[length - 5] = 'E';
|
||||
newName[length - 4] = 'R';
|
||||
}
|
||||
doAction = newName;
|
||||
}
|
||||
memcpy(interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE * 2, ResourceMgr_LoadTexByName(doAction), DO_ACTION_TEX_SIZE);
|
||||
|
||||
gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE * 2, G_IM_FMT_IA,
|
||||
DO_ACTION_TEX_WIDTH, DO_ACTION_TEX_HEIGHT, 0, G_TX_NOMIRROR | G_TX_WRAP,
|
||||
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user