生锈的Win32 OpenGL窗口:无法加载某些函数指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生锈的Win32 OpenGL窗口:无法加载某些函数指针相关的知识,希望对你有一定的参考价值。

#[cfg(windows)] extern crate winapi;

#[cfg(windows)] use winapi::shared::windef::HWND;
#[cfg(windows)] use winapi::shared::windef::HMENU;
#[cfg(windows)] use winapi::shared::windef::HBRUSH;
#[cfg(windows)] use winapi::shared::minwindef::HINSTANCE;

#[cfg(windows)] use winapi::shared::minwindef::UINT;
#[cfg(windows)] use winapi::shared::minwindef::DWORD;
#[cfg(windows)] use winapi::shared::minwindef::WPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LRESULT;
#[cfg(windows)] use winapi::um::winnt::LPCWSTR;

#[cfg(windows)] use winapi::um::winuser::WS_OVERLAPPEDWINDOW;
#[cfg(windows)] use winapi::um::winuser::WS_VISIBLE;
#[cfg(windows)] use winapi::um::winuser::WNDCLASSW;

#[cfg(windows)] use std::os::windows::ffi::OsStrExt;
#[cfg(windows)] use std::ffi::OsStr;

#[cfg(windows)] use std::os::raw::c_void;
#[cfg(windows)] use winapi::um::libloaderapi::GetProcAddress;
#[cfg(windows)] use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
static VS_SRC: &'static str = "
#version 150
in vec2 position;
void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}";

static FS_SRC: &'static str = "
#version 150
out vec4 out_color;
void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
}";

mod gl
{
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(windows)]
fn to_wstring(str : &str) -> Vec<u16>
{
    let v : Vec<u16> =
            OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
    v
}

#[cfg(windows)]
pub unsafe extern "system" fn window_proc(h_wnd :HWND,
    msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT
{
    if msg == winapi::um::winuser::WM_DESTROY {
        winapi::um::winuser::PostQuitMessage(0i32);
    }
    return winapi::um::winuser::DefWindowProcW(h_wnd, msg, w_param, l_param);
}

fn draw_gl_scene(window_width: i32, window_height: i32,
        h_dc: winapi::shared::windef::HDC)
{
    unsafe
    {
        let module = winapi::um::libloaderapi::LoadLibraryW(to_wstring("opengl32.dll")  .as_ptr());

        // gl::load_with(|s| GetProcAddress(module,
        //         s.as_ptr() as *const i8) as *const c_void);

        gl::Viewport::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::Viewport::is_loaded() {
            gl::Viewport(0, 0, window_width, window_height);
        } else {
            panic!("gl::Viewport was not loaded")
        }

        gl::ClearColor::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::ClearColor::is_loaded() {
            gl::ClearColor(0.12109375f32, 0.12109375f32, 0.12109375f32, 1.0f32);
        } else {
            panic!("gl::ClearColor was not loaded")
        }

        gl::GetError::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        let error_check_value: GLenum = gl::GetError();

        /*
        gl::CreateShader::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        let mut vertex_shader_id = 0u32;
        if gl::CreateShader::is_loaded() {
            vertex_shader_id = gl::CreateShader(gl::VERTEX_SHADER);
        } else {
            panic!("gl::CreateShader was not loaded")
        }
        */

        /*
        let c_str = std::ffi::CString::new(VS_SRC.as_bytes()).unwrap();
        gl::ShaderSource::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::ShaderSource::is_loaded() {
            gl::ShaderSource(vertex_shader_id, 1, &c_str.as_ptr(), std::ptr::null_mut());
        } else {
            // panic!("gl::ShaderSource was not loaded")
        }
        gl::CompileShader::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::CompileShader::is_loaded() {
            gl::CompileShader(vertex_shader_id);
        } else {
            // panic!("gl::CompileShader was not loaded")
        }
        let mut vertex_array_id: GLuint = 0u32;
        gl::GenVertexArrays::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::GenVertexArrays::is_loaded() {
            gl::GenVertexArrays(1, &mut vertex_array_id as *mut u32);
        } else {
            panic!("gl::GenVertexArrays was not loaded")
        }
        */

        gl::Clear::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::Clear::is_loaded() {
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT |     gl::STENCIL_BUFFER_BIT);
        } else {
            panic!("gl::Clear was not loaded")
        }
        winapi::um::wingdi::SwapBuffers(h_dc);
    }
}

fn main()
{
  unsafe
  {
    let class_name = to_wstring("OpenGL");

    let h_instance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null_mut());
    let wnd = WNDCLASSW {
        style: 0,
        lpfnWndProc: Some(window_proc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: winapi::um::winuser::LoadIconW(0 as HINSTANCE,
                                              winapi::um::winuser::IDI_APPLICATION),
        hCursor: winapi::um::winuser::LoadCursorW(0 as HINSTANCE,
                                                  winapi::um::winuser::IDI_APPLICATION),
        hbrBackground: 16 as HBRUSH,
        lpszMenuName: 0 as LPCWSTR,
        lpszClassName: class_name.as_ptr(),
    };

    winapi::um::winuser::RegisterClassW(&wnd);

    let window_width = 640;
    let window_height = 480;
    let h_wnd_window = winapi::um::winuser::CreateWindowExW(0, class_name.as_ptr(),
                       to_wstring("OpenGL Example").as_ptr(), WS_OVERLAPPEDWINDOW |     WS_VISIBLE,
                       0, 0, window_width, window_height, 0 as HWND, 0 as HMENU,    h_instance,
                       std::ptr::null_mut());

    let mut msg = winapi::um::winuser::MSG {
        hwnd : 0 as HWND,
        message : 0 as UINT,
        wParam : 0 as WPARAM,
        lParam : 0 as LPARAM,
        time : 0 as DWORD,
        pt : winapi::shared::windef::POINT { x: 0, y: 0, },
    };

    let h_dc = winapi::um::winuser::GetDC(h_wnd_window);
    let pfd = winapi::um::wingdi::PIXELFORMATDESCRIPTOR {
        nSize: std::mem::size_of::<winapi::um::wingdi::PIXELFORMATDESCRIPTOR>() as u16,
        nVersion: 1,
        dwFlags: winapi::um::wingdi::PFD_DRAW_TO_WINDOW
                | winapi::um::wingdi::PFD_SUPPORT_OPENGL |  winapi::um::wingdi::PFD_DOUBLEBUFFER,
        iPixelType: winapi::um::wingdi::PFD_TYPE_RGBA,
        cColorBits: 64,
        cRedBits: 0,
        cRedShift: 0,
        cGreenBits: 0,
        cGreenShift: 0,
        cBlueBits: 0,
        cBlueShift: 0,
        cAlphaBits: 0,
        cAlphaShift: 0,
        cAccumBits: 0,
        cAccumRedBits: 0,
        cAccumGreenBits: 0,
        cAccumBlueBits: 0,
        cAccumAlphaBits: 0,
        cDepthBits: 32,
        cStencilBits: 8,
        cAuxBuffers: 0,
        iLayerType: winapi::um::wingdi::PFD_MAIN_PLANE,
        bReserved: 0,
        dwLayerMask: 0,
        dwVisibleMask: 0,
        dwDamageMask: 0,
    };

    let pixel_format = winapi::um::wingdi::ChoosePixelFormat(h_dc,
            &pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
    winapi::um::wingdi::SetPixelFormat(h_dc, pixel_format,
            &pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
    let h_rc = winapi::um::wingdi::wglCreateContext(h_dc);
    winapi::um::wingdi::wglMakeCurrent(h_dc, h_rc);
    winapi::um::winuser::ShowWindow(h_wnd_window, winapi::um::winuser::SW_SHOW);

    loop
    {
        if winapi::um::winuser::PeekMessageW(&mut msg, 0u32 as HWND, 0u32, 0u32,
                                             winapi::um::winuser::PM_REMOVE) > 0i32 {
            if msg.message == winapi::um::winuser::WM_QUIT {
                break;
            } else {
                winapi::um::winuser::TranslateMessage(&mut msg);
                winapi::um::winuser::DispatchMessageW(&mut msg);
            }

        } else {
            draw_gl_scene(window_width, window_height, h_dc);
        }
    }
  }
}

上面的代码是我在这里过时项目的实现版本:https://www.codeproject.com/tips/1053658/win-gui-programming-in-rust-language/

使用最新版本的winapi和gl_generator作为唯一的两个依赖项,我扩展了入门代码,以便与Win32 API一起成功呈现OpenGL上下文,而不是像货物箱gl-rs的贡献者所建议的glfw。当在Windows机器上运行时,这个项目会显示一个黑屏,如this link.中所示

由于无法加载与着色器或顶点缓冲区对象相关的任何函数指针,因此到目前为止,任何进一步尝试渲染更实质的东西都没有结果。

如果你梳理函数draw_gl_scene,你会看到我有一个通用的“load_with”函数注释掉了一系列特定于函数的“load_with”函数以及执行代码或恐慌,具体取决于所讨论的函数是否“is_loaded”。通用的“load_with”我一直在遏制,直到编写功能特定的“加载”功能不再成立。

对于CreateShader,ShaderSource,CompileShader和GenVertexArrays,如果我取消注释其中任何一个,它们都不会成功加载。我确定这是一个用户错误,winapi和gl-rs之一的可能性或者winapi和gl_generator之间的异常交互是不可能的。我是如何解决这个问题的。如果你读到这么远,我感谢你的时间。

答案

阅读有关加载OGL指针的wikithis too

简而言之,对于Windows:

  • GetProcAddress仅对OpenGL <= 1.1有效
  • wglGetProcAddress仅对OpenGL> 1.1有效

此外,着色器的使用需要OpenGL> = 2.0。最好使用OGL> = 3.2 Core Profile。对于这种情况:

  • 你需要一个适当的OpenGL> = 3.0的上下文,它是使用wglCreateContextAttribsARB创建的。
  • 您需要一个有效的当前上下文来使用wglCreateContextAttribsARB获取指向wglGetProcAddress的指针。
  • 这种情况可能是暂时的。它可以用wglCreateContext创建。你得到那个指针后可以删除它;并创造“真实”的背景。

.

以上是关于生锈的Win32 OpenGL窗口:无法加载某些函数指针的主要内容,如果未能解决你的问题,请参考以下文章

使用 cygwin 编译器的定制 win32 窗口上的 OpenGL 不起作用

win32(全屏)无边框窗口重叠任务栏

在 Win32API 中注册一个窗口类

在启用 CLR 但没有 CRT 的 VC++ 中创建 Win32 dll

opengl窗口中,拾取物体后,如何弹出新窗口,并在新窗口里显示所拾取物体

Opengl:渲染到 Win32 API 上下文