package main import ( "flag" "fmt" "image" "log" "math" "os" "renderer1/hrend" "runtime/pprof" // For performance profiling (unnecessary) "time" _ "image/jpeg" rl "github.com/gen2brain/raylib-go/raylib" ) const ( Width = 640 Height = 480 NearClip = 0.1 FarClip = 100 FOV = 90.0 ZOffset = 1.5 Movement = 1.0 Rotation = 0.25 LookLock = math.Pi / 32 Fps = 60 ObjectFile = "../head.obj" TextureFile = "../head.jpg" ) func must(err error) { if err != nil { panic(err) } } func loadDefault() (*hrend.ObjModel, hrend.Framebuffer) { log.Printf("Loading obj %s, texture %s", ObjectFile, TextureFile) of, err := os.Open(ObjectFile) must(err) defer of.Close() o, err := hrend.ParseObj(of) must(err) jf, err := os.Open(TextureFile) must(err) defer jf.Close() timg, _, err := image.Decode(jf) must(err) texture := hrend.NewTexture(timg, 4) return o, texture } // However flag works... idk var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") // var dozbuf = flag.Bool("zbuffer", false, "Write zbuffer instead of image") // var p6file = flag.String("p6file", "", "Output binary ppm to given file instead") // var fov = flag.Float64("fov", 90, "Horizontal FOV in degrees") // var xofs = flag.Float64("xofs", 0, "Offset image by x") // var zofs = flag.Float64("zofs", -1.5, "Offset image by z (should be negative)") // var repeat = flag.Int("repeat", 60, "Amount of times to repeat render") func main() { log.Printf("Program start") flag.Parse() if *cpuprofile != "" { log.Printf("CPU profiling requested, write to %s", *cpuprofile) f, err := os.Create(*cpuprofile) must(err) defer f.Close() err = pprof.StartCPUProfile(f) must(err) defer pprof.StopCPUProfile() } rl.InitWindow(Width, Height, "Simple renderer with raylib") defer rl.CloseWindow() rl.SetTargetFPS(Fps) rl.DisableCursor() fb := NewRaylibBuffer(Width, Height) defer rl.UnloadTexture(fb.Texture) defer rl.UnloadImageColors(fb.Data) defer rl.UnloadImage(fb.Image) rb := hrend.NewRenderbuffer(fb, Width, Height) o, texture := loadDefault() // light := hrend.Vec3f{ // X: 0, // Y: 0, // Z: -1, // } var thing hrend.Vec2i log.Print(thing) var projection, viewport hrend.Mat44f // These don't really change projection.SetProjection(float32(FOV), float32(Width)/float32(Height), NearClip, FarClip) viewport.SetViewportSimple(int(fb.Width), int(fb.Height), 1) //65535) log.Printf("Starting raylib loop") frameSum := 0.0 frameCount := 0 frameAverage := 0.0 camtrans := hrend.Vec3f{X: 0, Y: 0, Z: ZOffset} camup := hrend.Vec3f{X: 0, Y: 1, Z: 0} lookvec := hrend.Vec3f{X: 0, Y: 0, Z: -1} // In our system, 0 degree yaw is facing -Z, into the scene yaw := float32(0) pitch := float32(math.Pi / 2) // Start looking flat // in all three directions... I think?? //yrot := float32(0.0) //var camrotation, camtrans hrend.Mat44f //camrotation.SetIdentity() //var camrotx, camroty, camrotz hrend.Mat44f //var camrotx, camroty hrend.Mat44f var camera hrend.Mat44f for !rl.WindowShouldClose() { start := time.Now() mouse := rl.GetMouseDelta() pitch += Rotation * mouse.Y / Fps yaw += Rotation * mouse.X / Fps // Need a clamp function or something if pitch < LookLock { pitch = LookLock } else if pitch > math.Pi-LookLock { pitch = math.Pi - LookLock } newcamtrans := hrend.Vec3f{X: 0, Y: 0, Z: 0} if rl.IsKeyDown(rl.KeyD) { newcamtrans.X += Movement / Fps } if rl.IsKeyDown(rl.KeyA) { newcamtrans.X -= Movement / Fps } // Moving forward moves in the negative z direction, since we FACE // the -z axis if rl.IsKeyDown(rl.KeyW) { newcamtrans.Z -= Movement / Fps } if rl.IsKeyDown(rl.KeyS) { newcamtrans.Z += Movement / Fps } if rl.IsKeyDown(rl.KeySpace) { newcamtrans.Y += Movement / Fps } if rl.IsKeyDown(rl.KeyLeftShift) { newcamtrans.Y -= Movement / Fps } lookvec.Z = float32(-math.Sin(float64(pitch)) * math.Cos(float64(yaw))) lookvec.X = float32(math.Sin(float64(pitch)) * math.Sin(float64(yaw))) lookvec.Y = float32(math.Cos(float64(pitch))) //camrotx.SetRotationX(rotvec.X) //camroty.SetRotationY(rotvec.Y) //lookvec := camroty.Multiply(&camrotx).MultiplyPoint3(baselook) camtrans = *camtrans.Add(&newcamtrans) //camrotz.SetRotationZ(zrot) //camrotation = *camrotation.Multiply( // This might (thought not currently) //camtrans.SetTranslation(xofs, yofs, zofs) camera.SetLookAt(&camtrans, camtrans.Add(&lookvec), &camup) //screenmat := camrotx.Multiply(&camroty).Multiply(&camrotz).Multiply(&camtrans).Inverse().Multiply(&projection) screenmat := camera.Inverse().Multiply(&projection) screenmat = screenmat.Multiply(&viewport) for i := 0; i < Width*Height; i++ { fb.Data[i].R = 0 fb.Data[i].G = 0 fb.Data[i].B = 0 } //rl.ImageDrawRectangle(fb.Image, 0, 0, Width, Height, rl.Black) //rl.ImageClearBackground(fb.Image, rl.Black) var sc [3]hrend.Vertex rb.ResetZBuffer() for _, f := range o.Faces { // Precompute perspective for vertices to save time. Notice Z // is not considered: is this orthographic projection? Yeah probably... //var fpt [3]hrend.Vec3f for i := range 3 { // Triangles, bro sc[i] = f[i] sc[i].Pos = screenmat.MultiplyPoint3(f[i].Pos) //fpt[i] = worldToCamera.MultiplyPoint3(f[i].Pos) } //l1 := fpt[2].Sub(fpt[0]) //n := l1.CrossProduct(fpt[1].Sub(fpt[0])) //n = n.Normalize() //intensity := n.MultSimp(&light) intensity := float32(1.0) if intensity > 0 { hrend.TriangleTextured(&rb, texture, intensity, sc[0], sc[1], sc[2]) //hrend.TriangleFlat(&rb, hrend.Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0].Pos, sc[1].Pos, sc[2].Pos) } } rl.UpdateTexture(fb.Texture, fb.Data) frameSum += time.Since(start).Seconds() frameCount += 1 if frameCount&0x7 == 0 { frameAverage = frameSum / float64(frameCount) frameSum = 0 frameCount = 0 } rl.BeginDrawing() rl.ClearBackground(rl.RayWhite) rl.DrawTexture(fb.Texture, 0, 0, rl.White) rl.DrawText(fmt.Sprintf("Frame: %fms", frameAverage*1000), 5, 5, 20, rl.Red) rl.EndDrawing() } }