我正在尝试在屏幕上绘制一个基本的“三角形”example,但在Haskell中使用gl和GLFW-b包。
我的代码是here:
-- https://learnopengl.com/#!Getting-started/Hello-Triangle
-- stuff from base
import Control.Monad (when, mapM)
import Foreign -- includes Ptr and Marshal, among other things.
-- we qualify these names so we can tell what's from GLFW
import qualified Graphics.UI.GLFW as GLFW
-- gl funcs all already have "gl" in their name
import Graphics.GL
width = 800 :: Int
height = 600 :: Int
vertexShaderSource = [
"#version 330 core\n",
"layout (location = 0) in vec3 position;\n",
"void main()\n",
"{\n",
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n",
"}\n"]
fragmentShaderSource = [
"#version 330 core\n",
"out vec4 color;\n",
"void main()\n",
"{\n",
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n",
"}\n"]
getSrcPointer :: [String] -> IO (Ptr (Ptr GLchar), Ptr GLint)
getSrcPointer sourceLines = do
let glcharLines = map (map (fromIntegral.fromEnum)) sourceLines
let linesLengths = map (fromIntegral.length) glcharLines
linesPtrs <- mapM newArray glcharLines
linesPtrsPtr <- newArray linesPtrs
lengthsPtr <- newArray linesLengths
return (linesPtrsPtr,lengthsPtr)
-- type KeyCallback = Window -> Key -> Int -> KeyState -> ModifierKeys -> IO ()
callback :: GLFW.KeyCallback
callback window key scanCode keyState modKeys = do
putStrLn (show key)
when (key == GLFW.Key'Escape && keyState == GLFW.KeyState'Pressed)
(GLFW.setWindowShouldClose window True)
main :: IO ()
main = do
-- init GLFW and set the appropriate options
_ <- GLFW.init
GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 3)
GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
GLFW.windowHint (GLFW.WindowHint'Resizable False)
-- create our window
maybeWindow <- GLFW.createWindow width height "Lesson 02" Nothing Nothing
case maybeWindow of
Nothing -> do
-- somehow we failed. Nothing to do but report that and quit.
putStrLn "Failed to create a GLFW window!"
GLFW.terminate
Just window -> do
-- set our context and callback
GLFW.makeContextCurrent (Just window)
GLFW.setKeyCallback window (Just callback)
-- define the viewport dimensions
(frameWidth,frameHeight) <- GLFW.getFramebufferSize window
glViewport 0 0 (fromIntegral frameWidth) (fromIntegral frameHeight)
-- build and compile our shader program.
successP <- malloc
-- vertex shader
vertexShader <- glCreateShader GL_VERTEX_SHADER
(linesPtrsPtr,lengthsPtr) <- getSrcPointer vertexShaderSource
glShaderSource vertexShader 1 linesPtrsPtr lengthsPtr
glCompileShader vertexShader
-- check for compilation errors
glGetShaderiv vertexShader GL_COMPILE_STATUS successP
success <- peek successP
when (success == 0) $ do
putStrLn "Vertex Shader Compile Error:"
let infoLength = 512
resultP <- malloc
infoLog <- mallocArray (fromIntegral infoLength)
glGetShaderInfoLog vertexShader (fromIntegral infoLength) resultP infoLog
result <- fromIntegral <$> peek resultP
logBytes <- peekArray result infoLog
putStrLn (map (toEnum.fromEnum) logBytes)
-- fragment shader
fragmentShader <- glCreateShader GL_FRAGMENT_SHADER
(linesPtrsPtr,lengthsPtr) <- getSrcPointer fragmentShaderSource
glShaderSource fragmentShader 1 linesPtrsPtr lengthsPtr
glCompileShader fragmentShader
-- check for compilation errors
glGetShaderiv fragmentShader GL_COMPILE_STATUS successP
success <- peek successP
when (success == 0) $ do
putStrLn "Fragment Shader Compile Error:"
let infoLength = 512
resultP <- malloc
infoLog <- mallocArray (fromIntegral infoLength)
glGetShaderInfoLog fragmentShader (fromIntegral infoLength) resultP infoLog
result <- fromIntegral <$> peek resultP
logBytes <- peekArray result infoLog
putStrLn (map (toEnum.fromEnum) logBytes)
-- link up the shaders
shaderProgram <- glCreateProgram
glAttachShader shaderProgram vertexShader
glAttachShader shaderProgram fragmentShader
glLinkProgram shaderProgram
-- check for linking errors
glGetProgramiv shaderProgram GL_LINK_STATUS successP
success <- peek successP
when (success == 0) $ do
putStrLn "Program Linking Error:"
let infoLength = 512
resultP <- malloc
infoLog <- mallocArray (fromIntegral infoLength)
glGetProgramInfoLog shaderProgram (fromIntegral infoLength) resultP infoLog
result <- fromIntegral <$> peek resultP
logBytes <- peekArray result infoLog
putStrLn (map (toEnum.fromEnum) logBytes)
-- cleanup the sub-programs now that our complete shader program is ready
glDeleteShader vertexShader
glDeleteShader fragmentShader
-- setup vertex data and attribute pointers
verticesP <- newArray ([
-0.5, -0.5, 0.0, -- Left
0.5, -0.5, 0.0, -- Right
0.0, 0.5, 0.0 -- Top
] :: [GLfloat])
let verticesSize = fromIntegral $ sizeOf (0.0 :: GLfloat) * 9
vboP <- malloc :: IO (Ptr GLuint)
vaoP <- malloc :: IO (Ptr GLuint)
glGenVertexArrays 1 vaoP
glGenBuffers 1 vboP
-- Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
vao <- peek vaoP
glBindVertexArray vao
vbo <- peek vboP
glBindBuffer GL_ARRAY_BUFFER vbo
glBufferData GL_ARRAY_BUFFER verticesSize (castPtr verticesP) GL_STATIC_DRAW
let threeFloats = fromIntegral $ sizeOf (0.0::GLfloat) * 3
glVertexAttribPointer 0 3 GL_FLOAT GL_FALSE threeFloats nullPtr
glEnableVertexAttribArray 0
-- Note that this is allowed, the call to glVertexAttribPointer
-- registered VBO as the currently bound vertex buffer object so
-- afterwards we can safely unbind
glBindBuffer GL_ARRAY_BUFFER 0
-- Unbind VAO (it's always a good thing to unbind any buffer/array
-- to prevent strange bugs)
glBindVertexArray 0
-- "game loop"
let loop :: IO ()
loop = do
shouldClose <- GLFW.windowShouldClose window
if shouldClose
then return ()
else do
-- event poll
GLFW.pollEvents
-- clear the screen
glClearColor 0.2 0.3 0.3 1.0
glClear GL_COLOR_BUFFER_BIT
-- draw a triangle
glUseProgram shaderProgram
glBindVertexArray vao
glDrawArrays GL_TRIANGLES 0 3
glBindVertexArray 0
-- swap buffers and go again
GLFW.swapBuffers window
loop
loop
-- clean up the gl resources
glDeleteVertexArrays 1 vaoP
glDeleteBuffers 1 vboP
-- clean up the GLFW resources
GLFW.terminate
它编译并运行时没有任何报告错误,但它只显示清晰的颜色;根本没有绘制三角形。