mirror of
https://github.com/tsoding/boomer
synced 2024-11-14 18:12:47 +00:00
(#26) Make MIT-SHM support available via -d:mitshm build flag
This commit is contained in:
parent
cc5d79ebbe
commit
eb57fe89ee
@ -39,6 +39,12 @@ See issue [#26]. For an experimental Live Update feature compile the application
|
||||
$ nimble build -d:live
|
||||
```
|
||||
|
||||
For a faster Live Update feature based on MIT-SHM X11 extension use `-d:mitshm`:
|
||||
|
||||
```console
|
||||
$ nimble build -d:live -d:mitshm
|
||||
```
|
||||
|
||||
The feature is really unstable and experimental, so use it at your own risk.
|
||||
|
||||
## NixOS Overlay
|
||||
|
@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
import navigation
|
||||
import image
|
||||
import screenshot
|
||||
import config
|
||||
|
||||
import x11/xlib, x11/x, x11/xutil, x11/keysym, x11/xrandr, x11/xshm
|
||||
@ -11,11 +11,6 @@ import syscall
|
||||
|
||||
type Shader = tuple[path, content: string]
|
||||
|
||||
const
|
||||
IPC_PRIVATE = 0
|
||||
IPC_CREAT = 512
|
||||
IPC_RMID = 0
|
||||
|
||||
proc readShader(file: string): Shader =
|
||||
when nimvm:
|
||||
result.path = file
|
||||
@ -97,7 +92,7 @@ proc update(flashlight: var Flashlight, dt: float32) =
|
||||
else:
|
||||
flashlight.shadow = max(flashlight.shadow - 6.0 * dt, 0.0)
|
||||
|
||||
proc draw(screenshot: Image, camera: Camera, shader, vao, texture: GLuint,
|
||||
proc draw(screenshot: PXImage, camera: Camera, shader, vao, texture: GLuint,
|
||||
windowSize: Vec2f, mouse: Mouse, flashlight: Flashlight) =
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0)
|
||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
|
||||
@ -181,27 +176,6 @@ proc main() =
|
||||
DefaultRootWindow(display),
|
||||
addr attributes)
|
||||
|
||||
var shminfo: TXShmSegmentInfo
|
||||
var screenshot = XShmCreateImage(
|
||||
display, vi.visual, 24.cuint, ZPixmap, nil,
|
||||
addr shminfo,
|
||||
attributes.width.cuint,
|
||||
attributes.height.cuint)
|
||||
|
||||
shminfo.shmid = syscall(SHMGET,
|
||||
IPC_PRIVATE,
|
||||
screenshot.bytes_per_line * screenshot.height,
|
||||
IPC_CREAT or 0o777).cint
|
||||
shminfo.shmaddr = cast[cstring](syscall(SHMAT, shminfo.shmid, 0, 0))
|
||||
screenshot.data = shminfo.shmaddr
|
||||
shminfo.readOnly = 0
|
||||
|
||||
let err = XShmAttach(display, addr shminfo)
|
||||
echo "Status of XShmAttach call = ", err
|
||||
discard XSync(display, 0)
|
||||
|
||||
discard XShmGetImage(display, DefaultRootWindow(display), screenshot, 0.cint, 0.cint, AllPlanes);
|
||||
|
||||
var win = XCreateWindow(
|
||||
display, root,
|
||||
0, 0, attributes.width.cuint, attributes.height.cuint, 0,
|
||||
@ -231,8 +205,15 @@ proc main() =
|
||||
|
||||
var shaderProgram = newShaderProgram(vertexShader, fragmentShader)
|
||||
|
||||
let w = screenshot.width.float32
|
||||
let h = screenshot.height.float32
|
||||
var screenshot =
|
||||
when defined(mitshm):
|
||||
newMitshmScreenshot(display)
|
||||
else:
|
||||
newDefaultScreenshot(display)
|
||||
defer: screenshot.destroy(display)
|
||||
|
||||
let w = screenshot.image.width.float32
|
||||
let h = screenshot.image.height.float32
|
||||
var
|
||||
vao, vbo, ebo: GLuint
|
||||
vertices = [
|
||||
@ -279,13 +260,13 @@ proc main() =
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB.GLint,
|
||||
screenshot.width,
|
||||
screenshot.height,
|
||||
screenshot.image.width,
|
||||
screenshot.image.height,
|
||||
0,
|
||||
# TODO(#13): the texture format is hardcoded
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
screenshot.data)
|
||||
screenshot.image.data)
|
||||
glGenerateMipmap(GL_TEXTURE_2D)
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderProgram, "tex".cstring), 0)
|
||||
@ -403,52 +384,29 @@ proc main() =
|
||||
else:
|
||||
discard
|
||||
|
||||
camera.update(config, dt, mouse, screenshot,
|
||||
camera.update(config, dt, mouse, screenshot.image,
|
||||
vec2(wa.width.float32, wa.height.float32))
|
||||
flashlight.update(dt)
|
||||
|
||||
screenshot.draw(camera, shaderProgram, vao, texture,
|
||||
vec2(wa.width.float32, wa.height.float32),
|
||||
mouse, flashlight)
|
||||
screenshot.image.draw(camera, shaderProgram, vao, texture,
|
||||
vec2(wa.width.float32, wa.height.float32),
|
||||
mouse, flashlight)
|
||||
|
||||
glXSwapBuffers(display, win)
|
||||
glFinish()
|
||||
|
||||
discard XShmGetImage(display, DefaultRootWindow(display), screenshot, 0.cint, 0.cint, AllPlanes);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB.GLint,
|
||||
screenshot.width,
|
||||
screenshot.height,
|
||||
0,
|
||||
# TODO(#13): the texture format is hardcoded
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
screenshot.data)
|
||||
|
||||
when defined(live):
|
||||
screenshot = XGetSubImage(display, root,
|
||||
0, 0,
|
||||
screenshot.width.cuint,
|
||||
screenshot.height.cuint,
|
||||
AllPlanes,
|
||||
ZPixmap,
|
||||
screenshot,
|
||||
0, 0)
|
||||
screenshot.refresh(display)
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB.GLint,
|
||||
screenshot.width,
|
||||
screenshot.height,
|
||||
screenshot.image.width,
|
||||
screenshot.image.height,
|
||||
0,
|
||||
# TODO(#13): the texture format is hardcoded
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
screenshot.data)
|
||||
|
||||
discard XShmDetach(display, addr shminfo)
|
||||
discard XDestroyImage(screenshot)
|
||||
discard syscall(SHMDT, shminfo.shmaddr)
|
||||
discard syscall(SHMCTL, shminfo.shmid, IPC_RMID, 0)
|
||||
screenshot.image.data)
|
||||
discard XSync(display, 0)
|
||||
|
||||
main()
|
||||
|
@ -1,29 +0,0 @@
|
||||
import x11/xlib, x11/x
|
||||
|
||||
type Image* = PXImage
|
||||
|
||||
proc saveToPPM*(image: Image, filePath: string) =
|
||||
var f = open(filePath, fmWrite)
|
||||
defer: f.close
|
||||
writeLine(f, "P6")
|
||||
writeLine(f, image.width, " ", image.height)
|
||||
writeLine(f, 255)
|
||||
for i in 0..<(image.width * image.height):
|
||||
f.write(image.data[i * 4 + 2])
|
||||
f.write(image.data[i * 4 + 1])
|
||||
f.write(image.data[i * 4 + 0])
|
||||
|
||||
# NOTE: it's not possible to deallocate the returned Image because the
|
||||
# reference to XImage is lost.
|
||||
proc takeScreenshot*(display: PDisplay, root: TWindow): Image =
|
||||
var attributes: TXWindowAttributes
|
||||
discard XGetWindowAttributes(display, root, addr attributes)
|
||||
|
||||
result = XGetImage(display, root,
|
||||
0, 0,
|
||||
attributes.width.cuint,
|
||||
attributes.height.cuint,
|
||||
AllPlanes,
|
||||
ZPixmap)
|
||||
if result == nil:
|
||||
quit "Could not get a screenshot"
|
@ -1,6 +1,7 @@
|
||||
import x11/xlib
|
||||
|
||||
import config
|
||||
import la
|
||||
import image
|
||||
|
||||
const VELOCITY_THRESHOLD = 15.0
|
||||
|
||||
@ -19,8 +20,7 @@ type Camera* = object
|
||||
proc world*(camera: Camera, v: Vec2f): Vec2f =
|
||||
v / camera.scale
|
||||
|
||||
proc update*(camera: var Camera, config: Config, dt: float, mouse: Mouse, image: Image,
|
||||
windowSize: Vec2f) =
|
||||
proc update*(camera: var Camera, config: Config, dt: float, mouse: Mouse, image: PXImage, windowSize: Vec2f) =
|
||||
if abs(camera.deltaScale) > 0.5:
|
||||
let p0 = (camera.scalePivot - (windowSize * 0.5)) / camera.scale
|
||||
camera.scale = max(camera.scale + camera.delta_scale * dt, 0.01)
|
||||
|
108
src/screenshot.nim
Normal file
108
src/screenshot.nim
Normal file
@ -0,0 +1,108 @@
|
||||
import x11/xlib, x11/x, x11/xutil, x11/xshm
|
||||
import syscall
|
||||
|
||||
const
|
||||
IPC_PRIVATE = 0
|
||||
IPC_CREAT = 512
|
||||
IPC_RMID = 0
|
||||
|
||||
type ScreenshotBackend* = enum
|
||||
DEFAULT, # XGetImage
|
||||
MITSHM # XShmGetImage
|
||||
|
||||
type Screenshot* = object
|
||||
backend*: ScreenshotBackend
|
||||
image*: PXImage
|
||||
shminfo*: PXShmSegmentInfo
|
||||
|
||||
proc newDefaultScreenshot*(display: PDisplay): Screenshot =
|
||||
result.backend = DEFAULT
|
||||
|
||||
var root = DefaultRootWindow(display)
|
||||
var attributes: TXWindowAttributes
|
||||
discard XGetWindowAttributes(display, root, addr attributes)
|
||||
result.image = XGetImage(display, root,
|
||||
0, 0,
|
||||
attributes.width.cuint,
|
||||
attributes.height.cuint,
|
||||
AllPlanes,
|
||||
ZPixmap)
|
||||
|
||||
proc newMitshmScreenshot*(display: PDisplay): Screenshot =
|
||||
result.backend = MITSHM
|
||||
result.shminfo = cast[PXShmSegmentInfo](allocShared(sizeof(TXShmSegmentInfo)))
|
||||
|
||||
var root = DefaultRootWindow(display)
|
||||
var attributes: TXWindowAttributes
|
||||
discard XGetWindowAttributes(display, root, addr attributes)
|
||||
|
||||
let screen = DefaultScreen(display)
|
||||
result.image = XShmCreateImage(
|
||||
display,
|
||||
DefaultVisual(display, screen),
|
||||
DefaultDepthOfScreen(ScreenOfDisplay(display, screen)).cuint,
|
||||
ZPixmap,
|
||||
nil,
|
||||
result.shminfo,
|
||||
attributes.width.cuint,
|
||||
attributes.height.cuint)
|
||||
|
||||
result.shminfo.shmid = syscall(
|
||||
SHMGET,
|
||||
IPC_PRIVATE,
|
||||
result.image.bytes_per_line * result.image.height,
|
||||
IPC_CREAT or 0o777).cint
|
||||
|
||||
result.shminfo.shmaddr = cast[cstring](syscall(
|
||||
SHMAT,
|
||||
result.shminfo.shmid,
|
||||
0, 0))
|
||||
result.image.data = result.shminfo.shmaddr
|
||||
result.shminfo.readOnly = 0
|
||||
|
||||
discard XShmAttach(display, result.shminfo)
|
||||
discard XShmGetImage(display, root, result.image, 0.cint, 0.cint, AllPlanes)
|
||||
|
||||
proc refresh*(screenshot: var Screenshot, display: PDisplay) =
|
||||
var root = DefaultRootWindow(display)
|
||||
|
||||
case screenshot.backend
|
||||
of DEFAULT:
|
||||
screenshot.image =
|
||||
XGetSubImage(display, root,
|
||||
0, 0,
|
||||
screenshot.image.width.cuint,
|
||||
screenshot.image.height.cuint,
|
||||
AllPlanes,
|
||||
ZPixmap,
|
||||
screenshot.image,
|
||||
0, 0)
|
||||
of MITSHM:
|
||||
discard XShmGetImage(
|
||||
display,
|
||||
root, screenshot.image,
|
||||
0.cint, 0.cint,
|
||||
AllPlanes)
|
||||
|
||||
proc destroy*(screenshot: var Screenshot, display: PDisplay) =
|
||||
case screenshot.backend
|
||||
of DEFAULT:
|
||||
discard XDestroyImage(screenshot.image)
|
||||
of MITSHM:
|
||||
discard XSync(display, 0)
|
||||
discard XShmDetach(display, screenshot.shminfo)
|
||||
discard XDestroyImage(screenshot.image)
|
||||
discard syscall(SHMDT, screenshot.shminfo.shmaddr)
|
||||
discard syscall(SHMCTL, screenshot.shminfo.shmid, IPC_RMID, 0)
|
||||
deallocShared(screenshot.shminfo)
|
||||
|
||||
proc saveToPPM*(image: PXImage, filePath: string) =
|
||||
var f = open(filePath, fmWrite)
|
||||
defer: f.close
|
||||
writeLine(f, "P6")
|
||||
writeLine(f, image.width, " ", image.height)
|
||||
writeLine(f, 255)
|
||||
for i in 0..<(image.width * image.height):
|
||||
f.write(image.data[i * 4 + 2])
|
||||
f.write(image.data[i * 4 + 1])
|
||||
f.write(image.data[i * 4 + 0])
|
Loading…
Reference in New Issue
Block a user