func moveCamera(camera *trace.FreeFlightCamera, dtf float32) { state := sdl.GetKeyboardState() switch { case state[sdl.GetScancodeFromKey(sdl.K_UP)] != 0: camera.YRot += dtf * cameraSpeed case state[sdl.GetScancodeFromKey(sdl.K_DOWN)] != 0: camera.YRot -= dtf * cameraSpeed case state[sdl.GetScancodeFromKey(sdl.K_LEFT)] != 0: camera.XRot += dtf * cameraSpeed case state[sdl.GetScancodeFromKey(sdl.K_RIGHT)] != 0: camera.XRot -= dtf * cameraSpeed case state[sdl.GetScancodeFromKey(sdl.K_w)] != 0: camera.Move(dtf * cameraSpeed) case state[sdl.GetScancodeFromKey(sdl.K_s)] != 0: camera.Move(dtf * -cameraSpeed) case state[sdl.GetScancodeFromKey(sdl.K_a)] != 0: camera.Strafe(dtf * cameraSpeed) case state[sdl.GetScancodeFromKey(sdl.K_d)] != 0: camera.Strafe(dtf * -cameraSpeed) case state[sdl.GetScancodeFromKey(sdl.K_e)] != 0: camera.Lift(dtf * cameraSpeed) case state[sdl.GetScancodeFromKey(sdl.K_q)] != 0: camera.Lift(dtf * -cameraSpeed) } }
func updateCamera(ws *websocket.WebSocket, gl *webgl.Context, renderer <-chan struct{}) { const tick30hz = (1000 / 30) * time.Millisecond var ( camera trace.FreeFlightCamera oldPos [3]float32 positions = make(chan [3]float32, 1) ) positions <- oldPos go func() { for { pos := <-positions fmt.Println("New position:", pos) m, err := json.Marshal(updateMessage{Position: pos}) assert(err) assert(ws.Send(string(m))) <-renderer } }() for _ = range time.Tick(tick30hz) { switch { case keys[38]: // Up camera.YRot += cameraSpeed case keys[40]: // Down camera.YRot -= cameraSpeed case keys[37]: // Left camera.XRot += cameraSpeed case keys[39]: // Right camera.XRot -= cameraSpeed case keys[87]: // W camera.Move(cameraSpeed) case keys[83]: // S camera.Move(-cameraSpeed) case keys[65]: // A camera.Strafe(cameraSpeed) case keys[68]: // D camera.Strafe(-cameraSpeed) case keys[69]: // E camera.Lift(cameraSpeed) case keys[81]: // Q camera.Lift(-cameraSpeed) } if oldPos != camera.Pos { select { case positions <- camera.Pos: oldPos = camera.Pos default: } } mat := mat4.Ident mat.AssignEulerRotation(camera.XRot, camera.YRot, 0) mat.Transpose() gl.UniformMatrix4fv(uniformViewLocation, false, mat.Slice()) gl.DrawArrays(gl.TRIANGLES, 0, 6) } }
func main() { flag.Parse() fmt.Sscanf(arguments.windowSize, "%d,%d", &screenWidth, &screenHeight) fmt.Sscanf(arguments.resolution, "%d,%d", &resolutionX, &resolutionY) fp, err := os.Open(arguments.inputFile) if err != nil { fmt.Fprintln(os.Stderr, err) return } defer fp.Close() tree, vpa, err := trace.LoadOctree(fp) if err != nil { panic(err) } maxDepth := trace.TreeWidthToDepth(vpa) sdl.Init(sdl.INIT_EVERYTHING) defer sdl.Quit() title := "AJ's Raytracer" window, err := sdl.CreateWindow(title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, screenWidth, screenHeight, sdl.WINDOW_SHOWN) if err != nil { panic(err) } defer window.Destroy() sdl.SetRelativeMouseMode(true) renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED) if err != nil { panic(err) } defer renderer.Destroy() sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, arguments.scaleFilter) renderer.SetLogicalSize(resolutionX, resolutionY) renderer.SetDrawColor(0, 0, 0, 255) rect := image.Rect(0, 0, resolutionX, resolutionY) if arguments.enableJitter { rect.Max.X /= 2 } surfaces := [2]*image.RGBA{image.NewRGBA(rect), image.NewRGBA(rect)} backBuffer := image.NewRGBA(image.Rect(0, 0, resolutionX, resolutionY)) texture, err := renderer.CreateTexture(sdl.PIXELFORMAT_ABGR8888, sdl.TEXTUREACCESS_STREAMING, resolutionX, resolutionY) if err != nil { panic(err) } defer texture.Destroy() var pos [3]float32 fmt.Sscanf(arguments.treePosition, "%f,%f,%f", &pos[0], &pos[1], &pos[2]) cfg := trace.Config{ FieldOfView: float32(arguments.fieldOfView), TreeScale: float32(arguments.treeScale), TreePosition: pos, ViewDist: float32(arguments.viewDistance), Images: surfaces, Jitter: arguments.enableJitter, MultiThreaded: arguments.multiThreaded, Depth: enableDepthTest, } raytracer := trace.NewRaytracer(cfg) defer raytracer.Close() camera := trace.FreeFlightCamera{XRot: 0, YRot: 0} nf := 0 dt := time.Duration(1000 / 60) ft := time.Duration(nf) if arguments.pprof { go func() { fmt.Fprintln(os.Stderr, http.ListenAndServe("localhost:6060", nil)) }() fp, err := os.Create("raytracer.pprof") if err != nil { panic(err) } defer fp.Close() pprof.StartCPUProfile(fp) defer pprof.StopCPUProfile() } for { t := time.Now() dtf := float32(dt / time.Millisecond) for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch t := event.(type) { case *sdl.QuitEvent: return case *sdl.MouseMotionEvent: if enableInput { camera.XRot -= dtf * float32(t.XRel) * mouseSpeed camera.YRot -= dtf * float32(t.YRel) * mouseSpeed } case *sdl.KeyUpEvent: switch t.Keysym.Sym { case sdl.K_ESCAPE: return case sdl.K_f: toggleFullscreen(window) case sdl.K_c: if !arguments.ppm { fmt.Println("Camera:", camera) } case sdl.K_SPACE: enableInput = !enableInput sdl.SetRelativeMouseMode(enableInput) } } } renderer.Clear() if enableInput || arguments.ppm || arguments.pprof { if enableInput { moveCamera(&camera, dtf) window.WarpMouseInWindow(screenWidth/2, screenHeight/2) } if enableDepthTest { raytracer.ClearDepth(raytracer.Frame()) } raytracer.Trace(&camera, tree, maxDepth) } if arguments.enableJitter { if err := trace.Reconstruct(raytracer.Image(0), raytracer.Image(1), backBuffer); err != nil { panic(err) } } else { backBuffer = surfaces[0] } texture.Update(nil, unsafe.Pointer(&backBuffer.Pix[0]), backBuffer.Stride) renderer.Copy(texture, nil, nil) renderer.Present() if arguments.ppm { writePPM(backBuffer) } dt = time.Since(t) ft += dt nf++ if ft >= time.Second { window.SetTitle(fmt.Sprintf("%v - fps: %v, dt: %vms", title, nf, int(ft/time.Millisecond)/nf)) nf = 0 ft = 0 } } }