func TestLoadTyped_RW(t *testing.T) { defer Quit() // test expected success rwops := sdl.RWFromMem(unsafe.Pointer(&testPNG[0]), len(testPNG)) defer rwops.RWclose() surf, err := LoadTyped_RW(rwops, false, "PNG") if surf != nil { defer surf.Free() } if surf == nil || err != nil { t.Errorf("LoadTyped_RW(%#v) == %v, %v; want surface without error", "PNG", surf, err) } // test expected failure rwops = sdl.RWFromMem(unsafe.Pointer(&testBadData[0]), len(testBadData)) defer rwops.RWclose() surf, err = LoadTyped_RW(rwops, false, "PNG") if surf != nil { defer surf.Free() } if surf != nil || err == nil { t.Errorf("LoadTyped_RW(%#v) == %v, %v; want error without surface", "PNG", surf, err) } }
func TestIsFormat(t *testing.T) { Init(INIT_JPG | INIT_PNG | INIT_TIF | INIT_WEBP) defer Quit() functions := map[string](func(*sdl.RWops) bool){ "BMP": IsBMP, "CUR": IsCUR, "GIF": IsGIF, "ICO": IsICO, "JPG": IsJPG, "LBM": IsLBM, "PCX": IsPCX, "PNG": IsPNG, "PNM": IsPNM, "TIF": IsTIF, "XCF": IsXCF, "XPM": IsXPM, "XV": IsXV, "WEBP": IsWEBP, } tests := []isTest{ {"BMP", IsBMP, testBMP}, {"GIF", IsGIF, testGIF}, {"ICO", IsICO, testICO}, {"JPG", IsJPG, testJPG}, {"PCX", IsPCX, testPCX}, {"PNG", IsPNG, testPNG}, {"PNM", IsPNM, testPNM}, {"TIF", IsTIF, testTIF}, {"WEBP", IsWEBP, testWEBP}, {"XCF", IsXCF, testXCF}, {"XPM", IsXPM, testXPM}, } for _, test := range tests { rwops := sdl.RWFromMem(unsafe.Pointer(&test.data[0]), len(test.data)) defer rwops.RWclose() for fname, function := range functions { got, want := function(rwops), fname == test.name if got != want { t.Errorf("%s: Is%s() == %v; want %v", test.name, fname, got, want) } } } }
func (l *sdlAssetLoader) loadResources() error { resourceData, err := payload.Read() if err != nil { return err } l.resources, err = blob.Read(bytes.NewBuffer(resourceData)) if err != nil { return err } // load the texture atlas atlas, found := l.resources.GetByID("atlas") if !found { panic("texture atlas not found in resources") } rwOps := sdl.RWFromMem(unsafe.Pointer(&atlas[0]), len(atlas)) surface, err := img.Load_RW(rwOps, false) check(err) defer surface.Free() texture, err := l.renderer.CreateTextureFromSurface(surface) check(err) l.textureAtlas = texture return err }
func loadImageRotated(image_name string, angle float64) (*sdl.Surface, error) { file, err := assets.Asset(image_name) if err != nil { return nil, err } i, _, err := image.Decode(bytes.NewReader(file)) if err != nil { return nil, err } dst := image.NewRGBA(i.Bounds()) err = graphics.Rotate(dst, i, &graphics.RotateOptions{ Angle: angle * tau}) if err != nil { return nil, err } var buf bytes.Buffer err = png.Encode(&buf, dst) if err != nil { return nil, err } b := buf.Bytes() return img.Load_RW(sdl.RWFromMem(unsafe.Pointer(&b[0]), len(b)), 0) }
func loadSounds() ( sounds map[string]*mix.Chunk, err error) { files, err := assets.AssetDir("final/sounds") if err != nil { return nil, err } sounds = make(map[string]*mix.Chunk) for _, file := range files { if !strings.HasSuffix(file, ".wav") { continue } data, err := assets.Asset(filepath.Join("final/sounds", file)) if err != nil { return nil, err } mem := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) sound, err := mix.LoadWAV_RW(mem, false) if err != nil { cleanupSounds(sounds) return nil, err } sounds[file[:len(file)-len(".wav")]] = sound } return sounds, nil }
func NewRenderer(title string, width, height, players int, update_duration time.Duration) (rv *SDLRenderer, err error) { return rv, exec(func() error { window, err := sdl.CreateWindow(title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { rv = nil return err } data, err := assets.Asset("final/Fixedsys500c.ttf") if err != nil { window.Destroy() rv = nil return err } mem := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) font, err := ttf.OpenFontRW(mem, 0, 128) if err != nil { window.Destroy() rv = nil return err } frames := int(frameRate * update_duration / time.Second) images, player_rotations, err := loadImages(frames, players) if err != nil { window.Destroy() font.Close() rv = nil return err } sounds, err := loadSounds() if err != nil { cleanupImages(images) cleanupRotations(player_rotations) window.Destroy() font.Close() rv = nil return err } var frame_time time.Duration if frames > 0 { frame_time = update_duration / time.Duration(frames) } rv = &SDLRenderer{Title: title, window: window, font: font, images: images, sounds: sounds, frame_time: frame_time, frames: frames, player_rotations: player_rotations, closed: false} return nil }) }
func TestLoadFormat(t *testing.T) { defer Quit() tests := []loadTest{ {"BMP", LoadBMP_RW, testBMP}, {"GIF", LoadGIF_RW, testGIF}, {"ICO", LoadICO_RW, testICO}, {"JPG", LoadJPG_RW, testJPG}, {"PCX", LoadPCX_RW, testPCX}, {"PNG", LoadPNG_RW, testPNG}, {"PNM", LoadPNM_RW, testPNM}, {"TGA", LoadTGA_RW, testTGA}, {"TIF", LoadTIF_RW, testTIF}, {"XCF", LoadXCF_RW, testXCF}, {"XPM", LoadXPM_RW, testXPM}, // WEBP is undocumented and panics, so none of that. } for _, test := range tests { // test expected success rwops := sdl.RWFromMem(unsafe.Pointer(&test.data[0]), len(test.data)) defer rwops.RWclose() surf, err := test.function(rwops) if surf != nil { defer surf.Free() } if surf == nil || err != nil { t.Errorf("Load%s_RW() == %v, %v; want surface without error", test.name, surf, err) } // test expected failure... unless we're loading XCF, since XCF will // load anything. if test.name == "XCF" { continue } rwops = sdl.RWFromMem(unsafe.Pointer(&testBadData[0]), len(testBadData)) defer rwops.RWclose() surf, err = test.function(rwops) if surf != nil { defer surf.Free() } if surf != nil || err == nil { t.Errorf("Load%s_RW() == %v, %v; want error without surface", test.name, surf, err) } } }
func loadImage(id string) *sdl.Texture { data := resource.Resources[id] rwOps := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) surface, err := img.Load_RW(rwOps, false) check(err) defer surface.Free() texture, err := renderer.CreateTextureFromSurface(surface) check(err) return texture }
func LoadSurface(p []byte) (*Surface, error) { if len(p) == 0 { return nil, errors.New("drip: LoadSurface passed an empty slice") } ptr := unsafe.Pointer(&p[0]) rw := sdl.RWFromMem(ptr, len(p)) surf, err := img.Load_RW(rw, true) if err != nil { return nil, err } return newSurface(surf), nil }
func overlay(surface *sdl.Surface, img_name string) error { data, err := assets.Asset(img_name) if err != nil { return err } mem := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) ontop, err := img.Load_RW(mem, 0) defer ontop.Free() if err != nil { return err } return ontop.BlitScaled(nil, surface, nil) }
func BackgroundMusic(asset string) error { return exec(func() error { data, err := assets.Asset(asset) if err != nil { return err } mem := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) music, err := mix.LoadMUS_RW(mem, 0) if err != nil { return err } return music.Play(-1) }) }
func (l *sdlAssetLoader) LoadSound(id string) Sound { if sound, ok := l.sounds[id]; ok { return sound } data := resource.Resources[id] if data == nil { panic("unknown sound resource: " + id) } rwOps := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) chunk, err := mix.LoadWAV_RW(rwOps, false) check(err) sound := &wavSound{chunk} l.sounds[id] = sound return sound }
func (l *sdlAssetLoader) LoadImage(id string) Image { if img, ok := l.images[id]; ok { return img } data := resource.Resources[id] if data == nil { panic("unknown image resource: " + id) } rwOps := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) surface, err := img.Load_RW(rwOps, false) check(err) defer surface.Free() texture, err := l.renderer.CreateTextureFromSurface(surface) check(err) image := &textureImage{l.renderer, l.camera, texture} l.images[id] = image return image }
func loadImages(frames, players int) ( images map[grid.Cell]*sdl.Surface, rotations map[grid.Owner][]*sdl.Surface, err error) { images = make(map[grid.Cell]*sdl.Surface) for _, simple := range []string{"battery", "floor", "wall"} { for _, exploding := range []bool{false, true} { data, err := assets.Asset(fmt.Sprintf("final/images/%s.png", simple)) if err != nil { cleanupImages(images) return nil, nil, err } mem := sdl.RWFromMem(unsafe.Pointer(&data[0]), len(data)) surface, err := img.Load_RW(mem, 0) if err != nil { cleanupImages(images) return nil, nil, err } if exploding { err = overlay(surface, "final/images/ex.png") if err != nil { surface.Free() cleanupImages(images) return nil, nil, err } } for orientation := 0; orientation < 4; orientation++ { for owner := 0; owner < players+1; owner++ { images[grid.Cell{ Exploding: exploding, Type: typeMapping(simple), Orientation: grid.Orientation(orientation), Owner: grid.Owner(owner)}] = surface } } } } for _, rotateable := range []string{"l", "p"} { for rotations := 0; rotations < 4; rotations++ { for player := 1; player <= players; player++ { for _, exploding := range []bool{false, true} { surface, err := loadImageRotated(fmt.Sprintf("final/images/%s%d.png", rotateable, (player-1)%2+1), float64(rotations)/4) if err != nil { cleanupImages(images) return nil, nil, err } if exploding { err = overlay(surface, "final/images/ex.png") if err != nil { surface.Free() cleanupImages(images) return nil, nil, err } } images[grid.Cell{ Exploding: exploding, Type: typeMapping(rotateable), Owner: grid.Owner(player), Orientation: grid.Orientation(rotations)}] = surface } } } } rotations = make(map[grid.Owner][]*sdl.Surface) for _, rotateable := range []string{"p"} { for player := 1; player <= players; player++ { for frame := 0; frame < 4*frames; frame++ { surface, err := loadImageRotated(fmt.Sprintf("final/images/%s%d.png", rotateable, (player-1)%2+1), float64(frame)/(4*float64(frames))) if err != nil { cleanupImages(images) cleanupRotations(rotations) return nil, nil, err } rotations[grid.Owner(player)] = append( rotations[grid.Owner(player)], surface) } } } return images, rotations, nil }
func main() { sdl.SetHint(sdl.HINT_RENDER_VSYNC, "1") check(sdl.Init(sdl.INIT_EVERYTHING)) defer sdl.Quit() check(mix.Init(mix.INIT_OGG)) defer mix.Quit() check(mix.OpenAudio(44100, mix.DEFAULT_FORMAT, 1, 512)) defer mix.CloseAudio() if img.Init(img.INIT_PNG)&img.INIT_PNG == 0 { panic("error init png") } defer img.Quit() window, renderer, err := sdl.CreateWindowAndRenderer( 640, 480, sdl.WINDOW_RESIZABLE, ) check(err) defer renderer.Destroy() defer window.Destroy() window.SetTitle("Gophette's Adventures") window.SetSize(800, 600) sdl.ShowCursor(0) window.SetFullscreen(sdl.WINDOW_FULLSCREEN_DESKTOP) fullscreen := true camera := newWindowCamera(window.GetSize()) assetLoader := newSDLAssetLoader(camera, renderer) defer assetLoader.close() // charIndex selects which character is being controlled by the user, for // the final game this must be 0 but for creating the "AI" for Barney, set // this to 1 and delete the recorded inputs so they are not applied // additionally to the user controls var charIndex int const recordingAI = false // NOTE switch for development mode if !recordingAI { charIndex = 0 } else { charIndex = 1 recordedInputs = recordedInputs[:0] recordingInput = true } game := NewGame( assetLoader, &sdlGraphics{renderer, camera}, camera, charIndex, ) musicData, found := assetLoader.resources.GetByID("music") if found { musicRWOps := sdl.RWFromMem(unsafe.Pointer(&musicData[0]), len(musicData)) music, err := mix.LoadMUS_RW(musicRWOps, 0) if err != nil { fmt.Println("error loading music:", err) } else { defer music.Free() music.FadeIn(-1, 500) } } frameTime := time.Second / 65 lastUpdate := time.Now().Add(-frameTime) for game.Running() { for e := sdl.PollEvent(); e != nil; e = sdl.PollEvent() { switch event := e.(type) { case *sdl.KeyDownEvent: if event.Repeat == 0 { switch event.Keysym.Sym { case sdl.K_LEFT: game.HandleInput(InputEvent{GoLeft, true, charIndex}) case sdl.K_RIGHT: game.HandleInput(InputEvent{GoRight, true, charIndex}) case sdl.K_UP, sdl.K_SPACE, sdl.K_LCTRL: game.HandleInput(InputEvent{Jump, true, charIndex}) case sdl.K_ESCAPE: game.HandleInput(InputEvent{QuitGame, true, charIndex}) } } case *sdl.KeyUpEvent: switch event.Keysym.Sym { case sdl.K_LEFT: game.HandleInput(InputEvent{GoLeft, false, charIndex}) case sdl.K_RIGHT: game.HandleInput(InputEvent{GoRight, false, charIndex}) case sdl.K_UP, sdl.K_SPACE, sdl.K_LCTRL: game.HandleInput(InputEvent{Jump, false, charIndex}) case sdl.K_F11: if fullscreen { window.SetFullscreen(0) } else { window.SetFullscreen(sdl.WINDOW_FULLSCREEN_DESKTOP) } fullscreen = !fullscreen case sdl.K_ESCAPE: game.HandleInput(InputEvent{QuitGame, false, charIndex}) } case *sdl.WindowEvent: if event.Event == sdl.WINDOWEVENT_SIZE_CHANGED { width, height := int(event.Data1), int(event.Data2) camera.setWindowSize(width, height) } case *sdl.QuitEvent: game.HandleInput(InputEvent{QuitGame, true, charIndex}) } } now := time.Now() dt := now.Sub(lastUpdate) if dt > frameTime { game.Update() lastUpdate = now } check(renderer.SetDrawColor(0, 95, 83, 255)) check(renderer.Clear()) game.Render() renderer.Present() } }