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