From e763bbea8400992883baaa8759f70f04a067ac39 Mon Sep 17 00:00:00 2001 From: ohadrau Date: Sun, 20 Jan 2019 20:22:24 -0500 Subject: [PATCH 1/4] Integrate Window.takeScreenshot into examples --- examples/Examples.re | 36 ++++++++++++++++++++++++++++++------ src/Core/Window.re | 14 ++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/examples/Examples.re b/examples/Examples.re index 6b290a90c..2ad1934b0 100644 --- a/examples/Examples.re +++ b/examples/Examples.re @@ -17,6 +17,8 @@ type example = { type state = { examples: list(example), selectedExample: string, + scrotCounter: int, + window: option(Window.t), }; let state: state = { @@ -33,6 +35,8 @@ let state: state = { {name: "Input", render: w => InputExample.render(w)}, ], selectedExample: "Animation", + scrotCounter: 0, + window: None, }; let noop = () => (); @@ -85,13 +89,25 @@ module ExampleButton = { }; type action = - | SelectExample(string); + | SelectExample(string) + | TakeScreenshot + | SetWindow(Window.t); let reducer = (s: state, a: action) => { - let SelectExample(name) = a; - - let ret: state = {...s, selectedExample: name}; - ret; + switch (a) { + | SelectExample(name) => + {...s, selectedExample: name} + | TakeScreenshot => + switch (s.window) { + | Some(win) => + let filename = Printf.sprintf("Scrot_%d.tga", s.scrotCounter); + Window.takeScreenshot(win, filename); + {...s, scrotCounter: s.scrotCounter + 1} + | None => s + } + | SetWindow(window) => + {...s, window: Some(window)} + }; }; let init = app => { @@ -103,6 +119,7 @@ let init = app => { "Welcome to Revery!", ~createOptions={...Window.defaultCreateOptions, maximized}, ); + App.dispatch(app, SetWindow(win)); let render = () => { let s = App.getState(app); @@ -116,7 +133,14 @@ let init = app => { />; }; - let buttons = List.map(renderButton, s.examples); + let buttons = [ + App.dispatch(app, TakeScreenshot)} + />, + ...List.map(renderButton, s.examples) + ]; let exampleRender = getRenderFunctionSelector(s); let example = exampleRender(win); diff --git a/src/Core/Window.re b/src/Core/Window.re index db7a5e210..9d86926b2 100644 --- a/src/Core/Window.re +++ b/src/Core/Window.re @@ -323,6 +323,20 @@ let getDevicePixelRatio = (w: t) => { /. float_of_int(windowSizeInScreenCoordinates.width); }; +let takeScreenshot = (w: t, filename: string) => { + open Glfw; + + let {width, height}: Window.frameBufferSize = glfwGetFramebufferSize(w.glfwWindow); + + let image = Image.create(~width, ~height, ~numChannels=4, ~channelSize=1); + let buffer = Image.getBuffer(image); + + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + Image.save(image, filename); + Image.destroy(image); +}; + let destroyWindow = (w: t) => Glfw.glfwDestroyWindow(w.glfwWindow); let shouldClose = (w: t) => Glfw.glfwWindowShouldClose(w.glfwWindow); From d8be26efe64adbafdb91c5504ec6f318f110736a Mon Sep 17 00:00:00 2001 From: ohadrau Date: Sun, 20 Jan 2019 15:33:40 -0500 Subject: [PATCH 2/4] Add Window.takeScreenshot --- src/Core/Window.re | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Core/Window.re b/src/Core/Window.re index 9d86926b2..9464d2c04 100644 --- a/src/Core/Window.re +++ b/src/Core/Window.re @@ -326,11 +326,17 @@ let getDevicePixelRatio = (w: t) => { let takeScreenshot = (w: t, filename: string) => { open Glfw; - let {width, height}: Window.frameBufferSize = glfwGetFramebufferSize(w.glfwWindow); + let width = w.framebufferWidth; + let height = w.framebufferHeight; let image = Image.create(~width, ~height, ~numChannels=4, ~channelSize=1); let buffer = Image.getBuffer(image); + /* WebGL is weird in that we can't capture with glReadPixels during + a render operation. Instead, we want to wait till it's over (we + can force this by triggering a new render) and then taking the + screenshot */ + render(w); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); Image.save(image, filename); From 6575d1d8f430376db0e73178755eeee52dd1cf38 Mon Sep 17 00:00:00 2001 From: ohadrau Date: Thu, 24 Jan 2019 16:00:07 -0500 Subject: [PATCH 3/4] Change screen capture example --- examples/Examples.re | 29 ++----------- examples/ScreenCapture.re | 87 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 examples/ScreenCapture.re diff --git a/examples/Examples.re b/examples/Examples.re index 2ad1934b0..3ed7fd0c4 100644 --- a/examples/Examples.re +++ b/examples/Examples.re @@ -17,8 +17,6 @@ type example = { type state = { examples: list(example), selectedExample: string, - scrotCounter: int, - window: option(Window.t), }; let state: state = { @@ -33,10 +31,9 @@ let state: state = { {name: "Focus", render: _ => Focus.render()}, {name: "Stopwatch", render: _ => Stopwatch.render()}, {name: "Input", render: w => InputExample.render(w)}, + {name: "Screen Capture", render: w => ScreenCapture.render(w)}, ], selectedExample: "Animation", - scrotCounter: 0, - window: None, }; let noop = () => (); @@ -89,24 +86,12 @@ module ExampleButton = { }; type action = - | SelectExample(string) - | TakeScreenshot - | SetWindow(Window.t); + | SelectExample(string); let reducer = (s: state, a: action) => { switch (a) { | SelectExample(name) => {...s, selectedExample: name} - | TakeScreenshot => - switch (s.window) { - | Some(win) => - let filename = Printf.sprintf("Scrot_%d.tga", s.scrotCounter); - Window.takeScreenshot(win, filename); - {...s, scrotCounter: s.scrotCounter + 1} - | None => s - } - | SetWindow(window) => - {...s, window: Some(window)} }; }; @@ -119,7 +104,6 @@ let init = app => { "Welcome to Revery!", ~createOptions={...Window.defaultCreateOptions, maximized}, ); - App.dispatch(app, SetWindow(win)); let render = () => { let s = App.getState(app); @@ -133,14 +117,7 @@ let init = app => { />; }; - let buttons = [ - App.dispatch(app, TakeScreenshot)} - />, - ...List.map(renderButton, s.examples) - ]; + let buttons = List.map(renderButton, s.examples); let exampleRender = getRenderFunctionSelector(s); let example = exampleRender(win); diff --git a/examples/ScreenCapture.re b/examples/ScreenCapture.re new file mode 100644 index 000000000..2a3a55358 --- /dev/null +++ b/examples/ScreenCapture.re @@ -0,0 +1,87 @@ +open Revery.UI; +open Revery.UI.Components; +open Revery.Core; + +let backgroundColor = Color.hex("#212733"); +let activeBackgroundColor = Color.hex("#2E3440"); +let inactiveBackgroundColor = Color.hex("#272d39"); +let selectionHighlight = Color.hex("#90f7ff"); + +module ActionButton = { + let component = React.component("ActionButton"); + + let make = (~name, ~onClick, ()) => + component((_slots: React.Hooks.empty) => { + let wrapperStyle = + Style.make( + ~backgroundColor=selectionHighlight, + ~border=Style.Border.make(~width=4, ~color=activeBackgroundColor, ()), + () + ); + let textHeaderStyle = + Style.make( + ~color=Colors.black, + ~fontFamily="Roboto-Regular.ttf", + ~fontSize=14, + ~margin=16, + (), + ); + + + + }); + + let createElement = (~children as _, ~name, ~onClick, ()) => + React.element(make(~name, ~onClick, ())); +}; + +module CaptureArea = { + let component = React.component("Capture Area"); + + let make = (w) => + component((slots) => { + let (count, setCount, slots) = React.Hooks.state(0, slots); + let (file, setFile, _slots: React.Hooks.empty) = React.Hooks.state(None, slots); + + let capture = () => { + let exed = Environment.getExecutingDirectory(); + let filename = Printf.sprintf("Scrot_%d.tga", count); + let fullname = exed ++ filename; + Window.takeScreenshot(w, fullname); + setCount(count + 1); + setFile(Some(filename)); + }; + + let viewStyle = + Style.make( + ~position=LayoutTypes.Absolute, + ~left=0, + ~right=0, + ~top=0, + ~bottom=0, + ~flexDirection=LayoutTypes.Column, + () + ); + + let imageStyle = + Style.make( + ~width=400, + ~height=300, + () + ); + + + + (switch (file) { + | None => + | Some(src) => + }) + ; + + }); + + let createElement = (~w, ~children as _, ()) => React.element(make(w)); +}; + +let render = (w) => + ; From 3ad4e55ab6e4dd9ddc7a404ffcf19c3620669ed8 Mon Sep 17 00:00:00 2001 From: ohadrau Date: Thu, 24 Jan 2019 21:47:55 -0500 Subject: [PATCH 4/4] Fix formatting --- examples/Examples.re | 3 +-- examples/ScreenCapture.re | 27 +++++++++++---------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/examples/Examples.re b/examples/Examples.re index ecad79659..3baa9033b 100644 --- a/examples/Examples.re +++ b/examples/Examples.re @@ -93,8 +93,7 @@ type action = let reducer = (s: state, a: action) => { switch (a) { - | SelectExample(name) => - {...s, selectedExample: name} + | SelectExample(name) => {...s, selectedExample: name} }; }; diff --git a/examples/ScreenCapture.re b/examples/ScreenCapture.re index 333487ee8..d09f01f9d 100644 --- a/examples/ScreenCapture.re +++ b/examples/ScreenCapture.re @@ -26,7 +26,7 @@ module ActionButton = { ]; - + ; }); let createElement = (~children as _, ~name, ~onClick, ()) => @@ -36,10 +36,11 @@ module ActionButton = { module CaptureArea = { let component = React.component("Capture Area"); - let make = (w) => - component((slots) => { + let make = w => + component(slots => { let (count, setCount, slots) = React.Hooks.state(0, slots); - let (file, setFile, _slots: React.Hooks.empty) = React.Hooks.state(None, slots); + let (file, setFile, _slots: React.Hooks.empty) = + React.Hooks.state(None, slots); let capture = () => { let exed = Environment.getExecutingDirectory(); @@ -60,24 +61,18 @@ module CaptureArea = { flexDirection(`Column), ]; - let imageStyle = - Style.[ - width(400), - height(300), - ]; + let imageStyle = Style.[width(400), height(300)]; - (switch (file) { - | None => - | Some(src) => - }) + {switch (file) { + | None => + | Some(src) => + }} ; - }); let createElement = (~w, ~children as _, ()) => React.element(make(w)); }; -let render = (w) => - ; +let render = w => ;