├── LICENSE ├── README.md ├── g3nplay ├── README.md ├── go.mod ├── go.sum ├── main.go └── test.ogg ├── g3nview ├── README.md ├── dialog.go ├── fileselect.go ├── go.mod ├── go.sum └── main.go ├── gopher3d ├── README.md ├── go.mod ├── go.sum ├── gopher.blend ├── gopher.mtl ├── gopher.obj └── main.go └── hellog3n ├── go.mod ├── go.sum ├── main.go └── screenshot.png /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The G3N Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # G3N Standalone demos 2 | 3 | This repository contains standalone demo programs 4 | for the [G3N](https://github.com/g3n/engine) Go 3D Game Engine. 5 | 6 | 7 | -------------------------------------------------------------------------------- /g3nplay/README.md: -------------------------------------------------------------------------------- 1 | # G3NPLAY demo 2 | 3 | `g3nplay` is a minimum command line audio player which shows 4 | the initialization and usage of the audio library. 5 | 6 | 7 | -------------------------------------------------------------------------------- /g3nplay/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/g3n/demos/g3nplay 2 | 3 | go 1.17 4 | 5 | require github.com/g3n/engine v0.2.0 6 | 7 | require ( 8 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb // indirect 9 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 10 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 // indirect 11 | gopkg.in/yaml.v2 v2.4.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /g3nplay/go.sum: -------------------------------------------------------------------------------- 1 | github.com/g3n/engine v0.2.0 h1:7dmj4c+3xHcBnYrVmRuVf/oZ2JycxJU9Y+2FQj1Af2Y= 2 | github.com/g3n/engine v0.2.0/go.mod h1:rnj8jiLdKEDI8VbveKhmdL4rovjjy+uxNP5YROg2x8g= 3 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw= 4 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 5 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 7 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 h1:D0iM1dTCbD5Dg1CbuvLC/v/agLc79efSj/L35Q3Vqhs= 8 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 9 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 10 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 14 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 15 | -------------------------------------------------------------------------------- /g3nplay/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/g3n/engine/app" 7 | "github.com/g3n/engine/audio" 8 | "github.com/g3n/engine/renderer" 9 | "os" 10 | "time" 11 | ) 12 | 13 | // usage shows the application usage 14 | func usage() { 15 | 16 | fmt.Fprintf(os.Stderr, "usage: g3nplay \n") 17 | } 18 | 19 | func main() { 20 | 21 | // Parse command line parameters 22 | flag.Usage = usage 23 | flag.Parse() 24 | 25 | // Get file to play 26 | args := flag.Args() 27 | if len(args) == 0 { 28 | usage() 29 | os.Exit(1) 30 | } 31 | fpath := args[0] 32 | 33 | // Create application 34 | app.App() 35 | 36 | // Create player 37 | player, err := audio.NewPlayer(fpath) 38 | if err != nil { 39 | fmt.Println(err) 40 | os.Exit(1) 41 | } 42 | 43 | // Get total play time 44 | total := player.TotalTime() 45 | fmt.Printf("Playing:[%s] (%3.1f seconds)\n", fpath, total) 46 | 47 | // Start player 48 | player.Play() 49 | 50 | // Run the application 51 | app.App().Run(func(renderer *renderer.Renderer, deltaTime time.Duration) {}) 52 | } 53 | -------------------------------------------------------------------------------- /g3nplay/test.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g3n/demos/541b62abcc93939ed4319f8f31cdb9ef9f50c070/g3nplay/test.ogg -------------------------------------------------------------------------------- /g3nview/README.md: -------------------------------------------------------------------------------- 1 | # G3NVIEW demo 2 | 3 | `g3nview` is a simple model viewer which loads and view external 4 | models in OBJ and COLLADA formats. 5 | -------------------------------------------------------------------------------- /g3nview/dialog.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/g3n/engine/app" 6 | "github.com/g3n/engine/gui" 7 | "github.com/g3n/engine/math32" 8 | ) 9 | 10 | type ErrorDialog struct { 11 | gui.Panel 12 | msg *gui.ImageLabel 13 | bok *gui.Button 14 | } 15 | 16 | func NewErrorDialog(width, height float32) *ErrorDialog { 17 | 18 | e := new(ErrorDialog) 19 | e.Initialize(e, width, height) 20 | e.SetBorders(2, 2, 2, 2) 21 | e.SetPaddings(4, 4, 4, 4) 22 | e.SetColor(math32.NewColor("White")) 23 | e.SetVisible(false) 24 | e.SetBounded(false) 25 | 26 | // Set vertical box layout for the whole panel 27 | l := gui.NewVBoxLayout() 28 | l.SetSpacing(4) 29 | e.SetLayout(l) 30 | 31 | // Creates error message label 32 | e.msg = gui.NewImageLabel("") 33 | e.msg.SetColor(math32.NewColor("black")) 34 | e.msg.SetLayoutParams(&gui.VBoxLayoutParams{Expand: 2, AlignH: gui.AlignWidth}) 35 | e.Add(e.msg) 36 | 37 | // Creates button 38 | e.bok = gui.NewButton("OK") 39 | e.bok.SetLayoutParams(&gui.VBoxLayoutParams{Expand: 1, AlignH: gui.AlignCenter}) 40 | e.bok.Subscribe(gui.OnClick, func(evname string, ev interface{}) { 41 | e.SetVisible(false) 42 | }) 43 | e.Add(e.bok) 44 | 45 | return e 46 | } 47 | 48 | func (e *ErrorDialog) Show(msg string) { 49 | 50 | e.msg.SetText(msg) 51 | fmt.Println(msg) 52 | e.SetVisible(true) 53 | width, height := app.App().GetSize() 54 | px := (float32(width) - e.Width()) / 2 55 | py := (float32(height) - e.Height()) / 2 56 | e.SetPosition(px, py) 57 | } 58 | -------------------------------------------------------------------------------- /g3nview/fileselect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "sort" 7 | 8 | "github.com/g3n/engine/app" 9 | "github.com/g3n/engine/gui" 10 | "github.com/g3n/engine/gui/assets/icon" 11 | "github.com/g3n/engine/math32" 12 | ) 13 | 14 | type FileSelect struct { 15 | gui.Panel 16 | path *gui.Label 17 | list *gui.List 18 | bok *gui.Button 19 | bcan *gui.Button 20 | } 21 | 22 | func NewFileSelect(width, height float32) (*FileSelect, error) { 23 | 24 | fs := new(FileSelect) 25 | fs.Panel.Initialize(fs, width, height) 26 | fs.SetBorders(2, 2, 2, 2) 27 | fs.SetPaddings(4, 4, 4, 4) 28 | fs.SetColor(math32.NewColor("White")) 29 | fs.SetVisible(false) 30 | fs.SetBounded(false) 31 | 32 | // Set vertical box layout for the whole panel 33 | l := gui.NewVBoxLayout() 34 | l.SetSpacing(4) 35 | fs.SetLayout(l) 36 | 37 | // Creates path label 38 | fs.path = gui.NewLabel("path") 39 | fs.Add(fs.path) 40 | 41 | // Creates list 42 | fs.list = gui.NewVList(0, 0) 43 | fs.list.SetLayoutParams(&gui.VBoxLayoutParams{Expand: 5, AlignH: gui.AlignWidth}) 44 | fs.list.Subscribe(gui.OnChange, func(evname string, ev interface{}) { 45 | fs.onSelect() 46 | }) 47 | fs.Add(fs.list) 48 | 49 | // Button container panel 50 | bc := gui.NewPanel(0, 0) 51 | bcl := gui.NewHBoxLayout() 52 | bcl.SetAlignH(gui.AlignWidth) 53 | bc.SetLayout(bcl) 54 | bc.SetLayoutParams(&gui.VBoxLayoutParams{Expand: 1, AlignH: gui.AlignWidth}) 55 | fs.Add(bc) 56 | 57 | // Creates OK button 58 | fs.bok = gui.NewButton("OK") 59 | fs.bok.SetLayoutParams(&gui.HBoxLayoutParams{Expand: 0, AlignV: gui.AlignCenter}) 60 | fs.bok.Subscribe(gui.OnClick, func(evname string, ev interface{}) { 61 | fs.Dispatch("OnOK", nil) 62 | }) 63 | bc.Add(fs.bok) 64 | 65 | // Creates Cancel button 66 | fs.bcan = gui.NewButton("Cancel") 67 | fs.bcan.SetLayoutParams(&gui.HBoxLayoutParams{Expand: 0, AlignV: gui.AlignCenter}) 68 | fs.bcan.Subscribe(gui.OnClick, func(evname string, ev interface{}) { 69 | fs.Dispatch("OnCancel", nil) 70 | }) 71 | bc.Add(fs.bcan) 72 | 73 | // Sets initial directory 74 | path, err := os.Getwd() 75 | if err != nil { 76 | return nil, err 77 | } else { 78 | fs.SetPath(path) 79 | } 80 | return fs, nil 81 | } 82 | 83 | // Show shows or hide the file selection dialog 84 | func (fs *FileSelect) Show(show bool) { 85 | 86 | if show { 87 | fs.SetVisible(true) 88 | width, height := app.App().GetSize() 89 | px := (float32(width) - fs.Width()) / 2 90 | py := (float32(height) - fs.Height()) / 2 91 | fs.SetPosition(px, py) 92 | } else { 93 | fs.SetVisible(false) 94 | } 95 | } 96 | 97 | func (fs *FileSelect) SetPath(path string) error { 98 | 99 | // Open path file or dir 100 | f, err := os.Open(path) 101 | if err != nil { 102 | return err 103 | } 104 | defer f.Close() 105 | 106 | // Checks if it is a directory 107 | files, err := f.Readdir(0) 108 | if err != nil { 109 | return err 110 | } 111 | fs.path.SetText(path) 112 | 113 | // Sort files by name 114 | sort.Sort(listFileInfo(files)) 115 | 116 | // Reads directory contents and loads into the list 117 | fs.list.Clear() 118 | // Adds previous directory 119 | prev := gui.NewImageLabel("..") 120 | prev.SetIcon(icon.FolderOpen) 121 | fs.list.Add(prev) 122 | // Adds directory files 123 | for i := 0; i < len(files); i++ { 124 | item := gui.NewImageLabel(files[i].Name()) 125 | if files[i].IsDir() { 126 | item.SetIcon(icon.FolderOpen) 127 | } else { 128 | item.SetIcon(icon.InsertPhoto) 129 | } 130 | fs.list.Add(item) 131 | } 132 | return nil 133 | } 134 | 135 | func (fs *FileSelect) Selected() string { 136 | 137 | selist := fs.list.Selected() 138 | if len(selist) == 0 { 139 | return "" 140 | } 141 | label := selist[0].(*gui.ImageLabel) 142 | text := label.Text() 143 | return filepath.Join(fs.path.Text(), text) 144 | } 145 | 146 | func (fs *FileSelect) onSelect() { 147 | 148 | // Get selected image label and its txt 149 | sel := fs.list.Selected()[0] 150 | label := sel.(*gui.ImageLabel) 151 | text := label.Text() 152 | 153 | // Checks if previous directory 154 | if text == ".." { 155 | dir, _ := filepath.Split(fs.path.Text()) 156 | fs.SetPath(filepath.Dir(dir)) 157 | return 158 | } 159 | 160 | // Checks if it is a directory 161 | path := filepath.Join(fs.path.Text(), text) 162 | s, err := os.Stat(path) 163 | if err != nil { 164 | panic(err) 165 | } 166 | if s.IsDir() { 167 | fs.SetPath(path) 168 | } 169 | } 170 | 171 | // For sorting array of FileInfo by Name 172 | type listFileInfo []os.FileInfo 173 | 174 | func (fi listFileInfo) Len() int { return len(fi) } 175 | func (fi listFileInfo) Swap(i, j int) { fi[i], fi[j] = fi[j], fi[i] } 176 | func (fi listFileInfo) Less(i, j int) bool { 177 | 178 | return fi[i].Name() < fi[j].Name() 179 | } 180 | -------------------------------------------------------------------------------- /g3nview/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/g3n/demos/g3nview 2 | 3 | go 1.17 4 | 5 | require github.com/g3n/engine v0.2.0 6 | 7 | require ( 8 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb // indirect 9 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 10 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 // indirect 11 | gopkg.in/yaml.v2 v2.4.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /g3nview/go.sum: -------------------------------------------------------------------------------- 1 | github.com/g3n/engine v0.2.0 h1:7dmj4c+3xHcBnYrVmRuVf/oZ2JycxJU9Y+2FQj1Af2Y= 2 | github.com/g3n/engine v0.2.0/go.mod h1:rnj8jiLdKEDI8VbveKhmdL4rovjjy+uxNP5YROg2x8g= 3 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw= 4 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 5 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 7 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 h1:D0iM1dTCbD5Dg1CbuvLC/v/agLc79efSj/L35Q3Vqhs= 8 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 9 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 10 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 14 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 15 | -------------------------------------------------------------------------------- /g3nview/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The G3N Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "flag" 9 | "fmt" 10 | "io" 11 | "log" 12 | "os" 13 | "path/filepath" 14 | "time" 15 | 16 | "github.com/g3n/engine/app" 17 | "github.com/g3n/engine/camera" 18 | "github.com/g3n/engine/core" 19 | "github.com/g3n/engine/gls" 20 | "github.com/g3n/engine/gui" 21 | "github.com/g3n/engine/gui/assets/icon" 22 | "github.com/g3n/engine/light" 23 | "github.com/g3n/engine/loader/collada" 24 | "github.com/g3n/engine/loader/obj" 25 | "github.com/g3n/engine/math32" 26 | "github.com/g3n/engine/renderer" 27 | "github.com/g3n/engine/util/helper" 28 | "github.com/g3n/engine/window" 29 | ) 30 | 31 | type g3nView struct { 32 | *app.Application // Embedded application object 33 | fs *FileSelect // File selection dialog 34 | ed *ErrorDialog // Error dialog 35 | axes *helper.Axes // Axis helper 36 | grid *helper.Grid // Grid helper 37 | viewAxes bool // Axis helper visible flag 38 | viewGrid bool // Grid helper visible flag 39 | camPos math32.Vector3 // Initial camera position 40 | models []*core.Node // Models being shown 41 | scene *core.Node 42 | cam *camera.Camera 43 | orbit *camera.OrbitControl 44 | } 45 | 46 | const ( 47 | checkON = icon.CheckBox 48 | checkOFF = icon.CheckBoxOutlineBlank 49 | ) 50 | 51 | func main() { 52 | 53 | // Parse command line parameters 54 | flag.Usage = usage 55 | 56 | // Creates G3N application 57 | gv := new(g3nView) 58 | a := app.App() 59 | gv.Application = a 60 | gv.scene = core.NewNode() 61 | 62 | // Adds ambient light 63 | ambLight := light.NewAmbient(math32.NewColor("white"), 0.5) 64 | gv.scene.Add(ambLight) 65 | 66 | // Add directional white light from right 67 | dirLight := light.NewDirectional(math32.NewColor("white"), 1.0) 68 | dirLight.SetPosition(1, 0, 0) 69 | gv.scene.Add(dirLight) 70 | 71 | // Add an axis helper to the scene initially not visible 72 | gv.axes = helper.NewAxes(2) 73 | gv.viewAxes = true 74 | gv.axes.SetVisible(gv.viewAxes) 75 | gv.scene.Add(gv.axes) 76 | 77 | // Adds a grid helper to the scene initially not visible 78 | gv.grid = helper.NewGrid(50, 1, &math32.Color{0.4, 0.4, 0.4}) 79 | gv.viewGrid = true 80 | gv.grid.SetVisible(gv.viewGrid) 81 | gv.scene.Add(gv.grid) 82 | 83 | // Sets the initial camera position 84 | gv.camPos = math32.Vector3{8.3, 4.7, 3.7} 85 | gv.cam = camera.New(1) 86 | gv.cam.SetPositionVec(&gv.camPos) 87 | gv.cam.LookAt(&math32.Vector3{0, 0, 0}, &math32.Vector3{0, 1, 0}) 88 | gv.orbit = camera.NewOrbitControl(gv.cam) 89 | 90 | // Set up callback to update viewport and camera aspect ratio when the window is resized 91 | onResize := func(evname string, ev interface{}) { 92 | // Get framebuffer size and update viewport accordingly 93 | width, height := a.GetSize() 94 | a.Gls().Viewport(0, 0, int32(width), int32(height)) 95 | // Update the camera's aspect ratio 96 | gv.cam.SetAspect(float32(width) / float32(height)) 97 | } 98 | a.Subscribe(window.OnWindowSize, onResize) 99 | onResize("", nil) 100 | 101 | // Build the user interface 102 | gv.buildGui() 103 | 104 | // Try to load models specified in the command line 105 | for _, m := range flag.Args() { 106 | err := gv.openModel(m) 107 | if err != nil { 108 | log.Printf("error: %s", err) 109 | return 110 | } 111 | } 112 | 113 | // Set background color to gray 114 | a.Gls().ClearColor(0.5, 0.5, 0.5, 1.0) 115 | 116 | // Run application main render loop 117 | a.Run(func(renderer *renderer.Renderer, deltaTime time.Duration) { 118 | a.Gls().Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT) 119 | renderer.Render(gv.scene, gv.cam) 120 | }) 121 | 122 | } 123 | 124 | // setupGui builds the GUI 125 | func (gv *g3nView) buildGui() error { 126 | 127 | gui.Manager().Set(gv.scene) 128 | 129 | // Adds menu bar 130 | mb := gui.NewMenuBar() 131 | mb.SetLayoutParams(&gui.VBoxLayoutParams{Expand: 0, AlignH: gui.AlignWidth}) 132 | gv.scene.Add(mb) 133 | 134 | // Create "File" menu and adds it to the menu bar 135 | m1 := gui.NewMenu() 136 | m1.AddOption("Open model").Subscribe(gui.OnClick, func(evname string, ev interface{}) { 137 | gv.fs.Show(true) 138 | }) 139 | m1.AddOption("Remove models").Subscribe(gui.OnClick, func(evname string, ev interface{}) { 140 | gv.removeModels() 141 | }) 142 | m1.AddOption("Reset camera").Subscribe(gui.OnClick, func(evname string, ev interface{}) { 143 | gv.cam.SetPositionVec(&gv.camPos) 144 | gv.cam.LookAt(&math32.Vector3{0, 0, 0}, &math32.Vector3{0, 1, 0}) 145 | gv.orbit.Reset() 146 | }) 147 | m1.AddSeparator() 148 | m1.AddOption("Quit").SetId("quit").Subscribe(gui.OnClick, func(evname string, ev interface{}) { 149 | gv.Exit() 150 | }) 151 | mb.AddMenu("File", m1) 152 | 153 | // Create "View" menu and adds it to the menu bar 154 | m2 := gui.NewMenu() 155 | vAxis := m2.AddOption("View axis helper").SetIcon(checkOFF) 156 | vAxis.SetIcon(getIcon(gv.viewAxes)) 157 | vAxis.Subscribe(gui.OnClick, func(evname string, ev interface{}) { 158 | gv.viewAxes = !gv.viewAxes 159 | vAxis.SetIcon(getIcon(gv.viewAxes)) 160 | gv.axes.SetVisible(gv.viewAxes) 161 | }) 162 | 163 | vGrid := m2.AddOption("View grid helper").SetIcon(checkOFF) 164 | vGrid.SetIcon(getIcon(gv.viewGrid)) 165 | vGrid.Subscribe(gui.OnClick, func(evname string, ev interface{}) { 166 | gv.viewGrid = !gv.viewGrid 167 | vGrid.SetIcon(getIcon(gv.viewGrid)) 168 | gv.grid.SetVisible(gv.viewGrid) 169 | }) 170 | mb.AddMenu("View", m2) 171 | 172 | // Creates file selection dialog 173 | fs, err := NewFileSelect(400, 300) 174 | if err != nil { 175 | return err 176 | } 177 | gv.fs = fs 178 | gv.fs.SetVisible(false) 179 | gv.fs.Subscribe("OnOK", func(evname string, ev interface{}) { 180 | fpath := gv.fs.Selected() 181 | if fpath == "" { 182 | gv.ed.Show("File not selected") 183 | return 184 | } 185 | err := gv.openModel(fpath) 186 | if err != nil { 187 | gv.ed.Show(err.Error()) 188 | return 189 | } 190 | gv.fs.SetVisible(false) 191 | 192 | }) 193 | gv.fs.Subscribe("OnCancel", func(evname string, ev interface{}) { 194 | gv.fs.Show(false) 195 | }) 196 | gv.scene.Add(gv.fs) 197 | 198 | // Creates error dialog 199 | gv.ed = NewErrorDialog(600, 100) 200 | gv.scene.Add(gv.ed) 201 | 202 | return nil 203 | } 204 | 205 | // openModel try to open the specified model and add it to the scene 206 | func (gv *g3nView) openModel(fpath string) error { 207 | 208 | dir, file := filepath.Split(fpath) 209 | ext := filepath.Ext(file) 210 | 211 | // Loads OBJ model 212 | if ext == ".obj" { 213 | // Checks for material file in the same dir 214 | matfile := file[:len(file)-len(ext)] 215 | matpath := filepath.Join(dir, matfile) 216 | _, err := os.Stat(matpath) 217 | if err != nil { 218 | matpath = "" 219 | } 220 | 221 | // Decodes model in in OBJ format 222 | dec, err := obj.Decode(fpath, matpath) 223 | if err != nil { 224 | return err 225 | } 226 | 227 | // Creates a new node with all the objects in the decoded file and adds it to the scene 228 | group, err := dec.NewGroup() 229 | if err != nil { 230 | return err 231 | } 232 | gv.scene.Add(group) 233 | gv.models = append(gv.models, group) 234 | return nil 235 | } 236 | 237 | // Loads COLLADA model 238 | if ext == ".dae" { 239 | dec, err := collada.Decode(fpath) 240 | if err != nil && err != io.EOF { 241 | return err 242 | } 243 | dec.SetDirImages(dir) 244 | 245 | // Loads collada scene 246 | s, err := dec.NewScene() 247 | if err != nil { 248 | return err 249 | } 250 | gv.scene.Add(s) 251 | gv.models = append(gv.models, s.GetNode()) 252 | return nil 253 | } 254 | return fmt.Errorf("Unrecognized model file extension:[%s]", ext) 255 | } 256 | 257 | // removeModels removes and disposes of all loaded models in the scene 258 | func (gv *g3nView) removeModels() { 259 | 260 | for i := 0; i < len(gv.models); i++ { 261 | model := gv.models[i] 262 | gv.scene.Remove(model) 263 | model.Dispose() 264 | } 265 | } 266 | 267 | func getIcon(state bool) string { 268 | 269 | if state { 270 | return checkON 271 | } else { 272 | return checkOFF 273 | } 274 | } 275 | 276 | // usage shows the application usage 277 | func usage() { 278 | 279 | fmt.Fprintf(os.Stderr, "usage: g3nview [model1 model2 modelN]\n") 280 | flag.PrintDefaults() 281 | os.Exit(2) 282 | } 283 | -------------------------------------------------------------------------------- /gopher3d/README.md: -------------------------------------------------------------------------------- 1 | gopher-3d 2 | ========= 3 | 4 | Gopher 3D model 5 | 6 | 7 | 8 | The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) 9 | The gopher 3D model was made by Takuya Ueda (https://twitter.com/tenntenn). 10 | Licensed under the Creative Commons 3.0 Attributions license. 11 | 12 | 13 | Creative Commons licensing 14 | 15 | -------------------------------------------------------------------------------- /gopher3d/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/g3n/demos/gopher3d 2 | 3 | go 1.17 4 | 5 | require github.com/g3n/engine v0.2.0 6 | 7 | require ( 8 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb // indirect 9 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 10 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 // indirect 11 | gopkg.in/yaml.v2 v2.4.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /gopher3d/go.sum: -------------------------------------------------------------------------------- 1 | github.com/g3n/engine v0.2.0 h1:7dmj4c+3xHcBnYrVmRuVf/oZ2JycxJU9Y+2FQj1Af2Y= 2 | github.com/g3n/engine v0.2.0/go.mod h1:rnj8jiLdKEDI8VbveKhmdL4rovjjy+uxNP5YROg2x8g= 3 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw= 4 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 5 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 7 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 h1:D0iM1dTCbD5Dg1CbuvLC/v/agLc79efSj/L35Q3Vqhs= 8 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 9 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 10 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 14 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 15 | -------------------------------------------------------------------------------- /gopher3d/gopher.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g3n/demos/541b62abcc93939ed4319f8f31cdb9ef9f50c070/gopher3d/gopher.blend -------------------------------------------------------------------------------- /gopher3d/gopher.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'gopher.blend' 2 | # Material Count: 7 3 | 4 | newmtl Body 5 | Ns 96.078431 6 | Ka 1.000000 1.000000 1.000000 7 | Kd 0.000000 0.429367 0.640000 8 | Ks 0.500000 0.500000 0.500000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | 14 | newmtl Eye-White 15 | Ns 96.078431 16 | Ka 1.000000 1.000000 1.000000 17 | Kd 0.800000 0.800000 0.800000 18 | Ks 1.000000 1.000000 1.000000 19 | Ke 0.000000 0.000000 0.000000 20 | Ni 1.000000 21 | d 1.000000 22 | illum 2 23 | 24 | newmtl Material 25 | Ns 96.078431 26 | Ka 1.000000 1.000000 1.000000 27 | Kd 0.640000 0.640000 0.640000 28 | Ks 0.500000 0.500000 0.500000 29 | Ke 0.000000 0.000000 0.000000 30 | Ni 1.000000 31 | d 1.000000 32 | illum 2 33 | 34 | newmtl Material.001 35 | Ns 96.078431 36 | Ka 1.000000 1.000000 1.000000 37 | Kd 0.000000 0.000000 0.000000 38 | Ks 0.000000 0.000000 0.000000 39 | Ke 0.000000 0.000000 0.000000 40 | Ni 1.000000 41 | d 1.000000 42 | illum 2 43 | 44 | newmtl NoseTop 45 | Ns 96.078431 46 | Ka 1.000000 1.000000 1.000000 47 | Kd 0.000000 0.000000 0.000000 48 | Ks 0.000000 0.000000 0.000000 49 | Ke 0.000000 0.000000 0.000000 50 | Ni 1.000000 51 | d 1.000000 52 | illum 2 53 | 54 | newmtl SkinColor 55 | Ns 96.078431 56 | Ka 1.000000 1.000000 1.000000 57 | Kd 0.609017 0.353452 0.144174 58 | Ks 0.500000 0.500000 0.500000 59 | Ke 0.000000 0.000000 0.000000 60 | Ni 1.000000 61 | d 1.000000 62 | illum 2 63 | 64 | newmtl Tooth 65 | Ns 96.078431 66 | Ka 1.000000 1.000000 1.000000 67 | Kd 0.640000 0.640000 0.640000 68 | Ks 0.500000 0.500000 0.500000 69 | Ke 0.000000 0.000000 0.000000 70 | Ni 1.000000 71 | d 1.000000 72 | illum 2 73 | -------------------------------------------------------------------------------- /gopher3d/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/g3n/engine/app" 5 | "github.com/g3n/engine/camera" 6 | "github.com/g3n/engine/core" 7 | "github.com/g3n/engine/gls" 8 | "github.com/g3n/engine/gui" 9 | "github.com/g3n/engine/light" 10 | "github.com/g3n/engine/loader/obj" 11 | "github.com/g3n/engine/math32" 12 | "github.com/g3n/engine/renderer" 13 | "github.com/g3n/engine/window" 14 | "time" 15 | ) 16 | 17 | func main() { 18 | 19 | // Create application and scene 20 | a := app.App() 21 | scene := core.NewNode() 22 | 23 | // Set the scene to be managed by the gui manager 24 | gui.Manager().Set(scene) 25 | 26 | // Create perspective camera 27 | cam := camera.New(1) 28 | cam.SetPosition(0, 0, 3) 29 | scene.Add(cam) 30 | 31 | // Set up orbit control for the camera 32 | camera.NewOrbitControl(cam) 33 | 34 | // Set up callback to update viewport and camera aspect ratio when the window is resized 35 | onResize := func(evname string, ev interface{}) { 36 | // Get framebuffer size and update viewport accordingly 37 | width, height := a.GetSize() 38 | a.Gls().Viewport(0, 0, int32(width), int32(height)) 39 | // Update the camera's aspect ratio 40 | cam.SetAspect(float32(width) / float32(height)) 41 | } 42 | a.Subscribe(window.OnWindowSize, onResize) 43 | onResize("", nil) 44 | 45 | // Decode model in in OBJ format 46 | dec, err := obj.Decode("gopher.obj", "gopher.mtl") 47 | if err != nil { 48 | panic(err.Error()) 49 | } 50 | 51 | // Create a new node with all the objects in the decoded file and adds it to the scene 52 | group, err := dec.NewGroup() 53 | if err != nil { 54 | panic(err.Error()) 55 | } 56 | group.SetScale(0.3, 0.3, 0.3) 57 | group.SetPosition(0.0, -0.8, -0.2) 58 | scene.Add(group) 59 | 60 | // Create and add ambient light to scene 61 | scene.Add(light.NewAmbient(&math32.Color{1.0, 1.0, 1.0}, 0.8)) 62 | 63 | // Create and add directional white light to the scene 64 | dirLight := light.NewDirectional(&math32.Color{1, 1, 1}, 1.0) 65 | dirLight.SetPosition(1, 0, 0) 66 | scene.Add(dirLight) 67 | 68 | // Set background color to gray 69 | a.Gls().ClearColor(0.5, 0.5, 0.5, 1.0) 70 | 71 | // Run the application 72 | a.Run(func(renderer *renderer.Renderer, deltaTime time.Duration) { 73 | a.Gls().Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT) 74 | renderer.Render(scene, cam) 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /hellog3n/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/g3n/demos/hellog3n 2 | 3 | go 1.17 4 | 5 | require github.com/g3n/engine v0.2.0 6 | 7 | require ( 8 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb // indirect 9 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 10 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 // indirect 11 | gopkg.in/yaml.v2 v2.4.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /hellog3n/go.sum: -------------------------------------------------------------------------------- 1 | github.com/g3n/engine v0.2.0 h1:7dmj4c+3xHcBnYrVmRuVf/oZ2JycxJU9Y+2FQj1Af2Y= 2 | github.com/g3n/engine v0.2.0/go.mod h1:rnj8jiLdKEDI8VbveKhmdL4rovjjy+uxNP5YROg2x8g= 3 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw= 4 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 5 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 7 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 h1:D0iM1dTCbD5Dg1CbuvLC/v/agLc79efSj/L35Q3Vqhs= 8 | golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 9 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 10 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 14 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 15 | -------------------------------------------------------------------------------- /hellog3n/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/g3n/engine/app" 5 | "github.com/g3n/engine/camera" 6 | "github.com/g3n/engine/core" 7 | "github.com/g3n/engine/geometry" 8 | "github.com/g3n/engine/gls" 9 | "github.com/g3n/engine/graphic" 10 | "github.com/g3n/engine/gui" 11 | "github.com/g3n/engine/light" 12 | "github.com/g3n/engine/material" 13 | "github.com/g3n/engine/math32" 14 | "github.com/g3n/engine/renderer" 15 | "github.com/g3n/engine/util/helper" 16 | "github.com/g3n/engine/window" 17 | "time" 18 | ) 19 | 20 | func main() { 21 | 22 | // Create application and scene 23 | a := app.App() 24 | scene := core.NewNode() 25 | 26 | // Set the scene to be managed by the gui manager 27 | gui.Manager().Set(scene) 28 | 29 | // Create perspective camera 30 | cam := camera.New(1) 31 | cam.SetPosition(0, 0, 3) 32 | scene.Add(cam) 33 | 34 | // Set up orbit control for the camera 35 | camera.NewOrbitControl(cam) 36 | 37 | // Set up callback to update viewport and camera aspect ratio when the window is resized 38 | onResize := func(evname string, ev interface{}) { 39 | // Get framebuffer size and update viewport accordingly 40 | width, height := a.GetSize() 41 | a.Gls().Viewport(0, 0, int32(width), int32(height)) 42 | // Update the camera's aspect ratio 43 | cam.SetAspect(float32(width) / float32(height)) 44 | } 45 | a.Subscribe(window.OnWindowSize, onResize) 46 | onResize("", nil) 47 | 48 | // Create a blue torus and add it to the scene 49 | geom := geometry.NewTorus(1, .4, 12, 32, math32.Pi*2) 50 | mat := material.NewStandard(math32.NewColor("DarkBlue")) 51 | mesh := graphic.NewMesh(geom, mat) 52 | scene.Add(mesh) 53 | 54 | // Create and add a button to the scene 55 | btn := gui.NewButton("Make Red") 56 | btn.SetPosition(100, 40) 57 | btn.SetSize(40, 40) 58 | btn.Subscribe(gui.OnClick, func(name string, ev interface{}) { 59 | mat.SetColor(math32.NewColor("DarkRed")) 60 | }) 61 | scene.Add(btn) 62 | 63 | // Create and add lights to the scene 64 | scene.Add(light.NewAmbient(&math32.Color{1.0, 1.0, 1.0}, 0.8)) 65 | pointLight := light.NewPoint(&math32.Color{1, 1, 1}, 5.0) 66 | pointLight.SetPosition(1, 0, 2) 67 | scene.Add(pointLight) 68 | 69 | // Create and add an axis helper to the scene 70 | scene.Add(helper.NewAxes(0.5)) 71 | 72 | // Set background color to gray 73 | a.Gls().ClearColor(0.5, 0.5, 0.5, 1.0) 74 | 75 | // Run the application 76 | a.Run(func(renderer *renderer.Renderer, deltaTime time.Duration) { 77 | a.Gls().Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT) 78 | renderer.Render(scene, cam) 79 | }) 80 | } 81 | -------------------------------------------------------------------------------- /hellog3n/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g3n/demos/541b62abcc93939ed4319f8f31cdb9ef9f50c070/hellog3n/screenshot.png --------------------------------------------------------------------------------