func (g *graphics) init() error { if err := g.loadImages(); err != nil { return err } gl.ClearColor(0, 0, 0.7, 1) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) g.fontStash = fontstash.New(512, 512) fontID, err := g.fontStash.AddFont(resourcePath("MorrisRoman-Black.ttf")) if err != nil { return err } g.fontStash.SetYInverted(true) g.font = NewGLFont(g.fontStash, fontID, 45, [4]float32{0, 0, 0, 1}) return nil }
func main() { runtime.LockOSThread() if err := glfw.Init(); err != nil { panic(err) } defer glfw.Terminate() window, err := glfw.CreateWindow(800, 600, "fontstash example", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() glfw.SwapInterval(1) gl.Init() stash := fontstash.New(512, 512) clearSansRegular, err := stash.AddFont(filepath.Join("..", "ClearSans-Regular.ttf")) if err != nil { panic(err) } clearSansItalic, err := stash.AddFont(filepath.Join("..", "ClearSans-Italic.ttf")) if err != nil { panic(err) } clearSansBold, err := stash.AddFont(filepath.Join("..", "ClearSans-Bold.ttf")) if err != nil { panic(err) } droidJapanese, err := stash.AddFont(filepath.Join("..", "DroidSansJapanese.ttf")) if err != nil { panic(err) } gl.ClearColor(0.3, 0.3, 0.32, 1.) for !window.ShouldClose() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.MatrixMode(gl.PROJECTION) gl.LoadIdentity() gl.Ortho(0, 800, 0, 600, -1, 1) gl.MatrixMode(gl.MODELVIEW) gl.LoadIdentity() gl.Disable(gl.DEPTH_TEST) gl.Color4ub(255, 255, 255, 255) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Disable(gl.TEXTURE_2D) gl.Begin(gl.QUADS) gl.Vertex2i(0, -5) gl.Vertex2i(5, -5) gl.Vertex2i(5, -11) gl.Vertex2i(0, -11) gl.End() sx := float64(100) sy := float64(250) stash.BeginDraw() dx := sx dy := sy dx = stash.DrawText(clearSansRegular, 24, dx, dy, "The quick ", [4]float32{0, 0, 0, 1}) dx = stash.DrawText(clearSansItalic, 48, dx, dy, "brown ", [4]float32{1, 1, 0.5, 1}) dx = stash.DrawText(clearSansRegular, 24, dx, dy, "fox ", [4]float32{0, 1, 0.5, 1}) _, _, lh := stash.VMetrics(clearSansItalic, 24) dx = sx dy -= lh * 1.2 dx = stash.DrawText(clearSansItalic, 24, dx, dy, "jumps over ", [4]float32{0, 1, 1, 1}) dx = stash.DrawText(clearSansBold, 24, dx, dy, "the lazy ", [4]float32{1, 0, 1, 1}) dx = stash.DrawText(clearSansRegular, 24, dx, dy, "dog.", [4]float32{0, 1, 0, 1}) dx = sx dy -= lh * 1.2 dx = stash.DrawText(clearSansRegular, 12, dx, dy, "Now is the time for all good men to come to the aid of the party.", [4]float32{0, 0, 1, 1}) _, _, lh = stash.VMetrics(clearSansItalic, 12) dx = sx dy -= lh * 1.2 * 2 dx = stash.DrawText(clearSansItalic, 18, dx, dy, "Ég get etið gler án þess að meiða mig.", [4]float32{1, 0, 0, 1}) _, _, lh = stash.VMetrics(clearSansItalic, 18) dx = sx dy -= lh * 1.2 stash.DrawText(droidJapanese, 18, dx, dy, "どこかに置き忘れた、サングラスと打ち明け話。", [4]float32{1, 1, 1, 1}) stash.EndDraw() gl.Enable(gl.DEPTH_TEST) window.SwapBuffers() glfw.PollEvents() } }
func main() { if err := glfw.Init(); err != nil { fmt.Println("glfw.Init():", err) return } defer glfw.Terminate() glfw.WindowHint(glfw.Decorated, glfw.True) glfw.WindowHint(glfw.ContextVersionMajor, 1) glfw.WindowHint(glfw.ContextVersionMinor, 0) glfw.WindowHint(glfw.Resizable, glfw.True) window, err := glfw.CreateWindow(10, 10, "Settlers", nil, nil) if err != nil { fmt.Println("glfw.CreateWindow():", err) return } window.MakeContextCurrent() if err := gl.Init(); err != nil { fmt.Println("gl.Init():", err) return } stash := fontstash.New(512, 512) fontID, err := stash.AddFont(resourcePath("MorrisRoman-Black.ttf")) if err != nil { fmt.Println(err) return } stash.SetYInverted(true) font := &font{stash, fontID, 35} gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.MatrixMode(gl.MODELVIEW) gl.LoadIdentity() rand.Seed(time.Now().UnixNano()) g := game.New([]game.Color{game.Red, game.White, game.Blue}, rand.Int()) var lines []string window.SetCharCallback(func(_ *glfw.Window, r rune) { if len(lines) == 0 { lines = []string{""} } lines[len(lines)-1] += string(r) }) window.SetCharModsCallback(func(_ *glfw.Window, r rune, _ glfw.ModifierKey) { }) window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, _ int, action glfw.Action, _ glfw.ModifierKey) { if action == glfw.Release { return } if key == glfw.KeyEscape { window.SetShouldClose(true) } if key == glfw.Key1 { g.CurrentPlayer = 0 } if key == glfw.Key2 { g.CurrentPlayer = 1 } if key == glfw.Key3 { g.CurrentPlayer = 2 } if key == glfw.Key4 { g.CurrentPlayer = 3 } if key == glfw.KeyR { state = buildingRoad } if key == glfw.KeyS { state = buildingSettlement } if key == glfw.KeyKP2 { g.DealResources(2) } if key == glfw.KeyKP3 { g.DealResources(3) } if key == glfw.KeyKP4 { g.DealResources(4) } if key == glfw.KeyKP5 { g.DealResources(5) } if key == glfw.KeyKP6 { g.DealResources(6) } if key == glfw.KeyKP8 { g.DealResources(8) } if key == glfw.KeyKP9 { g.DealResources(9) } if key == glfw.KeyKP0 { g.DealResources(10) } if key == glfw.KeyKP1 { g.DealResources(11) } if key == glfw.KeyKP7 { g.DealResources(12) } if len(lines) > 0 && key == glfw.KeyBackspace && (action == glfw.Press || action == glfw.Repeat) { if len(lines[len(lines)-1]) == 0 { lines = lines[:len(lines)-1] } else { lines[len(lines)-1] = removeLastRune(lines[len(lines)-1]) } } if (action == glfw.Press || action == glfw.Repeat) && (key == glfw.KeyEnter || key == glfw.KeyKPEnter) { lines = append(lines, "") } }) window.SetInputMode(glfw.CursorMode, glfw.CursorHidden) window.SetInputMode(glfw.CursorMode, glfw.CursorNormal) window.SetSizeCallback(func(_ *glfw.Window, w, h int) { windowW, windowH = w, h cam.WindowWidth, cam.WindowHeight = w, h gl.Viewport(0, 0, int32(w), int32(h)) }) if err := loadImages(); err != nil { fmt.Println(err) return } var background image.Image var backImg *glImage go func() { gameW, gameH := 7*200, 7*tileYOffset+tileSlopeHeight back := image.NewRGBA(image.Rect(0, 0, gameW, gameH)) clearToTransparent(back) drawGameBackgroundIntoImage(back, g) background = back }() gameColorToString := func(c game.Color) string { switch c { case game.Red: return "red" case game.Orange: return "orange" case game.Blue: return "blue" default: return "white" } } roadImage := func(pos game.TileEdge, c game.Color) *glImage { color := gameColorToString(c) dir := "up" if isEdgeVertical(pos) { dir = "vertical" } if isEdgeGoingDown(pos) { dir = "down" } return glImages["road_"+color+"_"+dir] } settlementImage := func(c game.Color) *glImage { return glImages["settlement_"+gameColorToString(c)] } cityImage := func(c game.Color) *glImage { return glImages["city_"+gameColorToString(c)] } // TODO this is for showing the road/settlement being built currently var movingSettlementCorner game.TileCorner var movingSettlementVisible bool var movingRoadEdge game.TileEdge var movingRoadVisible bool window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { mouseX, mouseY = x, y gameX, gameY := cam.screenToGame(x, y) movingSettlementCorner, movingSettlementVisible = screenToCorner(gameX, gameY) movingRoadEdge, movingRoadVisible = screenToEdge(gameX, gameY) }) window.SetCursorEnterCallback(func(_ *glfw.Window, entered bool) { mouseIn = entered if entered == false { movingSettlementVisible = false movingRoadVisible = true } }) ////////////////////////////////////////////////////////////////// drawGame := func() { if backImg == nil && background != nil { backImg, _ = NewGLImageFromImage(background) } if backImg != nil { backImg.DrawAtXY(0, 0) for _, p := range g.GetPlayers() { for _, r := range p.GetBuiltRoads() { x, y := edgeToScreen(r.Position) img := roadImage(r.Position, p.Color) img.DrawAtXY(x-img.Width/2, y-img.Height/2) } for _, s := range p.GetBuiltSettlements() { x, y := cornerToScreen(s.Position) img := settlementImage(p.Color) img.DrawAtXY(x-img.Width/2, y-(5*img.Height/8)) } for _, c := range p.GetBuiltCities() { x, y := cornerToScreen(c.Position) img := cityImage(p.Color) img.DrawAtXY(x-img.Width/2, y-(5*img.Height/8)) } } if state == buildingSettlement && movingSettlementVisible && mouseIn { color := [4]float32{1, 1, 1, 1} x, y := cornerToScreen(movingSettlementCorner) if !movingSettlementVisible || !g.CanBuildSettlementAt(movingSettlementCorner) { color = [4]float32{0.7, 0.7, 0.7, 0.7} x, y = cam.screenToGame(mouseX, mouseY) } img := settlementImage(g.GetCurrentPlayer().Color) // TODO duplicate code: img.DrawColoredAtXY(x-img.Width/2, y-(5*img.Height/8), color) } if state == buildingRoad && movingRoadVisible && mouseIn { color := [4]float32{1, 1, 1, 1} x, y := edgeToScreen(movingRoadEdge) if !(!movingRoadVisible || !g.CanBuildRoadAt(movingRoadEdge)) { img := roadImage(movingRoadEdge, g.GetCurrentPlayer().Color) // TODO duplicate code: img.DrawColoredAtXY(x-img.Width/2, y-(5*img.Height/8), color) } } x, y, w, h := tileToScreen(g.Robber.Position) robber := glImages["robber"] robber.DrawAtXY(x+(w-robber.Width)/2, y+(h-robber.Height)/2) } } buildMenu := &menu{color{0.5, 0.4, 0.8, 0.9}, rect{0, 500, 800, 250}} showCursor := 0 start := time.Now() frames := 0 window.SetSize(windowW, windowH) for !window.ShouldClose() { glfw.PollEvents() gl.MatrixMode(gl.PROJECTION) gl.LoadIdentity() const controlsHeight = 0 // TODO reserve are for stats and menus gameW, gameH := 7.0*200, 7.0*tileYOffset+tileSlopeHeight+controlsHeight gameRatio := gameW / gameH windowRatio := float64(windowW) / float64(windowH) var left, right, bottom, top float64 if windowRatio > gameRatio { // window is wider than game => borders left and right border := (windowRatio*gameH - gameW) / 2 left, right = -border, border+gameW bottom, top = gameH, 0 } else { // window is higher than game => borders on top and bottom border := (gameW/windowRatio - gameH) / 2 left, right = 0, gameW bottom, top = gameH+border, -border } gl.Ortho(left, right, bottom, top, -1, 1) cam.Left, cam.Right, cam.Bottom, cam.Top = left, right, bottom, top gl.ClearColor(0, 0, 1, 1) gl.Clear(gl.COLOR_BUFFER_BIT) drawGame() lines = make([]string, g.PlayerCount*6) for i, player := range g.GetPlayers() { lines[i*6+0] = fmt.Sprintf("player %v has %v ore", i+1, player.Resources[game.Ore]) lines[i*6+1] = fmt.Sprintf("player %v has %v grain", i+1, player.Resources[game.Grain]) lines[i*6+2] = fmt.Sprintf("player %v has %v lumber", i+1, player.Resources[game.Lumber]) lines[i*6+3] = fmt.Sprintf("player %v has %v wool", i+1, player.Resources[game.Wool]) lines[i*6+4] = fmt.Sprintf("player %v has %v brick", i+1, player.Resources[game.Brick]) } if len(lines) > 0 { stash.BeginDraw() const fontSize = 35 const cursorText = "" //"_" cursor := "" if showCursor > 60 { cursor = cursorText } for i, line := range lines { output := line if i == len(lines)-1 { output += cursor } font.Write(output, 0, float64(i+1)*fontSize) } if len(lines) == 0 { font.Write(cursor, 0, fontSize) } stash.EndDraw() } buildMenu.draw() window.SwapBuffers() showCursor = (showCursor + 1) % 120 frames++ if time.Now().Sub(start).Seconds() >= 1.0 { fmt.Println(frames, "fps") frames = 0 start = time.Now() } } }