diff --git a/examples/textures/textures_gif_player/main.go b/examples/textures/textures_gif_player/main.go new file mode 100644 index 0000000..784513a --- /dev/null +++ b/examples/textures/textures_gif_player/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "fmt" + "unsafe" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +func main() { + + const MAX_FRAME_DELAY int32 = 20 + const MIN_FRAME_DELAY int32 = 1 + + // Initialization + const screenWidth int32 = 800 + const screenHeight int32 = 450 + + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - gif playing") + + var animFrames int32 = 0 + + // Load all GIF animation frames into a single Image + // NOTE: GIF data is always loaded as RGBA (32bit) by default + // NOTE: Frames are just appended one after another in image.data memory + var imScarfyAnim *rl.Image = rl.LoadImageAnim("scarfy_run.gif", &animFrames) + + // Load texture from image + // NOTE: We will update this texture when required with next frame data + // WARNING: It's not recommended to use this technique for sprites animation, + // use spritesheets instead, like illustrated in textures_sprite_anim example + var texScarfyAnim rl.Texture2D = rl.LoadTextureFromImage(imScarfyAnim) + + var nextFrameDataOffset uint32 = 0 // Current byte offset to next frame in image.data + + var currentAnimFrame int32 = 0 // Current animation frame to load and draw + var frameDelay int32 = 8 // Frame delay to switch between animation frames + var frameCounter int32 = 0 // General frames counter + + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + + // Main game loop + for !rl.WindowShouldClose() { // Detect window close button or ESC key + // Update + frameCounter++ + if frameCounter >= frameDelay { + // Move to next frame + // NOTE: If final frame is reached we return to first frame + currentAnimFrame++ + if currentAnimFrame >= animFrames { + currentAnimFrame = 0 + } + + // Get memory offset position for next frame data in image.data + nextFrameDataOffset = uint32(imScarfyAnim.Width * imScarfyAnim.Height * int32(4) * currentAnimFrame) + + // Update GPU texture data with next frame image data + // WARNING: Data size (frame size) and pixel format must match already created texture + // here we needed to make the Data as public + rl.UpdateTextureUnsafe(texScarfyAnim, unsafe.Pointer(uintptr(imScarfyAnim.Data)+uintptr(nextFrameDataOffset))) + + frameCounter = 0 + } + + // Control frames delay + if rl.IsKeyPressed(rl.KeyRight) { + frameDelay++ + } else if rl.IsKeyPressed(rl.KeyLeft) { + frameDelay-- + } + + if frameDelay > MAX_FRAME_DELAY { + frameDelay = MAX_FRAME_DELAY + } else if frameDelay < MIN_FRAME_DELAY { + frameDelay = MIN_FRAME_DELAY + } + + // Draw + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawText(fmt.Sprintf("TOTAL GIF FRAMES: %02d", animFrames), 50, 30, 20, rl.LightGray) + rl.DrawText(fmt.Sprintf("CURRENT FRAME: %02d", currentAnimFrame), 50, 60, 20, rl.Gray) + rl.DrawText(fmt.Sprintf("CURRENT FRAME IMAGE.DATA OFFSET: %02d", nextFrameDataOffset), 50, 90, 20, rl.Gray) + + rl.DrawText("FRAMES DELAY: ", 100, 305, 10, rl.DarkGray) + rl.DrawText(fmt.Sprintf("%02d frames", frameDelay), 620, 305, 10, rl.DarkGray) + rl.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 350, 10, rl.DarkGray) + + for i := int32(0); i < MAX_FRAME_DELAY; i++ { + if i < frameDelay { + rl.DrawRectangle(190+21*i, 300, 20, 20, rl.Red) + } + rl.DrawRectangleLines(190+21*i, 300, 20, 20, rl.Maroon) + } + + rl.DrawTexture(texScarfyAnim, int32(rl.GetScreenWidth()/2)-texScarfyAnim.Width/2, 140, rl.White) + + rl.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, rl.Gray) + + rl.EndDrawing() + } + + // De-Initialization + defer rl.UnloadTexture(texScarfyAnim) // Unload texture + defer rl.UnloadImage(imScarfyAnim) // Unload image (contains all frames) + + defer rl.CloseWindow() // Close window and OpenGL context + +} diff --git a/examples/textures/textures_gif_player/scarfy_run.gif b/examples/textures/textures_gif_player/scarfy_run.gif new file mode 100644 index 0000000..f0f712c Binary files /dev/null and b/examples/textures/textures_gif_player/scarfy_run.gif differ diff --git a/examples/textures/textures_sprite_anim/main.go b/examples/textures/textures_sprite_anim/main.go new file mode 100644 index 0000000..52471e6 --- /dev/null +++ b/examples/textures/textures_sprite_anim/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +const ( + MAX_FRAME_SPEED = 15 + MIN_FRAME_SPEED = 1 +) + +func main() { + // Initialization + const screenWidth = 800 + const screenHeight = 450 + + rl.InitWindow(screenWidth, screenHeight, "raylib [texture] example - sprite anim") + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) + spriteFrames := float32(6) + scarfy := rl.LoadTexture("scarfy.png") // Texture loading + + position := rl.Vector2{X: 350.0, Y: 280.0} + frameRec := rl.Rectangle{X: 0.0, Y: 0.0, Width: float32(scarfy.Width) / spriteFrames, Height: float32(scarfy.Height)} + currentFrame := 0 + + framesCounter := 0 + framesSpeed := 8 // Number of spritesheet frames shown by second + + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + + // Main game loop + for !rl.WindowShouldClose() { // Detect window close button or ESC key + // Update + framesCounter++ + + if framesCounter >= (60 / framesSpeed) { + framesCounter = 0 + currentFrame++ + + if currentFrame > int(spriteFrames)-1 { + currentFrame = 0 + } + + frameRec.X = float32(currentFrame) * float32(scarfy.Width) / spriteFrames // select which image to show + } + + // Control frames speed + if rl.IsKeyPressed(rl.KeyRight) { + framesSpeed++ + } else if rl.IsKeyPressed(rl.KeyLeft) { + framesSpeed-- + } + + if framesSpeed > MAX_FRAME_SPEED { + framesSpeed = MAX_FRAME_SPEED + } else if framesSpeed < MIN_FRAME_SPEED { + framesSpeed = MIN_FRAME_SPEED + } + + // Draw + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawTexture(scarfy, 15, 40, rl.White) + rl.DrawRectangleLines(15, 40, int32(scarfy.Width), int32(scarfy.Height), rl.Lime) + rl.DrawRectangleLines(15+int32(frameRec.X), 40+int32(frameRec.Y), int32(frameRec.Width), int32(frameRec.Height), rl.Red) + + rl.DrawText("FRAME SPEED: ", 165, 210, 10, rl.DarkGray) + rl.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, rl.DarkGray) + rl.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, rl.DarkGray) + + for i := 0; i < MAX_FRAME_SPEED; i++ { + if i < framesSpeed { + rl.DrawRectangle(250+21*int32(i), screenHeight/2.5+15, 20, 20, rl.Red) + } + rl.DrawRectangleLines(250+21*int32(i), screenHeight/2.5+15, 20, 20, rl.Maroon) + } + + rl.DrawTextureRec(scarfy, frameRec, position, rl.White) // Draw part of the texture + + rl.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, rl.Gray) + + rl.EndDrawing() + } + + // De-Initialization + defer rl.UnloadTexture(scarfy) // Texture unloading + + defer rl.CloseWindow() // Close window and OpenGL context +} diff --git a/examples/textures/textures_sprite_anim/scarfy.png b/examples/textures/textures_sprite_anim/scarfy.png new file mode 100644 index 0000000..be3b83d Binary files /dev/null and b/examples/textures/textures_sprite_anim/scarfy.png differ diff --git a/raylib/raylib.go b/raylib/raylib.go index 1fa3d5c..8c9e46b 100644 --- a/raylib/raylib.go +++ b/raylib/raylib.go @@ -1090,8 +1090,8 @@ const ( // Image type, bpp always RGBA (32bit) // NOTE: Data stored in CPU memory (RAM) type Image struct { - // Image raw data - data unsafe.Pointer + // Image raw Data + Data unsafe.Pointer // Image base width Width int32 // Image base height diff --git a/raylib/rtextures.go b/raylib/rtextures.go index 23a1f37..9fce2a1 100644 --- a/raylib/rtextures.go +++ b/raylib/rtextures.go @@ -246,6 +246,14 @@ func UpdateTexture(texture Texture2D, pixels []color.RGBA) { C.UpdateTexture(*ctexture, cpixels) } +// UpdateTexture - Update GPU texture with new data +// NOTE: pixels data must match texture.format +func UpdateTextureUnsafe(texture Texture2D, pixels unsafe.Pointer) { + ctexture := texture.cptr() + cpixels := pixels + C.UpdateTexture(*ctexture, cpixels) +} + // UpdateTextureRec - Update GPU texture rectangle with new data func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []color.RGBA) { ctexture := texture.cptr()