func (sg *OpenGLGraphics) Line(x0, y0, x1, y1 int, style chart.Style) { //log.Panicf("Unimplemented: %s", whoami()) defer glh.OpenGLSentinel()() gl.LineWidth(float32(style.LineWidth)) // TODO: line stipple? //sc := chart.Color2RGBA(style.LineColor, uint8(style.Alpha*255)) //log.Printf("color: %s %d %d %d %d", style.FillColor, sc.R, sc.G, sc.B, sc.A) glh.ColorC(style.LineColor) //sc := style.LineColor //gl.Color4ub(sc.R, sc.G, sc.B, sc.A) // TODO: Check this works glh.With(glh.Attrib{gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT}, func() { gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) glh.With(glh.Primitive{gl.LINES}, func() { gl.Vertex2i(x0, y0) gl.Vertex2i(x1, y1) }) }) }
func (p *Planetoid) Render(dp float64) { glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Rotated(p.rising_node, 0, 1, 0) gl.Rotated(p.inclination, 0, 0, 1) gl.Rotated(p.phase0+p.phase, 0, 1, 0) p.phase += dp*10 + (1 - p.apogee) glh.With(glh.Matrix{gl.MODELVIEW}, func() { // TODO: Compute position correctly gl.Translated(p.apogee, 0, 0) Sphere(p.radius, 3) }) // TODO: Avoid depth thrashing when trails overlap // Trail glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Rotated(90, 1, 0, 0) gl.Scaled(p.apogee, p.apogee, 1) gl.LineWidth(2) glh.With(glh.Disable(gl.LIGHTING), func() { p.circle.Render(gl.LINE_STRIP) }) }) }) }
func (sg *OpenGLGraphics) Rect(x, y, w, h int, style chart.Style) { // log.Panicf("Unimplemented: %s", whoami()) x, y, w, h = chart.SanitizeRect(x, y, w, h, style.LineWidth) defer glh.OpenGLSentinel()() // glh.With(glh.Attrib{gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT}, func() { glh.ColorC(style.FillColor) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Begin(gl.QUADS) glh.Squarei(x, y, w, h) gl.End() }) if style.LineWidth != 0 { gl.LineWidth(float32(style.LineWidth)) //log.Print("Linewidth: ", float32(style.LineWidth)) glh.With(glh.Attrib{gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT}, func() { glh.ColorC(style.LineColor) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Begin(gl.LINE_LOOP) glh.Squarei(x, y, w, h) gl.End() }) } // linecol := style.LineColor // if linecol != "" { // s = fmt.Sprintf("stroke:%s; ", linecol) // } else { // linecol = "#808080" // } // s += fmt.Sprintf("stroke-width: %d; ", style.LineWidth) // s += fmt.Sprintf("opacity: %.2f; ", 1-style.Alpha) // if style.FillColor != "" { // s += fmt.Sprintf("fill: %s; fill-opacity: %.2f", style.FillColor, 1-style.Alpha) // } else { // s += "fill-opacity: 0" // } // sg.svg.Rect(x, y, w, h, s) // GenericRect(sg, x, y, w, h, style) // TODO }
func render() { modelMatrix = trig.MatrixMult(trig.RotateY(math.Pi/360), modelMatrix) gl.Viewport(0, 0, 768, 768) gl.ClearColor(0.0, 0.0, 0, 0) gl.Enable(gl.DEPTH_TEST) raytraceProgram.Use() mInput.UniformMatrix4f(false, (*[16]float32)(modelMatrix)) vInput.UniformMatrix4f(false, (*[16]float32)(viewMatrix)) pInput.UniformMatrix4f(false, (*[16]float32)(projMatrix)) glh.With(framebuffer, func() { framebuffer.UpdateTextures() gl.DrawBuffer(gl.COLOR_ATTACHMENT0) gl.Clear(gl.COLOR_BUFFER_BIT) gl.DepthFunc(gl.GREATER) gl.CullFace(gl.BACK) cube.Render(gl.TRIANGLES, raytraceProgram) gl.DrawBuffer(gl.COLOR_ATTACHMENT1) gl.Clear(gl.COLOR_BUFFER_BIT) gl.DepthFunc(gl.LESS) gl.CullFace(gl.FRONT) cube.Render(gl.TRIANGLES, raytraceProgram) }) }
func fill(canv *Canvas, alphaTex *glh.Texture, paint *Paint) { gGl.GlColorConfig.SetColor(paint.fillColor) defer gGl.GlColorConfig.Reset() gGl.Activate(gGl.FillDrawer) gl.ColorMask(true, true, true, true) gl.StencilMask(0x3) gl.StencilFunc(gl.LESS, 0, 0xff) w, h := canv.W, canv.H p := canv.toGLPoints([]Point{ iPt(0, 0), iPt(w, 0), iPt(w, h), iPt(0, h), }) vertices := []float32{ p[0].X, p[0].Y, 0, 1, p[1].X, p[1].Y, 1, 1, p[2].X, p[2].Y, 1, 0, p[3].X, p[3].Y, 0, 0, } gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, vertices, gl.STATIC_DRAW) elements := []uint32{ 0, 1, 2, 2, 3, 0, } gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(elements)*4, elements, gl.STATIC_DRAW) glh.With(alphaTex, func() { gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) }) }
// Render a sphere with the correct orientation (poles along y-axis) // Also makes a correction to avoid lighting flicker. // TODO: Replace with geodesic func Sphere(radius float32, granularity int) { glh.With(glh.Matrix{gl.MODELVIEW}, func() { // Needed to avoid a strange lighting effect gl.Rotatef(90, 0, 1, 0) // Rotate so that poles are on the y-axis gl.Rotatef(90, 1, 0, 0) glu.Sphere(quadric, radius, granularity, granularity) }) }
func (block *Block) RequestTexture() { block.requests.texture.Do(func() { // Schedule the main thread to build our texture for us go func() { main_thread_work <- func() { glh.With(&Timer{Name: "LoadTextures"}, func() { block.BuildTexture() }) // Allow generation once again block.requests.texture = sync.Once{} } }() }) }
func TexturedQuad(t *glh.Texture, x, y, w, h int) { glh.With(t, func() { gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Color4f(255.0, 255.0, 255.0, 1.0) gl.Begin(gl.TRIANGLE_FAN) gl.TexCoord2f(0, 0) gl.Vertex2i(x, y) gl.TexCoord2f(1, 0) gl.Vertex2i(x+w, y) gl.TexCoord2f(1, 1) gl.Vertex2i(x+w, y+h) gl.TexCoord2f(0, 1) gl.Vertex2i(x, y+h) gl.End() }) }
func (p *Path) draw(canv *Canvas, alphaBuffer *glh.Framebuffer, clrStencil bool) { gGl.QuadraticDrawConfig.SetExcludeTransluFrags(false) glh.With(alphaBuffer, func() { gl.ClearColor(0, 0, 0, 0) gl.Clear(gl.COLOR_BUFFER_BIT) p.glDraw(canv) }) if clrStencil { gl.StencilMask(0x3) gl.ClearStencil(0x0) gl.Clear(gl.STENCIL_BUFFER_BIT) } gl.ColorMask(false, false, false, false) gl.StencilMask(0x3) gl.StencilFunc(gl.ALWAYS, 0, 0xff) gl.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT) p.glDraw(canv) gl.StencilMask(0x1) gGl.QuadraticDrawConfig.SetExcludeTransluFrags(true) p.glDraw(canv) }
func (sg *OpenGLGraphics) Text(x, y int, t string, align string, rot int, f chart.Font) { if len(align) == 1 { align = "c" + align } _, fh, _ := sg.FontMetrics(f) tex := glh.MakeText(t, float64(fh)) tex.Flipped = true defer tex.Destroy() switch align[0] { case 'b': case 'c': y += fh / 2 case 't': y += fh default: log.Panicf("Unknown alignment: ", align) } switch align[1] { case 'l': case 'c': x -= tex.W / 2 case 'r': x -= tex.W default: log.Panicf("Unknown alignment: ", align) } if f.Color == nil { gl.Color4f(1, 1, 1, 1) } else { glh.ColorC(f.Color) } glh.With(tex, func() { tex.Draw(x, y) }) }
func (data *ProgramData) Draw(start_index, n int64) { nperblock := int64(10 * 1024 * 1024 / 56) start_block := start_index / nperblock if start_block < 0 { start_block = 0 } n_blocks := n/nperblock + 2 if n_blocks < 1 { n_blocks = 1 } if start_block+n_blocks >= int64(len(data.blocks)) { n_blocks = int64(len(data.blocks)) - start_block } // Threshold above which we use the full block detail detailed := false if n_blocks < 20 { detailed = true } // TODO // * Defer drawing through a block summary // Idea: use a drawing order that goes center-out so that we don't notice // blocks being loaded // 3 // 1 // 0 // 2 // 4 glh.With(&Timer{Name: "DrawBlocks"}, func() { for i := range ints(start_block, n_blocks) { b := data.blocks[i] from, N := start_index-int64(i)*b.nrecords, b.nrecords b.Draw(from, N, detailed) } }) }
func (p *Planetoid) RenderShadowVolume() { glh.With(glh.Matrix{gl.MODELVIEW}, func() { // gl.Rotated(90, 0, 1, 0) gl.Rotated(p.rising_node, 0, 1, 0) gl.Rotated(p.inclination, 0, 0, 1) gl.Rotated(p.phase0+p.phase, 0, 1, 0) // TODO: Compute position correctly gl.Translated(p.apogee, 0, 0) gl.Rotated(p.phase0+p.phase, 0, -1, 0) gl.Rotated(p.inclination, 0, 0, -1) gl.Rotated(p.rising_node, 0, -1, 0) // gl.Rotated(p.phase0+p.phase, 0, -1, 0) gl.Rotated(90, 0, -1, 0) glu.Cylinder(quadric, p.radius, p.radius, 2, 10, 1) }) }
func main_loop(data *ProgramData) { start := time.Now() frames := 0 lastblocks := 0 // Frame counter go func() { for { time.Sleep(time.Second) if *verbose { memstats := new(runtime.MemStats) runtime.ReadMemStats(memstats) fps := float64(frames) / time.Since(start).Seconds() blocks := len(data.blocks) bps := float64(blocks-lastblocks) / time.Since(start).Seconds() lastblocks = blocks log.Printf("fps = %5.2f; blocks = %4d; bps = %5.2f sparemem = %6d MB; alloc'd = %6.6f; (+footprint = %6.6f)", fps, len(data.blocks), bps, SpareRAM(), float64(memstats.Alloc)/1024/1024, float64(memstats.Sys-memstats.Alloc)/1024/1024) PrintTimers(frames) } start = time.Now() frames = 0 } }() // Necessary at the moment to prevent eventual OOM go func() { for { time.Sleep(5 * time.Second) if *verbose { log.Print("GC()") } runtime.GC() if *verbose { GCStats() } } }() var i int64 = -int64(*nback) // TODO(pwaller): Make this work again // text := glh.MakeText(data.filename, 32) // Location of mouse in record space var rec, rec_actual int64 = 0, 0 var stacktext, dwarftext []*glh.Text var recordtext *glh.Text = nil var mousex, mousey, mousedownx, mousedowny int var mousepx, mousepy float64 var lbutton bool escape_hit := false glfw.SetMouseWheelCallback(func(pos int) { nback_prev := *nback if pos < 0 { *nback = 40 * 1024 << uint(-pos) } else { *nback = 40 * 1024 >> uint(pos) } //log.Print("Mousewheel position: ", pos, " nback: ", *nback) if rec == 0 { return } // mouse cursor is at screen "rec_actual", and it should be after // the transformation // We need to adjust `i` to keep this value constant: // rec_actual == i + int64(constpart * float64(*nback)) // where constpart <- (-const + 2.) / 4. // (that way, the mouse is still pointing at the same place after scaling) constpart := float64(rec_actual-i) / float64(nback_prev) rec_actual_after := i + int64(constpart*float64(*nback)) delta := rec_actual_after - rec_actual i -= delta // Ensure the mouse cursor position doesn't change when zooming rec = rec_actual - i }) update_text := func() { if DoneThisFrame(RenderText) { return } if recordtext != nil { recordtext.Destroy() recordtext = nil } //r := 0 //data.GetRecord(rec_actual) //if r != nil { //log.Print(data.records[rec_actual]) //recordtext = MakeText(r.String(), 32) //} for j := range stacktext { stacktext[j].Destroy() } // TODO: Load records on demand if false { stack := data.GetStackNames(rec_actual) stacktext = make([]*glh.Text, len(stack)) for j := range stack { stacktext[j] = glh.MakeText(stack[j], 32) } } } glfw.SetMouseButtonCallback(func(button, action int) { switch button { case glfw.Mouse1: switch action { case glfw.KeyPress: mousedownx, mousedowny = mousex, mousey lbutton = true r := data.GetRecord(rec_actual) if r != nil { if r.Type == MEMA_ACCESS { log.Print(r) ma := r.MemAccess() dwarf := data.GetDwarf(ma.Pc) log.Print("Can has dwarf? ", len(dwarf)) for i := range dwarf { log.Print(" ", dwarf[i]) //recordtext = MakeText(data.records[rec_actual].String(), 32) } log.Print("") for j := range dwarftext { dwarftext[j].Destroy() } dwarftext = make([]*glh.Text, len(dwarf)) for j := range dwarf { dwarftext[j] = glh.MakeText(fmt.Sprintf("%q", dwarf[j]), 32) } } //recordtext = MakeText(data.records[rec_actual].String(), 32) } case glfw.KeyRelease: lbutton = false } } }) glfw.SetMousePosCallback(func(x, y int) { px, py := glh.WindowToProj(x, y) // Record index rec = int64((py+2)*float64(*nback)/4. + 0.5) rec_actual = rec + i dpy := py - mousepy di := int64(-dpy * float64(*nback) / 4.) if lbutton { i += di } mousepx, mousepy = px, py mousex, mousey = x, y //log.Printf("Mouse motion: (%3d, %3d), (%f, %f), (%d, %d) dpy=%f di=%d", //x, y, px, py, rec, rec_actual, dpy, di) update_text() }) glfw.SetKeyCallback(func(key, state int) { switch key { case glfw.KeyEsc: escape_hit = true } }) draw_mousepoint := func() { // Draw the mouse point glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(*nback), 1) gl.Translated(0, float64(rec), 0) gl.PointSize(10) glh.With(glh.Primitive{gl.POINTS}, func() { gl.Color4f(1, 1, 1, 1) gl.Vertex3d(mousepx, 0, 0) }) }) } draw_text := func() { // Draw any text glh.With(glh.WindowCoords{}, func() { w, h := glh.GetViewportWHD() glh.With(glh.Attrib{gl.ENABLE_BIT}, func() { gl.Enable(gl.TEXTURE_2D) // text.Draw(0, 0) for text_idx := range stacktext { stacktext[text_idx].Draw(int(w*0.55), int(h)-35-text_idx*16) } for text_idx := range dwarftext { dwarftext[text_idx].Draw(int(w*0.55), 35+text_idx*16) } if recordtext != nil { recordtext.Draw(int(w*0.55), 35) } }) }) } Draw = func() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // Draw the memory access/function data data.Draw(i, *nback) draw_mousepoint() draw_text() // Visible region quad // gl.Color4f(1, 1, 1, 0.25) // DrawQuadd(-2.1, -2.25, 4.4, 2.1 - -2.25) // StatsHUD() } interrupt := make(chan os.Signal) signal.Notify(interrupt, os.Interrupt) ctrlc_hit := false go func() { <-interrupt ctrlc_hit = true }() done := false for !done { done_this_frame = make(map[WorkType]bool) glh.With(&Timer{Name: "Draw"}, func() { Draw() }) glfw.SwapBuffers() DoMainThreadWork() done = ctrlc_hit || escape_hit || glfw.WindowParam(glfw.Opened) == 0 frames += 1 } }
func (block *Block) Draw(start, N int64, detailed bool) { if block.tex == nil { block.RequestTexture() } switch detailed { case true: block.detail_needed = true if block.vertex_data == nil { // Hey, we need vertices but don't have them! Let's fix that.. block.RequestVertices() } default: block.detail_needed = false } width := uint64(len(block.display_active_pages)) * *PAGE_SIZE if width == 0 { width = 1 } vc := glh.NewMeshBuffer(glh.RenderArrays, glh.NewPositionAttr(2, gl.FLOAT, gl.STATIC_DRAW), glh.NewPositionAttr(4, gl.UNSIGNED_INT, gl.STATIC_DRAW), ) colors := make([]int32, 0) positions := make([]float32, 0) // var vc glh.ColorVertices if *pageboundaries { // boundary_color := color.RGBA{64, 64, 64, 255} // If we try and draw too many of these, X will hang if width / *PAGE_SIZE < 10000 { for p := uint64(0); p <= width; p += *PAGE_SIZE { x := float32(p) / float32(width) x = (x - 0.5) * 4 colors = append(colors, 64, 64, 64, 255) positions = append(positions, x, float32(N)) // vc.Add(glh.ColorVertex{boundary_color, glh.Vertex{x, 0}}) // vc.Add(glh.ColorVertex{boundary_color, glh.Vertex{x, float32(N)}}) } } } var border_color [4]float64 gl.LineWidth(1) glh.With(&Timer{Name: "DrawPartial"}, func() { var x1, y1, x2, y2 float64 glh.With(glh.Matrix{gl.MODELVIEW}, func() { // TODO: A little less co-ordinate insanity? gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(*nback), 1) gl.Translated(0, -float64(start), 0) x1, y1 = glh.ProjToWindow(-2, 0) x2, y2 = glh.ProjToWindow(-2+WIDTH, float64(N)) }) border_color = [4]float64{1, 1, 1, 1} glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(*nback), 1) gl.Translated(0, -float64(start), 0) // Page boundaries // TODO: Use different blending scheme on textured quads so that the // lines show through glh.With(glh.Attrib{gl.ENABLE_BIT}, func() { gl.Disable(gl.LINE_SMOOTH) // vc.Draw(gl.LINES) vc.Render(gl.LINES) }) }) if block.tex != nil && (!detailed || block.vertex_data == nil) { border_color = [4]float64{0, 0, 1, 1} glh.With(glh.WindowCoords{Invert: true}, func() { gl.Color4f(1, 1, 1, 1) // Render textured block quad glh.With(block.tex, func() { glh.DrawQuadd(x1, y1, x2-x1, y2-y1) }) glh.With(glh.Primitive{gl.LINES}, func() { glh.Squared(x1, y1, x2-x1, y2-y1) }) }) if block.vertex_data != nil && !block.detail_needed { // TODO: figure out when we can unload // Hey, we can unload you, because you are not needed block.vertex_data = nil } } if detailed && block.vertex_data != nil { glh.With(glh.Matrix{gl.MODELVIEW}, func() { // TODO: A little less co-ordinate insanity? gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(*nback), 1) gl.Translated(0, -float64(start), 0) gl.PointSize(2) block.vertex_data.Render(gl.POINTS) }) } glh.With(glh.WindowCoords{Invert: true}, func() { // Block boundaries gl.Color4dv(&border_color) gl.LineWidth(1) glh.With(glh.Primitive{gl.LINE_LOOP}, func() { glh.Squared(x1, y1, x2-x1, y2-y1) }) }) }) }
func main() { window, err := initGL() if err != nil || window == nil { log.Printf("InitGL: %v", err) return } defer glfw.Terminate() shaderLoad() cube, square = createBuffers() defer cube.Release() defer square.Release() timeframe = 0.0 stack := trig.NewMatrixStack() stack.Push(trig.TranslateXYZ(-0.5, -0.5, 0), trig.RotateY(math.Pi/4)) modelMatrix = stack.Get() viewMatrix = trig.TranslateXYZ(0, 0, -2) projMatrix = trig.Frustum(-0.5, 0.5, -0.5, 0.5, 1, 10) textureBank = helper.InitTextureBank(4, 1) textureBank.InitSamplerWithDefaults(0) textureBank.InstantiateSamplers() textureBank.InstantiateGeometry(0, 768, 768, 0, 0) textureBank.InstantiateGeometry(1, 768, 768, 0, 0) textureBank.InstantiateGeometry(2, 256, 256, 256, 0) textureBank.InstantiateGeometry(3, 256, 0, 0, 0) textureBank.InstantiateFormat(0, gl.FLOAT, gl.RGB, gl.RGB32F) textureBank.InstantiateFormat(1, gl.FLOAT, gl.RGB, gl.RGB32F) textureBank.InstantiateFormat(2, gl.UNSIGNED_BYTE, gl.RED, gl.R8) textureBank.InstantiateFormat(3, gl.UNSIGNED_BYTE, gl.RGBA, gl.RGBA) textureBank.ConfigUnit(0, gl.TEXTURE_2D, 0) textureBank.ConfigUnit(1, gl.TEXTURE_2D, 0) textureBank.ConfigUnit(2, gl.TEXTURE_3D, 0) textureBank.ConfigUnit(3, gl.TEXTURE_1D, 0) loadTexture() textureBank.InstantiateTextures() glh.OpenGLSentinel()() glh.With(textureBank, func() { framebuffer = &helper.Framebuffer{} framebuffer.Outputs = []gl.Texture{ textureBank.Units[0].Texture, textureBank.Units[1].Texture, } framebuffer.Sizes = []*helper.TextureGeometry{ textureBank.PixelData[0].Geometry[0], textureBank.PixelData[1].Geometry[0], } for !window.ShouldClose() { render() compose() window.SwapBuffers() glfw.PollEvents() } }) os.Exit(0) }
func (block *Block) BuildTexture() { block.tex = glh.NewTexture(1024, 256) block.tex.Init() // TODO: use runtime.SetFinalizer() to clean up/delete the texture? glh.With(block.tex, func() { //gl.TexParameteri(gl.TEXTURE_2D, gl.GENERATE_MIPMAP, gl.TRUE) //gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) // TODO: Only try and activate anisotropic filtering if it is available gl.TexParameterf(gl.TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, MaxAnisotropy) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 1) }) for i := 0; i < 2; i++ { glh.With(&glh.Framebuffer{Texture: block.tex, Level: i}, func() { glh.With(glh.Attrib{gl.COLOR_BUFFER_BIT}, func() { gl.ClearColor(1, 0, 0, 0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) }) viewport_proj := glh.Compound(glh.Attrib{gl.VIEWPORT_BIT}, glh.Matrix{gl.PROJECTION}) glh.With(viewport_proj, func() { gl.Viewport(0, 0, block.tex.W/(1<<uint(i)), block.tex.H/(1<<uint(i))) gl.LoadIdentity() //gl.Ortho(0, float64(tex.w), 0, float64(tex.h), -1, 1) gl.Ortho(-2, -2+WIDTH, 2, -2, -1, 1) glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.LoadIdentity() //gl.Hint(gl.LINES, gl.NICEST) //gl.LineWidth(4) /* glh.With(glh.Primitive{gl.LINES}, func() { gl.Color4f(1, 1, 1, 1) gl.Vertex2f(-2, 0) gl.Vertex2f(2, 0) }) */ gl.PointSize(4) glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(block.nrecords), 1) block.vertex_data.Render(gl.POINTS) }) /* gl.Color4f(0.5, 0.5, 1, 1) With(Primitive{gl.LINE_LOOP}, func() { b := 0.2 Squared(-2.1+b, -2.1+b, 4.35-b*2, 4.2-b*2) }) */ }) }) }) } //block.img = block.tex.AsImage() if !block.detail_needed { block.vertex_data = nil runtime.GC() } blocks_rendered++ }
func InitStatsHUD() { plots := chart.ScatterChart{Title: "", Options: glchart.DarkStyle} start := time.Now() l := float64(start.UnixNano()) r := float64(start.Add(2 * time.Second).UnixNano()) plots.XRange.Fixed(l, r, 1e9) plots.YRange.Fixed(0.1, 100, 10) plots.XRange.TicSetting.Tics, plots.YRange.TicSetting.Tics = 1, 1 plots.XRange.TicSetting.Mirror, plots.YRange.TicSetting.Mirror = 2, 2 plots.XRange.TicSetting.Grid, plots.YRange.TicSetting.Grid = 2, 2 plots.YRange.ShowZero = true //plots.XRange.Log = true //plots.YRange.Log = true plots.Key.Pos, plots.Key.Cols = "obc", 3 plots.XRange.TicSetting.Format = func(f float64) string { t := time.Unix(int64(f)/1e9, int64(f)%1e9) return fmt.Sprintf("%.3v", time.Since(t)) } memhelper.GetMaxRSS() var gpufree float64 gpupoll := gpuinfo.PollGPUMemory() go func() { for gpustatus := range gpupoll { gpufree = float64(memhelper.ByteSize(gpustatus.Free()) * memhelper.MiB) } }() statistics := &Statistics{} statistics.Add(&plots, "GPU Free", "#FF9F00", func() float64 { return gpufree }) statistics.Add(&plots, "SpareRAM()", "#ff0000", func() float64 { return float64(SpareRAM() * 1e6) }) statistics.Add(&plots, "MaxRSS", "#FFE240", func() float64 { return float64(memhelper.GetMaxRSS()) }) statistics.Add(&plots, "Heap Idle", "#33ff33", func() float64 { return float64(memstats.HeapIdle) }) statistics.Add(&plots, "Alloc", "#FF6600", func() float64 { return float64(memstats.Alloc) }) statistics.Add(&plots, "Heap Alloc", "#006699", func() float64 { return float64(memstats.HeapAlloc) }) statistics.Add(&plots, "Sys", "#996699", func() float64 { return float64(memstats.Sys) }) statistics.Add(&plots, "System Free", "#3333ff", func() float64 { return float64(SystemFree()) }) statistics.Add(&plots, "nBlocks x 1e6", "#FFCC00", func() float64 { return float64(nblocks * 1e6) }) statistics.Add(&plots, "nDrawn x 1e6", "#9C8AA5", func() float64 { return float64(blocks_rendered * 1e6) }) go func() { top := 0. i := -1 for { time.Sleep(250 * time.Millisecond) max := statistics.Update() if max > top { top = max } i++ if i%4 != 0 { continue } segment := float64(1e9) if time.Since(start) > 10*time.Second { segment = 5e9 } if time.Since(start) > 1*time.Minute { segment = 30e9 } // Update axis limits nr := float64(time.Now().Add(2 * time.Second).UnixNano()) plots.XRange.Fixed(l, nr, segment) plots.YRange.Fixed(-1e9, top*1.1, 500e6) } }() const pw, ph = 640, 480 scalex, scaley := 0.4, 0.5 chart_gfxcontext := glchart.New(pw, ph, "", 10, color.RGBA{}) StatsHUD = func() { glh.With(glh.Matrix{gl.PROJECTION}, func() { gl.LoadIdentity() gl.Translated(1-scalex, scaley-1, 0) gl.Scaled(scalex, scaley, 1) gl.Ortho(0, pw, ph, 0, -1, 1) gl.Translated(0, -50, 0) glh.With(glh.Attrib{gl.ENABLE_BIT}, func() { gl.Disable(gl.DEPTH_TEST) glh.With(&Timer{Name: "Chart"}, func() { plots.Plot(chart_gfxcontext) }) }) }) } // TODO: figure out why this is broken DumpStatsHUD = func() { s2f, _ := os.Create("statshud-dump.svg") mysvg := svg.New(s2f) mysvg.Start(1600, 800) mysvg.Rect(0, 0, 2000, 800, "fill: #ffffff") sgr := svgg.New(mysvg, 2000, 800, "Arial", 18, color.RGBA{0xff, 0xff, 0xff, 0xff}) sgr.Begin() plots.Plot(sgr) sgr.End() mysvg.End() s2f.Close() log.Print("Saved statshud-dump.svg") } //log.Print("InitStatsHUD()") }
func (sg *OpenGLGraphics) Scatter(points []chart.EPoint, plotstyle chart.PlotStyle, style chart.Style) { //log.Panicf("Unimplemented: %s", whoami()) //chart.GenericScatter(sg, points, plotstyle, style) // TODO: Implement error bars/symbols buffer := glh.NewMeshBuffer(glh.RenderArrays, glh.NewPositionAttr(2, gl.DOUBLE, gl.STATIC_DRAW), glh.NewColorAttr(3, gl.UNSIGNED_INT, gl.STATIC_DRAW)) // var vertices glh.ColorVertices positions := make([]float64, len(points)*2) colors := make([]uint32, len(points)*3) for _, p := range points { r, g, b, _ := style.LineColor.RGBA() colors = append(colors, r, g, b) positions = append(positions, p.X, p.Y) // vertices.Add(glh.ColorVertex{ // glh.MkRGBA(style.LineColor), // glh.Vertex{float32(p.X), float32(p.Y)}}) } buffer.Add() if style.LineWidth != 0 { gl.LineWidth(float32(style.LineWidth)) } else { gl.LineWidth(1) } glh.With(glh.Attrib{gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT}, func() { gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) buffer.Render(gl.LINE_STRIP) }) /*********************************************** // First pass: Error bars ebs := style ebs.LineColor, ebs.LineWidth, ebs.LineStyle = ebs.FillColor, 1, chart.SolidLine if ebs.LineColor == "" { ebs.LineColor = "#404040" } if ebs.LineWidth == 0 { ebs.LineWidth = 1 } for _, p := range points { xl, yl, xh, yh := p.BoundingBox() // fmt.Printf("Draw %d: %f %f-%f\n", i, p.DeltaX, xl,xh) if !math.IsNaN(p.DeltaX) { sg.Line(int(xl), int(p.Y), int(xh), int(p.Y), ebs) } if !math.IsNaN(p.DeltaY) { sg.Line(int(p.X), int(yl), int(p.X), int(yh), ebs) } } // Second pass: Line if (plotstyle&chart.PlotStyleLines) != 0 && len(points) > 0 { path := fmt.Sprintf("M %d,%d", int(points[0].X), int(points[0].Y)) for i := 1; i < len(points); i++ { path += fmt.Sprintf("L %d,%d", int(points[i].X), int(points[i].Y)) } st := linestyle(style) sg.svg.Path(path, st) } // Third pass: symbols if (plotstyle&chart.PlotStylePoints) != 0 && len(points) != 0 { for _, p := range points { sg.Symbol(int(p.X), int(p.Y), style) } } ****************************************************/ }
func main() { var err error if err = glfw.Init(); err != nil { fmt.Fprintf(os.Stderr, "[e] %v\n", err) return } defer glfw.Terminate() w, h := 1980, 1080 // w, h := 1280, 768 if err = glfw.OpenWindow(w, h, 8, 8, 8, 16, 0, 32, glfw.Fullscreen); err != nil { fmt.Fprintf(os.Stderr, "[e] %v\n", err) return } defer glfw.CloseWindow() glfw.SetSwapInterval(1) glfw.SetWindowTitle("Debris") quadric = glu.NewQuadric() gl.Enable(gl.CULL_FACE) gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LEQUAL) gl.Enable(gl.NORMALIZE) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.ShadeModel(gl.SMOOTH) gl.Enable(gl.LIGHTING) var ( ambient = []float32{0.1, 0.3, 0.6, 1} diffuse = []float32{1, 1, 0.5, 1} specular = []float32{0.4, 0.4, 0.4, 1} light_position = []float32{1, 0, 0, 0} // mat_specular []float32 = []float32{1, 1, 0.5, 1} mat_specular = []float32{1, 1, 0.75, 1} mat_shininess = float32(120) // light_position []float32 = []float32{0.0, 0.0, 1.0, 0.0} ) const ( fov = 1.1 // degrees znear = 145 zfar = 155 camera_z_offset = -150 camera_x_rotation = 0 // degrees // camera_x_rotation = 20 // degrees starfield_fov = 45 faces = 1000 earth_radius = 1 ) gl.Lightfv(gl.LIGHT1, gl.AMBIENT, ambient) gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, diffuse) gl.Lightfv(gl.LIGHT1, gl.SPECULAR, specular) gl.Lightfv(gl.LIGHT1, gl.POSITION, light_position) gl.Enable(gl.LIGHT1) mat_emission := []float32{0, 0, 0.1, 1} gl.Materialfv(gl.FRONT_AND_BACK, gl.EMISSION, mat_emission) gl.Materialfv(gl.FRONT_AND_BACK, gl.SPECULAR, mat_specular) gl.Materialf(gl.FRONT_AND_BACK, gl.SHININESS, mat_shininess) gl.ClearColor(0.02, 0.02, 0.02, 1) gl.ClearDepth(1) gl.ClearStencil(0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) b := createBuffer() planetoids := []*Planetoid{} for i := 0; i < 1000; i++ { p := &Planetoid{ apogee: 1.2 + rand.Float64()*0.7, perigee: 1.5, // inclination: 45, inclination: rand.Float64()*20 - 10, // inclination: 0, phase0: rand.Float64() * 360, rising_node: rand.Float64() * 10, phase: 0, // radius: rand.Float32()*0.05 + 0.01, //float32(r), radius: rand.Float32()*0.0125 + 0.005, //float32(r), // quadric: glu.NewQuadric(), circle: b, } planetoids = append(planetoids, p) } // Initial projection matrix: var aspect float64 glfw.SetWindowSizeCallback(func(w, h int) { gl.Viewport(0, 0, w, h) gl.MatrixMode(gl.PROJECTION) gl.LoadIdentity() aspect = float64(w) / float64(h) glu.Perspective(fov, aspect, znear, zfar) }) d := float64(0) wireframe := false atmosphere := false polar := false rotating := false front := false earth := true cone := true shadowing := true tilt := false running := true glfw.SetKeyCallback(func(key, state int) { if state != glfw.KeyPress { // Don't act on key coming up return } switch key { case 'A': atmosphere = !atmosphere case 'C': cone = !cone case 'E': earth = !earth case 'R': rotating = !rotating case 'F': front = !front if front { gl.FrontFace(gl.CW) } else { gl.FrontFace(gl.CCW) } case 'S': shadowing = !shadowing case 'T': tilt = !tilt case 'W': wireframe = !wireframe method := gl.GLenum(gl.FILL) if wireframe { method = gl.LINE } gl.PolygonMode(gl.FRONT_AND_BACK, method) case glfw.KeyF2: println("Screenshot captured") // glh.CaptureToPng("screenshot.png") w, h := glh.GetViewportWH() im := image.NewRGBA(image.Rect(0, 0, w, h)) glh.ClearAlpha(1) gl.Flush() glh.CaptureRGBA(im) go func() { fd, err := os.Create("screenshot.png") if err != nil { panic("Unable to open file") } defer fd.Close() png.Encode(fd, im) }() case 'Q', glfw.KeyEsc: running = !running case glfw.KeySpace: polar = !polar } }) _ = rand.Float64 stars := glh.NewMeshBuffer( glh.RenderArrays, glh.NewPositionAttr(3, gl.DOUBLE, gl.STATIC_DRAW), glh.NewColorAttr(3, gl.DOUBLE, gl.STATIC_DRAW)) const Nstars = 50000 points := make([]float64, 3*Nstars) colors := make([]float64, 3*Nstars) for i := 0; i < Nstars; i++ { const R = 1 phi := rand.Float64() * 2 * math.Pi z := R * (2*rand.Float64() - 1) theta := math.Asin(z / R) points[i*3+0] = R * math.Cos(theta) * math.Cos(phi) points[i*3+1] = R * math.Cos(theta) * math.Sin(phi) points[i*3+2] = z const r = 0.8 v := rand.Float64()*r + (1 - r) colors[i*3+0] = v colors[i*3+1] = v colors[i*3+2] = v } stars.Add(points, colors) render_stars := func() { glh.With(glh.Attrib{gl.DEPTH_BUFFER_BIT | gl.ENABLE_BIT}, func() { gl.Disable(gl.LIGHTING) gl.PointSize(1) gl.Color4f(1, 1, 1, 1) gl.Disable(gl.DEPTH_TEST) gl.DepthMask(false) stars.Render(gl.POINTS) }) } render_scene := func() { // Update light position (sensitive to current modelview matrix) gl.Lightfv(gl.LIGHT1, gl.POSITION, light_position) gl.Lightfv(gl.LIGHT2, gl.POSITION, light_position) if earth { Sphere(earth_radius, faces) } unlit_points := glh.Compound(glh.Disable(gl.LIGHTING), glh.Primitive{gl.POINTS}) glh.With(unlit_points, func() { gl.Vertex3d(1, 0, 0) }) for _, p := range planetoids { const dt = 0.1 // TODO: Frame update p.Render(dt) } glh.With(glh.Disable(gl.LIGHTING), func() { // Atmosphere gl.Color4f(0.25, 0.25, 1, 0.1) if atmosphere && earth { Sphere(earth_radius*1.025, 100) } gl.PointSize(10) glh.With(glh.Primitive{gl.POINTS}, func() { gl.Color4f(1.75, 0.75, 0.75, 1) gl.Vertex3d(-1.04, 0, 0) }) }) } render_shadow_volume := func() { glh.With(glh.Attrib{ gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.ENABLE_BIT | gl.POLYGON_BIT | gl.STENCIL_BUFFER_BIT, }, func() { gl.Disable(gl.LIGHTING) if shadowing { // gl.Disable(gl.DEPTH_TEST) gl.DepthMask(false) gl.DepthFunc(gl.LEQUAL) gl.Enable(gl.STENCIL_TEST) gl.ColorMask(false, false, false, false) gl.StencilFunc(gl.ALWAYS, 1, 0xffffffff) } shadow_volume := func() { const sv_length = 2 const sv_granularity = 100 const sv_radius = earth_radius * 1.001 // Shadow cone glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Rotatef(90, 1, 0, 0) gl.Rotatef(90, 0, -1, 0) gl.Color4f(0.5, 0.5, 0.5, 1) glu.Cylinder(quadric, sv_radius, sv_radius*1.05, sv_length, sv_granularity, 1) glu.Disk(quadric, 0, sv_radius, sv_granularity, 1) glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Translated(0, 0, sv_length) glu.Disk(quadric, 0, sv_radius*1.05, sv_granularity, 1) }) }) for _, p := range planetoids { p.RenderShadowVolume() } } if cone { gl.FrontFace(gl.CCW) gl.StencilOp(gl.KEEP, gl.KEEP, gl.INCR) shadow_volume() gl.FrontFace(gl.CW) gl.StencilOp(gl.KEEP, gl.KEEP, gl.DECR) shadow_volume() } if shadowing { gl.StencilFunc(gl.NOTEQUAL, 0, 0xffffffff) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) gl.ColorMask(true, true, true, true) // gl.Disable(gl.STENCIL_TEST) gl.Disable(gl.DEPTH_TEST) gl.FrontFace(gl.CCW) // gl.Color4f(1, 0, 0, 0.75) gl.Color4f(0, 0, 0, 0.75) // gl.Color4f(1, 1, 1, 0.75) gl.LoadIdentity() gl.Translated(0, 0, camera_z_offset) // TODO: Figure out why this doesn't draw over the whole screen glh.With(glh.Disable(gl.LIGHTING), func() { glh.DrawQuadd(-10, -10, 20, 20) }) // gl.FrontFace(gl.CW) // gl.Enable(gl.LIGHTING) // gl.Disable(gl.LIGHT1) // render_scene() // gl.Enable(gl.LIGHT1) } }) } _ = render_stars for running { running = glfw.WindowParam(glfw.Opened) == 1 glfw.SwapBuffers() gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) rotation := func() { if tilt { gl.Rotated(20, 1, 0, 0) } if polar { gl.Rotated(90, 1, 0, 0) } gl.Rotated(d, 0, -1, 0) } // Star field glh.With(glh.Matrix{gl.PROJECTION}, func() { gl.LoadIdentity() glu.Perspective(starfield_fov, aspect, 0, 1) glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.LoadIdentity() rotation() render_stars() }) }) gl.MatrixMode(gl.MODELVIEW) gl.LoadIdentity() gl.Translated(0, 0, camera_z_offset) rotation() if rotating { d += 0.2 } _ = render_scene render_scene() _ = render_shadow_volume render_shadow_volume() } }