├── .gitignore ├── README.md ├── lesson01 └── lesson01.go ├── lesson02 └── lesson02.go ├── lesson03 └── lesson03.go ├── lesson04 └── lesson04.go ├── lesson05 └── lesson05.go ├── lesson06 ├── data │ └── nehe.bmp └── lesson06.go ├── lesson07 ├── data │ └── crate.bmp └── lesson07.go ├── lesson08 ├── data │ └── glass.bmp └── lesson08.go ├── lesson09 ├── data │ └── star.bmp └── lesson09.go └── lesson10 ├── data ├── mud.bmp └── world.txt └── lesson10.go /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.6 3 | _obj/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tutorials for OpenGL in Go 2 | 3 | Tutorials translated from "NeHe Productions":http://nehe.gamedev.net/ into Go with SDL. 4 | 5 | ## Dependencies 6 | 7 | First we need to install the dependencies: 8 | 9 | go get github.com/banthar/gl github.com/banthar/glu github.com/banthar/Go-SDL/sdl 10 | 11 | ## Running the examples 12 | 13 | You can use `go run`, like this: 14 | 15 | cd lesson01 16 | go run lesson01.go 17 | 18 | Please note that starting with lesson06, you _have_ to cd into the directory 19 | because we start using external data. 20 | -------------------------------------------------------------------------------- /lesson01/lesson01.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1366 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(width / height) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // enable smooth shading 79 | gl.ShadeModel(gl.SMOOTH) 80 | 81 | // Set the background to black 82 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 83 | 84 | // Depth buffer setup 85 | gl.ClearDepth(1.0) 86 | 87 | // Enable depth testing 88 | gl.Enable(gl.DEPTH_TEST) 89 | 90 | // The type of test 91 | gl.DepthFunc(gl.LEQUAL) 92 | 93 | // Nicest perspective correction 94 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 95 | } 96 | 97 | // used to calculate fps 98 | var t0 uint32 99 | var frames uint32 100 | 101 | // Here goes our drawing code 102 | func drawGLScene() { 103 | // Clear the screen and depth buffer 104 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 105 | 106 | // reset the view 107 | gl.LoadIdentity() 108 | 109 | // Draw to the screen 110 | sdl.GL_SwapBuffers() 111 | 112 | // Gather our frames per second 113 | frames++ 114 | t := sdl.GetTicks() 115 | if t-t0 >= 5000 { 116 | seconds := (t - t0) / 1000.0 117 | fps := frames / seconds 118 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 119 | t0 = t 120 | frames = 0 121 | } 122 | } 123 | 124 | func main() { 125 | // Initialize SDL 126 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 127 | panic("Video initialization failed: " + sdl.GetError()) 128 | } 129 | 130 | // flags to pass to sdl.SetVideoMode 131 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 132 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 133 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 134 | videoFlags |= sdl.RESIZABLE // Enable window resizing 135 | 136 | // get a SDL surface 137 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 138 | 139 | // verify there is a surface 140 | if surface == nil { 141 | panic("Video mode set failed: " + sdl.GetError()) 142 | Quit(1) 143 | } 144 | 145 | // When this function is finished, clean up and exit. 146 | defer Quit(0) 147 | 148 | // Sets up OpenGL double buffering 149 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 150 | 151 | // Execute everything needed for OpenGL 152 | initGL() 153 | 154 | // Resize the initial window 155 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 156 | 157 | // wait for events 158 | running := true 159 | isActive := true 160 | for running { 161 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 162 | switch e := ev.(type) { 163 | case *sdl.ActiveEvent: 164 | isActive = e.Gain != 0 165 | case *sdl.ResizeEvent: 166 | width, height := int(e.W), int(e.H) 167 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 168 | 169 | if surface == nil { 170 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 171 | Quit(1) 172 | } 173 | resizeWindow(width, height) 174 | case *sdl.KeyboardEvent: 175 | if e.Type == sdl.KEYDOWN { 176 | handleKeyPress(e.Keysym) 177 | } 178 | case *sdl.QuitEvent: 179 | running = false 180 | } 181 | } 182 | 183 | // draw the scene 184 | if isActive { 185 | drawGLScene() 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /lesson02/lesson02.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1366 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // enable smooth shading 79 | gl.ShadeModel(gl.SMOOTH) 80 | 81 | // Set the background to black 82 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 83 | 84 | // Depth buffer setup 85 | gl.ClearDepth(1.0) 86 | 87 | // Enable depth testing 88 | gl.Enable(gl.DEPTH_TEST) 89 | 90 | // The type of test 91 | gl.DepthFunc(gl.LEQUAL) 92 | 93 | // Nicest perspective correction 94 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 95 | } 96 | 97 | // used to calculate fps 98 | var t0 uint32 99 | var frames uint32 100 | 101 | // Here goes our drawing code 102 | func drawGLScene() { 103 | // Clear the screen and depth buffer 104 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 105 | 106 | // Move left 1.5 units and into the screen 6.0 units. 107 | gl.LoadIdentity() 108 | gl.Translatef(-1.5, 0.0, -6.0) 109 | 110 | gl.Begin(gl.TRIANGLES) // Draw triangles 111 | gl.Vertex3f(0.0, 1.0, 0.0) // top 112 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 113 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 114 | gl.End() // finish drawing the triangle 115 | 116 | // Move right 3 units 117 | gl.Translatef(3.0, 0.0, 0.0) 118 | 119 | gl.Begin(gl.QUADS) // draw quads 120 | gl.Vertex3f(-1.0, 1.0, 0.0) // top left 121 | gl.Vertex3f(1.0, 1.0, 0.0) // top right 122 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 123 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 124 | gl.End() // done drawing the quad 125 | 126 | // Draw to the screen 127 | sdl.GL_SwapBuffers() 128 | 129 | // Gather our frames per second 130 | frames++ 131 | t := sdl.GetTicks() 132 | if t-t0 >= 5000 { 133 | seconds := (t - t0) / 1000.0 134 | fps := frames / seconds 135 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 136 | t0 = t 137 | frames = 0 138 | } 139 | } 140 | 141 | func main() { 142 | // Initialize SDL 143 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 144 | panic("Video initialization failed: " + sdl.GetError()) 145 | } 146 | 147 | // flags to pass to sdl.SetVideoMode 148 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 149 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 150 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 151 | // FIXME: this causes segfault. 152 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 153 | 154 | // get a SDL surface 155 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 156 | 157 | // verify there is a surface 158 | if surface == nil { 159 | panic("Video mode set failed: " + sdl.GetError()) 160 | Quit(1) 161 | } 162 | 163 | // When this function is finished, clean up and exit. 164 | defer Quit(0) 165 | 166 | // Sets up OpenGL double buffering 167 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 168 | 169 | // Execute everything needed for OpenGL 170 | initGL() 171 | 172 | // Resize the initial window 173 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 174 | 175 | // wait for events 176 | running := true 177 | isActive := true 178 | for running { 179 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 180 | switch e := ev.(type) { 181 | case *sdl.ActiveEvent: 182 | isActive = e.Gain != 0 183 | case *sdl.ResizeEvent: 184 | width, height := int(e.W), int(e.H) 185 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 186 | 187 | if surface == nil { 188 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 189 | Quit(1) 190 | } 191 | resizeWindow(width, height) 192 | case *sdl.KeyboardEvent: 193 | if e.Type == sdl.KEYDOWN { 194 | handleKeyPress(e.Keysym) 195 | } 196 | case *sdl.QuitEvent: 197 | running = false 198 | } 199 | } 200 | 201 | // draw the scene 202 | if isActive { 203 | drawGLScene() 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /lesson03/lesson03.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1366 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // enable smooth shading 79 | gl.ShadeModel(gl.SMOOTH) 80 | 81 | // Set the background to black 82 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 83 | 84 | // Depth buffer setup 85 | gl.ClearDepth(1.0) 86 | 87 | // Enable depth testing 88 | gl.Enable(gl.DEPTH_TEST) 89 | 90 | // The type of test 91 | gl.DepthFunc(gl.LEQUAL) 92 | 93 | // Nicest perspective correction 94 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 95 | } 96 | 97 | var ( 98 | t0, frames uint32 // used to calculate fps 99 | ) 100 | 101 | // Here goes our drawing code 102 | func drawGLScene() { 103 | // Clear the screen and depth buffer 104 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 105 | 106 | // Move left 1.5 units and into the screen 6.0 units. 107 | gl.LoadIdentity() 108 | gl.Translatef(-1.5, 0.0, -6.0) 109 | 110 | gl.Begin(gl.TRIANGLES) // Draw triangles 111 | gl.Color3f(1.0, 0.0, 0.0) // Set The Color To Red 112 | gl.Vertex3f(0.0, 1.0, 0.0) // top 113 | gl.Color3f(0.0, 1.0, 0.0) // Set The Color To Red 114 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 115 | gl.Color3f(0.0, 0.0, 1.0) // Set The Color To Red 116 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 117 | gl.End() // finish drawing the triangle 118 | 119 | // Move right 3 units 120 | gl.Translatef(3.0, 0.0, 0.0) 121 | gl.Color3f(0.5, 0.5, 1.0) // Set The Color To Blue One Time Only 122 | 123 | gl.Begin(gl.QUADS) // draw quads 124 | gl.Vertex3f(-1.0, 1.0, 0.0) // top left 125 | gl.Vertex3f(1.0, 1.0, 0.0) // top right 126 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 127 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 128 | gl.End() // done drawing the quad 129 | 130 | // Draw to the screen 131 | sdl.GL_SwapBuffers() 132 | 133 | // Gather our frames per second 134 | frames++ 135 | t := sdl.GetTicks() 136 | if t-t0 >= 5000 { 137 | seconds := (t - t0) / 1000.0 138 | fps := frames / seconds 139 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 140 | t0 = t 141 | frames = 0 142 | } 143 | } 144 | 145 | func main() { 146 | // Initialize SDL 147 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 148 | panic("Video initialization failed: " + sdl.GetError()) 149 | } 150 | 151 | // flags to pass to sdl.SetVideoMode 152 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 153 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 154 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 155 | // FIXME: this causes segfault. 156 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 157 | 158 | // get a SDL surface 159 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 160 | 161 | // verify there is a surface 162 | if surface == nil { 163 | panic("Video mode set failed: " + sdl.GetError()) 164 | Quit(1) 165 | } 166 | 167 | // When this function is finished, clean up and exit. 168 | defer Quit(0) 169 | 170 | // Sets up OpenGL double buffering 171 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 172 | 173 | // Execute everything needed for OpenGL 174 | initGL() 175 | 176 | // Resize the initial window 177 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 178 | 179 | // wait for events 180 | running := true 181 | isActive := true 182 | for running { 183 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 184 | switch e := ev.(type) { 185 | case *sdl.ActiveEvent: 186 | isActive = e.Gain != 0 187 | case *sdl.ResizeEvent: 188 | width, height := int(e.W), int(e.H) 189 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 190 | 191 | if surface == nil { 192 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 193 | Quit(1) 194 | } 195 | resizeWindow(width, height) 196 | case *sdl.KeyboardEvent: 197 | if e.Type == sdl.KEYDOWN { 198 | handleKeyPress(e.Keysym) 199 | } 200 | case *sdl.QuitEvent: 201 | running = false 202 | } 203 | } 204 | 205 | // draw the scene 206 | if isActive { 207 | drawGLScene() 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /lesson04/lesson04.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1366 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // enable smooth shading 79 | gl.ShadeModel(gl.SMOOTH) 80 | 81 | // Set the background to black 82 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 83 | 84 | // Depth buffer setup 85 | gl.ClearDepth(1.0) 86 | 87 | // Enable depth testing 88 | gl.Enable(gl.DEPTH_TEST) 89 | 90 | // The type of test 91 | gl.DepthFunc(gl.LEQUAL) 92 | 93 | // Nicest perspective correction 94 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 95 | } 96 | 97 | var ( 98 | t0, frames uint32 // used to calculate fps 99 | rtri gl.GLfloat 100 | rquad gl.GLfloat 101 | ) 102 | 103 | // Here goes our drawing code 104 | func drawGLScene() { 105 | // Clear the screen and depth buffer 106 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 107 | 108 | // Move left 1.5 units and into the screen 6.0 units. 109 | gl.LoadIdentity() 110 | gl.Translatef(-1.5, 0.0, -6.0) 111 | gl.Rotatef(float32(rtri), 0.0, 1.0, 0.0) // Rotate the triangle on the Y axis 112 | 113 | gl.Begin(gl.TRIANGLES) // Draw triangles 114 | gl.Color3f(1.0, 0.0, 0.0) // Set The Color To Red 115 | gl.Vertex3f(0.0, 1.0, 0.0) // top 116 | gl.Color3f(0.0, 1.0, 0.0) // Set The Color To Red 117 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 118 | gl.Color3f(0.0, 0.0, 1.0) // Set The Color To Red 119 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 120 | gl.End() // finish drawing the triangle 121 | 122 | // Move right 3 units 123 | gl.LoadIdentity() 124 | gl.Translatef(1.5, 0.0, -6.0) 125 | gl.Color3f(0.5, 0.5, 1.0) // Set The Color To Blue One Time Only 126 | gl.Rotatef(float32(rquad), 1.0, 0.0, 0.0) // rotate the quad on the X axis 127 | 128 | gl.Begin(gl.QUADS) // draw quads 129 | gl.Vertex3f(-1.0, 1.0, 0.0) // top left 130 | gl.Vertex3f(1.0, 1.0, 0.0) // top right 131 | gl.Vertex3f(1.0, -1.0, 0.0) // bottom right 132 | gl.Vertex3f(-1.0, -1.0, 0.0) // bottom left 133 | gl.End() // done drawing the quad 134 | 135 | // Draw to the screen 136 | sdl.GL_SwapBuffers() 137 | 138 | rtri += 0.2 // Increase The Rotation Variable For The Triangle 139 | rquad -= 0.15 // Decrease The Rotation Variable For The Quad 140 | 141 | // Gather our frames per second 142 | frames++ 143 | t := sdl.GetTicks() 144 | if t-t0 >= 5000 { 145 | seconds := (t - t0) / 1000.0 146 | fps := frames / seconds 147 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 148 | t0 = t 149 | frames = 0 150 | } 151 | } 152 | 153 | func main() { 154 | // Initialize SDL 155 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 156 | panic("Video initialization failed: " + sdl.GetError()) 157 | } 158 | 159 | // flags to pass to sdl.SetVideoMode 160 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 161 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 162 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 163 | // FIXME: this causes segfault. 164 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 165 | 166 | // get a SDL surface 167 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 168 | 169 | // verify there is a surface 170 | if surface == nil { 171 | panic("Video mode set failed: " + sdl.GetError()) 172 | Quit(1) 173 | } 174 | 175 | // When this function is finished, clean up and exit. 176 | defer Quit(0) 177 | 178 | // Sets up OpenGL double buffering 179 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 180 | 181 | // Execute everything needed for OpenGL 182 | initGL() 183 | 184 | // Resize the initial window 185 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 186 | 187 | // wait for events 188 | running := true 189 | isActive := true 190 | for running { 191 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 192 | switch e := ev.(type) { 193 | case *sdl.ActiveEvent: 194 | isActive = e.Gain != 0 195 | case *sdl.ResizeEvent: 196 | width, height := int(e.W), int(e.H) 197 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 198 | if surface == nil { 199 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 200 | Quit(1) 201 | } 202 | resizeWindow(width, height) 203 | case *sdl.KeyboardEvent: 204 | if e.Type == sdl.KEYDOWN { 205 | handleKeyPress(e.Keysym) 206 | } 207 | case *sdl.QuitEvent: 208 | running = false 209 | } 210 | } 211 | // draw the scene 212 | if isActive { 213 | drawGLScene() 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /lesson05/lesson05.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1024 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // enable smooth shading 79 | gl.ShadeModel(gl.SMOOTH) 80 | 81 | // Set the background to black 82 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 83 | 84 | // Depth buffer setup 85 | gl.ClearDepth(1.0) 86 | 87 | // Enable depth testing 88 | gl.Enable(gl.DEPTH_TEST) 89 | 90 | // The type of test 91 | gl.DepthFunc(gl.LEQUAL) 92 | 93 | // Nicest perspective correction 94 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 95 | } 96 | 97 | var ( 98 | t0, frames uint32 // used to calculate fps 99 | rtri gl.GLfloat 100 | rquad gl.GLfloat 101 | ) 102 | 103 | // Here goes our drawing code 104 | func drawGLScene() { 105 | // Clear the screen and depth buffer 106 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 107 | 108 | // Move left 1.5 units and into the screen 6.0 units. 109 | gl.LoadIdentity() 110 | gl.Translatef(-1.5, 0.0, -6.0) 111 | gl.Rotatef(float32(rtri), 0.0, 1.0, 0.0) // Rotate the triangle on the Y axis 112 | 113 | gl.Begin(gl.TRIANGLES) // Draw triangles 114 | 115 | gl.Color3f(1.0, 0.0, 0.0) /* Red */ 116 | gl.Vertex3f(0.0, 1.0, 0.0) /* Top Of Triangle (Front) */ 117 | gl.Color3f(0.0, 1.0, 0.0) /* Green */ 118 | gl.Vertex3f(-1.0, -1.0, 1.0) /* Left Of Triangle (Front) */ 119 | gl.Color3f(0.0, 0.0, 1.0) /* Blue */ 120 | gl.Vertex3f(1.0, -1.0, 1.0) /* Right Of Triangle (Front) */ 121 | 122 | gl.Color3f(1.0, 0.0, 0.0) /* Red */ 123 | gl.Vertex3f(0.0, 1.0, 0.0) /* Top Of Triangle (Right) */ 124 | gl.Color3f(0.0, 0.0, 1.0) /* Blue */ 125 | gl.Vertex3f(1.0, -1.0, 1.0) /* Left Of Triangle (Right) */ 126 | gl.Color3f(0.0, 1.0, 0.0) /* Green */ 127 | gl.Vertex3f(1.0, -1.0, -1.0) /* Right Of Triangle (Right) */ 128 | 129 | gl.Color3f(1.0, 0.0, 0.0) /* Red */ 130 | gl.Vertex3f(0.0, 1.0, 0.0) /* Top Of Triangle (Back) */ 131 | gl.Color3f(0.0, 1.0, 0.0) /* Green */ 132 | gl.Vertex3f(1.0, -1.0, -1.0) /* Left Of Triangle (Back) */ 133 | gl.Color3f(0.0, 0.0, 1.0) /* Blue */ 134 | gl.Vertex3f(-1.0, -1.0, -1.0) /* Right Of Triangle (Back) */ 135 | 136 | gl.Color3f(1.0, 0.0, 0.0) /* Red */ 137 | gl.Vertex3f(0.0, 1.0, 0.0) /* Top Of Triangle (Left) */ 138 | gl.Color3f(0.0, 0.0, 1.0) /* Blue */ 139 | gl.Vertex3f(-1.0, -1.0, -1.0) /* Left Of Triangle (Left) */ 140 | gl.Color3f(0.0, 1.0, 0.0) /* Green */ 141 | gl.Vertex3f(-1.0, -1.0, 1.0) /* Right Of Triangle (Left) */ 142 | 143 | gl.End() // finish drawing the triangle 144 | 145 | // Move right 3 units 146 | gl.LoadIdentity() 147 | gl.Translatef(1.5, 0.0, -7.0) 148 | gl.Rotatef(float32(rquad), 1.0, 1.0, 1.0) // rotate the quad on the X axis 149 | 150 | gl.Begin(gl.QUADS) // draw quads 151 | gl.Color3f(0.0, 1.0, 0.0) // Set The Color To Green 152 | gl.Vertex3f(1.0, 1.0, -1.0) // Top Right Of The Quad (Top) 153 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top Left Of The Quad (Top) 154 | gl.Vertex3f(-1.0, 1.0, 1.0) // Bottom Left Of The Quad (Top) 155 | gl.Vertex3f(1.0, 1.0, 1.0) // Bottom Right Of The Quad (Top) 156 | gl.Color3f(1.0, 0.5, 0.0) // Set The Color To Orange 157 | gl.Vertex3f(1.0, -1.0, 1.0) // Top Right Of The Quad (Bottom) 158 | gl.Vertex3f(-1.0, -1.0, 1.0) // Top Left Of The Quad (Bottom) 159 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom Left Of The Quad (Bottom) 160 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom Right Of The Quad (Bottom) 161 | gl.Color3f(1.0, 0.0, 0.0) // Set The Color To Red 162 | gl.Vertex3f(1.0, 1.0, 1.0) // Top Right Of The Quad (Front) 163 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top Left Of The Quad (Front) 164 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom Left Of The Quad (Front) 165 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom Right Of The Quad (Front) 166 | gl.Color3f(1.0, 1.0, 0.0) // Set The Color To Yellow 167 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom Left Of The Quad (Back) 168 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom Right Of The Quad (Back) 169 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top Right Of The Quad (Back) 170 | gl.Vertex3f(1.0, 1.0, -1.0) // Top Left Of The Quad (Back) 171 | gl.Color3f(0.0, 0.0, 1.0) // Set The Color To Blue 172 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top Right Of The Quad (Left) 173 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top Left Of The Quad (Left) 174 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom Left Of The Quad (Left) 175 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom Right Of The Quad (Left) 176 | gl.Color3f(1.0, 0.0, 1.0) // Set The Color To Violet 177 | gl.Vertex3f(1.0, 1.0, -1.0) // Top Right Of The Quad (Right) 178 | gl.Vertex3f(1.0, 1.0, 1.0) // Top Left Of The Quad (Right) 179 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom Left Of The Quad (Right) 180 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom Right Of The Quad (Right) 181 | gl.End() // done drawing the quad 182 | 183 | // Draw to the screen 184 | sdl.GL_SwapBuffers() 185 | 186 | rtri += 0.2 // Increase The Rotation Variable For The Triangle 187 | rquad -= 0.15 // Decrease The Rotation Variable For The Quad 188 | 189 | // Gather our frames per second 190 | frames++ 191 | t := sdl.GetTicks() 192 | if t-t0 >= 5000 { 193 | seconds := (t - t0) / 1000.0 194 | fps := frames / seconds 195 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 196 | t0 = t 197 | frames = 0 198 | } 199 | } 200 | 201 | func main() { 202 | // Initialize SDL 203 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 204 | panic("Video initialization failed: " + sdl.GetError()) 205 | } 206 | 207 | // flags to pass to sdl.SetVideoMode 208 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 209 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 210 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 211 | // FIXME: this causes segfault. 212 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 213 | 214 | // get a SDL surface 215 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 216 | 217 | // verify there is a surface 218 | if surface == nil { 219 | panic("Video mode set failed: " + sdl.GetError()) 220 | Quit(1) 221 | } 222 | 223 | // When this function is finished, clean up and exit. 224 | defer Quit(0) 225 | 226 | // Sets up OpenGL double buffering 227 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 228 | 229 | // Execute everything needed for OpenGL 230 | initGL() 231 | 232 | // Resize the initial window 233 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 234 | 235 | // wait for events 236 | running := true 237 | isActive := true 238 | for running { 239 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 240 | switch e := ev.(type) { 241 | case *sdl.ActiveEvent: 242 | isActive = e.Gain != 0 243 | case *sdl.ResizeEvent: 244 | width, height := int(e.W), int(e.H) 245 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 246 | if surface == nil { 247 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 248 | Quit(1) 249 | } 250 | resizeWindow(width, height) 251 | case *sdl.KeyboardEvent: 252 | if e.Type == sdl.KEYDOWN { 253 | handleKeyPress(e.Keysym) 254 | } 255 | case *sdl.QuitEvent: 256 | running = false 257 | } 258 | } 259 | 260 | // draw the scene 261 | if isActive { 262 | drawGLScene() 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /lesson06/data/nehe.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manveru/opengl-go-tutorials/20aa51b091cf82318229087be800412b6c92bcb3/lesson06/data/nehe.bmp -------------------------------------------------------------------------------- /lesson06/lesson06.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "os" 9 | ) 10 | 11 | const ( 12 | SCREEN_WIDTH = 1024 13 | SCREEN_HEIGHT = 768 14 | SCREEN_BPP = 32 15 | ) 16 | 17 | var ( 18 | surface *sdl.Surface 19 | ) 20 | 21 | // release/destroy our resources and restoring the old desktop 22 | func Quit(status int) { 23 | // clean up the window 24 | sdl.Quit() 25 | 26 | // and exit appropriately 27 | os.Exit(status) 28 | } 29 | 30 | // reset our viewport after a window resize 31 | func resizeWindow(width, height int) { 32 | // protect against a divide by zero 33 | if height == 0 { 34 | height = 1 35 | } 36 | 37 | // Setup our viewport 38 | gl.Viewport(0, 0, width, height) 39 | 40 | // change to the projection matrix and set our viewing volume. 41 | gl.MatrixMode(gl.PROJECTION) 42 | gl.LoadIdentity() 43 | 44 | // aspect ratio 45 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 46 | 47 | // Set our perspective. 48 | // This code is equivalent to using gluPerspective as in the original tutorial. 49 | var fov, near, far gl.GLdouble 50 | fov = 45.0 51 | near = 0.1 52 | far = 100.0 53 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 54 | bottom := -top 55 | left := aspect * bottom 56 | right := aspect * top 57 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 58 | 59 | // Make sure we're changing the model view and not the projection 60 | gl.MatrixMode(gl.MODELVIEW) 61 | 62 | // Reset the view 63 | gl.LoadIdentity() 64 | } 65 | 66 | // handle key press events 67 | func handleKeyPress(keysym sdl.Keysym) { 68 | switch keysym.Sym { 69 | case sdl.K_ESCAPE: 70 | Quit(0) 71 | case sdl.K_F1: 72 | sdl.WM_ToggleFullScreen(surface) 73 | } 74 | } 75 | 76 | // general OpenGL initialization 77 | func initGL() { 78 | // Enable Texture Mapping 79 | gl.Enable(gl.TEXTURE_2D) 80 | 81 | // enable smooth shading 82 | gl.ShadeModel(gl.SMOOTH) 83 | 84 | // Set the background to black 85 | gl.ClearColor(0.0, 0.0, 0.0, 0.5) 86 | 87 | // Depth buffer setup 88 | gl.ClearDepth(1.0) 89 | 90 | // Enable depth testing 91 | gl.Enable(gl.DEPTH_TEST) 92 | 93 | // The type of test 94 | gl.DepthFunc(gl.LEQUAL) 95 | 96 | // Nicest perspective correction 97 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 98 | } 99 | 100 | var ( 101 | t0, frames uint32 // used to calculate fps 102 | xrot gl.GLfloat // X Rotation 103 | yrot gl.GLfloat // Y Rotation 104 | zrot gl.GLfloat // Z Rotation 105 | texture gl.Texture 106 | ) 107 | 108 | // load in bitmap as a GL texture 109 | func LoadGLTexture(path string) { 110 | image := sdl.Load(path) 111 | if image == nil { 112 | panic(sdl.GetError()) 113 | } 114 | 115 | fmt.Println("here") 116 | 117 | // Check that the image's width is a power of 2 118 | if image.W&(image.W-1) != 0 { 119 | fmt.Println("warning:", path, "has a width that is not a power of 2") 120 | } 121 | 122 | // Also check if the height is a power of 2 123 | if image.H&(image.H-1) != 0 { 124 | fmt.Println("warning:", path, "has an height that is not a power of 2") 125 | } 126 | 127 | // get the number of channels in the SDL surface 128 | nOfColors := image.Format.BytesPerPixel 129 | var textureFormat gl.GLenum 130 | 131 | if nOfColors == 4 { // contains alpha channel 132 | if image.Format.Rmask == 0x000000ff { 133 | textureFormat = gl.RGBA 134 | } else { 135 | textureFormat = gl.BGRA 136 | } 137 | } else if nOfColors == 3 { // no alpha channel 138 | if image.Format.Rmask == 0x000000ff { 139 | textureFormat = gl.RGB 140 | } else { 141 | textureFormat = gl.BGR 142 | } 143 | } else { 144 | fmt.Println("warning:", path, "is not truecolor, this will probably break") 145 | } 146 | 147 | // Create the texture 148 | texture = gl.GenTexture() 149 | 150 | // Typical texture generation using data from the bitmap 151 | texture.Bind(gl.TEXTURE_2D) 152 | 153 | fmt.Println("Generating image") 154 | fmt.Println(image) 155 | 156 | // Generate the texture 157 | gl.TexImage2D( 158 | gl.TEXTURE_2D, 159 | 0, 160 | int(image.Format.BytesPerPixel), 161 | int(image.W), 162 | int(image.H), 163 | 0, 164 | textureFormat, 165 | gl.UNSIGNED_BYTE, 166 | image.Pixels, 167 | ) 168 | fmt.Println("Generated") 169 | 170 | // linear filtering 171 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 172 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 173 | 174 | // free up memory we have used. 175 | image.Free() 176 | } 177 | 178 | // Here goes our drawing code 179 | func drawGLScene() { 180 | // Clear the screen and depth buffer 181 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 182 | 183 | // Move left 1.5 units and into the screen 6.0 units. 184 | gl.LoadIdentity() 185 | gl.Translatef(0.0, 0.0, -7.0) 186 | 187 | gl.Rotatef(float32(xrot), 1.0, 0.0, 0.0) /* Rotate On The X Axis */ 188 | gl.Rotatef(float32(yrot), 0.0, 1.0, 0.0) /* Rotate On The Y Axis */ 189 | gl.Rotatef(float32(zrot), 0.0, 0.0, 1.0) /* Rotate On The Z Axis */ 190 | 191 | /* Select Our Texture */ 192 | gl.BindTexture(gl.TEXTURE_2D, uint(texture)) 193 | 194 | gl.Begin(gl.QUADS) // Draw a quad 195 | /* Front Face */ 196 | gl.TexCoord2f(0.0, 1.0) 197 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom left 198 | gl.TexCoord2f(1.0, 1.0) 199 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom right 200 | gl.TexCoord2f(1.0, 0.0) 201 | gl.Vertex3f(1.0, 1.0, 1.0) // Top right 202 | gl.TexCoord2f(0.0, 0.0) 203 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top left 204 | 205 | /* Back Face */ 206 | gl.TexCoord2f(0.0, 0.0) 207 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom right 208 | gl.TexCoord2f(0.0, 1.0) 209 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top right 210 | gl.TexCoord2f(1.0, 1.0) 211 | gl.Vertex3f(1.0, 1.0, -1.0) // Top left 212 | gl.TexCoord2f(1.0, 0.0) 213 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom left 214 | 215 | /* Top Face */ 216 | gl.TexCoord2f(1.0, 1.0) 217 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 218 | gl.TexCoord2f(1.0, 0.0) 219 | gl.Vertex3f(-1.0, 1.0, 1.0) // Bottom left 220 | gl.TexCoord2f(0.0, 0.0) 221 | gl.Vertex3f(1.0, 1.0, 1.0) // Bottom right 222 | gl.TexCoord2f(0.0, 1.0) 223 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 224 | 225 | /* Bottom Face */ 226 | gl.TexCoord2f(0.0, 1.0) 227 | gl.Vertex3f(-1.0, -1.0, -1.0) // Top right 228 | gl.TexCoord2f(1.0, 1.0) 229 | gl.Vertex3f(1.0, -1.0, -1.0) // Top left 230 | gl.TexCoord2f(1.0, 0.0) 231 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 232 | gl.TexCoord2f(0.0, 0.0) 233 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 234 | 235 | /* Right face */ 236 | gl.TexCoord2f(0.0, 0.0) 237 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom right 238 | gl.TexCoord2f(0.0, 1.0) 239 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 240 | gl.TexCoord2f(1.0, 1.0) 241 | gl.Vertex3f(1.0, 1.0, 1.0) // Top left 242 | gl.TexCoord2f(1.0, 0.0) 243 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 244 | 245 | /* Left Face */ 246 | gl.TexCoord2f(1.0, 0.0) 247 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom left 248 | gl.TexCoord2f(0.0, 0.0) 249 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 250 | gl.TexCoord2f(0.0, 1.0) 251 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top right 252 | gl.TexCoord2f(1.0, 1.0) 253 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 254 | gl.End() // done drawing the quad 255 | 256 | // Draw to the screen 257 | sdl.GL_SwapBuffers() 258 | 259 | xrot += 0.3 /* X Axis Rotation */ 260 | yrot += 0.2 /* Y Axis Rotation */ 261 | zrot += 0.4 /* Z Axis Rotation */ 262 | 263 | // Gather our frames per second 264 | frames++ 265 | t := sdl.GetTicks() 266 | if t-t0 >= 5000 { 267 | seconds := (t - t0) / 1000.0 268 | fps := frames / seconds 269 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 270 | t0 = t 271 | frames = 0 272 | } 273 | } 274 | 275 | func main() { 276 | // Initialize SDL 277 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 278 | panic("Video initialization failed: " + sdl.GetError()) 279 | } 280 | 281 | // Sets up OpenGL double buffering 282 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 283 | 284 | // flags to pass to sdl.SetVideoMode 285 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 286 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 287 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 288 | // FIXME: this causes segfault. 289 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 290 | 291 | // get a SDL surface 292 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 293 | 294 | // verify there is a surface 295 | if surface == nil { 296 | panic("Video mode set failed: " + sdl.GetError()) 297 | Quit(1) 298 | } 299 | 300 | // When this function is finished, clean up and exit. 301 | defer Quit(0) 302 | 303 | fmt.Println("Loading image") 304 | LoadGLTexture("data/nehe.bmp") 305 | fmt.Println("Image loaded") 306 | 307 | // Initialize OpenGL 308 | initGL() 309 | 310 | // Resize the initial window 311 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 312 | 313 | // wait for events 314 | running := true 315 | isActive := true 316 | for running { 317 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 318 | switch e := ev.(type) { 319 | case *sdl.ActiveEvent: 320 | isActive = e.Gain != 0 321 | case *sdl.ResizeEvent: 322 | width, height := int(e.W), int(e.H) 323 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 324 | if surface == nil { 325 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 326 | Quit(1) 327 | } 328 | resizeWindow(width, height) 329 | case *sdl.KeyboardEvent: 330 | if e.Type == sdl.KEYDOWN { 331 | handleKeyPress(e.Keysym) 332 | } 333 | case *sdl.QuitEvent: 334 | running = false 335 | } 336 | } 337 | 338 | // draw the scene 339 | if isActive { 340 | drawGLScene() 341 | } 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /lesson07/data/crate.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manveru/opengl-go-tutorials/20aa51b091cf82318229087be800412b6c92bcb3/lesson07/data/crate.bmp -------------------------------------------------------------------------------- /lesson07/lesson07.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "github.com/banthar/glu" 8 | "math" 9 | "os" 10 | ) 11 | 12 | func p(a ...interface{}) { fmt.Println(a) } 13 | 14 | const ( 15 | SCREEN_WIDTH = 1024 16 | SCREEN_HEIGHT = 768 17 | SCREEN_BPP = 32 18 | ) 19 | 20 | var ( 21 | surface *sdl.Surface 22 | t0, frames uint32 // used to calculate fps 23 | 24 | light = false // Light is off at first 25 | lPressed = false // L button pressed? 26 | fPressed = false // F button pressed? 27 | 28 | xrot gl.GLfloat // X Rotation 29 | yrot gl.GLfloat // Y Rotation 30 | xspeed gl.GLfloat // X Rotation Speed 31 | yspeed gl.GLfloat // Y Rotation Speed 32 | z gl.GLfloat = -5.0 // Depth Into The Screen 33 | 34 | lightAmbient1 = [4]float32{0.0, 1.0, 0.0, 1.0} // Ambient light values 35 | lightDiffuse1 = [4]float32{0.0, 1.0, 0.0, 1.0} // Diffuse light values 36 | lightPosition1 = [4]float32{2.0, 0.0, 2.0, 1.0} // Light position 37 | 38 | lightAmbient2 = [4]float32{1.0, 0.0, 0.0, 1.0} // Ambient light values 39 | lightDiffuse2 = [4]float32{1.0, 0.0, 0.0, 1.0} // Diffuse light values 40 | lightPosition2 = [4]float32{-2.0, 0.0, 2.0, 1.0} // Light position 41 | 42 | filter gl.GLuint // Which filter to use 43 | textures [3]gl.Texture // Storage for 3 textures 44 | ) 45 | 46 | // release/destroy our resources and restoring the old desktop 47 | func Quit(status int) { 48 | // clean up the window 49 | sdl.Quit() 50 | 51 | // and exit appropriately 52 | os.Exit(status) 53 | } 54 | 55 | // reset our viewport after a window resize 56 | func resizeWindow(width, height int) { 57 | // protect against a divide by zero 58 | if height == 0 { 59 | height = 1 60 | } 61 | 62 | // Setup our viewport 63 | gl.Viewport(0, 0, width, height) 64 | 65 | // change to the projection matrix and set our viewing volume. 66 | gl.MatrixMode(gl.PROJECTION) 67 | gl.LoadIdentity() 68 | 69 | // aspect ratio 70 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 71 | 72 | // Set our perspective. 73 | // This code is equivalent to using gluPerspective as in the original tutorial. 74 | var fov, near, far gl.GLdouble 75 | fov = 45.0 76 | near = 0.1 77 | far = 100.0 78 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 79 | bottom := -top 80 | left := aspect * bottom 81 | right := aspect * top 82 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 83 | 84 | // Make sure we're changing the model view and not the projection 85 | gl.MatrixMode(gl.MODELVIEW) 86 | 87 | // Reset the view 88 | gl.LoadIdentity() 89 | } 90 | 91 | // handle key press events 92 | func handleKeyPress(keysym sdl.Keysym) { 93 | switch keysym.Sym { 94 | case sdl.K_f: // f key pages through filters 95 | filter = (filter + 1) % 3 96 | p("new filter:", filter) 97 | case sdl.K_l: // l key toggles light 98 | light = !light 99 | if light { 100 | p("light on") 101 | gl.Enable(gl.LIGHTING) 102 | } else { 103 | p("light off") 104 | gl.Disable(gl.LIGHTING) 105 | } 106 | case sdl.K_PAGEUP: // page up zooms into the scene 107 | z -= 0.02 108 | case sdl.K_PAGEDOWN: // zoom out of the scene 109 | z += 0.02 110 | case sdl.K_UP: // up arrow affects x rotation 111 | xspeed -= 0.01 112 | case sdl.K_DOWN: // down arrow affects x rotation 113 | xspeed += 0.01 114 | case sdl.K_RIGHT: // affect y rotation 115 | yspeed += 0.01 116 | case sdl.K_LEFT: // affect y rotation 117 | yspeed -= 0.01 118 | case sdl.K_ESCAPE: 119 | Quit(0) 120 | case sdl.K_F1: 121 | sdl.WM_ToggleFullScreen(surface) 122 | } 123 | } 124 | 125 | // general OpenGL initialization 126 | func initGL() { 127 | gl.Enable(gl.TEXTURE_2D) 128 | gl.ShadeModel(gl.SMOOTH) 129 | gl.ClearColor(0.0, 0.0, 0.0, 0.5) 130 | gl.ClearDepth(1.0) 131 | gl.Enable(gl.DEPTH_TEST) 132 | gl.DepthFunc(gl.LEQUAL) 133 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 134 | 135 | // Setup the light 136 | gl.Lightfv(gl.LIGHT1, gl.AMBIENT, lightAmbient1[:]) // ambient lighting 137 | gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, lightDiffuse1[:]) // make it diffuse 138 | gl.Lightfv(gl.LIGHT1, gl.POSITION, lightPosition1[:]) // and place it 139 | gl.Enable(gl.LIGHT1) // and finally turn it on. 140 | 141 | gl.Lightfv(gl.LIGHT2, gl.AMBIENT, lightAmbient2[:]) // ambient lighting 142 | gl.Lightfv(gl.LIGHT2, gl.DIFFUSE, lightDiffuse2[:]) // make it diffuse 143 | gl.Lightfv(gl.LIGHT2, gl.POSITION, lightPosition2[:]) // and place it 144 | gl.Enable(gl.LIGHT2) // and finally turn it on. 145 | } 146 | 147 | // load in bitmap as a GL texture 148 | func LoadGLTextures(path string) { 149 | image := sdl.Load(path) 150 | if image == nil { 151 | panic(sdl.GetError()) 152 | } 153 | 154 | // Check that the image's width is a power of 2 155 | if image.W&(image.W-1) != 0 { 156 | fmt.Println("warning:", path, "has a width that is not a power of 2") 157 | } 158 | 159 | // Also check if the height is a power of 2 160 | if image.H&(image.H-1) != 0 { 161 | fmt.Println("warning:", path, "has an height that is not a power of 2") 162 | } 163 | 164 | // get the number of channels in the SDL surface 165 | nOfColors := image.Format.BytesPerPixel 166 | var textureFormat gl.GLenum 167 | 168 | if nOfColors == 4 { // contains alpha channel 169 | if image.Format.Rmask == 0x000000ff { 170 | textureFormat = gl.RGBA 171 | } else { 172 | textureFormat = gl.BGRA 173 | } 174 | } else if nOfColors == 3 { // no alpha channel 175 | if image.Format.Rmask == 0x000000ff { 176 | textureFormat = gl.RGB 177 | } else { 178 | textureFormat = gl.BGR 179 | } 180 | } else { 181 | fmt.Println("warning:", path, "is not truecolor, this will probably break") 182 | } 183 | 184 | // Create the textures 185 | gl.GenTextures(textures[:]) 186 | 187 | // First texture 188 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[0])) 189 | gl.TexImage2D( 190 | gl.TEXTURE_2D, 191 | 0, 192 | 3, 193 | int(image.W), 194 | int(image.H), 195 | 0, 196 | textureFormat, 197 | gl.UNSIGNED_BYTE, 198 | image.Pixels, 199 | ) 200 | 201 | // linear filtering 202 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 203 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 204 | 205 | // Second texture 206 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[1])) 207 | gl.TexImage2D(gl.TEXTURE_2D, 0, 208 | 3, 209 | int(image.W), 210 | int(image.H), 211 | 0, textureFormat, gl.UNSIGNED_BYTE, 212 | image.Pixels, 213 | ) 214 | 215 | // Mipmapped filtering 216 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 217 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 218 | 219 | // Third texture 220 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[2])) 221 | gl.TexImage2D(gl.TEXTURE_2D, 0, 222 | 3, 223 | int(image.W), 224 | int(image.H), 225 | 0, textureFormat, gl.UNSIGNED_BYTE, 226 | image.Pixels, 227 | ) 228 | 229 | // Mipmapped filtering 230 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST) 231 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 232 | 233 | glu.Build2DMipmaps( 234 | gl.TEXTURE_2D, 235 | 3, 236 | int(image.W), 237 | int(image.H), 238 | textureFormat, 239 | image.Pixels, 240 | ) 241 | 242 | image.Free() 243 | } 244 | 245 | // Here goes our drawing code 246 | func drawGLScene() { 247 | // Clear the screen and depth buffer 248 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 249 | 250 | // Move left 1.5 units and into the screen 6.0 units. 251 | gl.LoadIdentity() 252 | gl.Translatef(0.0, 0.0, float32(z)) // translate by z 253 | 254 | gl.Rotatef(float32(xrot), 1.0, 0.0, 0.0) /* Rotate On The X Axis */ 255 | gl.Rotatef(float32(yrot), 0.0, 1.0, 0.0) /* Rotate On The Y Axis */ 256 | 257 | /* Select Our Texture */ 258 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[filter])) // based on filter 259 | 260 | gl.Begin(gl.QUADS) 261 | 262 | // Front face 263 | gl.Normal3f(0.0, 0.0, 1.0) // Normal Pointing Towards Viewer 264 | gl.TexCoord2f(0.0, 1.0) 265 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom left 266 | gl.TexCoord2f(1.0, 1.0) 267 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom right 268 | gl.TexCoord2f(1.0, 0.0) 269 | gl.Vertex3f(1.0, 1.0, 1.0) // Top right 270 | gl.TexCoord2f(0.0, 0.0) 271 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top left 272 | 273 | // Back Face 274 | gl.Normal3f(0.0, 0.0, -1.0) // Normal Pointing Away From Viewer 275 | gl.TexCoord2f(0.0, 0.0) 276 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom right 277 | gl.TexCoord2f(0.0, 1.0) 278 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top right 279 | gl.TexCoord2f(1.0, 1.0) 280 | gl.Vertex3f(1.0, 1.0, -1.0) // Top left 281 | gl.TexCoord2f(1.0, 0.0) 282 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom left 283 | 284 | // Top Face 285 | gl.Normal3f(0.0, 1.0, 0.0) // Normal Pointing Up 286 | gl.TexCoord2f(1.0, 1.0) 287 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 288 | gl.TexCoord2f(1.0, 0.0) 289 | gl.Vertex3f(-1.0, 1.0, 1.0) // Bottom left 290 | gl.TexCoord2f(0.0, 0.0) 291 | gl.Vertex3f(1.0, 1.0, 1.0) // Bottom right 292 | gl.TexCoord2f(0.0, 1.0) 293 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 294 | 295 | // Bottom Face 296 | gl.Normal3f(0.0, -1.0, 0.0) // Normal Pointing Down 297 | gl.TexCoord2f(0.0, 1.0) 298 | gl.Vertex3f(-1.0, -1.0, -1.0) // Top right 299 | gl.TexCoord2f(1.0, 1.0) 300 | gl.Vertex3f(1.0, -1.0, -1.0) // Top left 301 | gl.TexCoord2f(1.0, 0.0) 302 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 303 | gl.TexCoord2f(0.0, 0.0) 304 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 305 | 306 | // Right face 307 | gl.Normal3f(1.0, 0.0, 0.0) // Normal Pointing Right 308 | gl.TexCoord2f(0.0, 0.0) 309 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom right 310 | gl.TexCoord2f(0.0, 1.0) 311 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 312 | gl.TexCoord2f(1.0, 1.0) 313 | gl.Vertex3f(1.0, 1.0, 1.0) // Top left 314 | gl.TexCoord2f(1.0, 0.0) 315 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 316 | 317 | // Left Face 318 | gl.Normal3f(-1.0, 0.0, 0.0) // Normal Pointing Left 319 | gl.TexCoord2f(1.0, 0.0) 320 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom left 321 | gl.TexCoord2f(0.0, 0.0) 322 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 323 | gl.TexCoord2f(0.0, 1.0) 324 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top right 325 | gl.TexCoord2f(1.0, 1.0) 326 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 327 | 328 | gl.End() 329 | 330 | sdl.GL_SwapBuffers() 331 | 332 | xrot += xspeed 333 | yrot += yspeed 334 | 335 | // Gather our frames per second 336 | frames++ 337 | t := sdl.GetTicks() 338 | if t-t0 >= 5000 { 339 | seconds := (t - t0) / 1000.0 340 | fps := frames / seconds 341 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 342 | t0 = t 343 | frames = 0 344 | } 345 | } 346 | 347 | func main() { 348 | // Initialize SDL 349 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 350 | panic("Video initialization failed: " + sdl.GetError()) 351 | } 352 | 353 | // To avoid cramps 354 | sdl.EnableKeyRepeat(250, 25) 355 | 356 | // Sets up OpenGL double buffering 357 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 358 | 359 | // flags to pass to sdl.SetVideoMode 360 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 361 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 362 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 363 | // FIXME: this causes segfault. 364 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 365 | 366 | // get a SDL surface 367 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 368 | 369 | // verify there is a surface 370 | if surface == nil { 371 | panic("Video mode set failed: " + sdl.GetError()) 372 | Quit(1) 373 | } 374 | 375 | // When this function is finished, clean up and exit. 376 | defer Quit(0) 377 | 378 | LoadGLTextures("data/crate.bmp") 379 | 380 | // Initialize OpenGL 381 | initGL() 382 | // Resize the initial window 383 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 384 | 385 | // wait for events 386 | running := true 387 | isActive := true 388 | for running { 389 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 390 | switch e := ev.(type) { 391 | case *sdl.ActiveEvent: 392 | isActive = e.Gain != 0 393 | case *sdl.ResizeEvent: 394 | width, height := int(e.W), int(e.H) 395 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 396 | if surface == nil { 397 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 398 | Quit(1) 399 | } 400 | resizeWindow(width, height) 401 | case *sdl.KeyboardEvent: 402 | if e.Type == sdl.KEYDOWN { 403 | handleKeyPress(e.Keysym) 404 | } 405 | case *sdl.QuitEvent: 406 | running = false 407 | } 408 | } 409 | 410 | // draw the scene 411 | if isActive { 412 | drawGLScene() 413 | } 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /lesson08/data/glass.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manveru/opengl-go-tutorials/20aa51b091cf82318229087be800412b6c92bcb3/lesson08/data/glass.bmp -------------------------------------------------------------------------------- /lesson08/lesson08.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "github.com/banthar/glu" 8 | "math" 9 | "os" 10 | ) 11 | 12 | func p(a ...interface{}) { fmt.Println(a) } 13 | 14 | const ( 15 | SCREEN_WIDTH = 1024 16 | SCREEN_HEIGHT = 768 17 | SCREEN_BPP = 32 18 | ) 19 | 20 | var ( 21 | surface *sdl.Surface 22 | t0, frames uint32 // used to calculate fps 23 | 24 | light = false // Light is off at first 25 | blend = false // Blending is off at first 26 | 27 | xrot gl.GLfloat // X Rotation 28 | yrot gl.GLfloat // Y Rotation 29 | xspeed gl.GLfloat // X Rotation Speed 30 | yspeed gl.GLfloat // Y Rotation Speed 31 | z gl.GLfloat = -5.0 // Depth Into The Screen 32 | 33 | lightAmbient = [4]float32{0.5, 0.5, 0.5, 1.0} // Ambient light values 34 | lightDiffuse = [4]float32{1.0, 1.0, 1.0, 1.0} // Diffuse light values 35 | lightPosition = [4]float32{0.0, 0.0, 2.0, 1.0} // Light position 36 | 37 | filter gl.GLuint // Which filter to use 38 | textures [3]gl.Texture // Storage for 3 textures 39 | ) 40 | 41 | // release/destroy our resources and restoring the old desktop 42 | func Quit(status int) { 43 | // clean up the window 44 | sdl.Quit() 45 | 46 | // and exit appropriately 47 | os.Exit(status) 48 | } 49 | 50 | // reset our viewport after a window resize 51 | func resizeWindow(width, height int) { 52 | // protect against a divide by zero 53 | if height == 0 { 54 | height = 1 55 | } 56 | 57 | // Setup our viewport 58 | gl.Viewport(0, 0, int(width), int(height)) 59 | 60 | // change to the projection matrix and set our viewing volume. 61 | gl.MatrixMode(gl.PROJECTION) 62 | gl.LoadIdentity() 63 | 64 | // aspect ratio 65 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 66 | 67 | // Set our perspective. 68 | // This code is equivalent to using gluPerspective as in the original tutorial. 69 | var fov, near, far gl.GLdouble 70 | fov = 45.0 71 | near = 0.1 72 | far = 100.0 73 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 74 | bottom := -top 75 | left := aspect * bottom 76 | right := aspect * top 77 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 78 | 79 | // Make sure we're changing the model view and not the projection 80 | gl.MatrixMode(gl.MODELVIEW) 81 | 82 | // Reset the view 83 | gl.LoadIdentity() 84 | } 85 | 86 | // handle key press events 87 | func handleKeyPress(keysym sdl.Keysym) { 88 | switch keysym.Sym { 89 | case sdl.K_f: // f key pages through filters 90 | filter = (filter + 1) % 3 91 | p("new filter:", filter) 92 | case sdl.K_l: // l key toggles light 93 | light = !light 94 | if light { 95 | p("light on") 96 | gl.Enable(gl.LIGHTING) 97 | } else { 98 | p("light off") 99 | gl.Disable(gl.LIGHTING) 100 | } 101 | case sdl.K_b: // b key toggles blend 102 | blend = !blend 103 | if blend { 104 | gl.Enable(gl.BLEND) 105 | gl.Disable(gl.DEPTH_TEST) 106 | } else { 107 | gl.Disable(gl.BLEND) 108 | gl.Enable(gl.DEPTH_TEST) 109 | } 110 | case sdl.K_PAGEUP: // page up zooms into the scene 111 | z -= 0.02 112 | case sdl.K_PAGEDOWN: // zoom out of the scene 113 | z += 0.02 114 | case sdl.K_UP: // up arrow affects x rotation 115 | xspeed -= 0.01 116 | case sdl.K_DOWN: // down arrow affects x rotation 117 | xspeed += 0.01 118 | case sdl.K_RIGHT: // affect y rotation 119 | yspeed += 0.01 120 | case sdl.K_LEFT: // affect y rotation 121 | yspeed -= 0.01 122 | case sdl.K_ESCAPE: 123 | Quit(0) 124 | case sdl.K_F1: 125 | sdl.WM_ToggleFullScreen(surface) 126 | } 127 | } 128 | 129 | // general OpenGL initialization 130 | func initGL() { 131 | gl.Enable(gl.TEXTURE_2D) 132 | gl.ShadeModel(gl.SMOOTH) 133 | gl.ClearColor(0.0, 0.0, 0.0, 0.5) 134 | gl.ClearDepth(1.0) 135 | gl.Enable(gl.DEPTH_TEST) 136 | gl.DepthFunc(gl.LEQUAL) 137 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 138 | 139 | // Setup the light 140 | gl.Lightfv(gl.LIGHT1, gl.AMBIENT, lightAmbient[:]) // ambient lighting 141 | gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, lightDiffuse[:]) // make it diffuse 142 | gl.Lightfv(gl.LIGHT1, gl.POSITION, lightPosition[:]) // and place it 143 | gl.Enable(gl.LIGHT1) // and finally turn it on. 144 | 145 | gl.Color4f(1.0, 1.0, 1.0, 0.5) // Full Brightness, 50% Alpha ( NEW ) 146 | gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) // Blending Function For Translucency Based On Source Alpha Value ( NEW ) 147 | } 148 | 149 | // load in bitmap as a GL texture 150 | func LoadGLTextures(path string) { 151 | image := sdl.Load(path) 152 | if image == nil { 153 | panic(sdl.GetError()) 154 | } 155 | 156 | // Check that the image's width is a power of 2 157 | if image.W&(image.W-1) != 0 { 158 | fmt.Println("warning:", path, "has a width that is not a power of 2") 159 | } 160 | 161 | // Also check if the height is a power of 2 162 | if image.H&(image.H-1) != 0 { 163 | fmt.Println("warning:", path, "has an height that is not a power of 2") 164 | } 165 | 166 | // get the number of channels in the SDL surface 167 | nOfColors := image.Format.BytesPerPixel 168 | var textureFormat gl.GLenum 169 | 170 | if nOfColors == 4 { // contains alpha channel 171 | if image.Format.Rmask == 0x000000ff { 172 | textureFormat = gl.RGBA 173 | } else { 174 | textureFormat = gl.BGRA 175 | } 176 | } else if nOfColors == 3 { // no alpha channel 177 | if image.Format.Rmask == 0x000000ff { 178 | textureFormat = gl.RGB 179 | } else { 180 | textureFormat = gl.BGR 181 | } 182 | } else { 183 | fmt.Println("warning:", path, "is not truecolor, this will probably break") 184 | } 185 | 186 | // Create the textures 187 | gl.GenTextures(textures[:]) 188 | 189 | // First texture 190 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[0])) 191 | gl.TexImage2D( 192 | gl.TEXTURE_2D, 193 | 0, 194 | 3, 195 | int(image.W), 196 | int(image.H), 197 | 0, 198 | textureFormat, 199 | gl.UNSIGNED_BYTE, 200 | image.Pixels, 201 | ) 202 | 203 | // linear filtering 204 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 205 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 206 | 207 | // Second texture 208 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[1])) 209 | gl.TexImage2D(gl.TEXTURE_2D, 0, 210 | 3, 211 | int(image.W), 212 | int(image.H), 213 | 0, textureFormat, gl.UNSIGNED_BYTE, 214 | image.Pixels, 215 | ) 216 | 217 | // Mipmapped filtering 218 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 219 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 220 | 221 | // Third texture 222 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[2])) 223 | gl.TexImage2D(gl.TEXTURE_2D, 0, 224 | 3, 225 | int(image.W), 226 | int(image.H), 227 | 0, textureFormat, gl.UNSIGNED_BYTE, 228 | image.Pixels, 229 | ) 230 | 231 | // Mipmapped filtering 232 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST) 233 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 234 | 235 | glu.Build2DMipmaps( 236 | gl.TEXTURE_2D, 237 | 3, 238 | int(image.W), 239 | int(image.H), 240 | textureFormat, 241 | image.Pixels, 242 | ) 243 | } 244 | 245 | // Here goes our drawing code 246 | func drawGLScene() { 247 | // Clear the screen and depth buffer 248 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 249 | 250 | // Move left 1.5 units and into the screen 6.0 units. 251 | gl.LoadIdentity() 252 | gl.Translatef(0.0, 0.0, float32(z)) // translate by z 253 | 254 | gl.Rotatef(float32(xrot), 1.0, 0.0, 0.0) /* Rotate On The X Axis */ 255 | gl.Rotatef(float32(yrot), 0.0, 1.0, 0.0) /* Rotate On The Y Axis */ 256 | 257 | /* Select Our Texture */ 258 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[filter])) // based on filter 259 | 260 | gl.Begin(gl.QUADS) 261 | 262 | // Front face 263 | gl.Normal3f(0.0, 0.0, 1.0) // Normal Pointing Towards Viewer 264 | gl.TexCoord2f(0.0, 1.0) 265 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom left 266 | gl.TexCoord2f(1.0, 1.0) 267 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom right 268 | gl.TexCoord2f(1.0, 0.0) 269 | gl.Vertex3f(1.0, 1.0, 1.0) // Top right 270 | gl.TexCoord2f(0.0, 0.0) 271 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top left 272 | 273 | // Back Face 274 | gl.Normal3f(0.0, 0.0, -1.0) // Normal Pointing Away From Viewer 275 | gl.TexCoord2f(0.0, 0.0) 276 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom right 277 | gl.TexCoord2f(0.0, 1.0) 278 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top right 279 | gl.TexCoord2f(1.0, 1.0) 280 | gl.Vertex3f(1.0, 1.0, -1.0) // Top left 281 | gl.TexCoord2f(1.0, 0.0) 282 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom left 283 | 284 | // Top Face 285 | gl.Normal3f(0.0, 1.0, 0.0) // Normal Pointing Up 286 | gl.TexCoord2f(1.0, 1.0) 287 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 288 | gl.TexCoord2f(1.0, 0.0) 289 | gl.Vertex3f(-1.0, 1.0, 1.0) // Bottom left 290 | gl.TexCoord2f(0.0, 0.0) 291 | gl.Vertex3f(1.0, 1.0, 1.0) // Bottom right 292 | gl.TexCoord2f(0.0, 1.0) 293 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 294 | 295 | // Bottom Face 296 | gl.Normal3f(0.0, -1.0, 0.0) // Normal Pointing Down 297 | gl.TexCoord2f(0.0, 1.0) 298 | gl.Vertex3f(-1.0, -1.0, -1.0) // Top right 299 | gl.TexCoord2f(1.0, 1.0) 300 | gl.Vertex3f(1.0, -1.0, -1.0) // Top left 301 | gl.TexCoord2f(1.0, 0.0) 302 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 303 | gl.TexCoord2f(0.0, 0.0) 304 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 305 | 306 | // Right face 307 | gl.Normal3f(1.0, 0.0, 0.0) // Normal Pointing Right 308 | gl.TexCoord2f(0.0, 0.0) 309 | gl.Vertex3f(1.0, -1.0, -1.0) // Bottom right 310 | gl.TexCoord2f(0.0, 1.0) 311 | gl.Vertex3f(1.0, 1.0, -1.0) // Top right 312 | gl.TexCoord2f(1.0, 1.0) 313 | gl.Vertex3f(1.0, 1.0, 1.0) // Top left 314 | gl.TexCoord2f(1.0, 0.0) 315 | gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left 316 | 317 | // Left Face 318 | gl.Normal3f(-1.0, 0.0, 0.0) // Normal Pointing Left 319 | gl.TexCoord2f(1.0, 0.0) 320 | gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom left 321 | gl.TexCoord2f(0.0, 0.0) 322 | gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right 323 | gl.TexCoord2f(0.0, 1.0) 324 | gl.Vertex3f(-1.0, 1.0, 1.0) // Top right 325 | gl.TexCoord2f(1.0, 1.0) 326 | gl.Vertex3f(-1.0, 1.0, -1.0) // Top left 327 | 328 | gl.End() 329 | 330 | sdl.GL_SwapBuffers() 331 | 332 | xrot += xspeed 333 | yrot += yspeed 334 | 335 | // Gather our frames per second 336 | frames++ 337 | t := sdl.GetTicks() 338 | if t-t0 >= 5000 { 339 | seconds := (t - t0) / 1000.0 340 | fps := frames / seconds 341 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 342 | t0 = t 343 | frames = 0 344 | } 345 | } 346 | 347 | func main() { 348 | // Initialize SDL 349 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 350 | panic("Video initialization failed: " + sdl.GetError()) 351 | } 352 | 353 | // To avoid cramps 354 | sdl.EnableKeyRepeat(250, 25) 355 | 356 | // Sets up OpenGL double buffering 357 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 358 | 359 | // flags to pass to sdl.SetVideoMode 360 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 361 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 362 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 363 | // FIXME: this causes segfault. 364 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 365 | 366 | // get a SDL surface 367 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 368 | 369 | // verify there is a surface 370 | if surface == nil { 371 | panic("Video mode set failed: " + sdl.GetError()) 372 | Quit(1) 373 | } 374 | 375 | // When this function is finished, clean up and exit. 376 | defer Quit(0) 377 | 378 | LoadGLTextures("data/glass.bmp") 379 | 380 | // Initialize OpenGL 381 | initGL() 382 | 383 | // Resize the initial window 384 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 385 | 386 | // wait for events 387 | running := true 388 | isActive := true 389 | for running { 390 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 391 | switch e := ev.(type) { 392 | case *sdl.ActiveEvent: 393 | isActive = e.Gain != 0 394 | case *sdl.ResizeEvent: 395 | width, height := int(e.W), int(e.H) 396 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 397 | if surface == nil { 398 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 399 | Quit(1) 400 | } 401 | resizeWindow(width, height) 402 | case *sdl.KeyboardEvent: 403 | if e.Type == sdl.KEYDOWN { 404 | handleKeyPress(e.Keysym) 405 | } 406 | case *sdl.QuitEvent: 407 | running = false 408 | } 409 | } 410 | 411 | // draw the scene 412 | if isActive { 413 | drawGLScene() 414 | } 415 | } 416 | } 417 | -------------------------------------------------------------------------------- /lesson09/data/star.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manveru/opengl-go-tutorials/20aa51b091cf82318229087be800412b6c92bcb3/lesson09/data/star.bmp -------------------------------------------------------------------------------- /lesson09/lesson09.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/banthar/Go-SDL/sdl" 6 | "github.com/banthar/gl" 7 | "math" 8 | "math/rand" 9 | "os" 10 | ) 11 | 12 | func p(a ...interface{}) { fmt.Println(a) } 13 | 14 | const ( 15 | SCREEN_WIDTH = 640 16 | SCREEN_HEIGHT = 480 17 | SCREEN_BPP = 32 18 | ) 19 | 20 | type Star struct { 21 | r, g, b gl.GLubyte 22 | dist, angle gl.GLfloat 23 | } 24 | 25 | var ( 26 | surface *sdl.Surface 27 | t0, frames uint32 28 | 29 | twinkle bool 30 | stars = [50]*Star{} 31 | num = len(stars) 32 | 33 | zoom gl.GLfloat = -15.0 34 | tilt gl.GLfloat = 90.0 35 | spin gl.GLfloat 36 | 37 | texture gl.Texture 38 | ) 39 | 40 | // Load bitmap from path as GL texture 41 | func LoadGLTexture(path string) { 42 | image := sdl.Load(path) 43 | if image == nil { 44 | panic(sdl.GetError()) 45 | } 46 | 47 | // Check that the image's width is a power of 2 48 | if image.W&(image.W-1) != 0 { 49 | fmt.Println("warning:", path, "has a width that is not a power of 2") 50 | } 51 | 52 | // Also check if the height is a power of 2 53 | if image.H&(image.H-1) != 0 { 54 | fmt.Println("warning:", path, "has an height that is not a power of 2") 55 | } 56 | 57 | // get the number of channels in the SDL surface 58 | nOfColors := image.Format.BytesPerPixel 59 | var textureFormat gl.GLenum 60 | 61 | if nOfColors == 4 { // contains alpha channel 62 | if image.Format.Rmask == 0x000000ff { 63 | textureFormat = gl.RGBA 64 | } else { 65 | textureFormat = gl.BGRA 66 | } 67 | } else if nOfColors == 3 { // no alpha channel 68 | if image.Format.Rmask == 0x000000ff { 69 | textureFormat = gl.RGB 70 | } else { 71 | textureFormat = gl.BGR 72 | } 73 | } else { 74 | fmt.Println("warning:", path, "is not truecolor, this will probably break") 75 | } 76 | 77 | texture = gl.GenTexture() 78 | 79 | // Typical texture generation using data from the bitmap 80 | gl.BindTexture(gl.TEXTURE_2D, uint(texture)) 81 | 82 | // Generate the texture 83 | gl.TexImage2D(gl.TEXTURE_2D, 0, int(image.Format.BytesPerPixel), 84 | int(image.W), int(image.H), 85 | 0, textureFormat, gl.UNSIGNED_BYTE, image.Pixels, 86 | ) 87 | 88 | // linear filtering 89 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 90 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 91 | 92 | // free up memory we have used. 93 | image.Free() 94 | } 95 | 96 | // release/destroy our resources and restoring the old desktop 97 | func Quit(status int) { 98 | // clean up the window 99 | sdl.Quit() 100 | 101 | // and exit appropriately 102 | os.Exit(status) 103 | } 104 | 105 | // reset our viewport after a window resize 106 | func resizeWindow(width, height int) { 107 | // protect against a divide by zero 108 | if height == 0 { 109 | height = 1 110 | } 111 | 112 | // Setup our viewport 113 | gl.Viewport(0, 0, width, height) 114 | 115 | // change to the projection matrix and set our viewing volume. 116 | gl.MatrixMode(gl.PROJECTION) 117 | gl.LoadIdentity() 118 | 119 | // aspect ratio 120 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 121 | 122 | // Set our perspective. 123 | // This code is equivalent to using gluPerspective as in the original tutorial. 124 | var fov, near, far gl.GLdouble 125 | fov = 45.0 126 | near = 0.1 127 | far = 100.0 128 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 129 | bottom := -top 130 | left := aspect * bottom 131 | right := aspect * top 132 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 133 | 134 | // Make sure we're changing the model view and not the projection 135 | gl.MatrixMode(gl.MODELVIEW) 136 | 137 | // Reset the view 138 | gl.LoadIdentity() 139 | } 140 | 141 | // handle key press events 142 | func handleKeyPress(keysym sdl.Keysym) { 143 | switch keysym.Sym { 144 | case sdl.K_t: 145 | twinkle = !twinkle 146 | case sdl.K_UP: 147 | tilt -= 0.5 148 | case sdl.K_DOWN: 149 | tilt += 0.5 150 | case sdl.K_PAGEUP: 151 | zoom -= 0.2 152 | case sdl.K_PAGEDOWN: 153 | zoom += 0.2 154 | case sdl.K_ESCAPE: 155 | Quit(0) 156 | case sdl.K_F1: 157 | sdl.WM_ToggleFullScreen(surface) 158 | } 159 | } 160 | 161 | // general OpenGL initialization 162 | func initGL() { 163 | LoadGLTexture("data/star.bmp") 164 | 165 | gl.Enable(gl.TEXTURE_2D) 166 | gl.Enable(gl.BLEND) 167 | gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) 168 | gl.ShadeModel(gl.SMOOTH) 169 | gl.ClearColor(0.0, 0.0, 0.0, 0.5) 170 | gl.ClearDepth(1.0) 171 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 172 | } 173 | 174 | // Here goes our drawing code 175 | func drawGLScene() { 176 | // Clear the screen and depth buffer 177 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 178 | gl.BindTexture(gl.TEXTURE_2D, uint(texture)) 179 | 180 | for loop, star := range stars { 181 | gl.LoadIdentity() 182 | gl.Translatef(0.0, 0.0, float32(zoom)) 183 | gl.Rotatef(float32(tilt), 1.0, 0.0, 0.0) 184 | gl.Rotatef(float32(star.angle), 0.0, 1.0, 0.0) 185 | gl.Translatef(float32(star.dist), 0.0, 0.0) 186 | gl.Rotatef(float32(-star.angle), 0.0, 1.0, 0.0) 187 | gl.Rotatef(float32(-tilt), 1.0, 0.0, 0.0) 188 | 189 | if twinkle { 190 | other := stars[(num-loop)-1] 191 | gl.Color4ub(uint8(other.r), uint8(other.g), uint8(other.b), 255) 192 | gl.Begin(gl.QUADS) 193 | gl.TexCoord2f(0.0, 0.0) 194 | gl.Vertex3f(-1.0, -1.0, 0.0) 195 | gl.TexCoord2f(1.0, 0.0) 196 | gl.Vertex3f(1.0, -1.0, 0.0) 197 | gl.TexCoord2f(1.0, 1.0) 198 | gl.Vertex3f(1.0, 1.0, 0.0) 199 | gl.TexCoord2f(0.0, 1.0) 200 | gl.Vertex3f(-1.0, 1.0, 0.0) 201 | gl.End() 202 | } 203 | 204 | gl.Rotatef(float32(spin), 0.0, 0.0, 1.0) 205 | gl.Color4ub(uint8(star.r), uint8(star.g), uint8(star.b), 255) 206 | gl.Begin(gl.QUADS) 207 | gl.TexCoord2f(0.0, 0.0) 208 | gl.Vertex3f(-1.0, -1.0, 0.0) 209 | gl.TexCoord2f(1.0, 0.0) 210 | gl.Vertex3f(1.0, -1.0, 0.0) 211 | gl.TexCoord2f(1.0, 1.0) 212 | gl.Vertex3f(1.0, 1.0, 0.0) 213 | gl.TexCoord2f(0.0, 1.0) 214 | gl.Vertex3f(-1.0, 1.0, 0.0) 215 | gl.End() 216 | 217 | spin += 0.01 218 | star.angle += gl.GLfloat(loop) / gl.GLfloat(num) 219 | star.dist -= 0.01 220 | 221 | if star.dist < 0.0 { 222 | star.dist += 5.0 223 | star.r = gl.GLubyte(rand.Float32() * 255) 224 | star.g = gl.GLubyte(rand.Float32() * 255) 225 | star.b = gl.GLubyte(rand.Float32() * 255) 226 | } 227 | } 228 | 229 | // Draw to the screen 230 | sdl.GL_SwapBuffers() 231 | 232 | // Gather our frames per second 233 | frames++ 234 | t := sdl.GetTicks() 235 | if t-t0 >= 5000 { 236 | seconds := (t - t0) / 1000.0 237 | fps := frames / seconds 238 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 239 | t0 = t 240 | frames = 0 241 | } 242 | } 243 | 244 | func initStars() { 245 | // Create the first stars 246 | for loop, _ := range stars { 247 | stars[loop] = &Star{ 248 | angle: 0.0, 249 | dist: (gl.GLfloat(loop) / gl.GLfloat(num)) * 5.0, 250 | r: gl.GLubyte(rand.Float32() * 255), 251 | g: gl.GLubyte(rand.Float32() * 255), 252 | b: gl.GLubyte(rand.Float32() * 255), 253 | } 254 | } 255 | } 256 | 257 | func main() { 258 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 259 | panic("Video initialization failed: " + sdl.GetError()) 260 | } 261 | 262 | sdl.EnableKeyRepeat(250, 25) 263 | 264 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 265 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 266 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 267 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 268 | 269 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 270 | 271 | if surface == nil { 272 | panic("Video mode set failed: " + sdl.GetError()) 273 | Quit(1) 274 | } 275 | 276 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 277 | initGL() 278 | initStars() 279 | p(1) 280 | 281 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 282 | p(2) 283 | 284 | // wait for events 285 | running := true 286 | isActive := true 287 | for running { 288 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 289 | switch e := ev.(type) { 290 | case *sdl.ActiveEvent: 291 | isActive = e.Gain != 0 292 | case *sdl.ResizeEvent: 293 | width, height := int(e.W), int(e.H) 294 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 295 | if surface == nil { 296 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 297 | Quit(1) 298 | } 299 | resizeWindow(width, height) 300 | case *sdl.KeyboardEvent: 301 | if e.Type == sdl.KEYDOWN { 302 | handleKeyPress(e.Keysym) 303 | } 304 | case *sdl.QuitEvent: 305 | running = false 306 | } 307 | } 308 | 309 | // draw the scene 310 | if isActive { 311 | drawGLScene() 312 | } 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /lesson10/data/mud.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manveru/opengl-go-tutorials/20aa51b091cf82318229087be800412b6c92bcb3/lesson10/data/mud.bmp -------------------------------------------------------------------------------- /lesson10/data/world.txt: -------------------------------------------------------------------------------- 1 | 2 | NUMPOLLIES 36 3 | 4 | // Floor 1 5 | -3.0 0.0 -3.0 0.0 6.0 6 | -3.0 0.0 3.0 0.0 0.0 7 | 3.0 0.0 3.0 6.0 0.0 8 | 9 | -3.0 0.0 -3.0 0.0 6.0 10 | 3.0 0.0 -3.0 6.0 6.0 11 | 3.0 0.0 3.0 6.0 0.0 12 | 13 | // Ceiling 1 14 | -3.0 1.0 -3.0 0.0 6.0 15 | -3.0 1.0 3.0 0.0 0.0 16 | 3.0 1.0 3.0 6.0 0.0 17 | -3.0 1.0 -3.0 0.0 6.0 18 | 3.0 1.0 -3.0 6.0 6.0 19 | 3.0 1.0 3.0 6.0 0.0 20 | 21 | // A1 22 | 23 | -2.0 1.0 -2.0 0.0 1.0 24 | -2.0 0.0 -2.0 0.0 0.0 25 | -0.5 0.0 -2.0 1.5 0.0 26 | -2.0 1.0 -2.0 0.0 1.0 27 | -0.5 1.0 -2.0 1.5 1.0 28 | -0.5 0.0 -2.0 1.5 0.0 29 | 30 | // A2 31 | 32 | 2.0 1.0 -2.0 2.0 1.0 33 | 2.0 0.0 -2.0 2.0 0.0 34 | 0.5 0.0 -2.0 0.5 0.0 35 | 2.0 1.0 -2.0 2.0 1.0 36 | 0.5 1.0 -2.0 0.5 1.0 37 | 0.5 0.0 -2.0 0.5 0.0 38 | 39 | // B1 40 | 41 | -2.0 1.0 2.0 2.0 1.0 42 | -2.0 0.0 2.0 2.0 0.0 43 | -0.5 0.0 2.0 0.5 0.0 44 | -2.0 1.0 2.0 2.0 1.0 45 | -0.5 1.0 2.0 0.5 1.0 46 | -0.5 0.0 2.0 0.5 0.0 47 | 48 | // B2 49 | 50 | 2.0 1.0 2.0 2.0 1.0 51 | 2.0 0.0 2.0 2.0 0.0 52 | 0.5 0.0 2.0 0.5 0.0 53 | 2.0 1.0 2.0 2.0 1.0 54 | 0.5 1.0 2.0 0.5 1.0 55 | 0.5 0.0 2.0 0.5 0.0 56 | 57 | // C1 58 | 59 | -2.0 1.0 -2.0 0.0 1.0 60 | -2.0 0.0 -2.0 0.0 0.0 61 | -2.0 0.0 -0.5 1.5 0.0 62 | -2.0 1.0 -2.0 0.0 1.0 63 | -2.0 1.0 -0.5 1.5 1.0 64 | -2.0 0.0 -0.5 1.5 0.0 65 | 66 | // C2 67 | 68 | -2.0 1.0 2.0 2.0 1.0 69 | -2.0 0.0 2.0 2.0 0.0 70 | -2.0 0.0 0.5 0.5 0.0 71 | -2.0 1.0 2.0 2.0 1.0 72 | -2.0 1.0 0.5 0.5 1.0 73 | -2.0 0.0 0.5 0.5 0.0 74 | 75 | // D1 76 | 77 | 2.0 1.0 -2.0 0.0 1.0 78 | 2.0 0.0 -2.0 0.0 0.0 79 | 2.0 0.0 -0.5 1.5 0.0 80 | 2.0 1.0 -2.0 0.0 1.0 81 | 2.0 1.0 -0.5 1.5 1.0 82 | 2.0 0.0 -0.5 1.5 0.0 83 | 84 | // D2 85 | 86 | 2.0 1.0 2.0 2.0 1.0 87 | 2.0 0.0 2.0 2.0 0.0 88 | 2.0 0.0 0.5 0.5 0.0 89 | 2.0 1.0 2.0 2.0 1.0 90 | 2.0 1.0 0.5 0.5 1.0 91 | 2.0 0.0 0.5 0.5 0.0 92 | 93 | // Upper hallway - L 94 | -0.5 1.0 -3.0 0.0 1.0 95 | -0.5 0.0 -3.0 0.0 0.0 96 | -0.5 0.0 -2.0 1.0 0.0 97 | -0.5 1.0 -3.0 0.0 1.0 98 | -0.5 1.0 -2.0 1.0 1.0 99 | -0.5 0.0 -2.0 1.0 0.0 100 | 101 | // Upper hallway - R 102 | 0.5 1.0 -3.0 0.0 1.0 103 | 0.5 0.0 -3.0 0.0 0.0 104 | 0.5 0.0 -2.0 1.0 0.0 105 | 0.5 1.0 -3.0 0.0 1.0 106 | 0.5 1.0 -2.0 1.0 1.0 107 | 0.5 0.0 -2.0 1.0 0.0 108 | 109 | // Lower hallway - L 110 | -0.5 1.0 3.0 0.0 1.0 111 | -0.5 0.0 3.0 0.0 0.0 112 | -0.5 0.0 2.0 1.0 0.0 113 | -0.5 1.0 3.0 0.0 1.0 114 | -0.5 1.0 2.0 1.0 1.0 115 | -0.5 0.0 2.0 1.0 0.0 116 | 117 | // Lower hallway - R 118 | 0.5 1.0 3.0 0.0 1.0 119 | 0.5 0.0 3.0 0.0 0.0 120 | 0.5 0.0 2.0 1.0 0.0 121 | 0.5 1.0 3.0 0.0 1.0 122 | 0.5 1.0 2.0 1.0 1.0 123 | 0.5 0.0 2.0 1.0 0.0 124 | 125 | 126 | // Left hallway - Lw 127 | 128 | -3.0 1.0 0.5 1.0 1.0 129 | -3.0 0.0 0.5 1.0 0.0 130 | -2.0 0.0 0.5 0.0 0.0 131 | -3.0 1.0 0.5 1.0 1.0 132 | -2.0 1.0 0.5 0.0 1.0 133 | -2.0 0.0 0.5 0.0 0.0 134 | 135 | // Left hallway - Hi 136 | 137 | -3.0 1.0 -0.5 1.0 1.0 138 | -3.0 0.0 -0.5 1.0 0.0 139 | -2.0 0.0 -0.5 0.0 0.0 140 | -3.0 1.0 -0.5 1.0 1.0 141 | -2.0 1.0 -0.5 0.0 1.0 142 | -2.0 0.0 -0.5 0.0 0.0 143 | 144 | // Right hallway - Lw 145 | 146 | 3.0 1.0 0.5 1.0 1.0 147 | 3.0 0.0 0.5 1.0 0.0 148 | 2.0 0.0 0.5 0.0 0.0 149 | 3.0 1.0 0.5 1.0 1.0 150 | 2.0 1.0 0.5 0.0 1.0 151 | 2.0 0.0 0.5 0.0 0.0 152 | 153 | // Right hallway - Hi 154 | 155 | 3.0 1.0 -0.5 1.0 1.0 156 | 3.0 0.0 -0.5 1.0 0.0 157 | 2.0 0.0 -0.5 0.0 0.0 158 | 3.0 1.0 -0.5 1.0 1.0 159 | 2.0 1.0 -0.5 0.0 1.0 160 | 2.0 0.0 -0.5 0.0 0.0 -------------------------------------------------------------------------------- /lesson10/lesson10.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/banthar/Go-SDL/sdl" 7 | "github.com/banthar/gl" 8 | "io/ioutil" 9 | "math" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | const ( 15 | SCREEN_WIDTH = 640 16 | SCREEN_HEIGHT = 480 17 | SCREEN_BPP = 32 18 | 19 | // used for conversion to radians 20 | PiOver100 = 0.0174532925199433 21 | ) 22 | 23 | var ( 24 | surface *sdl.Surface 25 | t0, frames uint32 26 | 27 | sector1 Sector // our sector 28 | yrot float64 // camera rotation 29 | xpos, zpos float64 // camera position 30 | walkbias, walkbiasangle float64 // head-bobbing.... 31 | lookupdown gl.GLfloat 32 | 33 | lightAmbient = [4]float32{0.5, 0.5, 0.5, 1.0} 34 | lightDiffuse = [4]float32{1.0, 1.0, 1.0, 1.0} 35 | lightPosition = [4]float32{0.0, 0.0, 2.0, 1.0} 36 | 37 | filter gl.GLuint 38 | textures [3]gl.Texture 39 | ) 40 | 41 | type Vertex struct { 42 | x, y, z gl.GLfloat 43 | u, v gl.GLfloat 44 | } 45 | 46 | type Triangle [3]*Vertex 47 | type Sector []*Triangle 48 | 49 | func p(a ...interface{}) { fmt.Println(a) } 50 | 51 | // load in bitmap as a GL texture 52 | func LoadGLTextures(path string) { 53 | // storage space for the textures 54 | image, format := LoadImage(path) 55 | 56 | // Create the textures 57 | gl.GenTextures(textures[:]) 58 | 59 | genTexture(textures[0], image, format) 60 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 61 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 62 | 63 | genTexture(textures[1], image, format) 64 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 65 | gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 66 | 67 | genTexture(textures[2], image, format) 68 | gl.TexParameteri(gl.TEXTURE_2D, gl.GENERATE_MIPMAP, gl.TRUE) 69 | } 70 | 71 | func LoadImage(path string) (image *sdl.Surface, format gl.GLenum) { 72 | image = sdl.Load(path) 73 | if image == nil { 74 | panic(sdl.GetError()) 75 | } 76 | 77 | // Check that the image's width is a power of 2 78 | if image.W&(image.W-1) != 0 { 79 | fmt.Println("warning:", path, "has a width that is not a power of 2") 80 | } 81 | 82 | // Also check if the height is a power of 2 83 | if image.H&(image.H-1) != 0 { 84 | fmt.Println("warning:", path, "has an height that is not a power of 2") 85 | } 86 | 87 | // get the number of channels in the SDL surface 88 | nOfColors := image.Format.BytesPerPixel 89 | if nOfColors == 4 { // contains alpha channel 90 | if image.Format.Rmask == 0x000000ff { 91 | format = gl.RGBA 92 | } else { 93 | format = gl.BGRA 94 | } 95 | } else if nOfColors == 3 { // no alpha channel 96 | if image.Format.Rmask == 0x000000ff { 97 | format = gl.RGB 98 | } else { 99 | format = gl.BGR 100 | } 101 | } else { 102 | fmt.Println("warning:", path, "is not truecolor, this will probably break") 103 | } 104 | 105 | return image, format 106 | } 107 | 108 | func genTexture(into gl.Texture, from *sdl.Surface, format gl.GLenum) { 109 | gl.BindTexture(gl.TEXTURE_2D, uint(into)) 110 | gl.TexImage2D(gl.TEXTURE_2D, 0, 3, int(from.W), int(from.H), 111 | 0, format, gl.UNSIGNED_BYTE, from.Pixels, 112 | ) 113 | } 114 | 115 | func SetupWorld(path string) { 116 | content, err := ioutil.ReadFile(path) 117 | if err != nil { 118 | panic(err) 119 | } 120 | 121 | triangle := &Triangle{} 122 | triangles := []*Triangle{triangle} 123 | tindex := 0 124 | 125 | lines := bytes.Split(content, []byte("\n")) 126 | for _, line := range lines { 127 | fields := bytes.Fields(line) 128 | 129 | if len(fields) == 5 && fields[0][0] != '/' { 130 | vertex := &Vertex{ 131 | x: atof(fields[0]), y: atof(fields[1]), z: atof(fields[2]), 132 | u: atof(fields[3]), v: atof(fields[4]), 133 | } 134 | 135 | idx := tindex % 3 136 | if triangle[idx] == nil { 137 | triangle[idx] = vertex 138 | } else { 139 | triangle = &Triangle{vertex} 140 | triangles = append(triangles, triangle) 141 | } 142 | 143 | tindex++ 144 | } 145 | } 146 | 147 | sector1 = make(Sector, len(triangles)) 148 | for idx, tri := range triangles { 149 | sector1[idx] = tri 150 | } 151 | } 152 | 153 | func atof(s []byte) gl.GLfloat { 154 | f, err := strconv.ParseFloat(string(s), 32) 155 | if err != nil { 156 | panic(err) 157 | } 158 | return gl.GLfloat(f) 159 | } 160 | 161 | // release/destroy our resources and restoring the old desktop 162 | func Quit(status int) { 163 | // clean up the window 164 | sdl.Quit() 165 | 166 | // and exit appropriately 167 | os.Exit(status) 168 | } 169 | 170 | // reset our viewport after a window resize 171 | func resizeWindow(width, height int) { 172 | // protect against a divide by zero 173 | if height == 0 { 174 | height = 1 175 | } 176 | 177 | // Setup our viewport 178 | gl.Viewport(0, 0, width, height) 179 | 180 | // change to the projection matrix and set our viewing volume. 181 | gl.MatrixMode(gl.PROJECTION) 182 | gl.LoadIdentity() 183 | 184 | // aspect ratio 185 | aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) 186 | 187 | // Set our perspective. 188 | // This code is equivalent to using gluPerspective as in the original tutorial. 189 | var fov, near, far gl.GLdouble 190 | fov = 45.0 191 | near = 0.1 192 | far = 100.0 193 | top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near 194 | bottom := -top 195 | left := aspect * bottom 196 | right := aspect * top 197 | gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) 198 | 199 | // Make sure we're changing the model view and not the projection 200 | gl.MatrixMode(gl.MODELVIEW) 201 | 202 | // Reset the view 203 | gl.LoadIdentity() 204 | } 205 | 206 | // handle key press events 207 | func handleKeyPress(keysym sdl.Keysym) { 208 | keys := sdl.GetKeyState() 209 | 210 | if keys[sdl.K_ESCAPE] == 1 { 211 | Quit(0) 212 | } 213 | 214 | if keys[sdl.K_F1] == 1 { 215 | sdl.WM_ToggleFullScreen(surface) 216 | } 217 | 218 | if keys[sdl.K_f] == 1 { 219 | filter = (filter + 1) % 3 220 | } 221 | 222 | if keys[sdl.K_RIGHT] == 1 { 223 | yrot -= 1.5 224 | } 225 | 226 | if keys[sdl.K_LEFT] == 1 { 227 | yrot += 1.5 228 | } 229 | 230 | if keys[sdl.K_UP] == 1 { 231 | xpos -= math.Sin(yrot*PiOver100) * 0.05 232 | zpos -= math.Cos(yrot*PiOver100) * 0.05 233 | if walkbiasangle >= 359.0 { 234 | walkbiasangle = 0.0 235 | } else { 236 | walkbiasangle += 10.0 237 | } 238 | walkbias = math.Sin(walkbiasangle*PiOver100) / 20.0 239 | } 240 | 241 | if keys[sdl.K_DOWN] == 1 { 242 | xpos += math.Sin(yrot*PiOver100) * 0.05 243 | zpos += math.Cos(yrot*PiOver100) * 0.05 244 | if walkbiasangle <= 1.0 { 245 | walkbiasangle = 359.0 246 | } else { 247 | walkbiasangle -= 10.0 248 | } 249 | walkbias = math.Sin(walkbiasangle*PiOver100) / 20.0 250 | } 251 | } 252 | 253 | // general OpenGL initialization 254 | func initGL() { 255 | LoadGLTextures("data/mud.bmp") 256 | 257 | gl.Enable(gl.TEXTURE_2D) 258 | gl.ShadeModel(gl.SMOOTH) 259 | gl.ClearColor(0.0, 0.0, 0.0, 0.0) 260 | gl.ClearDepth(1.0) 261 | gl.Enable(gl.DEPTH_TEST) 262 | gl.DepthFunc(gl.LEQUAL) 263 | gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) 264 | 265 | gl.Lightfv(gl.LIGHT1, gl.AMBIENT, lightAmbient[:]) 266 | gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, lightDiffuse[:]) 267 | gl.Lightfv(gl.LIGHT1, gl.POSITION, lightPosition[:]) 268 | gl.Enable(gl.LIGHT1) 269 | 270 | gl.Color4f(1.0, 1.0, 1.0, 0.5) 271 | gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) 272 | } 273 | 274 | // Here goes our drawing code 275 | func drawGLScene(sector Sector) { 276 | xtrans := gl.GLfloat(-xpos) 277 | ztrans := gl.GLfloat(-zpos) 278 | ytrans := gl.GLfloat(-walkbias - 0.25) 279 | scenroty := gl.GLfloat(360.0 - yrot) 280 | 281 | // Clear the screen and depth buffer 282 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 283 | 284 | // reset the view 285 | gl.LoadIdentity() 286 | 287 | // Rotate up and down to look up and down 288 | gl.Rotatef(float32(lookupdown), 1.0, 0.0, 0.0) 289 | // Rotate depending on direction player is facing 290 | gl.Rotatef(float32(scenroty), 0.0, 1.0, 0.0) 291 | // translate the scene based on player position 292 | gl.Translatef(float32(xtrans), float32(ytrans), float32(ztrans)) 293 | 294 | gl.BindTexture(gl.TEXTURE_2D, uint(textures[filter])) 295 | 296 | for _, vertices := range sector { 297 | gl.Begin(gl.TRIANGLES) 298 | for _, triangle := range *vertices { 299 | gl.Normal3f(0.0, 0.0, 1.0) 300 | gl.TexCoord2f(float32(triangle.u), float32(triangle.v)) 301 | gl.Vertex3f(float32(triangle.x), float32(triangle.y), float32(triangle.z)) 302 | } 303 | gl.End() 304 | } 305 | 306 | // Draw to the screen 307 | sdl.GL_SwapBuffers() 308 | 309 | // Gather our frames per second 310 | frames++ 311 | t := sdl.GetTicks() 312 | if t-t0 >= 5000 { 313 | seconds := (t - t0) / 1000.0 314 | fps := frames / seconds 315 | fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS") 316 | t0 = t 317 | frames = 0 318 | } 319 | } 320 | 321 | func main() { 322 | if sdl.Init(sdl.INIT_VIDEO) < 0 { 323 | panic("Video initialization failed: " + sdl.GetError()) 324 | } 325 | 326 | if sdl.EnableKeyRepeat(100, 25) != 0 { 327 | panic("Setting keyboard repeat failed: " + sdl.GetError()) 328 | } 329 | 330 | videoFlags := sdl.OPENGL // Enable OpenGL in SDL 331 | videoFlags |= sdl.DOUBLEBUF // Enable double buffering 332 | videoFlags |= sdl.HWPALETTE // Store the palette in hardware 333 | // FIXME: this causes segfault. 334 | // videoFlags |= sdl.RESIZABLE // Enable window resizing 335 | 336 | surface = sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, uint32(videoFlags)) 337 | 338 | if surface == nil { 339 | panic("Video mode set failed: " + sdl.GetError()) 340 | } 341 | 342 | sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1) 343 | initGL() 344 | resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT) 345 | 346 | SetupWorld("data/world.txt") 347 | 348 | // wait for events 349 | running := true 350 | isActive := true 351 | for running { 352 | for ev := sdl.PollEvent(); ev != nil; ev = sdl.PollEvent() { 353 | switch e := ev.(type) { 354 | case *sdl.ActiveEvent: 355 | isActive = e.Gain != 0 356 | case *sdl.ResizeEvent: 357 | width, height := int(e.W), int(e.H) 358 | surface = sdl.SetVideoMode(width, height, SCREEN_BPP, uint32(videoFlags)) 359 | if surface == nil { 360 | fmt.Println("Could not get a surface after resize:", sdl.GetError()) 361 | Quit(1) 362 | } 363 | resizeWindow(width, height) 364 | case *sdl.KeyboardEvent: 365 | if e.Type == sdl.KEYDOWN { 366 | handleKeyPress(e.Keysym) 367 | } 368 | case *sdl.QuitEvent: 369 | running = false 370 | } 371 | } 372 | 373 | // draw the scene 374 | if isActive { 375 | drawGLScene(sector1) 376 | } 377 | } 378 | } 379 | --------------------------------------------------------------------------------