Can't run OpenGL on Haskell [duplicate] - opengl

Here is my source code I'm trying to get to work:
In Main.hs:
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Bindings
import Data.IORef
main = do
(progname,_) <- getArgsAndInitialize
createWindow "Hello World"
reshapeCallback $= Just reshape
keyboardMouseCallback $= Just keyboardMouse
angle <- newIORef 0.0
displayCallback $= display
idleCallback $= Just idle
mouseWheelCallback $= Just mouseWheel
mainLoop
In Bindings.hs:
module Bindings where
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
display :: IO ()
display = return ()
overlayDisplay :: IO ()
overlayDisplay = return ()
visibility :: Visibility -> IO ()
visibility v = return ()
reshape :: Size -> IO ()
reshape s#(Size w h) = do
viewport $= (Position 0 0, s)
close :: IO ()
close = return ()
keyboardMouse :: Key -> KeyState -> Modifiers -> Position -> IO ()
keyboardMouse key state modifiers position = return ()
mouseWheel :: WheelNumber -> WheelDirection -> Position -> IO ()
mouseWheel wn wd p = return ()
idle :: IO ()
idle = return ()
It works if I use normal glut32.dll and none of the freeglut extensions in my code, but I want to use the freeglut extensions.
When I use freeglut.dll, rename it to glut32.dll, and put it in the same folder as my .exe, it gives me the error:
main: user error (unknown GLUT entry glutInit)
When I use the normal glut32.dll in the same way I get the error:
main: user error (unknown GLUT entry glutMouseWheelFunc)

download glut from http://www.transmissionzero.co.uk/software/freeglut-devel/. Be sure to download the MinGW version.
copy the file freeglut-MinGW-3.0.0-1.mp.zip\freeglut\bin\x64\freeglut.dll to C:\Windows\System32. Make sure you get the 64 bit version from the x64 folder.
rename it as glut32.dll
I just solved this problem and hope this could help others.

You have to use freeglut .lib/.dll from Mingw or compile it yourself.

Related

Rust and OpenGL setup

I'm trying to export my OpenGL game from C++ to Rust and achieve 2 things:
1. Print OpenGL error messages to console.
2. Autocompletion of GL functions and constants in my IDE (Visual Studio Code).
I simly generated OpenGL bindings with gl_generator crate and copied bindings.rs file to my cargo.
extern crate sdl2;
mod bindings;
use bindings as GL;
fn main() {
let sdl = sdl2::init().unwrap();
let mut event_pump = sdl.event_pump().unwrap();
let video_subsystem = sdl.video().unwrap();
let gl_attr = video_subsystem.gl_attr();
gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
gl_attr.set_context_version(4, 5);
let window = video_subsystem.window("Window", 900, 700).opengl().resizable().build().unwrap();
let _gl_context = window.gl_create_context().unwrap();
let gl = GL::Gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void);
unsafe{ gl.Viewport(0, 0, 900, 700); }
'main: loop {
unsafe {
gl.UseProgram(42); // <- error (^ GL error triggered: 1281)
gl.ClearColor(0.0, 0.3, 0.6, 1.0 );
gl.Clear(GL::COLOR_BUFFER_BIT);
}
window.gl_swap_window();
for event in event_pump.poll_iter() {
match event {
sdl2::event::Event::Quit {..} => { break 'main },
_ => {},
}
}
}
}
The problem is that gl variable, where all functions are stored, is not global and I'm not sure how to use it with different modules/functions.
The reason why all functions are inside Gl struct is because I used DebugStructGenerator in my build function. It prints not only errors but all OpenGL function calls (e.g., [OpenGL] ClearColor(0.0, 0.3, 0.6, 1.0)). Would be great if it only printed error messages.
My build.rs file:
extern crate gl_generator;
use gl_generator::{Registry, Fallbacks, /*StructGenerator, GlobalGenerator,*/ DebugStructGenerator, Api, Profile};
use std::env;
use std::fs::File;
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let mut file_gl = File::create(&Path::new(&out_dir).join("bindings.rs")).unwrap();
let registry = Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [ "GL_NV_command_list" ]);
registry.write_bindings(DebugStructGenerator, &mut file_gl).unwrap();
}
There is no need to include the bindings.rs:
pub mod gl {
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}
Include this in your main.rs or lib.rs. Then you can include the gl functions from any of your modules just with (as gl is includes as pub module):
// anywhere in a module
use crate::gl; // static gl with lot of constants e.g gl::ARRAY_BUFFER
use crate::gl::Gl; // gl instance struct with gl: &Gl => gl.bindBuffer(...)
use crate::gl::types::*; // include all gl types like GLuint, GLenum, ...
As we are in rust, you need to provide your gl instance to your functions as reference or whatever you want.
Maybe check lazy_static, which can be used as global variable:
lazy_static! {
pub static ref gl: gl::Gl = create_opengl_context();
}
First access to gl will call the create context function. Repeated calls will use the created instance.
Maybe have a look at my game-gl library (graphics branch) at
https://github.com/Kaiser1989/game-gl or the example at https://github.com/Kaiser1989/rust-android-example. (Android and Windows openGL game loop framework)
.

Why glium `Headless` can not render an image like normal window context?

I am working on an off-screen render program and I use crate glium to do this. I have followed the example of screenshot.rs and this example worked well.
Then I made some change:
The orignal code was
fn main() {
// building the display, ie. the main object
let event_loop = glutin::EventsLoop::new();
let wb = glutin::WindowBuilder::new().with_visible(true);
let cb = glutin::ContextBuilder::new();
let display = glium::Display::new(wb, cb, &event_loop).unwrap();
// building the vertex buffer, which contains all the vertices that we will draw
I grouped these codes into a function:
fn main() {
// building the display, ie. the main object
let event_loop = glutin::EventsLoop::new();
let display = build_display((128,128), &event_loop);
// building the vertex buffer, which contains all the vertices that we will draw
pub fn build_display(size: (u32, u32), event_loop: &glutin::EventsLoop) -> glium::Display {
let version = parse_version(); //this will return `OpenGL 3.3`
let wb = glutin::WindowBuilder::new()
.with_visibility(false)
.with_dimensions(glutin::dpi::LogicalSize::from(size));
let cb = glutin::ContextBuilder::new()
.with_gl(version);
glium::Display::new(wb, cb, &event_loop).unwrap()
}
After this modification, the program still worked well. So I continued to add the headless-context:
fn main() {
// building the display, ie. the main object
let event_loop = glutin::EventsLoop::new();
let display = build_display_headless((128,128), &event_loop);
// building the vertex buffer, which contains all the vertices that we will draw
pub fn build_display_headless(size: (u32, u32), event_loop: &glutin::EventsLoop) -> glium::HeadlessRenderer {
let version = parse_version(); // this will return `OpenGL 3.3`
let ctx = glutin::ContextBuilder::new()
.with_gl(version)
.build_headless(&event_loop, glutin::dpi::PhysicalSize::from(size))
.expect("1");
//let ctx = unsafe { ctx.make_current().expect("3") };
glium::HeadlessRenderer::new(ctx).expect("4")
}
But this time, the program did not work. There was no panic during the running, but the output image was empty with black, and its size was not 128x128 but 800x600.
I have tried to remove the libEGL.dll so that, due to the doc of crate glutin, the function .build_headless will build a window and hide it, just as my function build_display does. However, this failed too. So what can cause this?

How can i read two buttons being pressed at the same time in Ocaml Graphics?

I'm making a simple space invaders in Ocaml using the graphics module. You can move the ship with 'a' and 'd', and shoot with space. My problem is that i cant make that you move and shoot at the same time. When I'm pressing 'd' to move and then i press space to shoot, the ship shoots but stop moving even if i never stop pressing 'd'.
let rec handler state old_time =
...
...
let event = Graphics.wait_next_event [ Graphics.Poll ] in
if event.Graphics.keypressed then
match (read_key ()) with
|'a' -> handler { new_state with player = ((fst new_state.player) - 20, snd new_state.player) } new_time
|'d' -> handler { new_state with player = ((fst new_state.player) + 20, snd new_state.player) } new_time
|' ' -> handler (fire_bullet new_state) new_time
| _ -> handler new_state new_time
else
handler new_state new_time
;;
I know about read_key reading from a queue and all that, but the problem is that he stops seeing that i'm holding down a key when i press another key.
Does anyone know how to solve this?
thanks.
The keyboard interface exposed by the graphics module is a bit limited.
You might consider using OCamlSDL instead. The Sdlkey and Sdlevent modules provide a more fine grained interface to the keyboard (amongst other things). In particular, you can detect KEYDOWN and KEYUP events.
let printf = Format.printf
let rec poll_keys () =
let open Sdlevent in
if has_event () then begin
match wait_event () with
| KEYDOWN {keysym=key} -> printf "keydown '%c'#." (Sdlkey.char_of_key key)
| KEYUP {keysym=key} -> printf "keyup '%c'#." (Sdlkey.char_of_key key)
| _ -> Sdltimer.delay 5
end;
poll_keys ()
let () =
Sdl.init [`VIDEO];
(* Sdlkey.enable_key_repeat (); *)
poll_keys ()

PureScript FFI & Aff Monad: Why does the effect never run?

I'm a total PureScript newbie and need a bit of help figuring out why a FFI function modeled with the Aff monad doesn't seem to be working for me.
The expected behavior is to log a message "keyMessage" to the console after 1000ms.
Instead, the program just hangs indefinitely after the following output:
Compiling Main
* Build successful.
Waiting for message...
Main.purs:
module Main where
import Prelude
import Control.Monad.Aff (Aff, Fiber, launchAff)
import Control.Monad.Aff.Console (log)
import Control.Monad.Eff (Eff, kind Effect)
import Control.Monad.Eff.Console (CONSOLE)
main :: forall e. Eff (console :: CONSOLE, to :: TIMEOUT | e) (Fiber (console :: CONSOLE, to :: TIMEOUT | e) Unit)
main = launchAff do
log "Waiting for message..."
m <- message "key"
log m
foreign import data TIMEOUT :: Effect
foreign import message :: forall e. String -> Aff (to :: TIMEOUT | e) String
Main.js:
'use strict';
exports.message = function(key) {
return function(errback, callback) {
var timeout = setTimeout(function() {
callback(key + 'Message');
}, 1000);
return function() {
return function (cancelErrback, cancelCallback) {
clearTimeout(timeout);
return cancelCallback();
};
};
};
};
Thanks in advance for your insights!
If you're using the latest major version of purescript-aff (v4 or later) then the runtime representation of Aff has changed, and you can't create it directly using the errback/callback function style anymore.
Take a look at the https://pursuit.purescript.org/packages/purescript-aff/4.0.2/docs/Control.Monad.Aff.Compat module, in particular the EffFnAff type / fromEffFnAff functions for an explanation of how the equivalent thing works now.
Alternatively you can also construct Affs with makeAff, but that would require reformulating your FFI code a bit.

different output with mono on linux as on visual studio on win7 with calling a webservice

I use the Exchange webservices to extract attachments from exchange mailserver.
When i call the code on linux with mono a certain text attachment contain some mixed-up strings.
like so
"sam winglin vz" becomes "sainglin vz" -> so it is missing "m w".
I see this about 3 times in a 150kb file. 3 bytes are missing in the linux output vs the windows output.
When i extract it from visual studio the text attachment is perfect.
It is like this example
Save attachments from exchange inbox
Any idea in what direction i should look to fix this?
Code:
#r "Microsoft.Exchange.WebServices.dll"
open Microsoft
open Microsoft.Exchange.WebServices.Data
open System
open System.Net
type PgzExchangeService(url,user,password) =
let service = new ExchangeService(ExchangeVersion.Exchange2007_SP1,
TimeZoneInfo.CreateCustomTimeZone("Central Standard Time",new TimeSpan(-6, 0, 0),"(GMT-06:00) Central Time (US & Canada)","Central Standard Time"))
do
ServicePointManager.ServerCertificateValidationCallback <- ( fun _ _ _ _ -> true )
service.Url <- new Uri(url)
service.Credentials <- new WebCredentials(user, password, "domain")
member this.Service with get() = service
member this.InboxItems = this.Service.FindItems(WellKnownFolderName.Inbox, new ItemView(10))
member this.GetFileAttachments ( item : Item ) =
let emailMessage =
EmailMessage.Bind( this.Service,
item.Id,
new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments))
item, emailMessage.Attachments |> Seq.choose (fun attachment -> match box attachment with
| :? FileAttachment as x -> Some(x) | _ -> None)
let mailAtdomain = new PgzExchangeService("https://xx.xx.XX.XX/EWS/Exchange.asmx", "user", "passw")
let printsave (item : Item ,att : seq<FileAttachment>) =
if (Seq.length att) > 0 then
printfn "%A - saving %i attachments" item.Subject (Seq.length att)
att |> Seq.iter ( fun attachment -> printfn "%A" attachment.Name
attachment.Load(#"/tmp/test/" + attachment.Name ) )
// filter so we only have items with attachements and ...
let itemsWithAttachments = mailAtdomain.InboxItems
|> Seq.map mailAtdomain.GetFileAttachments
|> Seq.iter printsave
The code doesn't run on Windows with mono due to a bug in TimeZoneInfo
This sample code runs on linux but not on windows. because of the TimeZoneInfo bug.
But with this the code that works on linux to extract attachments.
Try csv attachments and see if the result is the same. i loose data ! about 3 bytes every somemany lines
mail me if you need the sample csv attachment that gives the problem
Here is a c# version that i used for testing. Running from VS2010 it works perfect but on linux with mono the attachment has wrong size , some bytes are missing?!.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace Exchange_SDP_Attachment_Extracter
{
public class PgzExchangeService
{
public void Extract()
{
ExchangeService service = new ExchangeService (ExchangeVersion.Exchange2007_SP1,TimeZoneInfo.Local);
service.Credentials = new NetworkCredential("user", "pass", "domain");
service.Url = new Uri("https://xx.xx.xx.xx/EWS/Exchange.asmx");
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, new ItemView(10));
foreach (Item item in findResults.Items)
{
EmailMessage e = EmailMessage.Bind
(service,
item.Id,
new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
foreach ( Attachment att in e.Attachments )
{
if (att is FileAttachment)
{
FileAttachment fileAttachment = (FileAttachment)att;
fileAttachment.Load(#"/tmp/testsdp/" + fileAttachment.Name);
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
PgzExchangeService pgz = new PgzExchangeService();
pgz.Extract();
}
}
}
My suggestion would be to try examining the text attachment with a hex editor. There has be something unusual about those three occurrences. You need to find out what those three lines have in common before any of us can recommend a course of action to you.