diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 774e6dd2e31..9a408760bb1 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -4052,74 +4052,14 @@ static void transform_view(struct wined3d_context *context, const struct wined3d void transform_projection(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { const struct wined3d_gl_info *gl_info = context->gl_info; + struct wined3d_matrix projection; gl_info->gl_ops.gl.p_glMatrixMode(GL_PROJECTION); checkGLcall("glMatrixMode(GL_PROJECTION)"); - /* There are a couple of additional things we have to take into account - * here besides the projection transformation itself: - * - We need to flip along the y-axis in case of offscreen rendering. - * - OpenGL Z range is {-Wc,...,Wc} while D3D Z range is {0,...,Wc}. - * - D3D coordinates refer to pixel centers while GL coordinates refer - * to pixel corners. - * - D3D has a top-left filling convention. We need to maintain this - * even after the y-flip mentioned above. - * In order to handle the last two points, we translate by - * (63.0 / 128.0) / VPw and (63.0 / 128.0) / VPh. This is equivalent to - * translating slightly less than half a pixel. We want the difference to - * be large enough that it doesn't get lost due to rounding inside the - * driver, but small enough to prevent it from interfering with any - * anti-aliasing. */ - - if (context->last_was_rhw) - { - /* Transform D3D RHW coordinates to OpenGL clip coordinates. */ - double x = state->viewport.x; - double y = state->viewport.y; - double w = state->viewport.width; - double h = state->viewport.height; - double x_scale = 2.0 / w; - double x_offset = ((63.0 / 64.0) - (2.0 * x) - w) / w; - double y_scale = context->render_offscreen ? 2.0 / h : 2.0 / -h; - double y_offset = context->render_offscreen - ? ((63.0 / 64.0) - (2.0 * y) - h) / h - : ((63.0 / 64.0) - (2.0 * y) - h) / -h; - enum wined3d_depth_buffer_type zenable = state->fb->depth_stencil ? - state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE; - double z_scale = zenable ? 2.0f : 0.0f; - double z_offset = zenable ? -1.0f : 0.0f; - const GLdouble projection[] = - { - x_scale, 0.0, 0.0, 0.0, - 0.0, y_scale, 0.0, 0.0, - 0.0, 0.0, z_scale, 0.0, - x_offset, y_offset, z_offset, 1.0, - }; - - gl_info->gl_ops.gl.p_glLoadMatrixd(projection); - checkGLcall("glLoadMatrixd"); - } - else - { - double y_scale = context->render_offscreen ? -1.0 : 1.0; - double x_offset = (63.0 / 64.0) / state->viewport.width; - double y_offset = context->render_offscreen - ? (63.0 / 64.0) / state->viewport.height - : -(63.0 / 64.0) / state->viewport.height; - const GLdouble projection[] = - { - 1.0, 0.0, 0.0, 0.0, - 0.0, y_scale, 0.0, 0.0, - 0.0, 0.0, 2.0, 0.0, - x_offset, y_offset, -1.0, 1.0, - }; - - gl_info->gl_ops.gl.p_glLoadMatrixd(projection); - checkGLcall("glLoadMatrixd"); - - gl_info->gl_ops.gl.p_glMultMatrixf(&state->transforms[WINED3D_TS_PROJECTION]._11); - checkGLcall("glLoadMatrixf"); - } + get_projection_matrix(context, state, &projection); + gl_info->gl_ops.gl.p_glLoadMatrixf(&projection._11); + checkGLcall("glLoadMatrixf"); } /* This should match any arrays loaded in load_vertex_data. diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index a43029c1d12..4452f7cdf50 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -3138,6 +3138,70 @@ void get_modelview_matrix(const struct wined3d_context *context, const struct wi multiply_matrix(mat, &state->transforms[WINED3D_TS_VIEW], &state->transforms[WINED3D_TS_WORLD_MATRIX(0)]); } +void get_projection_matrix(const struct wined3d_context *context, const struct wined3d_state *state, + struct wined3d_matrix *mat) +{ + /* There are a couple of additional things we have to take into account + * here besides the projection transformation itself: + * - We need to flip along the y-axis in case of offscreen rendering. + * - OpenGL Z range is {-Wc,...,Wc} while D3D Z range is {0,...,Wc}. + * - D3D coordinates refer to pixel centers while GL coordinates refer + * to pixel corners. + * - D3D has a top-left filling convention. We need to maintain this + * even after the y-flip mentioned above. + * In order to handle the last two points, we translate by + * (63.0 / 128.0) / VPw and (63.0 / 128.0) / VPh. This is equivalent to + * translating slightly less than half a pixel. We want the difference to + * be large enough that it doesn't get lost due to rounding inside the + * driver, but small enough to prevent it from interfering with any + * anti-aliasing. */ + + if (context->last_was_rhw) + { + /* Transform D3D RHW coordinates to OpenGL clip coordinates. */ + float x = state->viewport.x; + float y = state->viewport.y; + float w = state->viewport.width; + float h = state->viewport.height; + float x_scale = 2.0f / w; + float x_offset = (float)((63.0 / 64.0 - (2.0 * x) - w) / w); + float y_scale = context->render_offscreen ? 2.0f / h : 2.0f / -h; + float y_offset = (float)(context->render_offscreen + ? (63.0 / 64.0 - (2.0 * y) - h) / h + : (63.0 / 64.0 - (2.0 * y) - h) / -h); + enum wined3d_depth_buffer_type zenable = state->fb->depth_stencil ? + state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE; + float z_scale = zenable ? 2.0f : 0.0f; + float z_offset = zenable ? -1.0f : 0.0f; + const struct wined3d_matrix projection = + { + x_scale, 0.0f, 0.0f, 0.0f, + 0.0f, y_scale, 0.0f, 0.0f, + 0.0f, 0.0f, z_scale, 0.0f, + x_offset, y_offset, z_offset, 1.0f, + }; + + *mat = projection; + } + else + { + float y_scale = context->render_offscreen ? -1.0f : 1.0f; + float x_offset = 63.0f / 64.0f * (1.0f / state->viewport.width); + float y_offset = context->render_offscreen + ? 63.0f / 64.0f * (1.0f / state->viewport.height) + : -63.0f / 64.0f * (1.0f / state->viewport.height); + const struct wined3d_matrix projection = + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, y_scale, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f, + x_offset, y_offset, -1.0f, 1.0f, + }; + + multiply_matrix(mat, &projection, &state->transforms[WINED3D_TS_PROJECTION]); + } +} + /* Setup this textures matrix according to the texture flags. */ /* Context activation is done by the caller (state handler). */ void set_texture_matrix(const struct wined3d_gl_info *gl_info, const struct wined3d_matrix *matrix, DWORD flags, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 98df60c4881..bd4f2e2afaa 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3037,6 +3037,8 @@ static inline BOOL shader_constant_is_local(const struct wined3d_shader *shader, void get_identity_matrix(struct wined3d_matrix *mat) DECLSPEC_HIDDEN; void get_modelview_matrix(const struct wined3d_context *context, const struct wined3d_state *state, struct wined3d_matrix *mat) DECLSPEC_HIDDEN; +void get_projection_matrix(const struct wined3d_context *context, const struct wined3d_state *state, + struct wined3d_matrix *mat) DECLSPEC_HIDDEN; /* Using additional shader constants (uniforms in GLSL / program environment * or local parameters in ARB) is costly: