Created
July 18, 2023 12:22
-
-
Save TheComputerGuy96/4b23d46429f29424587086b87b756299 to your computer and use it in GitHub Desktop.
A rebased version of MattKC's ddraw fix for LEGO Island (and some other games)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 1f932e005efdf7948891c5dd26402bd0d2cc4366 Mon Sep 17 00:00:00 2001 | |
From: Matthew Wong <itsmattkc(a)gmail.com> | |
Date: Fri, 18 Sep 2020 00:47:13 +0000 | |
Subject: [PATCH] ddraw: Implement Pick() and GetPickRecords(). | |
Implement functions used by some games (notably LEGO Island) for | |
determining which 3D object in a scene was clicked by the mouse cursor. | |
Fighting Steel also uses this function for mouse over. Previous stubs | |
would cause LEGO Island to crash upon any click and Fighting Steel | |
to crash on game start. A patch posted years ago on the bug thread | |
provided the minimum functionality to prevent crashes, but still | |
rendered large portions of the game inaccessible without them | |
implemented correctly. | |
Picking has been implemented by adding a "pick mode" in | |
d3d_execute_buffer_execute() which skips any drawing functions | |
leaving just the vertex processing. Adds click tests for each triangle | |
when in pick mode for creating an array of D3DPICKRECORDs. | |
Stress testing reveals this patch's Pick() implementation may have | |
slight inaccuracies to the original function; occasionally pixels right | |
on triangle edges result in successful picks when they don't with the | |
original function (and vice versa). It may be some sort of floating | |
point rounding error or other algorithm difference that would be | |
difficult to determine without seeing the original code. In practice, I | |
believe this inaccuracy is so negligible that it won't produce any | |
undesirable results for the user. | |
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=10729 | |
Signed-off-by: Matthew Wong <itsmattkc(a)gmail.com> | |
Signed-off-by: Myah Caron <qsniyg(a)protonmail.com> | |
--- | |
dlls/ddraw/ddraw_private.h | 7 +- | |
dlls/ddraw/device.c | 65 ++++++++++-- | |
dlls/ddraw/executebuffer.c | 196 +++++++++++++++++++++++++++++++++++-- | |
dlls/ddraw/tests/ddraw1.c | 131 +++++++++++++++++++++++++ | |
4 files changed, 382 insertions(+), 17 deletions(-) | |
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h | |
index a3f309f89f0..a5c90e55c75 100644 | |
--- a/dlls/ddraw/ddraw_private.h | |
+++ b/dlls/ddraw/ddraw_private.h | |
@@ -338,6 +338,11 @@ struct d3d_device | |
struct d3d_viewport *current_viewport; | |
D3DVIEWPORT7 active_viewport; | |
+ /* Pick data */ | |
+ D3DPICKRECORD *pick_records; | |
+ DWORD pick_record_count; | |
+ DWORD pick_record_size; | |
+ | |
/* Required to keep track which of two available texture blending modes in d3ddevice3 is used */ | |
BOOL legacyTextureBlending; | |
D3DTEXTUREBLEND texture_map_blend; | |
@@ -571,7 +576,7 @@ struct d3d_execute_buffer *unsafe_impl_from_IDirect3DExecuteBuffer(IDirect3DExec | |
/* The execute function */ | |
HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *execute_buffer, | |
- struct d3d_device *device) DECLSPEC_HIDDEN; | |
+ struct d3d_device *device, D3DRECT *pick_rect) DECLSPEC_HIDDEN; | |
/***************************************************************************** | |
* IDirect3DVertexBuffer | |
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c | |
index 1cfef5007d5..fd748308f3d 100644 | |
--- a/dlls/ddraw/device.c | |
+++ b/dlls/ddraw/device.c | |
@@ -349,6 +349,9 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface) | |
IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface); | |
} | |
+ if (This->pick_record_size > 0) | |
+ heap_free(This->pick_records); | |
+ | |
TRACE("Releasing render target %p.\n", This->rt_iface); | |
rt_iface = This->rt_iface; | |
This->rt_iface = NULL; | |
@@ -758,7 +761,7 @@ static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface, | |
/* Execute... */ | |
wined3d_mutex_lock(); | |
- hr = d3d_execute_buffer_execute(buffer, device); | |
+ hr = d3d_execute_buffer_execute(buffer, device, NULL); | |
wined3d_mutex_unlock(); | |
return hr; | |
@@ -1025,16 +1028,44 @@ static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface, | |
* x2 and y2 are ignored. | |
* | |
* Returns: | |
- * D3D_OK because it's a stub | |
+ * D3D_OK on success | |
+ * DDERR_INVALIDPARAMS if any of the parameters == NULL | |
* | |
*****************************************************************************/ | |
static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer, | |
IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect) | |
{ | |
- FIXME("iface %p, buffer %p, viewport %p, flags %#lx, rect %s stub!\n", | |
+ struct d3d_device *device = impl_from_IDirect3DDevice(iface); | |
+ struct d3d_execute_buffer *buffer_impl = unsafe_impl_from_IDirect3DExecuteBuffer(buffer); | |
+ struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport); | |
+ HRESULT hr; | |
+ | |
+ TRACE("iface %p, buffer %p, viewport %p, flags %#lx, rect %s.\n", | |
iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect)); | |
- return D3D_OK; | |
+ /* Sanity checks */ | |
+ if (!buffer) | |
+ { | |
+ WARN("NULL buffer, returning DDERR_INVALIDPARAMS\n"); | |
+ return DDERR_INVALIDPARAMS; | |
+ } | |
+ | |
+ if (!viewport) | |
+ { | |
+ WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n"); | |
+ return DDERR_INVALIDPARAMS; | |
+ } | |
+ | |
+ if (FAILED(hr = IDirect3DDevice3_SetCurrentViewport | |
+ (&device->IDirect3DDevice3_iface, &viewport_impl->IDirect3DViewport3_iface))) | |
+ return hr; | |
+ | |
+ /* Execute the pick */ | |
+ wined3d_mutex_lock(); | |
+ hr = d3d_execute_buffer_execute(buffer_impl, device, rect); | |
+ wined3d_mutex_unlock(); | |
+ | |
+ return hr; | |
} | |
/***************************************************************************** | |
@@ -1050,13 +1081,35 @@ static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteB | |
* D3DPickRec: Address to store the resulting D3DPICKRECORD array. | |
* | |
* Returns: | |
- * D3D_OK, because it's a stub | |
+ * D3D_OK always | |
* | |
*****************************************************************************/ | |
static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface, | |
DWORD *count, D3DPICKRECORD *records) | |
{ | |
- FIXME("iface %p, count %p, records %p stub!\n", iface, count, records); | |
+ struct d3d_device *device; | |
+ | |
+ TRACE("iface %p, count %p, records %p.\n", iface, count, records); | |
+ | |
+ /* Windows doesn't check if count is non-NULL */ | |
+ | |
+ wined3d_mutex_lock(); | |
+ | |
+ device = impl_from_IDirect3DDevice(iface); | |
+ | |
+ /* Set count to the number of pick records we have */ | |
+ *count = device->pick_record_count; | |
+ | |
+ /* It is correct usage according to documentation to call this function with records == NULL | |
+ to retrieve _just_ the record count, which the caller can then use to allocate an | |
+ appropriately sized array, then call this function again to fill that array with data. */ | |
+ if (records && count) | |
+ { | |
+ /* If we have a destination array and records to copy, copy them now */ | |
+ memcpy(records, device->pick_records, sizeof(*device->pick_records) * device->pick_record_count); | |
+ } | |
+ | |
+ wined3d_mutex_unlock(); | |
return D3D_OK; | |
} | |
diff --git a/dlls/ddraw/executebuffer.c b/dlls/ddraw/executebuffer.c | |
index 2f4c121789d..7d29cb5be62 100644 | |
--- a/dlls/ddraw/executebuffer.c | |
+++ b/dlls/ddraw/executebuffer.c | |
@@ -45,15 +45,106 @@ static void _dump_D3DEXECUTEBUFFERDESC(const D3DEXECUTEBUFFERDESC *lpDesc) { | |
TRACE("lpData : %p\n", lpDesc->lpData); | |
} | |
-HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d_device *device) | |
+#define TRIANGLE_SIZE 3 | |
+/***************************************************************************** | |
+ * d3d_execute_buffer_pick_test | |
+ * | |
+ * Determines whether a "point" is inside a "triangle". Mainly used when | |
+ * executing a "pick" from an execute buffer to determine whether a pixel | |
+ * coordinate (often a mouse coordinate) is inside a triangle (and | |
+ * therefore clicking or hovering over a 3D object in the scene). This | |
+ * function uses triangle rasterization algorithms to determine if the | |
+ * pixel falls inside (using the top-left rule, in accordance with | |
+ * documentation). | |
+ * | |
+ * Params: | |
+ * x: The X coordinate of the point to verify. | |
+ * y: The Y coordinate of the point to verify. | |
+ * verts: An array of vertices describing the screen coordinates of the | |
+ * triangle. This function expects 3 elements in this array. | |
+ * | |
+ * Returns: | |
+ * TRUE if the pixel coordinate is inside this triangle | |
+ * FALSE if not | |
+ * | |
+ *****************************************************************************/ | |
+static BOOL d3d_execute_buffer_pick_test(LONG x, LONG y, D3DTLVERTEX* verts) | |
+{ | |
+ UINT i; | |
+ | |
+ for (i = 0; i < TRIANGLE_SIZE; i++) | |
+ { | |
+ D3DTLVERTEX* v1 = &verts[(i) % TRIANGLE_SIZE]; | |
+ D3DTLVERTEX* v2 = &verts[(i + 1) % TRIANGLE_SIZE]; | |
+ D3DVALUE bias = 0.0f; | |
+ | |
+ /* Edge function - determines whether pixel is inside triangle */ | |
+ D3DVALUE w = (v2->sx - v1->sx) * (y - v1->sy) - (v2->sy - v1->sy) * (x - v1->sx); | |
+ | |
+ /* Force top-left rule */ | |
+ if ((v1->sy == v2->sy && v1->sx > v2->sx) || (v1->sy < v2->sy)) | |
+ bias = 1.0f; | |
+ | |
+ if (w < bias) | |
+ return FALSE; | |
+ } | |
+ | |
+ return TRUE; | |
+} | |
+ | |
+/***************************************************************************** | |
+ * d3d_execute_buffer_z_value_at_coords | |
+ * | |
+ * Returns the Z point of a triangle given an X, Y coordinate somewhere inside | |
+ * the triangle. Used as the `dvZ` parameter of D3DPICKRECORD. | |
+ * | |
+ * Params: | |
+ * x: The X coordinate of the point to verify. | |
+ * y: The Y coordinate of the point to verify. | |
+ * verts: An array of vertices describing the screen coordinates of the | |
+ * triangle. This function expects 3 elements in this array. | |
+ * | |
+ * Returns: | |
+ * A floating-point Z value that can be used directly as the dvZ member of a | |
+ * D3DPICKRECORD. | |
+ * | |
+ *****************************************************************************/ | |
+static D3DVALUE d3d_execute_buffer_z_value_at_coords(LONG x, LONG y, D3DTLVERTEX* verts) | |
+{ | |
+ UINT i; | |
+ | |
+ D3DVALUE z1 = 0; | |
+ D3DVALUE z2 = 0; | |
+ | |
+ for (i = 0; i < TRIANGLE_SIZE; i++) | |
+ { | |
+ D3DTLVERTEX* v1 = &verts[i]; | |
+ D3DTLVERTEX* v2 = &verts[(i + 1) % TRIANGLE_SIZE]; | |
+ D3DTLVERTEX* v3 = &verts[(i + 2) % TRIANGLE_SIZE]; | |
+ | |
+ z1 += v3->sz * (x - v1->sx) * (y - v2->sy) - v2->sz * (x - v1->sx) * (y - v3->sy); | |
+ z2 += (x - v1->sx) * (y - v2->sy) - (x - v1->sx) * (y - v3->sy); | |
+ } | |
+ | |
+ return z1 / z2; | |
+} | |
+ | |
+HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d_device *device, | |
+ D3DRECT* pick_rect) | |
{ | |
DWORD is = buffer->data.dwInstructionOffset; | |
char *instr = (char *)buffer->desc.lpData + is; | |
unsigned int i, primitive_size; | |
- struct wined3d_map_desc map_desc; | |
+ struct wined3d_map_desc map_desc, vert_map_desc; | |
struct wined3d_box box = {0}; | |
HRESULT hr; | |
+ /* Variables used for picking */ | |
+ const unsigned int vertex_size = get_flexible_vertex_size(D3DFVF_TLVERTEX); | |
+ D3DTLVERTEX verts[TRIANGLE_SIZE]; | |
+ | |
+ device->pick_record_count = 0; | |
+ | |
TRACE("ExecuteData :\n"); | |
if (TRACE_ON(ddraw)) | |
_dump_executedata(&(buffer->data)); | |
@@ -69,6 +160,26 @@ HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d | |
instr += sizeof(*current); | |
primitive_size = 0; | |
+ if (pick_rect != NULL) | |
+ { | |
+ switch (current->bOpcode) | |
+ { | |
+ /* None of these opcodes seem to be necessary for picking */ | |
+ case D3DOP_POINT: | |
+ case D3DOP_LINE: | |
+ case D3DOP_STATETRANSFORM: | |
+ case D3DOP_STATELIGHT: | |
+ case D3DOP_STATERENDER: | |
+ case D3DOP_TEXTURELOAD: | |
+ case D3DOP_SPAN: | |
+ FIXME("ignoring opcode %d for picking\n", current->bOpcode); | |
+ instr += count * size; | |
+ continue; | |
+ default: | |
+ break; | |
+ } | |
+ } | |
+ | |
switch (current->bOpcode) | |
{ | |
case D3DOP_POINT: | |
@@ -174,6 +285,66 @@ HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d | |
{ | |
case 3: | |
indices[(i * primitive_size) + 2] = ci->v3; | |
+ | |
+ if (pick_rect != NULL) { | |
+ UINT j; | |
+ | |
+ /* Get D3DTLVERTEX objects for each triangle vertex */ | |
+ for (j = 0; j < TRIANGLE_SIZE; j++) { | |
+ | |
+ /* Get index of vertex from D3DTRIANGLE struct */ | |
+ switch (j) { | |
+ case 0: box.left = vertex_size * ci->v1; break; | |
+ case 1: box.left = vertex_size * ci->v2; break; | |
+ case 2: box.left = vertex_size * ci->v3; break; | |
+ } | |
+ | |
+ box.right = box.left + vertex_size; | |
+ if (FAILED(hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->dst_vertex_buffer), | |
+ 0, &vert_map_desc, &box, WINED3D_MAP_WRITE))) { | |
+ return hr; | |
+ } else { | |
+ /* Copy vert data into stack array */ | |
+ verts[j] = *((D3DTLVERTEX*)vert_map_desc.data); | |
+ | |
+ wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->dst_vertex_buffer), 0); | |
+ } | |
+ } | |
+ | |
+ /* Use vertices acquired above to test for clicking */ | |
+ if (d3d_execute_buffer_pick_test(pick_rect->x1, pick_rect->y1, verts)) | |
+ { | |
+ D3DPICKRECORD* record; | |
+ | |
+ device->pick_record_count++; | |
+ | |
+ /* Grow the array if necessary */ | |
+ if (device->pick_record_count > device->pick_record_size) | |
+ { | |
+ if (device->pick_record_size == 0) device->pick_record_size = 1; | |
+ device->pick_record_size *= 2; | |
+ device->pick_records = heap_realloc(device->pick_records, | |
+ sizeof(*device->pick_records) * device->pick_record_size); | |
+ } | |
+ | |
+ /* Fill record parameters */ | |
+ record = &device->pick_records[device->pick_record_count - 1]; | |
+ | |
+ record->bOpcode = current->bOpcode; | |
+ record->bPad = 0; | |
+ | |
+ /* Write current instruction offset into file */ | |
+ record->dwOffset = (DWORD *)instr - (DWORD *)buffer->desc.lpData - is; | |
+ | |
+ /* Formula for returning the Z value at this X/Y */ | |
+ record->dvZ = d3d_execute_buffer_z_value_at_coords(pick_rect->x1, pick_rect->y1, verts); | |
+ | |
+ /* We have a successful pick so we can skip the rest of the triangles */ | |
+ instr += size * (count - i - 1); | |
+ count = i; | |
+ } | |
+ } | |
+ | |
/* Drop through. */ | |
case 2: | |
indices[(i * primitive_size) + 1] = ci->v2; | |
@@ -184,14 +355,18 @@ HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d | |
wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->index_buffer), 0); | |
- wined3d_stateblock_set_stream_source(device->state, 0, | |
- buffer->dst_vertex_buffer, 0, sizeof(D3DTLVERTEX)); | |
- wined3d_stateblock_set_vertex_declaration(device->state, | |
- ddraw_find_decl(device->ddraw, D3DFVF_TLVERTEX)); | |
- wined3d_stateblock_set_index_buffer(device->state, buffer->index_buffer, WINED3DFMT_R16_UINT); | |
- wined3d_device_apply_stateblock(device->wined3d_device, device->state); | |
- d3d_device_sync_surfaces(device); | |
- wined3d_device_context_draw_indexed(device->immediate_context, 0, index_pos, index_count, 0, 0); | |
+ /* Skip drawing if we're picking */ | |
+ if (pick_rect == NULL) | |
+ { | |
+ wined3d_stateblock_set_stream_source(device->state, 0, | |
+ buffer->dst_vertex_buffer, 0, sizeof(D3DTLVERTEX)); | |
+ wined3d_stateblock_set_vertex_declaration(device->state, | |
+ ddraw_find_decl(device->ddraw, D3DFVF_TLVERTEX)); | |
+ wined3d_stateblock_set_index_buffer(device->state, buffer->index_buffer, WINED3DFMT_R16_UINT); | |
+ wined3d_device_apply_stateblock(device->wined3d_device, device->state); | |
+ d3d_device_sync_surfaces(device); | |
+ wined3d_device_context_draw_indexed(device->immediate_context, 0, index_pos, index_count, 0, 0); | |
+ } | |
buffer->index_pos = index_pos + index_count; | |
break; | |
@@ -426,6 +601,7 @@ HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer, struct d3d | |
end_of_buffer: | |
return D3D_OK; | |
} | |
+#undef TRIANGLE_SIZE | |
static inline struct d3d_execute_buffer *impl_from_IDirect3DExecuteBuffer(IDirect3DExecuteBuffer *iface) | |
{ | |
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c | |
index cde80c58e99..a41f13badf7 100644 | |
--- a/dlls/ddraw/tests/ddraw1.c | |
+++ b/dlls/ddraw/tests/ddraw1.c | |
@@ -15432,6 +15432,136 @@ static void test_enum_devices(void) | |
ok(!refcount, "Device has %lu references left.\n", refcount); | |
} | |
+static void test_pick(void) | |
+{ | |
+ static D3DTLVERTEX tquad[] = | |
+ { | |
+ {{320.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, | |
+ {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, | |
+ {{320.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, | |
+ {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, | |
+ }; | |
+ IDirect3DExecuteBuffer *execute_buffer; | |
+ D3DEXECUTEBUFFERDESC exec_desc; | |
+ IDirect3DViewport *viewport; | |
+ IDirect3DDevice *device; | |
+ IDirectDraw *ddraw; | |
+ UINT inst_length; | |
+ HWND window; | |
+ HRESULT hr; | |
+ void *ptr; | |
+ DWORD rec_count; | |
+ D3DRECT pick_rect; | |
+ UINT screen_width = 640; | |
+ UINT screen_height = 480; | |
+ UINT hits = 0; | |
+ UINT nohits = 0; | |
+ int i, j; | |
+ | |
+ window = create_window(); | |
+ ddraw = create_ddraw(); | |
+ ok(!!ddraw, "Failed to create a ddraw object.\n"); | |
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL))) | |
+ { | |
+ skip("Failed to create a 3D device, skipping test.\n"); | |
+ IDirectDraw_Release(ddraw); | |
+ DestroyWindow(window); | |
+ return; | |
+ } | |
+ | |
+ viewport = create_viewport(device, 0, 0, screen_width, screen_height); | |
+ | |
+ memset(&exec_desc, 0, sizeof(exec_desc)); | |
+ exec_desc.dwSize = sizeof(exec_desc); | |
+ exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS; | |
+ exec_desc.dwBufferSize = 1024; | |
+ exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY; | |
+ | |
+ hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL); | |
+ ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr); | |
+ hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc); | |
+ ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr); | |
+ memcpy(exec_desc.lpData, tquad, sizeof(tquad)); | |
+ ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad); | |
+ emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4); | |
+ emit_tquad(&ptr, 0); | |
+ emit_end(&ptr); | |
+ inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData; | |
+ inst_length -= sizeof(tquad); | |
+ hr = IDirect3DExecuteBuffer_Unlock(execute_buffer); | |
+ ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr); | |
+ | |
+ set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length); | |
+ | |
+ /* Perform a number of picks, we should have a specific amount by the end */ | |
+ for (i = 0; i < screen_width; i += 80) | |
+ { | |
+ for (j = 0; j < screen_height; j += 60) | |
+ { | |
+ pick_rect.x1 = i; | |
+ pick_rect.y1 = j; | |
+ | |
+ hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); | |
+ ok(SUCCEEDED(hr), "Failed to perform pick, hr %#x.\n", hr); | |
+ hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); | |
+ ok(SUCCEEDED(hr), "Failed to get pick records, hr %#x.\n", hr); | |
+ if (rec_count > 0) | |
+ hits++; | |
+ else | |
+ nohits++; | |
+ } | |
+ } | |
+ | |
+ /* | |
+ We should have gotten precisely equal numbers of hits and no hits since our quad | |
+ covers exactly half the screen | |
+ */ | |
+ ok(hits == nohits, "Got a non-equal amount of pick successes/failures: %i vs %i.\n", hits, nohits); | |
+ | |
+ /* Try some specific pixel picks */ | |
+ pick_rect.x1 = 480; | |
+ pick_rect.y1 = 360; | |
+ hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); | |
+ ok(SUCCEEDED(hr), "Failed to perform pick, hr %#x.\n", hr); | |
+ hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); | |
+ ok(SUCCEEDED(hr), "Failed to get pick records, hr %#x.\n", hr); | |
+ ok(rec_count == 0, "Got incorrect number of pick records (expected 0): %i.\n", rec_count); | |
+ | |
+ pick_rect.x1 = 240; | |
+ pick_rect.y1 = 120; | |
+ hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); | |
+ ok(SUCCEEDED(hr), "Failed to perform pick, hr %#x.\n", hr); | |
+ rec_count = 0; | |
+ hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); | |
+ ok(SUCCEEDED(hr), "Failed to get pick records, hr %#x.\n", hr); | |
+ ok(rec_count == 1, "Got incorrect number of pick records (expected 1): %i.\n", rec_count); | |
+ | |
+ if (rec_count == 1) | |
+ { | |
+ D3DPICKRECORD record; | |
+ | |
+ hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record); | |
+ ok(SUCCEEDED(hr), "Failed to get pick records, hr %#x.\n", hr); | |
+ ok(rec_count == 1, "Got incorrect number of pick records (expected 1): %i.\n", rec_count); | |
+ | |
+ hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record); | |
+ ok(SUCCEEDED(hr), "Failed to get pick records, hr %#x.\n", hr); | |
+ ok(rec_count == 1, "Got incorrect number of pick records (expected 1): %i.\n", rec_count); | |
+ | |
+ /* Tests D3DPICKRECORD for correct information */ | |
+ ok(record.bOpcode == 3, "Got incorrect bOpcode: %i.\n", record.bOpcode); | |
+ ok(record.bPad == 0, "Got incorrect bPad: %i.\n", record.bPad); | |
+ ok(record.dwOffset == 24, "Got incorrect dwOffset: %i.\n", record.dwOffset); | |
+ ok(compare_float(record.dvZ, 1.0, 0.1), "Got incorrect dvZ: %f.\n", record.dvZ); | |
+ } | |
+ | |
+ destroy_viewport(device, viewport); | |
+ IDirect3DExecuteBuffer_Release(execute_buffer); | |
+ IDirect3DDevice_Release(device); | |
+ IDirectDraw_Release(ddraw); | |
+ DestroyWindow(window); | |
+} | |
+ | |
START_TEST(ddraw1) | |
{ | |
DDDEVICEIDENTIFIER identifier; | |
@@ -15551,4 +15681,5 @@ START_TEST(ddraw1) | |
run_for_each_device_type(test_texture_wrong_caps); | |
test_filling_convention(); | |
test_enum_devices(); | |
+ test_pick(); | |
} | |
-- | |
2.41.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment