// Create is the startup asset creation. func (kc *kctag) Create(eng vu.Eng, s *vu.State) { top := eng.Root().NewPov() view := top.NewView() view.SetUI() kc.ui = view.Cam() kc.positions = kc.keyPositions() // Create the keyboard image. kc.kb = top.NewPov().SetScale(900, 255, 0).SetLocation(450, 100+85, 0) kc.kb.NewModel("uv").LoadMesh("icon").AddTex("keyboard") // Pressed key focus kc.focus = top.NewPov().SetScale(50, 50, 0) kc.focus.NewModel("uv").LoadMesh("icon").AddTex("particle") // Place the key symbols over the keys. font := "lucidiaSu18" fontColour := "lucidiaSu18Black" for code, key := range kc.positions { // map key is key code, map value is key struct if char := vu.Keysym(code); char > 0 { cx, cy := key.location() letter := top.NewPov().SetLocation(cx, cy, 0) model := letter.NewModel("uv") model.AddTex(fontColour).LoadFont(font).SetPhrase(string(char)) } } // Have a lighter default background. eng.SetColor(0.45, 0.45, 0.45, 1) kc.resize(s.W, s.H) }
// Create is the engine callback for initial asset creation. func (sg *sgtag) Create(eng vu.Eng, s *vu.State) { sg.run = 10 // move so many cubes worth in one second. sg.spin = 270 // spin so many degrees in one second. sg.cam = eng.Root().NewCam() sg.cam.SetPerspective(60, float64(800)/float64(600), 0.1, 50) sg.cam.SetLocation(0, 0, 6) sg.tr = newTrooper(eng, 1) // initialize the reactions sg.reacts = map[int]inputHandler{ vu.K_W: sg.forward, vu.K_A: sg.left, vu.K_S: sg.back, vu.K_D: sg.right, vu.K_Equal: sg.attach, vu.K_Minus: sg.detach, vu.K_0: func(i *vu.Input, down int) { sg.setTr(down, 0) }, vu.K_1: func(i *vu.Input, down int) { sg.setTr(down, 1) }, vu.K_2: func(i *vu.Input, down int) { sg.setTr(down, 2) }, vu.K_3: func(i *vu.Input, down int) { sg.setTr(down, 3) }, vu.K_4: func(i *vu.Input, down int) { sg.setTr(down, 4) }, vu.K_5: func(i *vu.Input, down int) { sg.setTr(down, 5) }, vu.K_P: sg.stats, } eng.SetColor(0.1, 0.1, 0.1, 1.0) }
// Create is the engine callback for initial asset creation. func (rl *rltag) Create(eng vu.Eng, s *vu.State) { rl.ww, rl.wh = 800, 600 rl.floors = make(map[int]*floor) rl.setLevel(eng, vu.K_1) eng.SetColor(0.15, 0.15, 0.15, 1) return }
// Create is the startup asset creation. func (sm *smtag) Create(eng vu.Eng, s *vu.State) { scene := eng.Root().NewPov() sm.cam = scene.NewCam() // need a light for shadows. sm.sun = scene.NewPov().SetLocation(0, 0, 0) sm.sun.NewLight().SetColour(0.8, 0.8, 0.8) // create a scene that will render a shadow map. sm.cam = scene.NewCam() sm.cam.SetLocation(0, 0, 10) sm.cam.SetPerspective(60, float64(s.W)/float64(s.H), 0.1, 50) // create a few objects that cast shadows. sm.cube = scene.NewPov().SetLocation(-1, -1, -4) sm.cube.NewModel("gouraud").LoadMesh("box").LoadMat("gray").CastShadow() sm.cube.Spin(45, 45, 0) sm.sphere = scene.NewPov().SetLocation(1, 1, -4) sm.sphere.NewModel("gouraud").LoadMesh("sphere").LoadMat("red").CastShadow() // create a ground block to show shadows. ground := scene.NewPov().SetLocation(0, 0, -20).SetScale(50, 50, 5) model := ground.NewModel("shadow").LoadMesh("box").LoadMat("gray").HasShadows() model.AddTex("tile") }
// Update is the regular engine callback. func (bb *bbtag) Update(eng vu.Eng, in *vu.Input, s *vu.State) { run := 10.0 // move so many cubes worth in one second. spin := 270.0 // spin so many degrees in one second. if in.Resized { bb.resize(s.W, s.H) } dt := in.Dt for press, _ := range in.Down { switch press { case vu.K_W: bb.cam.Move(0, 0, dt*-run, bb.cam.Lookxz()) case vu.K_S: bb.cam.Move(0, 0, dt*run, bb.cam.Lookxz()) case vu.K_Q: bb.cam.Move(dt*-run, 0, 0, bb.cam.Lookxz()) case vu.K_E: bb.cam.Move(dt*run, 0, 0, bb.cam.Lookxz()) case vu.K_A: bb.cam.AdjustYaw(dt * spin) case vu.K_D: bb.cam.AdjustYaw(dt * -spin) case vu.K_T: eng.Shutdown() } } // Use screen coordinates from world coordinates. if sx, sy := bb.cam.Screen(5, 2, -15, s.W, s.H); sx == -1 { bb.screenText.SetVisible(false) } else { bb.screenText.SetVisible(true) bb.screenText.SetLocation(float64(sx), float64(sy), 0) } }
// Create is the engine callback for initial asset creation. func (rl *rltag) Create(eng vu.Eng, s *vu.State) { rl.run = 5 // move so many cubes worth in one second. rl.spin = 270 // spin so many degrees in one second. rl.ww, rl.wh = 800, 600 rl.floors = make(map[int]*floor) rl.setLevel(eng, vu.K_1) eng.SetColor(0.15, 0.15, 0.15, 1) return }
// Create is the engine callback for initial asset creation. func (tm *tmtag) Create(eng vu.Eng, s *vu.State) { tm.ww, tm.wh = s.W, s.H view := eng.Root().NewView() tm.cam = view.Cam() tm.cam.SetOrthographic(0, float64(tm.ww), 0, float64(tm.wh), 0, 50) sun := eng.Root().NewPov().SetLocation(0, 5, 0) sun.NewLight().SetColour(0.4, 0.7, 0.9) // create the world surface. seed := int64(123) patchSize := 128 tm.world = land.New(1, patchSize, seed) worldTile := tm.world.NewTile(1, 0, 0) textureRatio := 256.0 / 1024.0 tm.surface = vu.NewSurface(patchSize, patchSize, 16, float32(textureRatio), 10) // create a separate surface for generating initial land textures. emap := land.New(1, patchSize, seed-1) etile := emap.NewTile(1, 0, 0) etopo := etile.Topo() // merge the land height and land texture information into a single surface. tm.evo = make([][]float64, patchSize) for x := range tm.evo { tm.evo[x] = make([]float64, patchSize) } numTextures := 3.0 pts := tm.surface.Pts() topo := worldTile.Topo() for x := range topo { for y := range topo[x] { pts[x][y].Height = float32(topo[x][y]) evolution := (etopo[x][y] + 1) * 0.5 * numTextures // (-1,1 map to 0-2), map to 0-3 pts[x][y].Tindex = int(evolution) pts[x][y].Blend = float32(evolution) - float32(int(evolution)) tm.evo[x][y] = evolution // remember for later. } } // Add a rendering component for the surface data. scale := 10.0 tm.ground = eng.Root().NewPov().SetLocation(0, -300, -10).SetScale(scale, scale, 1) tm.gm = tm.ground.NewModel("land").AddTex("land") tm.gm.LoadMat("land").SetUniform("ratio", textureRatio) tm.gm.NewMesh("land") tm.surface.Update(tm.gm, 0, 0) // Add water planes. tm.ocean = eng.Root().NewPov() tm.ocean.SetLocation(256, 0, -10.5) tm.ocean.SetScale(float64(tm.ww), float64(tm.wh), 1) tm.ocean.NewModel("alpha").LoadMesh("plane").LoadMat("blue2") tm.coast = eng.Root().NewPov().SetLocation(256, 0, -10) tm.coast.SetScale(float64(tm.ww), float64(tm.wh), 1) tm.coast.NewModel("alpha").LoadMesh("plane").LoadMat("blue") return }
// Create is the engine callback for initial asset creation. func (cr *crtag) Create(eng vu.Eng, s *vu.State) { cr.run = 10 // move so many cubes worth in one second. cr.spin = 270 // spin so many degrees in one second. cr.top = eng.Root().NewPov() sun := cr.top.NewPov().SetLocation(0, 10, 10) sun.NewLight().SetColour(0.8, 0.8, 0.8) cr.view = cr.top.NewView() cr.cam = cr.view.Cam() cr.cam.SetPerspective(60, float64(800)/float64(600), 0.1, 500) cr.cam.SetLocation(0, 10, 25) // load the static slab. slab := cr.top.NewPov().SetScale(50, 50, 50).SetLocation(0, -25, 0) slab.NewBody(vu.NewBox(25, 25, 25)) slab.SetSolid(0, 0.4) slab.NewModel("gouraud").LoadMesh("cube").LoadMat("floor") // create a single moving body. useBalls := true // Flip to use boxes instead of spheres. cr.striker = cr.top.NewPov() cr.striker.SetLocation(15, 15, 0) // -5, 15, -3 if useBalls { cr.getBall(cr.striker) } else { cr.getBox(cr.striker) cr.striker.SetRotation(&lin.Q{X: 0.1825742, Y: 0.3651484, Z: 0.5477226, W: 0.7302967}) } cr.striker.Model().SetColour(rand.Float64(), rand.Float64(), rand.Float64()) // create a block of physics bodies. cubeSize := 3 startX := -5 - cubeSize/2 startY := -5 startZ := -3 - cubeSize/2 for k := 0; k < cubeSize; k++ { for i := 0; i < cubeSize; i++ { for j := 0; j < cubeSize; j++ { bod := cr.top.NewPov() lx := float64(2*i + startX) ly := float64(20 + 2*k + startY) lz := float64(2*j + startZ) bod.SetLocation(lx, ly, lz) if useBalls { cr.getBall(bod) } else { cr.getBox(bod) } } } } // set non default engine state. eng.SetColor(0.15, 0.15, 0.15, 1) rand.Seed(time.Now().UTC().UnixNano()) }
// create the game screens before the main action/update loop is started. func (mp *bampf) Create(eng vu.Eng, s *vu.State) { rand.Seed(time.Now().UnixNano()) mp.eng = eng mp.ani = &animator{} mp.setMute(mp.mute) mp.eventq = list.New() mp.createScreens(s.W, s.H) mp.state = mp.choosing mp.active = mp.launch mp.active.activate(screenActive) eng.SetColor(1, 1, 1, 1) // White as default background. }
// Create is the engine callback for initial asset creation. func (fm *fmtag) Create(eng vu.Eng, s *vu.State) { fm.view = eng.Root().NewView() fm.view.SetUI() eng.SetColor(0.95, 0.95, 0.95, 1) // create the panel layout examples. fm.layouts = append(fm.layouts, fm.simpleLayout(eng, s.W, s.H)) fm.layouts = append(fm.layouts, fm.spanLayout(eng, s.W, s.H)) fm.layouts = append(fm.layouts, fm.grabLayout(eng)) fm.layouts = append(fm.layouts, fm.largeLayout(eng, s.W, s.H)) fm.layouts = append(fm.layouts, fm.doubleLayout(eng)) fm.layouts[fm.example].setVisible(true) // set non default engine state. fm.resize(s.W, s.H) }
// newHud creates all the various parts of the heads up display. func newHud(eng vu.Eng, sentryCount, wx, wy, ww, wh int) *hud { hd := &hud{} hd.root = eng.Root().NewPov() hd.view = hd.root.NewView() hd.view.SetUI() hd.cam = hd.view.Cam() hd.setSize(wx, wy, ww, wh) // create the HUD parts. hd.pl = newPlayer(hd.root, hd.w, hd.h) hd.xp = newXpbar(hd.root, hd.w, hd.h) hd.mm = newMinimap(eng.Root().NewPov(), sentryCount) hd.ce = hd.cloakingEffect(hd.root) hd.te = hd.teleportEffect(hd.root) hd.ee = hd.energyLossEffect(hd.root) hd.resize(hd.w, hd.h) return hd }
// Create is the startup asset creation. func (bb *bbtag) Create(eng vu.Eng, s *vu.State) { bb.run = 10 // move so many cubes worth in one second. bb.spin = 270 // spin so many degrees in one second. top := eng.Root().NewPov() view := top.NewView() bb.cam = view.Cam() bb.cam.SetLocation(0.5, 2, 2.5) sun := top.NewPov().SetLocation(0, 3, -3) sun.NewLight().SetColour(0.4, 0.7, 0.9) // Load the floor model. floor := top.NewPov() floor.NewModel("gouraud").LoadMesh("floor").LoadMat("floor") // Create a single image from multiple textures using a shader. c4 := top.NewPov().SetLocation(0.5, 2, -1).SetScale(0.25, 0.25, 0.25) model := c4.NewModel("spinball").LoadMesh("billboard") model.AddTex("core").AddTex("core").AddTex("halo").AddTex("halo") model.SetAlpha(0.4) // Try banner text with the 3D scene perspective camera. font := "lucidiaSu22" banner := top.NewPov().SetScale(0.1, 0.1, 0.1).SetLocation(-10, 3, -15) banner.NewModel("uv").AddTex(font + "White").LoadFont(font).SetPhrase("Floating Text") // Try billboard banner text with the 3D scene perspective camera. banner = top.NewPov().SetScale(0.025, 0.025, 0.025).SetLocation(-10, 2, -15) banner.NewModel("bb").AddTex(font + "White").LoadFont(font).SetPhrase("Billboard Text") // Banner text with an ortho overlay. v2D := eng.Root().NewPov() view2D := v2D.NewView() view2D.SetUI() bb.ui = view2D.Cam() // 2D static location. banner = v2D.NewPov().SetLocation(100, 100, 0) banner.NewModel("uv").AddTex(font + "White").LoadFont(font).SetPhrase("Overlay Text") // 3D world to 2D screen location. bb.screenText = v2D.NewPov() bb.screenText.NewModel("uv").AddTex(font + "White").LoadFont(font).SetPhrase("Screen Text") bb.resize(s.W, s.H) }
// Create is the engine callback for initial asset creation. func (ff *fftag) Create(eng vu.Eng, s *vu.State) { rand.Seed(time.Now().UTC().UnixNano()) // create the overlay ff.top = eng.Root().NewPov() view := ff.top.NewView() view.SetUI() ff.cam = view.Cam() ff.mmap = ff.top.NewPov().SetScale(10, 10, 0) ff.mmap.SetLocation(30, 30, 0) // populate the map ff.msize = 69 ff.plan = grid.New(grid.ROOMS_SKIRMISH) ff.plan.Generate(ff.msize, ff.msize) width, height := ff.plan.Size() for x := 0; x < width; x++ { for y := 0; y < height; y++ { if ff.plan.IsOpen(x, y) { block := ff.mmap.NewPov() block.SetLocation(float64(x), float64(y), 0) block.NewModel("uv").LoadMesh("icon").AddTex("wall") ff.spots = append(ff.spots, ff.id(x, y)) } } } // populate chasers and a goal. numChasers := 30 for cnt := 0; cnt < numChasers; cnt++ { chaser := ff.mmap.NewPov() chaser.NewModel("uv").LoadMesh("icon").AddTex("token") ff.chasers = append(ff.chasers, chaser) } ff.goal = ff.mmap.NewPov() ff.goal.NewModel("uv").LoadMesh("icon").AddTex("goal") ff.flow = grid.NewFlow(ff.plan) // flow field for the given plan. ff.resetLocations() // set non default engine state. eng.SetColor(0.15, 0.15, 0.15, 1) ff.resize(s.W, s.H) }
// Called once to create the visual parts of a panel. func (lo *layout) visualize(eng vu.Eng) { lo.top = eng.Root().NewPov() lo.setVisible(false) lo.sects = make([]vu.Pov, len(lo.form.Sections())) lo.labels = make([]vu.Pov, len(lo.form.Sections())) for cnt, sect := range lo.form.Sections() { // place a box at the section location. lo.sects[cnt] = lo.top.NewPov() lo.sects[cnt].NewModel("uv").LoadMesh("icon").AddTex("cell") // place the cell name in the middle of the cell. lo.labels[cnt] = lo.top.NewPov() model := lo.labels[cnt].NewModel("uv").AddTex("lucidiaSu16Black") if sect.Label() == "" { model.LoadFont("lucidiaSu16").SetPhrase("-") } else { model.LoadFont("lucidiaSu16").SetPhrase(sect.Label()) } } }
// Update is the regular engine callback. func (tt *totex) Update(eng vu.Eng, in *vu.Input, s *vu.State) { spin := 270.0 // spin so many degrees in one second. if in.Resized { tt.resize(s.W, s.H) } dt := in.Dt for press, _ := range in.Down { switch press { case vu.K_Q: tt.frame.Spin(0, dt*-spin, 0) case vu.K_E: tt.frame.Spin(0, dt*+spin, 0) case vu.K_A: tt.monkey.Spin(0, dt*-spin, 0) case vu.K_D: tt.monkey.Spin(0, dt*+spin, 0) case vu.K_T: eng.Shutdown() } } }
// Create is the engine callback for initial asset creation. func (ps *pstag) Create(eng vu.Eng, s *vu.State) { ps.run = 10 // move so many cubes worth in one second. ps.spin = 270 // spin so many degrees in one second. ps.live = []*vu.EffectParticle{} ps.random = rand.New(rand.NewSource(time.Now().UTC().UnixNano())) view := eng.Root().NewView() ps.cam = view.Cam() ps.cam.SetPerspective(60, float64(800)/float64(600), 0.1, 50) ps.cam.SetLocation(0, 0, 2.5) // A GPU/shader based particle example using a particle shader. gpu := eng.Root().NewPov() gpu.SetVisible(false) m := gpu.NewModel("particle").AddTex("particle") m.NewMesh("gpu").SetDrawMode(vu.POINTS).SetDepth(false) ps.makeParticles(m) ps.effects = append(ps.effects, gpu) // A CPU/shader based particle example using an effect shader. cpu := eng.Root().NewPov() cpu.SetVisible(false) m = cpu.NewModel("effect").AddTex("particle").SetDrawMode(vu.POINTS) m.SetEffect(ps.fall, 250) ps.effects = append(ps.effects, cpu) // A jet engine exhaust attempt. // FUTURE: update textures to look like engine exhaust. jet := eng.Root().NewPov().SetLocation(0, -1, 0) jet.SetVisible(false) m = jet.NewModel("exhaust").AddTex("exhaust").SetDrawMode(vu.POINTS) m.SetEffect(ps.vent, 40) ps.effects = append(ps.effects, jet) // Make the first particle effect visible to kick things off. ps.effect = ps.effects[ps.index] ps.effect.SetVisible(true) // Non default engine state. Have a lighter default background. eng.SetColor(0.15, 0.15, 0.15, 1) }
// Create is the engine callback for initial asset creation. func (lt *lttag) Create(eng vu.Eng, s *vu.State) { lt.run = 10 // move so many cubes worth in one second. lt.spin = 270 // spin so many degrees in one second. top := eng.Root().NewPov() view := top.NewView() lt.cam3D = view.Cam() lt.cam3D.SetLocation(0.5, 2, 0.5) lt.sun = top.NewPov().SetLocation(0, 2.5, -1.75).SetScale(0.05, 0.05, 0.05) lt.sun.NewLight().SetColour(0.4, 0.7, 0.9) // Model at the light position. lt.sun.NewModel("solid").LoadMesh("sphere").LoadMat("sphere") // Create solid spheres to test the lighting shaders. c4 := top.NewPov().SetLocation(-0.5, 2, -2).SetScale(0.25, 0.25, 0.25) c4.NewModel("diffuse").LoadMesh("sphere").LoadMat("floor") c5 := top.NewPov().SetLocation(0.5, 2, -2).SetScale(0.25, 0.25, 0.25) c5.NewModel("gouraud").LoadMesh("sphere").LoadMat("floor") c6 := top.NewPov().SetLocation(1.5, 2, -2).SetScale(0.25, 0.25, 0.25) c6.NewModel("phong").LoadMesh("sphere").LoadMat("floor") lt.resize(s.W, s.H) }
// Create is the startup asset creation. func (tt *totex) Create(eng vu.Eng, s *vu.State) { // create a scene that will render the blender monkey model to a texture. scene0 := eng.Root().NewPov() tt.cam0 = scene0.NewCam() scene0.NewLayer() // render scene to texture. background := scene0.NewPov().SetLocation(0, 0, -10).SetScale(100, 100, 1) background.NewModel("uv").LoadMesh("icon").AddTex("wall") tt.monkey = scene0.NewPov().SetLocation(0, 0, -5) tt.monkey.NewModel("monkey").LoadMesh("monkey").LoadMat("gray") // create a scene consisting of a single quad. The quad will display // the rendered texture from scene0. The texture image is flipped from // normal so reorient it using flipped texture coordinates in flipboard. scene1 := eng.Root().NewPov() tt.cam1 = scene1.NewCam() tt.frame = scene1.NewPov().SetLocation(0, 0, -0.5).SetScale(0.25, 0.25, 0.25) model := tt.frame.NewModel("uv").LoadMesh("flipboard") model.UseLayer(scene0.Layer()) // use rendered texture from scene0. // set camera perspectives and default background colour. tt.resize(s.W, s.H) }
// Create is the engine callback for initial asset creation. func (lt *lttag) Create(eng vu.Eng, s *vu.State) { top := eng.Root().NewPov() lt.cam3D = top.NewCam() lt.cam3D.SetLocation(0.5, 2, 0.5) lt.sun = top.NewPov().SetLocation(0, 2.5, -1.75).SetScale(0.05, 0.05, 0.05) lt.sun.NewLight().SetColour(0.4, 0.7, 0.9) // Model at the light position. lt.sun.NewModel("solid").LoadMesh("sphere").LoadMat("red") // Create solid spheres to test the lighting shaders. c4 := top.NewPov().SetLocation(-0.5, 2, -2).SetScale(0.25, 0.25, 0.25) c4.NewModel("diffuse").LoadMesh("sphere").LoadMat("gray") c5 := top.NewPov().SetLocation(0.5, 2, -2).SetScale(0.25, 0.25, 0.25) c5.NewModel("gouraud").LoadMesh("sphere").LoadMat("gray") c6 := top.NewPov().SetLocation(1.5, 2, -2).SetScale(0.25, 0.25, 0.25) c6.NewModel("phong").LoadMesh("sphere").LoadMat("gray") // place and angle a large flat box behind the spheres. wall := top.NewPov().SetLocation(0, 2, -10).SetScale(5, 5, 5) wall.Spin(45, 45, 0) wall.NewModel("diffuse").LoadMesh("box").LoadMat("gray") lt.resize(s.W, s.H) }
// Create is the engine callback for initial asset creation. func (ma *matag) Create(eng vu.Eng, s *vu.State) { ma.run = 10 // move so many cubes worth in one second. ma.spin = 270 // spin so many degrees in one second. ma.top = eng.Root().NewPov() ma.view = ma.top.NewView() ma.cam = ma.view.Cam() ma.cam.SetPerspective(60, float64(800)/float64(600), 0.1, 50) ma.cam.SetLocation(0, 3, 10) // load any available IQM/E models. The loaded model data is fed to // the animation capable shader "anim". for _, modelFile := range ma.modelFiles() { pov := ma.top.NewPov() pov.SetScale(-1, 1, 1) if modelFile == "runner" { pov.SetScale(-3, 3, 3) // Runner is a bit small. } pov.Spin(-90, 0, 0) // Have the model face the camera. pov.SetVisible(false) // Hide initially. // Most IQ* files are expected to be animated. // Use a "uv" shader to handle IQ* files without animations. pov.NewModel("anim").LoadAnim(modelFile) ma.models = append(ma.models, pov) ma.names = append(ma.names, modelFile) } ma.model = ma.models[ma.index] // should always have at least one. ma.model.SetVisible(true) // Have a lighter default background. eng.SetColor(0.15, 0.15, 0.15, 1) // Create a banner to show the model name. top2D := eng.Root().NewPov() view2D := top2D.NewView() view2D.SetUI() ma.ui = view2D.Cam() ma.ui.SetOrthographic(0, float64(s.W), 0, float64(s.H), 0, 10) title := top2D.NewPov() title.SetLocation(10, 5, 0) ma.title = title.NewModel("uv").AddTex("lucidiaSu22White").LoadFont("lucidiaSu22") ma.title.SetPhrase(" ") }
// Create is the engine callback for initial asset creation. func (rc *rctag) Create(eng vu.Eng, s *vu.State) { top := eng.Root().NewPov() view := top.NewView() rc.cam = view.Cam() rc.cam.SetPitch(45) // Tilt the camera and rc.cam.SetLocation(0, -14, 14) // ...point directly at 0, 0, 0 rc.gsize = 32 // 4x8 ie. image is 4x4 grid, tile.obj is oversampled by 8. // The ray cast target is a plane displaying the image of a 32x32 grid. rc.fsize = 10.0 // 2x2 plane to 20x20 plane. rc.floor = top.NewPov() // create the floor. rc.floor.NewBody(vu.NewPlane(0, 0, -1)) // the floors ray intersect shape. rc.floor.SetScale(rc.fsize, rc.fsize, 0) // scale the model to fsize. m := rc.floor.NewModel("uv").LoadMesh("tile") // put the image on the floor. m.AddTex("tile").SetTexMode(0, vu.TEX_REPEAT) // create a selected tile tracker. rc.hilite = top.NewPov().SetScale(0.625, 0.625, 0.001) // scale to cover a single tile. rc.hilite.NewModel("uv").LoadMesh("icon").AddTex("image") // Put spheres at the floor corners. rc.s0 = rc.makeSphere(top, 10, 10, 0, 1, 0, 0) rc.s1 = rc.makeSphere(top, -10, 10, 0, 0, 1, 0) rc.s2 = rc.makeSphere(top, 10, -10, 0, 0, 0, 1) rc.s3 = rc.makeSphere(top, -10, -10, 0, 1, 1, 0) // Add a banner to show the currently selected grid location. top2D := eng.Root().NewPov() view2D := top2D.NewView() view2D.SetUI() rc.ui = view2D.Cam() rc.banner = top2D.NewPov() rc.banner.SetLocation(100, 100, 0) rc.banner.SetVisible(false) m = rc.banner.NewModel("uv").AddTex("lucidiaSu22White") m.LoadFont("lucidiaSu22").SetPhrase("Overlay Text") // set non default engine state. eng.SetColor(0.2, 0.2, 0.2, 1.0) rc.resize(s.W, s.H) }
// Update is the regular engine callback. func (rl *rltag) Update(eng vu.Eng, in *vu.Input, s *vu.State) { run := 5.0 // move so many cubes worth in one second. spin := 270.0 // spin so many degrees in one second. if in.Resized { rl.resize(s.W, s.H) } // pre-process user presses. // reduce individual move amounts for multiple move requests. dt := in.Dt moveDelta := dt * 2 for press, _ := range in.Down { switch press { case vu.K_W, vu.K_S, vu.K_Q, vu.K_E: moveDelta *= 0.5 } } // process user presses. for press, down := range in.Down { switch press { case vu.K_W: rl.flr.cam.Move(0, 0, moveDelta*-run, rl.flr.cam.Lookxz()) rl.arrow.SetLocation(rl.flr.cam.Location()) case vu.K_S: rl.flr.cam.Move(0, 0, moveDelta*run, rl.flr.cam.Lookxz()) rl.arrow.SetLocation(rl.flr.cam.Location()) case vu.K_Q: rl.flr.cam.Move(moveDelta*-run, 0, 0, rl.flr.cam.Lookxz()) rl.arrow.SetLocation(rl.flr.cam.Location()) case vu.K_E: rl.flr.cam.Move(moveDelta*run, 0, 0, rl.flr.cam.Lookxz()) rl.arrow.SetLocation(rl.flr.cam.Location()) case vu.K_A: rl.flr.cam.AdjustYaw(dt * spin) rl.arrow.SetRotation(rl.flr.cam.Lookxz()) case vu.K_D: rl.flr.cam.AdjustYaw(dt * -spin) rl.arrow.SetRotation(rl.flr.cam.Lookxz()) case vu.K_1, vu.K_2, vu.K_3, vu.K_4, vu.K_5, vu.K_6, vu.K_7, vu.K_8, vu.K_9, vu.K_0: if down == 1 { rl.setLevel(eng, press) } } } // show some stats to see the effectiveness of culling. allModels, allVerts := eng.Modelled() renModels, renVerts := eng.Rendered() modelStats := fmt.Sprintf("%d models culled to %d", allModels, renModels) vertexStats := fmt.Sprintf("%d verticies culled to %d", allVerts, renVerts) rl.flr.modelStats.SetPhrase(modelStats) rl.flr.vertexStats.SetPhrase(vertexStats) // http://stackoverflow.com/questions/87304/calculating-frames-per-second-in-a-game t := eng.Usage() rl.elapsed += t.Elapsed rl.update += t.Update rl.renders += t.Renders if in.Ut%50 == 0 { // average over 50 updates. fps := float64(rl.renders) / rl.elapsed.Seconds() update := rl.update.Seconds() / 50.0 * 1000 timings := fmt.Sprintf("FPS %2.2f Update %3.2fms", fps, update) rl.flr.times.SetPhrase(timings) rl.renders = 0 rl.elapsed = 0 rl.update = 0 } }
// setLevel switches to the indicated level. func (rl *rltag) setLevel(eng vu.Eng, keyCode int) { if _, ok := rl.floors[keyCode]; !ok { var gridSizes = map[int]int{ vu.K_1: 15, vu.K_2: 21, vu.K_3: 27, vu.K_4: 33, vu.K_5: 39, vu.K_6: 45, vu.K_7: 51, vu.K_8: 57, vu.K_9: 63, vu.K_0: 69, } var gridType = map[int]grid.Grid{ vu.K_1: grid.New(grid.DENSE_SKIRMISH), vu.K_2: grid.New(grid.DENSE_SKIRMISH), vu.K_3: grid.New(grid.SPARSE_SKIRMISH), vu.K_4: grid.New(grid.SPARSE_SKIRMISH), vu.K_5: grid.New(grid.ROOMS_SKIRMISH), vu.K_6: grid.New(grid.ROOMS_SKIRMISH), vu.K_7: grid.New(grid.CAVE), vu.K_8: grid.New(grid.CAVE), vu.K_9: grid.New(grid.DUNGEON), vu.K_0: grid.New(grid.DUNGEON), } flr := &floor{} // create the scene flr.top = eng.Root().NewPov() flr.plan = flr.top.NewPov() flr.cam = flr.plan.NewCam() flr.cam.SetLocation(1, 0, -1) flr.cam.SetPerspective(60, float64(rl.ww)/float64(rl.wh), 0.1, 50) flr.cam.SetCull(vu.NewFrontCull(10)) // create the overlay flr.mmap = flr.top.NewPov() flr.ui = flr.mmap.NewCam() flr.ui.SetUI() flr.ui.SetView(vu.XZ_XY) flr.ui.SetOrthographic(0, float64(rl.ww), 0, float64(rl.wh), 0, 20) flr.mapPart = flr.mmap.NewPov() flr.mapPart.SetScale(7.5, 7.5, 7.5) flr.mapPart.SetLocation(20, 0, -20) // display some rendering statistics. flr.modelStats = rl.newText(flr.mmap, 0) flr.vertexStats = rl.newText(flr.mmap, 1) flr.times = rl.newText(flr.mmap, 2) // populate the scenes lsize := gridSizes[keyCode] flr.layout = gridType[keyCode] flr.layout.Generate(lsize, lsize) width, height := flr.layout.Size() for x := 0; x < width; x++ { for y := 0; y < height; y++ { if flr.layout.IsOpen(x, y) { block := flr.mapPart.NewPov().SetLocation(float64(x), 0, float64(-y)) block.NewModel("alpha").LoadMesh("cube").LoadMat("transparent_gray") } else { block := flr.plan.NewPov().SetLocation(float64(x), 0, float64(-y)) block.NewModel("uv").LoadMesh("box").AddTex("tile") } } } flr.arrow = flr.mapPart.NewPov().SetLocation(flr.cam.Location()) flr.arrow.NewModel("solid").LoadMesh("arrow").LoadMat("transparent_blue") rl.floors[keyCode] = flr } if rl.flr != nil { rl.flr.plan.SetVisible(false) rl.flr.mmap.SetVisible(false) } rl.flr = rl.floors[keyCode] rl.flr.plan.SetVisible(true) rl.flr.mmap.SetVisible(true) rl.arrow = rl.flr.arrow }
// newTrooper creates a trooper at the starting size for the given level. // level 0: 1x1x1 : 1 cube // level 1: 2x2x2 : 8 edge cubes + 6 panels of 0x0 cubes + 0x0x0 center. // level 2: 3x3x3 : 20 edge cubes + 6 panels of 1x1 cubes + 1x1x1 center. // level 3: 4x4x4 : 32 edge cubes + 6 panels of 2x2 cubes + 2x2x2 center. // ... func newTrooper(eng vu.Eng, level int) *trooper { tr := &trooper{} tr.lvl = level tr.eng = eng tr.bits = []box{} tr.mid = tr.lvl*tr.lvl*tr.lvl*8 - (tr.lvl-1)*(tr.lvl-1)*(tr.lvl-1)*8 tr.top = eng.Root().NewPov() // if tr.lvl == 0 { cube := newCube(tr.top, 0, 0, 0, 1) cube.edgeSort(1) tr.bits = append(tr.bits, cube) return tr } // create the panels. These are used in each level but the first. cubeSize := 1.0 / float64(tr.lvl+1) centerOffset := cubeSize * 0.5 panelCenter := float64(tr.lvl) * centerOffset tr.bits = append(tr.bits, newBlock(tr.top, panelCenter, 0.0, 0.0, tr.lvl)) tr.bits = append(tr.bits, newBlock(tr.top, -panelCenter, 0.0, 0.0, tr.lvl)) tr.bits = append(tr.bits, newBlock(tr.top, 0.0, panelCenter, 0.0, tr.lvl)) tr.bits = append(tr.bits, newBlock(tr.top, 0.0, -panelCenter, 0.0, tr.lvl)) tr.bits = append(tr.bits, newBlock(tr.top, 0.0, 0.0, panelCenter, tr.lvl)) tr.bits = append(tr.bits, newBlock(tr.top, 0.0, 0.0, -panelCenter, tr.lvl)) // troopers are made out of cubes and panels. mx := float64(-tr.lvl) for cx := 0; cx <= tr.lvl; cx++ { my := float64(-tr.lvl) for cy := 0; cy <= tr.lvl; cy++ { mz := float64(-tr.lvl) for cz := 0; cz <= tr.lvl; cz++ { // create the outer edges. newCells := 0 if (cx == 0 || cx == tr.lvl) && (cy == 0 || cy == tr.lvl) && (cz == 0 || cz == tr.lvl) { // corner cube newCells = 1 } else if (cx == 0 || cx == tr.lvl) && (cy == 0 || cy == tr.lvl) || (cx == 0 || cx == tr.lvl) && (cz == 0 || cz == tr.lvl) || (cy == 0 || cy == tr.lvl) && (cz == 0 || cz == tr.lvl) { // edge cube newCells = 2 } else if cx == 0 || cx == tr.lvl || cy == 0 || cy == tr.lvl || cz == 0 || cz == tr.lvl { // side cubes are added to (controlled by) a panel. x, y, z := mx*centerOffset, my*centerOffset, mz*centerOffset if cx == tr.lvl && x > y && x > z { tr.bits[0].(*block).addCube(x, y, z, float64(cubeSize)) } else if cx == 0 && x < y && x < z { tr.bits[1].(*block).addCube(x, y, z, float64(cubeSize)) } else if cy == tr.lvl && y > x && y > z { tr.bits[2].(*block).addCube(x, y, z, float64(cubeSize)) } else if cy == 0 && y < x && y < z { tr.bits[3].(*block).addCube(x, y, z, float64(cubeSize)) } else if cz == tr.lvl && z > x && z > y { tr.bits[4].(*block).addCube(x, y, z, float64(cubeSize)) } else if cz == 0 && z < x && z < y { tr.bits[5].(*block).addCube(x, y, z, float64(cubeSize)) } } if newCells > 0 { x, y, z := mx*centerOffset, my*centerOffset, mz*centerOffset cube := newCube(tr.top, x, y, z, float64(cubeSize)) cube.edgeSort(newCells) tr.bits = append(tr.bits, cube) } mz += 2 } my += 2 } mx += 2 } tr.addCenter() return tr }