main.go (8722B)
1 package main 2 3 import ( 4 "log" 5 "math" 6 "path/filepath" 7 "runtime" 8 "time" 9 10 "git.mtkn.jp/tofu" 11 ) 12 13 const ( 14 winW, winH = 800, 600 15 ) 16 17 var camera *tofu.Camera 18 19 func init() { 20 runtime.LockOSThread() 21 } 22 23 func processInput(app *App) { 24 const speed = 0.05 25 if tofu.IsKeyPressed(tofu.KeyQ) { 26 app.termination = true 27 return 28 } 29 if tofu.IsKeyPressed(tofu.KeyUp) { 30 alpha += 0.01 31 if alpha > 1.0 { 32 alpha = 1.0 33 } 34 } 35 if tofu.IsKeyPressed(tofu.KeyDown) { 36 alpha -= 0.01 37 if alpha < 0 { 38 alpha = 0 39 } 40 } 41 if tofu.IsKeyPressed(tofu.KeyW) { 42 camera.Move2(0, -speed) 43 } 44 if tofu.IsKeyPressed(tofu.KeyS) { 45 camera.Move2(0, speed) 46 } 47 if tofu.IsKeyPressed(tofu.KeyA) { 48 camera.Move2(-speed, 0) 49 } 50 if tofu.IsKeyPressed(tofu.KeyD) { 51 camera.Move2(speed, 0) 52 } 53 if tofu.IsKeyPressed(tofu.KeySpace) { 54 camera.MoveVert(speed) 55 } 56 if tofu.IsKeyPressed(tofu.KeyLeftShift) { 57 camera.MoveVert(-speed) 58 } 59 } 60 61 func watchCursor(app *App) { 62 const sensitivity = 0.005 63 firstTime := true 64 for cur := range app.cursorChan { 65 if firstTime { 66 app.cur = cur 67 firstTime = false 68 continue 69 } 70 dx, dy := float32(app.cur.X-cur.X), float32(app.cur.Y-cur.Y) 71 dx *= sensitivity 72 dy *= sensitivity 73 app.cur = cur 74 camera.YawPitch(dx, -dy) 75 } 76 } 77 78 // directional light 79 type DirLight struct { 80 Dir tofu.Vec3 81 Ambient tofu.Vec3 82 Diffuse tofu.Vec3 83 Specular tofu.Vec3 84 } 85 86 type SpotLight struct { 87 Pos tofu.Vec3 88 Dir tofu.Vec3 89 Ambient tofu.Vec3 90 Diffuse tofu.Vec3 91 Specular tofu.Vec3 92 Kc, Kl, Kq float32 93 CutOff float32 94 OuterCutOff float32 95 } 96 97 var ( 98 sunCol = tofu.Vec3{1, 1, 1} 99 sun = &DirLight{ 100 Dir: tofu.Vec3{-0.2, -1.0, -0.3}, 101 Ambient: sunCol.MulF(0.5), 102 Diffuse: sunCol.MulF(0.3), 103 Specular: sunCol, 104 } 105 spotLightCol = tofu.Vec3{1, 1, 1} 106 spotLight = &SpotLight{ 107 Ambient: spotLightCol.MulF(0.5), 108 Diffuse: spotLightCol.MulF(0.3), 109 Specular: spotLightCol, 110 CutOff: float32(math.Cos(25 * math.Pi / 180)), 111 OuterCutOff: float32(math.Cos(35 * math.Pi / 180)), 112 Kc: 1.0, 113 Kl: 0.0009, 114 Kq: 0.00032, 115 } 116 ) 117 118 var teapot *tofu.Object 119 var cube = &tofu.Object{ 120 Vertices: []tofu.Vec3{ 121 tofu.Vec3{0.5, 0.5, -0.5}, 122 tofu.Vec3{0.5, -0.5, -0.5}, 123 tofu.Vec3{-0.5, -0.5, -0.5}, 124 tofu.Vec3{-0.5, 0.5, -0.5}, 125 tofu.Vec3{0.5, 0.5, 0.5}, 126 tofu.Vec3{0.5, -0.5, 0.5}, 127 tofu.Vec3{-0.5, -0.5, 0.5}, 128 tofu.Vec3{-0.5, 0.5, 0.5}, 129 }, 130 Normals: []tofu.Vec3{ 131 {0.0, 0.0, -1.0}, 132 {1.0, 0.0, 0.0}, 133 {0.0, -1.0, 0.0}, 134 {-1.0, 0.0, 0.0}, 135 {0.0, 1.0, 0.0}, 136 {0.0, 0.0, 1.0}, 137 }, 138 TexCoords: []tofu.Vec2{ 139 tofu.Vec2{1.0, 1.0}, 140 tofu.Vec2{1.0, 0.0}, 141 tofu.Vec2{0.0, 0.0}, 142 tofu.Vec2{0.0, 1.0}, 143 }, 144 Faces: []tofu.Face{ 145 {{0, 0, 0}, {1, 0, 1}, {2, 0, 2}}, 146 {{0, 0, 0}, {2, 0, 2}, {3, 0, 3}}, 147 {{0, 1, 0}, {1, 1, 1}, {5, 1, 2}}, 148 {{0, 1, 0}, {5, 1, 2}, {4, 1, 3}}, 149 {{1, 2, 0}, {2, 2, 1}, {6, 2, 2}}, 150 {{1, 2, 0}, {6, 2, 2}, {5, 2, 3}}, 151 {{2, 3, 0}, {3, 3, 1}, {7, 3, 2}}, 152 {{2, 3, 0}, {7, 3, 2}, {6, 3, 3}}, 153 {{3, 4, 0}, {0, 4, 1}, {4, 4, 2}}, 154 {{3, 4, 0}, {4, 4, 2}, {7, 4, 3}}, 155 {{4, 5, 0}, {5, 5, 1}, {6, 5, 2}}, 156 {{4, 5, 0}, {6, 5, 2}, {7, 5, 3}}, 157 }, 158 } 159 var light = &tofu.Object{ 160 Vertices: []tofu.Vec3{ 161 tofu.Vec3{0.5, 0.5, -0.5}, 162 tofu.Vec3{0.5, -0.5, -0.5}, 163 tofu.Vec3{-0.5, -0.5, -0.5}, 164 tofu.Vec3{-0.5, 0.5, -0.5}, 165 tofu.Vec3{0.5, 0.5, 0.5}, 166 tofu.Vec3{0.5, -0.5, 0.5}, 167 tofu.Vec3{-0.5, -0.5, 0.5}, 168 tofu.Vec3{-0.5, 0.5, 0.5}, 169 }, 170 Normals: []tofu.Vec3{ 171 {0.0, 0.0, -1.0}, 172 {1.0, 0.0, 0.0}, 173 {0.0, -1.0, 0.0}, 174 {-1.0, 0.0, 0.0}, 175 {0.0, 1.0, 0.0}, 176 {0.0, 0.0, 1.0}, 177 }, 178 TexCoords: []tofu.Vec2{ 179 tofu.Vec2{1.0, 1.0}, 180 tofu.Vec2{1.0, 0.0}, 181 tofu.Vec2{0.0, 0.0}, 182 tofu.Vec2{0.0, 1.0}, 183 }, 184 Faces: []tofu.Face{ 185 {{0, 0, 0}, {1, 0, 1}, {2, 0, 2}}, 186 {{0, 0, 0}, {2, 0, 2}, {3, 0, 3}}, 187 {{0, 1, 0}, {1, 1, 1}, {5, 1, 2}}, 188 {{0, 1, 0}, {5, 1, 2}, {4, 1, 3}}, 189 {{1, 2, 0}, {2, 2, 1}, {6, 2, 2}}, 190 {{1, 2, 0}, {6, 2, 2}, {5, 2, 3}}, 191 {{2, 3, 0}, {3, 3, 1}, {7, 3, 2}}, 192 {{2, 3, 0}, {7, 3, 2}, {6, 3, 3}}, 193 {{3, 4, 0}, {0, 4, 1}, {4, 4, 2}}, 194 {{3, 4, 0}, {4, 4, 2}, {7, 4, 3}}, 195 {{4, 5, 0}, {5, 5, 1}, {6, 5, 2}}, 196 {{4, 5, 0}, {6, 5, 2}, {7, 5, 3}}, 197 }, 198 } 199 200 type Trans struct { 201 Projection, View, Model tofu.Mat4 202 } 203 204 var teapotTrans = new(Trans) 205 var cubeTrans = new(Trans) 206 207 var cubePositions = []tofu.Vec3{ 208 {4.24, 0.94, -1.94}, 209 {0.79, 2.40, 2.87}, 210 {-0.64, -1.68, 2.79}, 211 {-3.99, 2.85, 3.35}, 212 {2.61, -0.04, -0.74}, 213 {4.46, 3.22, 2.09}, 214 {-3.42, -3.80, 4.10}, 215 {3.68, -0.51, 2.05}, 216 {-1.00, 1.45, 1.96}, 217 {-2.00, 0.92, 4.57}, 218 } 219 220 var alpha float32 = 0.2 221 222 type App struct { 223 program *tofu.Program 224 lightProgram *tofu.Program 225 teapotProgram *tofu.Program 226 cursorChan chan tofu.Cursor 227 cur tofu.Cursor 228 keyChan chan struct{} 229 camera *tofu.Camera 230 termination bool 231 startedAt time.Time 232 texture *tofu.Texture 233 specularMap *tofu.Texture 234 } 235 236 func (app *App) Update() error { 237 now := float32(time.Since(app.startedAt).Seconds()) 238 processInput(app) 239 if app.termination { 240 return tofu.Termination 241 } 242 243 view := camera.View() 244 projection := tofu.Perspective(80*math.Pi/180, 800/600, 0.1, 100) 245 246 lightModel := tofu.Rotate(now, tofu.Vec3{0, 1, 0}). 247 Mul(tofu.Translate(tofu.Vec3{5, 4.5, 0})). 248 Mul(tofu.Scale(0.3)) 249 spotLight.Pos = tofu.Rotate3(now, tofu.Vec3{0, 1, 0}). 250 MulV(tofu.Vec3{5, 4.5, 0}) 251 spotLight.Dir = tofu.Vec3{0, 0, 0}.Sub(spotLight.Pos) 252 253 app.program.Use() 254 cubeTrans.View = view 255 cubeTrans.Projection = projection 256 app.program.SetVec3("camPos", camera.Pos) 257 app.program.SetTexture("material.diffuse", app.texture) 258 app.program.SetTexture("material.specular", app.specularMap) 259 app.program.SetFloat32("material.shiness", 32) 260 for _, p := range cubePositions { 261 model := tofu.Translate(p.Inverse()) 262 cubeTrans.Model = model 263 app.program.SetUniforms() 264 cube.Draw(app.program) 265 } 266 app.teapotProgram.Use() 267 teapotTrans.View = view 268 teapotTrans.Projection = projection 269 teapotTrans.Model = tofu.Translate(tofu.Vec3{0, 0, 0}). 270 Mul(tofu.Rotate(now, tofu.Vec3{0, 1, 0})). 271 Mul(tofu.Scale(0.06)) 272 app.teapotProgram.SetVec3("camPos", camera.Pos) 273 app.teapotProgram.SetVec3("material.diffuse", tofu.Vec3{0.3, 0.4, 0.4}) 274 app.teapotProgram.SetVec3("material.specular", tofu.Vec3{0.3, 0.4, 0.4}) 275 app.teapotProgram.SetFloat32("material.shiness", 32) 276 app.teapotProgram.SetUniforms() 277 teapot.Draw(app.teapotProgram) 278 279 app.lightProgram.Use() 280 app.lightProgram.SetMat4("Trans.View", view) 281 app.lightProgram.SetMat4("Trans.Projection", projection) 282 app.lightProgram.SetMat4("Trans.Model", lightModel) 283 app.lightProgram.SetVec3("lightCol", spotLight.Specular) 284 app.lightProgram.SetUniforms() 285 light.Draw(app.lightProgram) 286 287 return nil 288 } 289 290 func (app *App) CursorChan() chan<- tofu.Cursor { 291 return app.cursorChan 292 } 293 294 func main() { 295 var err error 296 app := &App{} 297 app.cursorChan = make(chan tofu.Cursor) 298 app.startedAt = time.Now() 299 go watchCursor(app) 300 tofu.SetWindowSize(winW, winH) 301 tofu.SetWindowTitle("Sample") 302 tofu.Init() 303 304 cube.Load() 305 light.Load() 306 307 _, f, _, ok := runtime.Caller(0) 308 if !ok { 309 log.Fatalf("unable to get source file information") 310 } 311 vpath := filepath.Join(filepath.Dir(f), "vertex.glsl") 312 fpath := filepath.Join(filepath.Dir(f), "fragment.glsl") 313 lightFpath := filepath.Join(filepath.Dir(f), "light_fragment.glsl") 314 texturePath := filepath.Join(filepath.Dir(f), "container2.png") 315 specularMapPath := filepath.Join(filepath.Dir(f), "container2_specular.png") 316 teapotPath := filepath.Join(filepath.Dir(f), "teapot.obj") 317 teapotFpath := filepath.Join(filepath.Dir(f), "teapot.glsl") 318 319 teapot, err = tofu.DecodeObject(teapotPath) 320 if err != nil { 321 log.Fatal(err) 322 } 323 teapot.SetNormals() 324 teapot.Load() 325 326 app.program, err = tofu.NewProgram(vpath, fpath) 327 if err != nil { 328 log.Fatalf("create shader program: %v", err) 329 } 330 app.program.Uniforms = struct { 331 Sun *DirLight 332 Light *SpotLight 333 Trans *Trans 334 }{ 335 sun, 336 spotLight, 337 cubeTrans, 338 } 339 app.lightProgram, err = tofu.NewProgram(vpath, lightFpath) 340 if err != nil { 341 log.Fatalf("create light shader program: %v", err) 342 } 343 app.teapotProgram, err = tofu.NewProgram(vpath, teapotFpath) 344 if err != nil { 345 log.Fatalf("create teapot shader program: %v", err) 346 } 347 app.teapotProgram.Uniforms = struct { 348 Sun *DirLight 349 Light *SpotLight 350 Trans *Trans 351 }{ 352 Sun: sun, 353 Light: spotLight, 354 Trans: teapotTrans, 355 } 356 app.texture, err = tofu.NewTexture(texturePath) 357 if err != nil { 358 log.Fatalf("NewTesture: %v", err) 359 } 360 app.specularMap, err = tofu.NewTexture(specularMapPath) 361 if err != nil { 362 log.Fatalf("NewTesture: %v", err) 363 } 364 365 camera = tofu.NewCamera() 366 camera.MoveTo(tofu.Vec3{0, 0, 3}) 367 camera.LookAt(tofu.Vec3{0, 0, 0}) 368 369 if err := tofu.Run(app); err != nil { 370 log.Fatal(err) 371 } 372 }