diff --git a/README.md b/README.md index b8be978..e81894a 100644 --- a/README.md +++ b/README.md @@ -99,14 +99,9 @@ Q q T t | ✅ | quadratic to | A a | ✅ | arc to | z | ✅ | close path | -### Realtime Examples +### Pixie + GPU -Here are some examples of using Pixie for realtime rendering with some popular windowing libraries: - -* [examples/realtime_glfw.nim](examples/realtime_glfw.nim) -* [examples/realtime_glut.nim](examples/realtime_glut.nim) -* [examples/realtime_sdl.nim](examples/realtime_sdl.nim) -* [examples/realtime_win32.nim](examples/realtime_win32.nim) +To learn how to use Pixie for realtime graphics with GPU, check out [Boxy](https://github.com/treeform/boxy). ## Testing diff --git a/examples/realtime_glfw.nim b/examples/realtime_glfw.nim deleted file mode 100644 index 4a2d348..0000000 --- a/examples/realtime_glfw.nim +++ /dev/null @@ -1,81 +0,0 @@ -## This example show how to have real time pixie using glfw API. - -import math, opengl, pixie, staticglfw - -let - w: int32 = 256 - h: int32 = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - frameCount = 0 - window: Window - -proc display() = - ## Called every frame by main while loop - - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - - # update texture with new pixels from surface - var dataPtr = ctx.image.data[0].addr - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GLsizei w, GLsizei h, GL_RGBA, - GL_UNSIGNED_BYTE, dataPtr) - - # draw a quad over the whole screen - glClear(GL_COLOR_BUFFER_BIT) - glBegin(GL_QUADS) - glTexCoord2d(0.0, 0.0); glVertex2d(-1.0, +1.0) - glTexCoord2d(1.0, 0.0); glVertex2d(+1.0, +1.0) - glTexCoord2d(1.0, 1.0); glVertex2d(+1.0, -1.0) - glTexCoord2d(0.0, 1.0); glVertex2d(-1.0, -1.0) - glEnd() - - inc frameCount - swapBuffers(window) - -if init() == 0: - quit("Failed to Initialize GLFW.") - -windowHint(RESIZABLE, false.cint) -window = createWindow(w.cint, h.cint, "GLFW/Pixie", nil, nil) - -makeContextCurrent(window) -loadExtensions() - -# allocate a texture and bind it -var dataPtr = ctx.image.data[0].addr -glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei w, GLsizei h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, dataPtr) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) -glEnable(GL_TEXTURE_2D) - -while windowShouldClose(window) != 1: - pollEvents() - display() diff --git a/examples/realtime_glut.nim b/examples/realtime_glut.nim deleted file mode 100644 index 155f266..0000000 --- a/examples/realtime_glut.nim +++ /dev/null @@ -1,78 +0,0 @@ -## This example show how to have real time pixie using glut API. - -import math, opengl, opengl/glu, opengl/glut, pixie - -let - w: int32 = 256 - h: int32 = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - frameCount = 0 - -proc display() {.cdecl.} = - ## Called every frame by GLUT - - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - # update texture with new pixels from surface - var dataPtr = ctx.image.data[0].addr - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GLsizei w, GLsizei h, GL_RGBA, - GL_UNSIGNED_BYTE, dataPtr) - - # draw a quad over the whole screen - glClear(GL_COLOR_BUFFER_BIT) - glBegin(GL_QUADS) - glTexCoord2d(0.0, 0.0); glVertex2d(-1.0, +1.0) - glTexCoord2d(1.0, 0.0); glVertex2d(+1.0, +1.0) - glTexCoord2d(1.0, 1.0); glVertex2d(+1.0, -1.0) - glTexCoord2d(0.0, 1.0); glVertex2d(-1.0, -1.0) - glEnd() - glutSwapBuffers() - - inc frameCount - - glutPostRedisplay() # ask glut to draw next frame - -glutInit() -glutInitDisplayMode(GLUT_DOUBLE) -glutInitWindowSize(w, h) -discard glutCreateWindow("GLUT/Pixie") - -glutDisplayFunc(display) -loadExtensions() - -# allocate a texture and bind it -var dataPtr = ctx.image.data[0].addr -glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei w, GLsizei h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, dataPtr) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) -glEnable(GL_TEXTURE_2D) - -glutMainLoop() diff --git a/examples/realtime_sdl.nim b/examples/realtime_sdl.nim deleted file mode 100644 index 1a69b48..0000000 --- a/examples/realtime_sdl.nim +++ /dev/null @@ -1,75 +0,0 @@ -## This example show how to have real time pixie using sdl2 API. - -import math, pixie, sdl2, sdl2/gfx - -const - rmask = uint32 0x000000ff - gmask = uint32 0x0000ff00 - bmask = uint32 0x00ff0000 - amask = uint32 0xff000000 - -let - w: int32 = 256 - h: int32 = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - frameCount = 0 - window: WindowPtr - render: RendererPtr - mainSurface: SurfacePtr - mainTexture: TexturePtr - evt = sdl2.defaultEvent - -proc display() = - ## Called every frame by main while loop - - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: pixie.color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: pixie.color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: pixie.color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: pixie.color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - inc frameCount - - var dataPtr = ctx.image.data[0].addr - mainSurface = createRGBSurfaceFrom(dataPtr, cint w, cint h, cint 32, cint 4*w, - rmask, gmask, bmask, amask) - mainTexture = render.createTextureFromSurface(mainSurface) - destroy(mainSurface) - - render.clear() - render.copy(mainTexture, nil, nil) - destroy(mainTexture) - - render.present() - -discard sdl2.init(INIT_EVERYTHING) -window = createWindow("SDL/Pixie", 100, 100, cint w, cint h, SDL_WINDOW_SHOWN) -render = createRenderer(window, -1, 0) - -while true: - while pollEvent(evt): - if evt.kind == QuitEvent: - quit(0) - display() - delay(14) diff --git a/examples/realtime_win32.nim b/examples/realtime_win32.nim deleted file mode 100644 index 3010ed6..0000000 --- a/examples/realtime_win32.nim +++ /dev/null @@ -1,144 +0,0 @@ -## This example show how to have real time pixie using win32 API. - -import pixie, winim/lean - -let - w: int32 = 256 - h: int32 = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - frameCount = 0 - hwnd: HWND - running = true - -proc draw() = - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - - inc frameCount - - # Draw image pixels onto win32 window. - let - w = screen.width.int32 - h = screen.height.int32 - dc = GetDC(hwnd) - var info = BITMAPINFO() - info.bmiHeader.biBitCount = 32 - info.bmiHeader.biWidth = w - info.bmiHeader.biHeight = h - info.bmiHeader.biPlanes = 1 - info.bmiHeader.biSize = DWORD sizeof(BITMAPINFOHEADER) - info.bmiHeader.biSizeImage = w * h * 4 - info.bmiHeader.biCompression = BI_RGB - var bgrBuffer = newSeq[uint8](screen.data.len * 4) - # Convert to BGRA. - for i, c in screen.data: - bgrBuffer[i*4+0] = c.b - bgrBuffer[i*4+1] = c.g - bgrBuffer[i*4+2] = c.r - discard StretchDIBits( - dc, - 0, - h - 1, - w, - -h, - 0, - 0, - w, - h, - bgrBuffer[0].addr, - info, - DIB_RGB_COLORS, - SRCCOPY - ) - discard ReleaseDC(hwnd, dc) - -proc windowProc(hwnd: HWND, message: UINT, wParam: WPARAM, - lParam: LPARAM): LRESULT {.stdcall.} = - case message - of WM_DESTROY: - PostQuitMessage(0) - running = false - return 0 - else: - return DefWindowProc(hwnd, message, wParam, lParam) - -proc main() = - var - hInstance = GetModuleHandle(nil) - appName = "Win32/Pixie" - msg: MSG - wndclass: WNDCLASS - - wndclass.style = CS_HREDRAW or CS_VREDRAW - wndclass.lpfnWndProc = windowProc - wndclass.cbClsExtra = 0 - wndclass.cbWndExtra = 0 - wndclass.hInstance = hInstance - wndclass.hIcon = LoadIcon(0, IDI_APPLICATION) - wndclass.hCursor = LoadCursor(0, IDC_ARROW) - wndclass.hbrBackground = GetStockObject(WHITE_BRUSH) - wndclass.lpszMenuName = nil - wndclass.lpszClassName = appName - - if RegisterClass(wndclass) == 0: - MessageBox(0, "This program requires Windows NT!", appName, MB_ICONERROR) - return - - # Figure out the right size of the window we want. - var rect: lean.RECT - rect.left = 0 - rect.top = 0 - rect.right = w - rect.bottom = h - AdjustWindowRectEx(cast[LPRECT](rect.addr), WS_OVERLAPPEDWINDOW, 0, 0) - - # Open the window. - hwnd = CreateWindow( - appName, - "Win32/Pixie", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - rect.right - rect.left, - rect.bottom - rect.top, - 0, - 0, - hInstance, - nil - ) - - ShowWindow(hwnd, SW_SHOW) - UpdateWindow(hwnd) - - while running: - draw() - PeekMessage(msg, 0, 0, 0, PM_REMOVE) - TranslateMessage(msg) - DispatchMessage(msg) - -main() diff --git a/examples/realtime_wnim.nim b/examples/realtime_wnim.nim deleted file mode 100644 index 976dfcf..0000000 --- a/examples/realtime_wnim.nim +++ /dev/null @@ -1,72 +0,0 @@ -import pixie, wNim/wApp, wNim/wFrame, wNim/wImage, wNim/wPaintDC - -let - w = 256 - h = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - frameCount = 0 - image = Image(w, h) - app = App() - frame = Frame(title = "wNim/Pixie") - -proc draw() = - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - inc frameCount - -proc render() = - - proc GdipCreateBitmapFromScan0(width: cint, height: cint, stride: cint, - format: cint, scan0: pointer, bitmap: pointer): cint - {.stdcall, discardable, dynlib: "gdiplus", importc.} - - proc GdipDisposeImage(image: pointer): cint - {.stdcall, discardable, dynlib: "gdiplus", importc.} - - const PixelFormat32bppARGB = 2498570 - - GdipDisposeImage(image.mGdipBmp) - - GdipCreateBitmapFromScan0(cint w, cint h, cint w * 4, - PixelFormat32bppARGB, ctx.image.data[0].addr, addr image.mGdipBmp) - -frame.clientSize = (w, h) - -frame.startTimer(0.01) - -frame.wEvent_Timer do (): - draw() - render() - frame.refresh(false) - -frame.wEvent_Paint do (): - var dc = PaintDC(frame) - dc.drawImage(image) - -frame.show() -app.mainLoop() diff --git a/examples/realtime_xlib.nim b/examples/realtime_xlib.nim deleted file mode 100644 index d89a07f..0000000 --- a/examples/realtime_xlib.nim +++ /dev/null @@ -1,120 +0,0 @@ -## This example show how to have real time pixie using the X11 API. - -import math, pixie, std/os -import - x11/xlib, - x11/xutil, - x11/x - -let - w: int32 = 256 - h: int32 = 256 - -var - screen = newImage(w, h) - ctx = newContext(screen) - -var - display: PDisplay - window: Window - deleteMessage: Atom - graphicsContext: GC - frameCount = 0 - -proc render() = - ## Called every frame by main while loop - - # draw shiny sphere on gradient background - let linerGradient = newPaint(pkGradientLinear) - linerGradient.gradientHandlePositions.add(vec2(0, 0)) - linerGradient.gradientHandlePositions.add(vec2(0, 256)) - linerGradient.gradientStops.add( - ColorStop(color: pixie.color(0, 0, 0, 1), position: 0)) - linerGradient.gradientStops.add( - ColorStop(color: pixie.color(1, 1, 1, 1), position: 1)) - ctx.fillStyle = linerGradient - ctx.fillRect(0, 0, 256, 256) - let radialGradient = newPaint(pkGradientRadial) - radialGradient.gradientHandlePositions.add(vec2(128, 128)) - radialGradient.gradientHandlePositions.add(vec2(256, 128)) - radialGradient.gradientHandlePositions.add(vec2(128, 256)) - radialGradient.gradientStops.add( - ColorStop(color: pixie.color(1, 1, 1, 1), position: 0)) - radialGradient.gradientStops.add( - ColorStop(color: pixie.color(0, 0, 0, 1), position: 1)) - ctx.fillStyle = radialGradient - ctx.fillCircle(circle( - vec2(128.0, 128.0 + sin(float32(frameCount)/10.0) * 20), - 76.8 - )) - inc frameCount - var frameBuffer = addr ctx.image.data[0] - let image = XCreateImage(display, DefaultVisualOfScreen( - DefaultScreenOfDisplay(display)), 24, ZPixmap, 0, cast[cstring]( - frameBuffer), w.cuint, h.cuint, 8, w*4) - discard XPutImage(display, window, graphicsContext, image, 0, 0, 0, 0, w.cuint, h.cuint) - -const - borderWidth = 0 - eventMask = ButtonPressMask or KeyPressMask or ExposureMask - -proc init() = - display = XOpenDisplay(nil) - if display == nil: - quit "Failed to open display" - - let - screen = XDefaultScreen(display) - rootWindow = XRootWindow(display, screen) - foregroundColor = XBlackPixel(display, screen) - backgroundColor = XWhitePixel(display, screen) - - window = XCreateSimpleWindow(display, rootWindow, -1, -1, w.cuint, h.cuint, - borderWidth, foregroundColor, backgroundColor) - - - discard XSetStandardProperties(display, window, "X11 Example", "window", 0, - nil, 0, nil) - - discard XSelectInput(display, window, eventMask) - discard XMapWindow(display, window) - - deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false.XBool) - discard XSetWMProtocols(display, window, deleteMessage.addr, 1) - - graphicsContext = XDefaultGC(display, screen) - - -proc mainLoop() = - ## Process events until the quit event is received - var event: XEvent - var exposed: bool = false - while true: - if exposed: render() - if XPending(display) > 0: - discard XNextEvent(display, event.addr) - case event.theType - of Expose: - render() - exposed = true - of ClientMessage: - if cast[Atom](event.xclient.data.l[0]) == deleteMessage: - break - of KeyPress: - let key = XLookupKeysym(cast[PXKeyEvent](event.addr), 0) - if key != 0: - echo "Key ", key, " pressed" - of ButtonPressMask: - echo "Mouse button ", event.xbutton.button, " pressed at ", - event.xbutton.x, ",", event.xbutton.y - else: - discard - sleep 14 - -proc main() = - init() - mainLoop() - discard XDestroyWindow(display, window) - discard XCloseDisplay(display) - -main()