func renderServer(ws *websocket.Conn) { addr := ws.RemoteAddr() log.Println("new connection:", addr) defer func() { log.Println(addr, "was disconnected") }() // Setup watchdog. shutdownWatch := make(chan struct{}, 1) defer func() { shutdownWatch <- struct{}{} }() go func() { select { case <-shutdownWatch: case <-time.After(time.Duration(arguments.timeout) * time.Minute): log.Println("session timeout") ws.Close() } }() var setup setupMessage if err := messageCodec.Receive(ws, &setup); err != nil { log.Println(err) return } log.Println(setup) if setup.Resolution < 16 || setup.Resolution > 4096 { log.Println("invalid setup") return } var ( surfaces [6]*image.RGBA raytracers [6]*trace.Raytracer cameras [6]lookAtCamera rect = image.Rect(0, 0, setup.Resolution, setup.Resolution) ) for i, _ := range surfaces { surfaces[i] = image.NewRGBA(rect) cfg := trace.Config{ FieldOfView: 1.55, TreeScale: 1, ViewDist: float32(arguments.viewDistance), Images: [2]*image.RGBA{surfaces[i], nil}, Jitter: false, MultiThreaded: true, } raytracers[i] = trace.NewRaytracer(cfg) clear := setup.ClearColor raytracers[i].SetClearColor(color.RGBA{clear[0], clear[1], clear[2], clear[3]}) cameras[i] = cameraMatrix[i] } updateChan := make(chan updateMessage, 2) go func() { var update updateMessage for { if err := messageCodec.Receive(ws, &update); err != nil { log.Println(err) return } // TODO Verify message. updateChan <- update } }() for { update := <-updateChan for i := 0; i < 6; i++ { camera := cameras[i] camera.pos = update.Position camera.at[0] += camera.pos[0] camera.at[1] += camera.pos[1] camera.at[2] += camera.pos[2] raytracers[i].Trace(&camera, loadedTree.tree, loadedTree.maxDepth) } for _, rt := range raytracers { if err := streamCodec.Send(ws, rt.Image(0).Pix); err != nil { log.Println(err) return } } } }
func renderServer(ws *websocket.Conn) { addr := ws.RemoteAddr() log.Println("new connection:", addr) defer func() { log.Println(addr, "was disconnected") }() // Setup watchdog. shutdownWatch := make(chan struct{}, 1) defer func() { shutdownWatch <- struct{}{} }() go func() { select { case <-shutdownWatch: case <-time.After(time.Duration(arguments.timeout) * time.Minute): log.Println("session timeout") ws.Close() } }() var setup setupMessage if err := messageCodec.Receive(ws, &setup); err != nil { log.Println(err) return } log.Println(setup) if setup.Width*setup.Height > 1280*720 || setup.FieldOfView < 45 || setup.FieldOfView > 180 { log.Println("invalid setup") log.Println(setup) return } rect := image.Rect(0, 0, setup.Width/2, setup.Height) backBuffer := image.NewPaletted(rect, loadedTree.pal) surfaces := [2]*image.RGBA{ image.NewRGBA(rect), image.NewRGBA(rect), } cfg := trace.Config{ FieldOfView: setup.FieldOfView, TreeScale: 1, ViewDist: float32(arguments.viewDistance), Images: surfaces, Jitter: true, MultiThreaded: true, FrameSeed: 1, } raytracer := trace.NewRaytracer(cfg) clear := setup.ClearColor raytracer.SetClearColor(color.RGBA{clear[0], clear[1], clear[2], clear[3]}) updateChan := make(chan updateMessage, 2) go func() { var update updateMessage for { if err := messageCodec.Receive(ws, &update); err != nil { log.Println(err) return } // TODO Verify message. updateChan <- update } }() // Send palette. if setup.ColorFormat == "PALETTED" { log.Println("sending palette...") if err := streamCodec.Send(ws, loadedTree.rawPal); err != nil { log.Println(err) return } } for { update := <-updateChan camera := trace.FreeFlightCamera{ Pos: update.Camera.Position, XRot: update.Camera.XRot, YRot: update.Camera.YRot, } frame := 1 + raytracer.Trace(&camera, loadedTree.tree, loadedTree.maxDepth) idx := frame % 2 var err error if setup.ColorFormat == "PALETTED" { draw.Draw(backBuffer, rect, raytracer.Image(idx), image.ZP, draw.Src) err = streamCodec.Send(ws, backBuffer.Pix) } else { err = streamCodec.Send(ws, raytracer.Image(idx).Pix) } if err != nil { log.Println(err) return } } }
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 } } }