Update C sources, add new functions

This commit is contained in:
Milan Nikolic 2018-05-06 09:34:11 +02:00
parent e6a1abb290
commit a6d36a3699
98 changed files with 7964 additions and 2985 deletions

0
examples/android/example/bootstrap.sh Executable file → Normal file
View file

View file

@ -19,13 +19,13 @@ func main() {
buildings := make([]raylib.Rectangle, maxBuildings) buildings := make([]raylib.Rectangle, maxBuildings)
buildColors := make([]raylib.Color, maxBuildings) buildColors := make([]raylib.Color, maxBuildings)
spacing := int32(0) spacing := float32(0)
for i := 0; i < maxBuildings; i++ { for i := 0; i < maxBuildings; i++ {
r := raylib.Rectangle{} r := raylib.Rectangle{}
r.Width = raylib.GetRandomValue(50, 200) r.Width = float32(raylib.GetRandomValue(50, 200))
r.Height = raylib.GetRandomValue(100, 800) r.Height = float32(raylib.GetRandomValue(100, 800))
r.Y = screenHeight - 130 - r.Height r.Y = float32(screenHeight) - 130 - r.Height
r.X = -6000 + spacing r.X = -6000 + spacing
spacing += r.Width spacing += r.Width
@ -89,7 +89,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin2dMode(camera) raylib.BeginMode2D(camera)
raylib.DrawRectangle(-6000, 320, 13000, 8000, raylib.DarkGray) raylib.DrawRectangle(-6000, 320, 13000, 8000, raylib.DarkGray)
@ -102,7 +102,7 @@ func main() {
raylib.DrawRectangle(int32(camera.Target.X), -500, 1, screenHeight*4, raylib.Green) raylib.DrawRectangle(int32(camera.Target.X), -500, 1, screenHeight*4, raylib.Green)
raylib.DrawRectangle(-500, int32(camera.Target.Y), screenWidth*4, 1, raylib.Green) raylib.DrawRectangle(-500, int32(camera.Target.Y), screenWidth*4, 1, raylib.Green)
raylib.End2dMode() raylib.EndMode2D()
raylib.DrawText("SCREEN AREA", 640, 10, 20, raylib.Red) raylib.DrawText("SCREEN AREA", 640, 10, 20, raylib.Red)

View file

@ -11,11 +11,12 @@ const (
func main() { func main() {
raylib.InitWindow(800, 450, "raylib [core] example - 3d camera first person") raylib.InitWindow(800, 450, "raylib [core] example - 3d camera first person")
camera := raylib.Camera{} camera := raylib.Camera3D{}
camera.Position = raylib.NewVector3(4.0, 2.0, 4.0) camera.Position = raylib.NewVector3(4.0, 2.0, 4.0)
camera.Target = raylib.NewVector3(0.0, 1.8, 0.0) camera.Target = raylib.NewVector3(0.0, 1.8, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 60.0 camera.Fovy = 60.0
camera.Type = raylib.CameraPerspective
// Generates some random columns // Generates some random columns
heights := make([]float32, maxColumns) heights := make([]float32, maxColumns)
@ -39,7 +40,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawPlane(raylib.NewVector3(0.0, 0.0, 0.0), raylib.NewVector2(32.0, 32.0), raylib.LightGray) // Draw ground raylib.DrawPlane(raylib.NewVector3(0.0, 0.0, 0.0), raylib.NewVector2(32.0, 32.0), raylib.LightGray) // Draw ground
raylib.DrawCube(raylib.NewVector3(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, raylib.Blue) // Draw a blue wall raylib.DrawCube(raylib.NewVector3(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, raylib.Blue) // Draw a blue wall
@ -52,7 +53,7 @@ func main() {
raylib.DrawCubeWires(positions[i], 2.0, heights[i], 2.0, raylib.Maroon) raylib.DrawCubeWires(positions[i], 2.0, heights[i], 2.0, raylib.Maroon)
} }
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawRectangle(10, 10, 220, 70, raylib.Fade(raylib.SkyBlue, 0.5)) raylib.DrawRectangle(10, 10, 220, 70, raylib.Fade(raylib.SkyBlue, 0.5))
raylib.DrawRectangleLines(10, 10, 220, 70, raylib.Blue) raylib.DrawRectangleLines(10, 10, 220, 70, raylib.Blue)

View file

@ -7,11 +7,12 @@ import (
func main() { func main() {
raylib.InitWindow(800, 450, "raylib [core] example - 3d camera free") raylib.InitWindow(800, 450, "raylib [core] example - 3d camera free")
camera := raylib.Camera{} camera := raylib.Camera3D{}
camera.Position = raylib.NewVector3(10.0, 10.0, 10.0) camera.Position = raylib.NewVector3(10.0, 10.0, 10.0)
camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) camera.Target = raylib.NewVector3(0.0, 0.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) cubePosition := raylib.NewVector3(0.0, 0.0, 0.0)
@ -30,14 +31,14 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red)
raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon)
raylib.DrawGrid(10, 1.0) raylib.DrawGrid(10, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawRectangle(10, 10, 320, 133, raylib.Fade(raylib.SkyBlue, 0.5)) raylib.DrawRectangle(10, 10, 320, 133, raylib.Fade(raylib.SkyBlue, 0.5))
raylib.DrawRectangleLines(10, 10, 320, 133, raylib.Blue) raylib.DrawRectangleLines(10, 10, 320, 133, raylib.Blue)

View file

@ -7,11 +7,12 @@ import (
func main() { func main() {
raylib.InitWindow(800, 450, "raylib [core] example - 3d mode") raylib.InitWindow(800, 450, "raylib [core] example - 3d mode")
camera := raylib.Camera{} camera := raylib.Camera3D{}
camera.Position = raylib.NewVector3(0.0, 10.0, 10.0) camera.Position = raylib.NewVector3(0.0, 10.0, 10.0)
camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) camera.Target = raylib.NewVector3(0.0, 0.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) cubePosition := raylib.NewVector3(0.0, 0.0, 0.0)
@ -22,14 +23,14 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red)
raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon)
raylib.DrawGrid(10, 1.0) raylib.DrawGrid(10, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("Welcome to the third dimension!", 10, 40, 20, raylib.DarkGray) raylib.DrawText("Welcome to the third dimension!", 10, 40, 20, raylib.DarkGray)

View file

@ -10,11 +10,12 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking") raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking")
camera := raylib.Camera{} camera := raylib.Camera3D{}
camera.Position = raylib.NewVector3(10.0, 10.0, 10.0) camera.Position = raylib.NewVector3(10.0, 10.0, 10.0)
camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) camera.Target = raylib.NewVector3(0.0, 0.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
cubePosition := raylib.NewVector3(0.0, 1.0, 0.0) cubePosition := raylib.NewVector3(0.0, 1.0, 0.0)
cubeSize := raylib.NewVector3(2.0, 2.0, 2.0) cubeSize := raylib.NewVector3(2.0, 2.0, 2.0)
@ -44,7 +45,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
if collision { if collision {
raylib.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.Red) raylib.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.Red)
@ -60,7 +61,7 @@ func main() {
raylib.DrawGrid(10, 1.0) raylib.DrawGrid(10, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("Try selecting the box with mouse!", 240, 10, 20, raylib.DarkGray) raylib.DrawText("Try selecting the box with mouse!", 240, 10, 20, raylib.DarkGray)

View file

@ -18,8 +18,8 @@ func main() {
// Fills colorsRecs data (for every rectangle) // Fills colorsRecs data (for every rectangle)
for i := 0; i < 21; i++ { for i := 0; i < 21; i++ {
r := raylib.Rectangle{} r := raylib.Rectangle{}
r.X = int32(20 + 100*(i%7) + 10*(i%7)) r.X = float32(20 + 100*(i%7) + 10*(i%7))
r.Y = int32(60 + 100*(i/7) + 10*(i/7)) r.Y = float32(60 + 100*(i/7) + 10*(i/7))
r.Width = 100 r.Width = 100
r.Height = 100 r.Height = 100
@ -56,10 +56,10 @@ func main() {
// Draw four rectangles around selected rectangle // Draw four rectangles around selected rectangle
if selected[i] { if selected[i] {
raylib.DrawRectangle(colorsRecs[i].X, colorsRecs[i].Y, 100, 10, raylib.RayWhite) // Square top rectangle raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 100, 10, raylib.RayWhite) // Square top rectangle
raylib.DrawRectangle(colorsRecs[i].X, colorsRecs[i].Y, 10, 100, raylib.RayWhite) // Square left rectangle raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 10, 100, raylib.RayWhite) // Square left rectangle
raylib.DrawRectangle(colorsRecs[i].X+90, colorsRecs[i].Y, 10, 100, raylib.RayWhite) // Square right rectangle raylib.DrawRectangle(int32(colorsRecs[i].X+90), int32(colorsRecs[i].Y), 10, 100, raylib.RayWhite) // Square right rectangle
raylib.DrawRectangle(colorsRecs[i].X, colorsRecs[i].Y+90, 100, 10, raylib.RayWhite) // Square bottom rectangle raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y)+90, 100, 10, raylib.RayWhite) // Square bottom rectangle
} }
} }

View file

@ -15,7 +15,7 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection") raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection")
touchPosition := raylib.NewVector2(0, 0) touchPosition := raylib.NewVector2(0, 0)
touchArea := raylib.NewRectangle(220, 10, screenWidth-230, screenHeight-20) touchArea := raylib.NewRectangle(220, 10, float32(screenWidth)-230, float32(screenHeight)-20)
gestureStrings := make([]string, 0) gestureStrings := make([]string, 0)

View file

@ -36,14 +36,14 @@ func main() {
raylib.BeginVrDrawing() raylib.BeginVrDrawing()
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red)
raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon)
raylib.DrawGrid(40, 1.0) raylib.DrawGrid(40, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.EndVrDrawing() raylib.EndVrDrawing()

View file

@ -33,14 +33,14 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red)
raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon)
raylib.DrawGrid(10, 1.0) raylib.DrawGrid(10, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("Enemy: 100 / 100", int32(cubeScreenPosition.X)-raylib.MeasureText("Enemy: 100 / 100", 20)/2, int32(cubeScreenPosition.Y), 20, raylib.Black) raylib.DrawText("Enemy: 100 / 100", int32(cubeScreenPosition.X)-raylib.MeasureText("Enemy: 100 / 100", 20)/2, int32(cubeScreenPosition.Y), 20, raylib.Black)
raylib.DrawText("Text is always on top of the cube", (screenWidth-raylib.MeasureText("Text is always on top of the cube", 20))/2, 25, 20, raylib.Gray) raylib.DrawText("Text is always on top of the cube", (screenWidth-raylib.MeasureText("Text is always on top of the cube", 20))/2, 25, 20, raylib.Gray)

View file

@ -15,6 +15,7 @@ func main() {
camera.Target = raylib.NewVector3(0.0, 2.0, 0.0) camera.Target = raylib.NewVector3(0.0, 2.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
bill := raylib.LoadTexture("billboard.png") // Our texture billboard bill := raylib.LoadTexture("billboard.png") // Our texture billboard
billPosition := raylib.NewVector3(0.0, 2.0, 0.0) // Position where draw billboard billPosition := raylib.NewVector3(0.0, 2.0, 0.0) // Position where draw billboard
@ -30,13 +31,13 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawBillboard(camera, bill, billPosition, 2.0, raylib.White) raylib.DrawBillboard(camera, bill, billPosition, 2.0, raylib.White)
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.EndDrawing() raylib.EndDrawing()
} }

View file

@ -15,6 +15,7 @@ func main() {
camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) camera.Target = raylib.NewVector3(0.0, 0.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
playerPosition := raylib.NewVector3(0.0, 1.0, 2.0) playerPosition := raylib.NewVector3(0.0, 1.0, 2.0)
playerSize := raylib.NewVector3(1.0, 2.0, 1.0) playerSize := raylib.NewVector3(1.0, 2.0, 1.0)
@ -81,7 +82,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
// Draw enemy-box // Draw enemy-box
raylib.DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, raylib.Gray) raylib.DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, raylib.Gray)
@ -96,7 +97,7 @@ func main() {
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("Move player with cursors to collide", 220, 40, 20, raylib.Gray) raylib.DrawText("Move player with cursors to collide", 220, 40, 20, raylib.Gray)

View file

@ -15,6 +15,7 @@ func main() {
camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) camera.Target = raylib.NewVector3(0.0, 0.0, 0.0)
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) camera.Up = raylib.NewVector3(0.0, 1.0, 0.0)
camera.Fovy = 45.0 camera.Fovy = 45.0
camera.Type = raylib.CameraPerspective
image := raylib.LoadImage("cubicmap.png") // Load cubicmap image (RAM) image := raylib.LoadImage("cubicmap.png") // Load cubicmap image (RAM)
cubicmap := raylib.LoadTextureFromImage(image) // Convert image to texture to display (VRAM) cubicmap := raylib.LoadTextureFromImage(image) // Convert image to texture to display (VRAM)
@ -45,11 +46,11 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(model, mapPosition, 1.0, raylib.White) raylib.DrawModel(model, mapPosition, 1.0, raylib.White)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawTextureEx(cubicmap, raylib.NewVector2(float32(screenWidth-cubicmap.Width*4-20), 20), 0.0, 4.0, raylib.White) raylib.DrawTextureEx(cubicmap, raylib.NewVector2(float32(screenWidth-cubicmap.Width*4-20), 20), 0.0, 4.0, raylib.White)
raylib.DrawRectangleLines(screenWidth-cubicmap.Width*4-20, 20, cubicmap.Width*4, cubicmap.Height*4, raylib.Green) raylib.DrawRectangleLines(screenWidth-cubicmap.Width*4-20, 20, cubicmap.Width*4, cubicmap.Height*4, raylib.Green)

View file

@ -23,7 +23,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawCube(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Red) raylib.DrawCube(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Red)
raylib.DrawCubeWires(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Gold) raylib.DrawCubeWires(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Gold)
@ -41,7 +41,7 @@ func main() {
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawFPS(10, 10) raylib.DrawFPS(10, 10)

View file

@ -42,13 +42,13 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(model, mapPosition, 1.0, raylib.Red) raylib.DrawModel(model, mapPosition, 1.0, raylib.Red)
raylib.DrawGrid(20, 1.0) raylib.DrawGrid(20, 1.0)
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawTexture(texture, screenWidth-texture.Width-20, 20, raylib.White) raylib.DrawTexture(texture, screenWidth-texture.Width-20, 20, raylib.White)
raylib.DrawRectangleLines(screenWidth-texture.Width-20, 20, texture.Width, texture.Height, raylib.Green) raylib.DrawRectangleLines(screenWidth-texture.Width-20, 20, texture.Width, texture.Height, raylib.Green)

View file

@ -30,7 +30,7 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture
@ -38,7 +38,7 @@ func main() {
raylib.DrawGizmo(position) // Draw gizmo raylib.DrawGizmo(position) // Draw gizmo
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray) raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray)

0
examples/rpi/basic_window/bootstrap.sh Executable file → Normal file
View file

View file

@ -13,8 +13,9 @@ out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float renderWidth = 800.0; // HARDCODED for example! // NOTE: Render size values should be passed from code
const float renderHeight = 480.0; // Use uniforms instead... const float renderWidth = 800;
const float renderHeight = 450;
float radius = 250.0; float radius = 250.0;
float angle = 0.8; float angle = 0.8;

View file

@ -62,13 +62,13 @@ func main() {
raylib.BeginTextureMode(target) // Enable drawing to texture raylib.BeginTextureMode(target) // Enable drawing to texture
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, raylib.Red) raylib.DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, raylib.Red)
@ -77,7 +77,7 @@ func main() {
raylib.BeginShaderMode(shader) raylib.BeginShaderMode(shader)
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, target.Texture.Width, -target.Texture.Height), raylib.NewVector2(0, 0), raylib.White) raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), raylib.NewVector2(0, 0), raylib.White)
raylib.EndShaderMode() raylib.EndShaderMode()

View file

@ -40,13 +40,13 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray) raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray)

View file

@ -102,13 +102,13 @@ func main() {
raylib.BeginTextureMode(target) // Enable drawing to texture raylib.BeginTextureMode(target) // Enable drawing to texture
raylib.Begin3dMode(camera) raylib.BeginMode3D(camera)
raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture
raylib.DrawGrid(10, 1.0) // Draw a grid raylib.DrawGrid(10, 1.0) // Draw a grid
raylib.End3dMode() raylib.EndMode3D()
raylib.EndTextureMode() // End drawing to texture (now we have a texture available for next passes) raylib.EndTextureMode() // End drawing to texture (now we have a texture available for next passes)
@ -116,7 +116,7 @@ func main() {
raylib.BeginShaderMode(shaders[currentShader]) raylib.BeginShaderMode(shaders[currentShader])
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, target.Texture.Width, -target.Texture.Height), raylib.NewVector2(0, 0), raylib.White) raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), raylib.NewVector2(0, 0), raylib.White)
raylib.EndShaderMode() raylib.EndShaderMode()

View file

@ -14,8 +14,8 @@ func main() {
msgTtf := "THIS SPRITE FONT has been GENERATED from a TTF" msgTtf := "THIS SPRITE FONT has been GENERATED from a TTF"
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
fontBm := raylib.LoadSpriteFont("fonts/bmfont.fnt") // BMFont (AngelCode) fontBm := raylib.LoadFont("fonts/bmfont.fnt") // BMFont (AngelCode)
fontTtf := raylib.LoadSpriteFont("fonts/pixantiqua.ttf") // TTF font fontTtf := raylib.LoadFont("fonts/pixantiqua.ttf") // TTF font
fontPosition := raylib.Vector2{} fontPosition := raylib.Vector2{}
@ -35,8 +35,8 @@ func main() {
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadSpriteFont(fontBm) // AngelCode SpriteFont unloading raylib.UnloadFont(fontBm) // AngelCode Font unloading
raylib.UnloadSpriteFont(fontTtf) // TTF SpriteFont unloading raylib.UnloadFont(fontTtf) // TTF Font unloading
raylib.CloseWindow() raylib.CloseWindow()
} }

View file

@ -17,7 +17,7 @@ func main() {
msg := "ASCII extended characters:\n¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆ\nÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæ\nçèéêëìíîïðñòóôõö÷øùúûüýþÿ" msg := "ASCII extended characters:\n¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆ\nÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæ\nçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
// NOTE: Loaded font has an unordered list of characters (chars in the range 32..255) // NOTE: Loaded font has an unordered list of characters (chars in the range 32..255)
font := raylib.LoadSpriteFont("fonts/pixantiqua.fnt") // BMFont (AngelCode) font := raylib.LoadFont("fonts/pixantiqua.fnt") // BMFont (AngelCode)
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
@ -35,7 +35,7 @@ func main() {
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadSpriteFont(font) // AngelCode SpriteFont unloading raylib.UnloadFont(font) // AngelCode Font unloading
raylib.CloseWindow() raylib.CloseWindow()
} }

View file

@ -12,15 +12,15 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts") raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts")
fonts := make([]raylib.SpriteFont, maxFonts) fonts := make([]raylib.Font, maxFonts)
fonts[0] = raylib.LoadSpriteFont("fonts/alagard.png") fonts[0] = raylib.LoadFont("fonts/alagard.png")
fonts[1] = raylib.LoadSpriteFont("fonts/pixelplay.png") fonts[1] = raylib.LoadFont("fonts/pixelplay.png")
fonts[2] = raylib.LoadSpriteFont("fonts/mecha.png") fonts[2] = raylib.LoadFont("fonts/mecha.png")
fonts[3] = raylib.LoadSpriteFont("fonts/setback.png") fonts[3] = raylib.LoadFont("fonts/setback.png")
fonts[4] = raylib.LoadSpriteFont("fonts/romulus.png") fonts[4] = raylib.LoadFont("fonts/romulus.png")
fonts[5] = raylib.LoadSpriteFont("fonts/pixantiqua.png") fonts[5] = raylib.LoadFont("fonts/pixantiqua.png")
fonts[6] = raylib.LoadSpriteFont("fonts/alpha_beta.png") fonts[6] = raylib.LoadFont("fonts/alpha_beta.png")
fonts[7] = raylib.LoadSpriteFont("fonts/jupiter_crash.png") fonts[7] = raylib.LoadFont("fonts/jupiter_crash.png")
messages := []string{ messages := []string{
"ALAGARD FONT designed by Hewett Tsoi", "ALAGARD FONT designed by Hewett Tsoi",
@ -33,7 +33,7 @@ func main() {
"JUPITER_CRASH FONT designed by Brian Kent (AEnigma)", "JUPITER_CRASH FONT designed by Brian Kent (AEnigma)",
} }
spacings := []int32{2, 4, 8, 4, 3, 4, 4, 1} spacings := []float32{2, 4, 8, 4, 3, 4, 4, 1}
positions := make([]raylib.Vector2, maxFonts) positions := make([]raylib.Vector2, maxFonts)
var i int32 var i int32
@ -67,7 +67,7 @@ func main() {
} }
for i = 0; i < maxFonts; i++ { for i = 0; i < maxFonts; i++ {
raylib.UnloadSpriteFont(fonts[i]) raylib.UnloadFont(fonts[i])
} }
raylib.CloseWindow() raylib.CloseWindow()

View file

@ -15,9 +15,9 @@ func main() {
msg3 := "...and a THIRD one! GREAT! :D" msg3 := "...and a THIRD one! GREAT! :D"
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
font1 := raylib.LoadSpriteFont("fonts/custom_mecha.png") // SpriteFont loading font1 := raylib.LoadFont("fonts/custom_mecha.png") // Font loading
font2 := raylib.LoadSpriteFont("fonts/custom_alagard.png") // SpriteFont loading font2 := raylib.LoadFont("fonts/custom_alagard.png") // Font loading
font3 := raylib.LoadSpriteFont("fonts/custom_jupiter_crash.png") // SpriteFont loading font3 := raylib.LoadFont("fonts/custom_jupiter_crash.png") // Font loading
var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2 var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2
@ -44,9 +44,9 @@ func main() {
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadSpriteFont(font1) // SpriteFont unloading raylib.UnloadFont(font1) // Font unloading
raylib.UnloadSpriteFont(font2) // SpriteFont unloading raylib.UnloadFont(font2) // Font unloading
raylib.UnloadSpriteFont(font3) // SpriteFont unloading raylib.UnloadFont(font3) // Font unloading
raylib.CloseWindow() raylib.CloseWindow()
} }

View file

@ -12,14 +12,14 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - ttf loading") raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - ttf loading")
msg := "TTF SpriteFont" msg := "TTF Font"
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
fontChars := int32(0) fontChars := int32(0)
// TTF SpriteFont loading with custom generation parameters // TTF Font loading with custom generation parameters
font := raylib.LoadSpriteFontEx("fonts/KAISG.ttf", 96, 0, &fontChars) font := raylib.LoadFontEx("fonts/KAISG.ttf", 96, 0, &fontChars)
// Generate mipmap levels to use trilinear filtering // Generate mipmap levels to use trilinear filtering
// NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR
@ -68,8 +68,8 @@ func main() {
droppedFiles = raylib.GetDroppedFiles(&count) droppedFiles = raylib.GetDroppedFiles(&count)
if count == 1 { // Only support one ttf file dropped if count == 1 { // Only support one ttf file dropped
raylib.UnloadSpriteFont(font) raylib.UnloadFont(font)
font = raylib.LoadSpriteFontEx(droppedFiles[0], fontSize, 0, &fontChars) font = raylib.LoadFontEx(droppedFiles[0], fontSize, 0, &fontChars)
raylib.ClearDroppedFiles() raylib.ClearDroppedFiles()
} }
} }
@ -104,7 +104,7 @@ func main() {
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadSpriteFont(font) // SpriteFont unloading raylib.UnloadFont(font) // Font unloading
raylib.ClearDroppedFiles() // Clear internal buffers raylib.ClearDroppedFiles() // Clear internal buffers

View file

@ -19,8 +19,8 @@ func main() {
parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM) parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM)
// Draw one image over the other with a scaling of 1.5f // Draw one image over the other with a scaling of 1.5f
raylib.ImageDraw(parrots, cat, raylib.NewRectangle(0, 0, cat.Width, cat.Height), raylib.NewRectangle(30, 40, int32(float32(cat.Width)*1.5), int32(float32(cat.Height)*1.5))) raylib.ImageDraw(parrots, cat, raylib.NewRectangle(0, 0, float32(cat.Width), float32(cat.Height)), raylib.NewRectangle(30, 40, float32(cat.Width)*1.5, float32(cat.Height)*1.5))
raylib.ImageCrop(parrots, raylib.NewRectangle(0, 50, parrots.Width, parrots.Height-100)) // Crop resulting image raylib.ImageCrop(parrots, raylib.NewRectangle(0, 50, float32(parrots.Width), float32(parrots.Height-100))) // Crop resulting image
raylib.UnloadImage(cat) // Unload image from RAM raylib.UnloadImage(cat) // Unload image from RAM

View file

@ -36,7 +36,7 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing") raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing")
image := raylib.LoadImage("parrots.png") // Loaded in CPU memory (RAM) image := raylib.LoadImage("parrots.png") // Loaded in CPU memory (RAM)
raylib.ImageFormat(image, int32(raylib.UncompressedR8g8b8a8)) // Format image to RGBA 32bit (required for texture update) raylib.ImageFormat(image, raylib.UncompressedR8g8b8a8) // Format image to RGBA 32bit (required for texture update)
texture := raylib.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) texture := raylib.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM)
currentProcess := None currentProcess := None
@ -44,8 +44,8 @@ func main() {
selectRecs := make([]raylib.Rectangle, numProcesses) selectRecs := make([]raylib.Rectangle, numProcesses)
for i := int32(0); i < numProcesses; i++ { for i := 0; i < numProcesses; i++ {
selectRecs[i] = raylib.NewRectangle(40, 50+32*i, 150, 30) selectRecs[i] = raylib.NewRectangle(40, 50+32*float32(i), 150, 30)
} }
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
@ -114,12 +114,12 @@ func main() {
for i := 0; i < numProcesses; i++ { for i := 0; i < numProcesses; i++ {
if i == currentProcess { if i == currentProcess {
raylib.DrawRectangleRec(selectRecs[i], raylib.SkyBlue) raylib.DrawRectangleRec(selectRecs[i], raylib.SkyBlue)
raylib.DrawRectangleLines(selectRecs[i].X, selectRecs[i].Y, selectRecs[i].Width, selectRecs[i].Height, raylib.Blue) raylib.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), raylib.Blue)
raylib.DrawText(processText[i], selectRecs[i].X+selectRecs[i].Width/2-raylib.MeasureText(processText[i], 10)/2, selectRecs[i].Y+11, 10, raylib.DarkBlue) raylib.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-raylib.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, raylib.DarkBlue)
} else { } else {
raylib.DrawRectangleRec(selectRecs[i], raylib.LightGray) raylib.DrawRectangleRec(selectRecs[i], raylib.LightGray)
raylib.DrawRectangleLines(selectRecs[i].X, selectRecs[i].Y, selectRecs[i].Width, selectRecs[i].Height, raylib.Gray) raylib.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), raylib.Gray)
raylib.DrawText(processText[i], selectRecs[i].X+selectRecs[i].Width/2-raylib.MeasureText(processText[i], 10)/2, selectRecs[i].Y+11, 10, raylib.DarkGray) raylib.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-raylib.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, raylib.DarkGray)
} }
} }

View file

@ -10,9 +10,9 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image text drawing") raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image text drawing")
// TTF SpriteFont loading with custom generation parameters // TTF Font loading with custom generation parameters
var fontChars int32 var fontChars int32
font := raylib.LoadSpriteFontEx("fonts/KAISG.ttf", 64, 0, &fontChars) font := raylib.LoadFontEx("fonts/KAISG.ttf", 64, 0, &fontChars)
parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM) parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM)
@ -56,7 +56,7 @@ func main() {
} }
raylib.UnloadTexture(texture) raylib.UnloadTexture(texture)
raylib.UnloadSpriteFont(font) raylib.UnloadFont(font)
raylib.CloseWindow() raylib.CloseWindow()
} }

View file

@ -95,8 +95,8 @@ func main() {
if mouseTail[i].Active { if mouseTail[i].Active {
raylib.DrawTexturePro( raylib.DrawTexturePro(
smoke, smoke,
raylib.NewRectangle(0, 0, smoke.Width, smoke.Height), raylib.NewRectangle(0, 0, float32(smoke.Width), float32(smoke.Height)),
raylib.NewRectangle(int32(mouseTail[i].Position.X), int32(mouseTail[i].Position.Y), smoke.Width*int32(mouseTail[i].Size), smoke.Height*int32(mouseTail[i].Size)), raylib.NewRectangle(mouseTail[i].Position.X, mouseTail[i].Position.Y, float32(smoke.Width)*mouseTail[i].Size, float32(smoke.Height)*mouseTail[i].Size),
raylib.NewVector2(float32(smoke.Width)*mouseTail[i].Size/2, float32(smoke.Height)*mouseTail[i].Size/2), raylib.NewVector2(float32(smoke.Width)*mouseTail[i].Size/2, float32(smoke.Height)*mouseTail[i].Size/2),
mouseTail[i].Rotation, mouseTail[i].Rotation,
raylib.Fade(mouseTail[i].Color, mouseTail[i].Alpha), raylib.Fade(mouseTail[i].Color, mouseTail[i].Alpha),

View file

@ -21,8 +21,8 @@ func main() {
scarfy := raylib.LoadTexture("scarfy.png") // Texture loading scarfy := raylib.LoadTexture("scarfy.png") // Texture loading
position := raylib.NewVector2(350.0, 280.0) position := raylib.NewVector2(350.0, 280.0)
frameRec := raylib.NewRectangle(0, 0, scarfy.Width/6, scarfy.Height) frameRec := raylib.NewRectangle(0, 0, float32(scarfy.Width/6), float32(scarfy.Height))
currentFrame := int32(0) currentFrame := float32(0)
framesCounter := 0 framesCounter := 0
framesSpeed := 8 // Number of spritesheet frames shown by second framesSpeed := 8 // Number of spritesheet frames shown by second
@ -40,7 +40,7 @@ func main() {
currentFrame = 0 currentFrame = 0
} }
frameRec.X = currentFrame * scarfy.Width / 6 frameRec.X = currentFrame * float32(scarfy.Width) / 6
} }
if raylib.IsKeyPressed(raylib.KeyRight) { if raylib.IsKeyPressed(raylib.KeyRight) {
@ -61,7 +61,7 @@ func main() {
raylib.DrawTexture(scarfy, 15, 40, raylib.White) raylib.DrawTexture(scarfy, 15, 40, raylib.White)
raylib.DrawRectangleLines(15, 40, scarfy.Width, scarfy.Height, raylib.Lime) raylib.DrawRectangleLines(15, 40, scarfy.Width, scarfy.Height, raylib.Lime)
raylib.DrawRectangleLines(15+frameRec.X, 40+frameRec.Y, frameRec.Width, frameRec.Height, raylib.Red) raylib.DrawRectangleLines(15+int32(frameRec.X), 40+int32(frameRec.Y), int32(frameRec.Width), int32(frameRec.Height), raylib.Red)
raylib.DrawText("FRAME SPEED: ", 165, 210, 10, raylib.DarkGray) raylib.DrawText("FRAME SPEED: ", 165, 210, 10, raylib.DarkGray)
raylib.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, raylib.DarkGray) raylib.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, raylib.DarkGray)

View file

@ -13,14 +13,14 @@ func main() {
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
scarfy := raylib.LoadTexture("scarfy.png") // Texture loading scarfy := raylib.LoadTexture("scarfy.png") // Texture loading
frameWidth := scarfy.Width / 7 frameWidth := float32(scarfy.Width) / 7
frameHeight := scarfy.Height frameHeight := float32(scarfy.Height)
// NOTE: Source rectangle (part of the texture to use for drawing) // NOTE: Source rectangle (part of the texture to use for drawing)
sourceRec := raylib.NewRectangle(0, 0, int32(frameWidth), int32(frameHeight)) sourceRec := raylib.NewRectangle(0, 0, frameWidth, frameHeight)
// NOTE: Destination rectangle (screen rectangle where drawing part of texture) // NOTE: Destination rectangle (screen rectangle where drawing part of texture)
destRec := raylib.NewRectangle(screenWidth/2, screenHeight/2, frameWidth*2, frameHeight*2) destRec := raylib.NewRectangle(float32(screenWidth)/2, float32(screenHeight)/2, frameWidth*2, frameHeight*2)
// NOTE: Origin of the texture (rotation/scale point), it's relative to destination rectangle size // NOTE: Origin of the texture (rotation/scale point), it's relative to destination rectangle size
origin := raylib.NewVector2(float32(frameWidth), float32(frameHeight)) origin := raylib.NewVector2(float32(frameWidth), float32(frameHeight))
@ -45,8 +45,8 @@ func main() {
// rotation defines the texture rotation (using origin as rotation point) // rotation defines the texture rotation (using origin as rotation point)
raylib.DrawTexturePro(scarfy, sourceRec, destRec, origin, rotation, raylib.White) raylib.DrawTexturePro(scarfy, sourceRec, destRec, origin, rotation, raylib.White)
raylib.DrawLine(destRec.X, 0, destRec.X, screenHeight, raylib.Gray) raylib.DrawLine(int32(destRec.X), 0, int32(destRec.X), screenHeight, raylib.Gray)
raylib.DrawLine(0, destRec.Y, screenWidth, destRec.Y, raylib.Gray) raylib.DrawLine(0, int32(destRec.Y), screenWidth, int32(destRec.Y), raylib.Gray)
raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray) raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray)

View file

@ -360,25 +360,27 @@ func Label(bounds raylib.Rectangle, text string) {
// LabelEx - Label element extended, configurable colors // LabelEx - Label element extended, configurable colors
func LabelEx(bounds raylib.Rectangle, text string, textColor, border, inner raylib.Color) { func LabelEx(bounds raylib.Rectangle, text string, textColor, border, inner raylib.Color) {
b := bounds.ToInt32()
// Update control // Update control
textWidth := raylib.MeasureText(text, int32(style[GlobalTextFontsize])) textWidth := raylib.MeasureText(text, int32(style[GlobalTextFontsize]))
textHeight := int32(style[GlobalTextFontsize]) textHeight := int32(style[GlobalTextFontsize])
if bounds.Width < textWidth { if b.Width < textWidth {
bounds.Width = textWidth + int32(style[LabelTextPadding]) b.Width = textWidth + int32(style[LabelTextPadding])
} }
if bounds.Height < textHeight { if b.Height < textHeight {
bounds.Height = textHeight + int32(style[LabelTextPadding])/2 b.Height = textHeight + int32(style[LabelTextPadding])/2
} }
// Draw control // Draw control
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, border) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, border)
raylib.DrawRectangle(bounds.X+int32(style[LabelBorderWidth]), bounds.Y+int32(style[LabelBorderWidth]), bounds.Width-(2*int32(style[LabelBorderWidth])), bounds.Height-(2*int32(style[LabelBorderWidth])), inner) raylib.DrawRectangle(b.X+int32(style[LabelBorderWidth]), b.Y+int32(style[LabelBorderWidth]), b.Width-(2*int32(style[LabelBorderWidth])), b.Height-(2*int32(style[LabelBorderWidth])), inner)
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(textWidth/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), textColor) raylib.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), textColor)
} }
// Button - Button element, returns true when clicked // Button - Button element, returns true when clicked
func Button(bounds raylib.Rectangle, text string) bool { func Button(bounds raylib.Rectangle, text string) bool {
b := bounds.ToInt32()
state := Normal state := Normal
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
clicked := false clicked := false
@ -387,12 +389,12 @@ func Button(bounds raylib.Rectangle, text string) bool {
textHeight := int32(style[GlobalTextFontsize]) textHeight := int32(style[GlobalTextFontsize])
// Update control // Update control
if bounds.Width < textWidth { if b.Width < textWidth {
bounds.Width = textWidth + int32(style[ButtonTextPadding]) b.Width = textWidth + int32(style[ButtonTextPadding])
} }
if bounds.Height < textHeight { if b.Height < textHeight {
bounds.Height = textHeight + int32(style[ButtonTextPadding])/2 b.Height = textHeight + int32(style[ButtonTextPadding])/2
} }
if raylib.CheckCollisionPointRec(mousePoint, bounds) { if raylib.CheckCollisionPointRec(mousePoint, bounds) {
@ -408,21 +410,21 @@ func Button(bounds raylib.Rectangle, text string) bool {
// Draw control // Draw control
switch state { switch state {
case Normal: case Normal:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ButtonDefaultBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonDefaultBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ButtonBorderWidth]), bounds.Y+int32(style[ButtonBorderWidth]), bounds.Width-(2*int32(style[ButtonBorderWidth])), bounds.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonDefaultInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonDefaultInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonDefaultTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonDefaultTextColor])))
break break
case Focused: case Focused:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ButtonHoverBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonHoverBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ButtonBorderWidth]), bounds.Y+int32(style[ButtonBorderWidth]), bounds.Width-(2*int32(style[ButtonBorderWidth])), bounds.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonHoverInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonHoverInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonHoverTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonHoverTextColor])))
break break
case Pressed: case Pressed:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ButtonPressedBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonPressedBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ButtonBorderWidth]), bounds.Y+int32(style[ButtonBorderWidth]), bounds.Width-(2*int32(style[ButtonBorderWidth])), bounds.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonPressedInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonPressedInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonPressedTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonPressedTextColor])))
break break
default: default:
@ -438,6 +440,7 @@ func Button(bounds raylib.Rectangle, text string) bool {
// ToggleButton - Toggle Button element, returns true when active // ToggleButton - Toggle Button element, returns true when active
func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool { func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool {
b := bounds.ToInt32()
state := Normal state := Normal
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
@ -445,11 +448,11 @@ func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool {
textHeight := int32(style[GlobalTextFontsize]) textHeight := int32(style[GlobalTextFontsize])
// Update control // Update control
if bounds.Width < textWidth { if b.Width < textWidth {
bounds.Width = textWidth + int32(style[ToggleTextPadding]) b.Width = textWidth + int32(style[ToggleTextPadding])
} }
if bounds.Height < textHeight { if b.Height < textHeight {
bounds.Height = textHeight + int32(style[ToggleTextPadding])/2 b.Height = textHeight + int32(style[ToggleTextPadding])/2
} }
if raylib.CheckCollisionPointRec(mousePoint, bounds) { if raylib.CheckCollisionPointRec(mousePoint, bounds) {
@ -467,24 +470,24 @@ func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool {
switch state { switch state {
case Normal: case Normal:
if active { if active {
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleActiveInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleActiveInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor])))
} else { } else {
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ToggleDefaultBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleDefaultBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleDefaultInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleDefaultInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor])))
} }
break break
case Focused: case Focused:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ToggleHoverBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleHoverBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleHoverInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleHoverInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleHoverTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleHoverTextColor])))
break break
case Pressed: case Pressed:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[TogglePressedBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[TogglePressedBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[TogglePressedInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[TogglePressedInsideColor])))
raylib.DrawText(text, bounds.X+((bounds.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[TogglePressedTextColor]))) raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[TogglePressedTextColor])))
break break
default: default:
break break
@ -497,8 +500,8 @@ func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool {
func ToggleGroup(bounds raylib.Rectangle, toggleText []string, active int) int { func ToggleGroup(bounds raylib.Rectangle, toggleText []string, active int) int {
for i := 0; i < len(toggleText); i++ { for i := 0; i < len(toggleText); i++ {
if i == active { if i == active {
ToggleButton(raylib.NewRectangle(bounds.X+int32(i)*(bounds.Width+int32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) ToggleButton(raylib.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true)
} else if ToggleButton(raylib.NewRectangle(bounds.X+int32(i)*(bounds.Width+int32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { } else if ToggleButton(raylib.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) {
active = i active = i
} }
} }
@ -508,10 +511,12 @@ func ToggleGroup(bounds raylib.Rectangle, toggleText []string, active int) int {
// ComboBox - Combo Box element, returns selected item index // ComboBox - Combo Box element, returns selected item index
func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int { func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int {
b := bounds.ToInt32()
state := Normal state := Normal
clicked := false clicked := false
click := raylib.NewRectangle(bounds.X+bounds.Width+int32(style[ComboboxPadding]), bounds.Y, int32(style[boundsWidth]), int32(style[boundsHeight])) click := raylib.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(style[boundsWidth]), float32(style[boundsHeight]))
c := click.ToInt32()
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
@ -525,11 +530,11 @@ func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int {
// Update control // Update control
textWidth = raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize])) textWidth = raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))
if bounds.Width < textWidth { if b.Width < textWidth {
bounds.Width = textWidth + int32(style[ToggleTextPadding]) b.Width = textWidth + int32(style[ToggleTextPadding])
} }
if bounds.Height < textHeight { if b.Height < textHeight {
bounds.Height = textHeight + int32(style[ToggleTextPadding])/2 b.Height = textHeight + int32(style[ToggleTextPadding])/2
} }
if raylib.CheckCollisionPointRec(mousePoint, bounds) || raylib.CheckCollisionPointRec(mousePoint, click) { if raylib.CheckCollisionPointRec(mousePoint, bounds) || raylib.CheckCollisionPointRec(mousePoint, click) {
@ -545,44 +550,44 @@ func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int {
// Draw control // Draw control
switch state { switch state {
case Normal: case Normal:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ComboboxBorderWidth]), bounds.Y+int32(style[ComboboxBorderWidth]), bounds.Width-(2*int32(style[ComboboxBorderWidth])), bounds.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor])))
raylib.DrawRectangle(click.X, click.Y, click.Width, click.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor]))) raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor])))
raylib.DrawRectangle(click.X+int32(style[ComboboxBorderWidth]), click.Y+int32(style[ComboboxBorderWidth]), click.Width-(2*int32(style[ComboboxBorderWidth])), click.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor]))) raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor])))
raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), click.X+((click.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), click.Y+((click.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultListTextColor]))) raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultListTextColor])))
raylib.DrawText(comboText[i], bounds.X+((bounds.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultTextColor]))) raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultTextColor])))
break break
case Focused: case Focused:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ComboboxBorderWidth]), bounds.Y+int32(style[ComboboxBorderWidth]), bounds.Width-(2*int32(style[ComboboxBorderWidth])), bounds.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor])))
raylib.DrawRectangle(click.X, click.Y, click.Width, click.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor]))) raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor])))
raylib.DrawRectangle(click.X+int32(style[ComboboxBorderWidth]), click.Y+int32(style[ComboboxBorderWidth]), click.Width-(2*int32(style[ComboboxBorderWidth])), click.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor]))) raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor])))
raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), click.X+((click.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), click.Y+((click.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverListTextColor]))) raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverListTextColor])))
raylib.DrawText(comboText[i], bounds.X+((bounds.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverTextColor]))) raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverTextColor])))
break break
case Pressed: case Pressed:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ComboboxBorderWidth]), bounds.Y+int32(style[ComboboxBorderWidth]), bounds.Width-(2*int32(style[ComboboxBorderWidth])), bounds.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor])))
raylib.DrawRectangle(click.X, click.Y, click.Width, click.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor]))) raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor])))
raylib.DrawRectangle(click.X+int32(style[ComboboxBorderWidth]), click.Y+int32(style[ComboboxBorderWidth]), click.Width-(2*int32(style[ComboboxBorderWidth])), click.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor]))) raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor])))
raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), click.X+((click.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), click.Y+((click.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor]))) raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor])))
raylib.DrawText(comboText[i], bounds.X+((bounds.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor]))) raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor])))
break break
default: default:
break break
} }
if clicked { if clicked {
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ComboboxBorderWidth]), bounds.Y+int32(style[ComboboxBorderWidth]), bounds.Width-(2*int32(style[ComboboxBorderWidth])), bounds.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor])))
raylib.DrawRectangle(click.X, click.Y, click.Width, click.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor]))) raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor])))
raylib.DrawRectangle(click.X+int32(style[ComboboxBorderWidth]), click.Y+int32(style[ComboboxBorderWidth]), click.Width-(2*int32(style[ComboboxBorderWidth])), click.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor]))) raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor])))
raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), click.X+((click.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), click.Y+((click.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor]))) raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor])))
raylib.DrawText(comboText[i], bounds.X+((bounds.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), bounds.Y+((bounds.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor]))) raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor])))
} }
} }
@ -602,6 +607,7 @@ func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int {
// CheckBox - Check Box element, returns true when active // CheckBox - Check Box element, returns true when active
func CheckBox(bounds raylib.Rectangle, checked bool) bool { func CheckBox(bounds raylib.Rectangle, checked bool) bool {
b := bounds.ToInt32()
state := Normal state := Normal
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
@ -620,23 +626,23 @@ func CheckBox(bounds raylib.Rectangle, checked bool) bool {
// Draw control // Draw control
switch state { switch state {
case Normal: case Normal:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[CheckboxDefaultBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxDefaultBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxDefaultInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxDefaultInsideColor])))
break break
case Focused: case Focused:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[CheckboxHoverBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxHoverBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxHoverInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxHoverInsideColor])))
break break
case Pressed: case Pressed:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[CheckboxClickBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxClickBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[ToggleBorderWidth]), bounds.Y+int32(style[ToggleBorderWidth]), bounds.Width-(2*int32(style[ToggleBorderWidth])), bounds.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxClickInsideColor]))) raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxClickInsideColor])))
break break
default: default:
break break
} }
if checked { if checked {
raylib.DrawRectangle(bounds.X+int32(style[CheckboxInsideWidth]), bounds.Y+int32(style[CheckboxInsideWidth]), bounds.Width-(2*int32(style[CheckboxInsideWidth])), bounds.Height-(2*int32(style[CheckboxInsideWidth])), raylib.GetColor(int32(style[CheckboxDefaultActiveColor]))) raylib.DrawRectangle(b.X+int32(style[CheckboxInsideWidth]), b.Y+int32(style[CheckboxInsideWidth]), b.Width-(2*int32(style[CheckboxInsideWidth])), b.Height-(2*int32(style[CheckboxInsideWidth])), raylib.GetColor(int32(style[CheckboxDefaultActiveColor])))
} }
return checked return checked
@ -644,6 +650,7 @@ func CheckBox(bounds raylib.Rectangle, checked bool) bool {
// Slider - Slider element, returns selected value // Slider - Slider element, returns selected value
func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 { func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 {
b := bounds.ToInt32()
sliderPos := float32(0) sliderPos := float32(0)
state := Normal state := Normal
@ -659,17 +666,17 @@ func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32
sliderPos = (value - minValue) / (maxValue - minValue) sliderPos = (value - minValue) / (maxValue - minValue)
sliderButton := raylib.Rectangle{} sliderButton := raylib.RectangleInt32{}
sliderButton.Width = (bounds.Width-(2*int32(style[SliderButtonBorderWidth])))/10 - 8 sliderButton.Width = (b.Width-(2*int32(style[SliderButtonBorderWidth])))/10 - 8
sliderButton.Height = bounds.Height - (2 * int32(style[SliderBorderWidth]+2*style[SliderButtonBorderWidth])) sliderButton.Height = b.Height - (2 * int32(style[SliderBorderWidth]+2*style[SliderButtonBorderWidth]))
sliderButtonMinPos := bounds.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) sliderButtonMinPos := b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth])
sliderButtonMaxPos := bounds.X + bounds.Width - (int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButton.Width) sliderButtonMaxPos := b.X + b.Width - (int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButton.Width)
buttonTravelDistance = float32(sliderButtonMaxPos - sliderButtonMinPos) buttonTravelDistance = float32(sliderButtonMaxPos - sliderButtonMinPos)
sliderButton.X = bounds.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + int32(sliderPos*buttonTravelDistance) sliderButton.X = b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + int32(sliderPos*buttonTravelDistance)
sliderButton.Y = bounds.Y + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) sliderButton.Y = b.Y + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth])
if raylib.CheckCollisionPointRec(mousePoint, bounds) { if raylib.CheckCollisionPointRec(mousePoint, bounds) {
state = Focused state = Focused
@ -694,8 +701,8 @@ func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32
} }
// Draw control // Draw control
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[SliderBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[SliderBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[SliderBorderWidth]), bounds.Y+int32(style[SliderBorderWidth]), bounds.Width-(2*int32(style[SliderBorderWidth])), bounds.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderInsideColor]))) raylib.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderInsideColor])))
switch state { switch state {
case Normal: case Normal:
@ -716,6 +723,7 @@ func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32
// SliderBar - Slider Bar element, returns selected value // SliderBar - Slider Bar element, returns selected value
func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 { func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 {
b := bounds.ToInt32()
state := Normal state := Normal
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
@ -734,12 +742,12 @@ func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float
fixedValue = maxValue fixedValue = maxValue
} }
sliderBar := raylib.Rectangle{} sliderBar := raylib.RectangleInt32{}
sliderBar.X = bounds.X + int32(style[SliderBorderWidth]) sliderBar.X = b.X + int32(style[SliderBorderWidth])
sliderBar.Y = bounds.Y + int32(style[SliderBorderWidth]) sliderBar.Y = b.Y + int32(style[SliderBorderWidth])
sliderBar.Width = int32((fixedValue * (float32(bounds.Width) - 2*float32(style[SliderBorderWidth]))) / (maxValue - fixedMinValue)) sliderBar.Width = int32((fixedValue * (float32(b.Width) - 2*float32(style[SliderBorderWidth]))) / (maxValue - fixedMinValue))
sliderBar.Height = bounds.Height - 2*int32(style[SliderBorderWidth]) sliderBar.Height = b.Height - 2*int32(style[SliderBorderWidth])
if raylib.CheckCollisionPointRec(mousePoint, bounds) { if raylib.CheckCollisionPointRec(mousePoint, bounds) {
state = Focused state = Focused
@ -747,23 +755,23 @@ func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float
if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { if raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
state = Pressed state = Pressed
sliderBar.Width = (int32(mousePoint.X) - bounds.X - int32(style[SliderBorderWidth])) sliderBar.Width = (int32(mousePoint.X) - b.X - int32(style[SliderBorderWidth]))
if int32(mousePoint.X) <= (bounds.X + int32(style[SliderBorderWidth])) { if int32(mousePoint.X) <= (b.X + int32(style[SliderBorderWidth])) {
sliderBar.Width = 0 sliderBar.Width = 0
} else if int32(mousePoint.X) >= (bounds.X + bounds.Width - int32(style[SliderBorderWidth])) { } else if int32(mousePoint.X) >= (b.X + b.Width - int32(style[SliderBorderWidth])) {
sliderBar.Width = bounds.Width - 2*int32(style[SliderBorderWidth]) sliderBar.Width = b.Width - 2*int32(style[SliderBorderWidth])
} }
} }
} else { } else {
state = Normal state = Normal
} }
fixedValue = (float32(sliderBar.Width) * (maxValue - fixedMinValue)) / (float32(bounds.Width) - 2*float32(style[SliderBorderWidth])) fixedValue = (float32(sliderBar.Width) * (maxValue - fixedMinValue)) / (float32(b.Width) - 2*float32(style[SliderBorderWidth]))
// Draw control // Draw control
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[SliderbarBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[SliderbarBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[SliderBorderWidth]), bounds.Y+int32(style[SliderBorderWidth]), bounds.Width-(2*int32(style[SliderBorderWidth])), bounds.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderbarInsideColor]))) raylib.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderbarInsideColor])))
switch state { switch state {
case Normal: case Normal:
@ -780,7 +788,7 @@ func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float
} }
if minValue < 0 && maxValue > 0 { if minValue < 0 && maxValue > 0 {
raylib.DrawRectangle((bounds.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(bounds.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, raylib.GetColor(int32(style[SliderbarZeroLineColor]))) raylib.DrawRectangle((b.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(b.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, raylib.GetColor(int32(style[SliderbarZeroLineColor])))
} }
return fixedValue + minValue return fixedValue + minValue
@ -788,36 +796,38 @@ func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float
// ProgressBar - Progress Bar element, shows current progress value // ProgressBar - Progress Bar element, shows current progress value
func ProgressBar(bounds raylib.Rectangle, value float32) { func ProgressBar(bounds raylib.Rectangle, value float32) {
b := bounds.ToInt32()
if value > 1.0 { if value > 1.0 {
value = 1.0 value = 1.0
} else if value < 0.0 { } else if value < 0.0 {
value = 0.0 value = 0.0
} }
progressBar := raylib.NewRectangle(bounds.X+int32(style[ProgressbarBorderWidth]), bounds.Y+int32(style[ProgressbarBorderWidth]), bounds.Width-(int32(style[ProgressbarBorderWidth])*2), bounds.Height-(int32(style[ProgressbarBorderWidth])*2)) progressBar := raylib.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), b.Width - (int32(style[ProgressbarBorderWidth]) * 2), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)}
progressValue := raylib.NewRectangle(bounds.X+int32(style[ProgressbarBorderWidth]), bounds.Y+int32(style[ProgressbarBorderWidth]), int32(value*float32(bounds.Width-int32(style[ProgressbarBorderWidth])*2)), bounds.Height-(int32(style[ProgressbarBorderWidth])*2)) progressValue := raylib.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), int32(value * float32(b.Width-int32(style[ProgressbarBorderWidth])*2)), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)}
// Draw control // Draw control
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ProgressbarBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ProgressbarBorderColor])))
raylib.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, raylib.GetColor(int32(style[ProgressbarInsideColor]))) raylib.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, raylib.GetColor(int32(style[ProgressbarInsideColor])))
raylib.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, raylib.GetColor(int32(style[ProgressbarProgressColor]))) raylib.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, raylib.GetColor(int32(style[ProgressbarProgressColor])))
} }
// Spinner - Spinner element, returns selected value // Spinner - Spinner element, returns selected value
func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int { func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int {
b := bounds.ToInt32()
state := Normal state := Normal
mousePoint := raylib.GetMousePosition() mousePoint := raylib.GetMousePosition()
labelBoxBound := raylib.NewRectangle(bounds.X+bounds.Width/4+1, bounds.Y, bounds.Width/2, bounds.Height) labelBoxBound := raylib.RectangleInt32{b.X + b.Width/4 + 1, b.Y, b.Width / 2, b.Height}
leftButtonBound := raylib.NewRectangle(bounds.X, bounds.Y, bounds.Width/4, bounds.Height) leftButtonBound := raylib.RectangleInt32{b.X, b.Y, b.Width / 4, b.Height}
rightButtonBound := raylib.NewRectangle(bounds.X+bounds.Width-bounds.Width/4+1, bounds.Y, bounds.Width/4, bounds.Height) rightButtonBound := raylib.RectangleInt32{b.X + b.Width - b.Width/4 + 1, b.Y, b.Width / 4, b.Height}
textWidth := raylib.MeasureText(fmt.Sprintf("%d", value), int32(style[GlobalTextFontsize])) textWidth := raylib.MeasureText(fmt.Sprintf("%d", value), int32(style[GlobalTextFontsize]))
buttonSide := 0 buttonSide := 0
// Update control // Update control
if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound) || raylib.CheckCollisionPointRec(mousePoint, rightButtonBound) || raylib.CheckCollisionPointRec(mousePoint, labelBoxBound) { if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) || raylib.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) || raylib.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) {
if raylib.IsKeyDown(raylib.KeyLeft) { if raylib.IsKeyDown(raylib.KeyLeft) {
state = Pressed state = Pressed
buttonSide = 1 buttonSide = 1
@ -835,7 +845,7 @@ func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int {
} }
} }
if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound) { if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) {
buttonSide = 1 buttonSide = 1
state = Focused state = Focused
@ -857,7 +867,7 @@ func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int {
} }
} }
} }
} else if raylib.CheckCollisionPointRec(mousePoint, rightButtonBound) { } else if raylib.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) {
buttonSide = 2 buttonSide = 2
state = Focused state = Focused
@ -879,7 +889,7 @@ func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int {
} }
} }
} }
} else if !raylib.CheckCollisionPointRec(mousePoint, labelBoxBound) { } else if !raylib.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) {
buttonSide = 0 buttonSide = 0
} }
@ -966,6 +976,7 @@ func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int {
// TextBox - Text Box element, updates input text // TextBox - Text Box element, updates input text
func TextBox(bounds raylib.Rectangle, text string) string { func TextBox(bounds raylib.Rectangle, text string) string {
b := bounds.ToInt32()
state := Normal state := Normal
keyBackspaceText := int32(259) // GLFW BACKSPACE: 3 + 256 keyBackspaceText := int32(259) // GLFW BACKSPACE: 3 + 256
@ -997,17 +1008,17 @@ func TextBox(bounds raylib.Rectangle, text string) string {
// Draw control // Draw control
switch state { switch state {
case Normal: case Normal:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[TextboxBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[TextboxBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[TextboxBorderWidth]), bounds.Y+int32(style[TextboxBorderWidth]), bounds.Width-(int32(style[TextboxBorderWidth])*2), bounds.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor]))) raylib.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor])))
raylib.DrawText(text, bounds.X+2, bounds.Y+int32(style[TextboxBorderWidth])+bounds.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor]))) raylib.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor])))
break break
case Focused: case Focused:
raylib.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor]))) raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor])))
raylib.DrawRectangle(bounds.X+int32(style[TextboxBorderWidth]), bounds.Y+int32(style[TextboxBorderWidth]), bounds.Width-(int32(style[TextboxBorderWidth])*2), bounds.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor]))) raylib.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor])))
raylib.DrawText(text, bounds.X+2, bounds.Y+int32(style[TextboxBorderWidth])+bounds.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor]))) raylib.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor])))
if (framesCounter2/20)%2 == 0 && raylib.CheckCollisionPointRec(mousePoint, bounds) { if (framesCounter2/20)%2 == 0 && raylib.CheckCollisionPointRec(mousePoint, bounds) {
raylib.DrawRectangle(bounds.X+4+raylib.MeasureText(text, int32(style[GlobalTextFontsize])), bounds.Y+2, 1, bounds.Height-4, raylib.GetColor(int32(style[TextboxLineColor]))) raylib.DrawRectangle(b.X+4+raylib.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, raylib.GetColor(int32(style[TextboxLineColor])))
} }
break break
case Pressed: case Pressed:

View file

@ -26,6 +26,7 @@
* #define SUPPORT_FILEFORMAT_XM * #define SUPPORT_FILEFORMAT_XM
* #define SUPPORT_FILEFORMAT_MOD * #define SUPPORT_FILEFORMAT_MOD
* #define SUPPORT_FILEFORMAT_FLAC * #define SUPPORT_FILEFORMAT_FLAC
* #define SUPPORT_FILEFORMAT_MP3
* Selected desired fileformats to be supported for loading. Some of those formats are * Selected desired fileformats to be supported for loading. Some of those formats are
* supported by default, to remove support, just comment unrequired #define in this module * supported by default, to remove support, just comment unrequired #define in this module
* *
@ -74,13 +75,7 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features) #include "config.h"
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_WAV
#define SUPPORT_FILEFORMAT_OGG
#define SUPPORT_FILEFORMAT_XM
#define SUPPORT_FILEFORMAT_MOD
//-------------------------------------------------
#if !defined(USE_OPENAL_BACKEND) #if !defined(USE_OPENAL_BACKEND)
#define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL.
@ -135,6 +130,11 @@
#include "external/dr_flac.h" // FLAC loading functions #include "external/dr_flac.h" // FLAC loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3)
#define DR_MP3_IMPLEMENTATION
#include "external/dr_mp3.h" // MP3 loading functions
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#undef bool #undef bool
#endif #endif
@ -1555,7 +1555,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_OGG: case MUSIC_AUDIO_OGG:
{ {
// NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels);
} break; } break;
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)

142
raylib/config.h Normal file
View file

@ -0,0 +1,142 @@
/**********************************************************************************************
*
* raylib configuration flags
*
* This file defines all the configuration flags for the different raylib modules
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2018 Ahmad Fatoum & Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#define RAYLIB_VERSION "2.0-dev"
// Edit to control what features Makefile'd raylib is compiled with
#if defined(RAYLIB_CMAKE)
// Edit CMakeOptions.txt for CMake instead
#include "cmake/config.h"
#else
//------------------------------------------------------------------------------------
// Module: core - Configuration Flags
//------------------------------------------------------------------------------------
// Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
#define SUPPORT_CAMERA_SYSTEM 1
// Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag
#define SUPPORT_GESTURES_SYSTEM 1
// Mouse gestures are directly mapped like touches and processed by gestures system
#define SUPPORT_MOUSE_GESTURES 1
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
//#define SUPPORT_BUSY_WAIT_LOOP 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
#define SUPPORT_GIF_RECORDING 1
//------------------------------------------------------------------------------------
// Module: rlgl - Configuration Flags
//------------------------------------------------------------------------------------
// Support VR simulation functionality (stereo rendering)
#define SUPPORT_VR_SIMULATOR 1
// Include stereo rendering distortion shader (shader_distortion.h)
#define SUPPORT_DISTORTION_SHADER 1
//------------------------------------------------------------------------------------
// Module: shapes - Configuration Flags
//------------------------------------------------------------------------------------
// Draw rectangle shapes using font texture white character instead of default white texture
// Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
#define SUPPORT_FONT_TEXTURE
// Use QUADS instead of TRIANGLES for drawing when possible
// Some lines-based shapes could still use lines
#define SUPPORT_QUADS_DRAW_MODE
//------------------------------------------------------------------------------------
// Module: textures - Configuration Flags
//------------------------------------------------------------------------------------
// Selecte desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
//#define SUPPORT_FILEFORMAT_GIF 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_HDR 1
#define SUPPORT_FILEFORMAT_KTX 1
#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
// Support proedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define SUPPORT_IMAGE_GENERATION 1
//------------------------------------------------------------------------------------
// Module: text - Configuration Flags
//------------------------------------------------------------------------------------
// Default font is loaded on window initialization to be available for the user to render simple text
// NOTE: If enabled, uses external module functions to load default raylib font
#define SUPPORT_DEFAULT_FONT 1
// Selected desired font fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1
//------------------------------------------------------------------------------------
// Module: models - Configuration Flags
//------------------------------------------------------------------------------------
// Selected desired model fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_OBJ 1
#define SUPPORT_FILEFORMAT_MTL 1
// Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1
//------------------------------------------------------------------------------------
// Module: audio - Configuration Flags
//------------------------------------------------------------------------------------
// Desired audio fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_WAV 1
#define SUPPORT_FILEFORMAT_OGG 1
#define SUPPORT_FILEFORMAT_XM 1
#define SUPPORT_FILEFORMAT_MOD 1
//#define SUPPORT_FILEFORMAT_FLAC 1
//#define SUPPORT_FILEFORMAT_MP3 1
//------------------------------------------------------------------------------------
// Module: utils - Configuration Flags
//------------------------------------------------------------------------------------
// Show TraceLog() output messages
// NOTE: By default LOG_DEBUG traces not shown
#define SUPPORT_TRACELOG 1
// Support saving image data fileformats
// NOTE: Requires stb_image_write library
#define SUPPORT_SAVE_PNG 1
//#define SUPPORT_SAVE_BMP 1
#endif //defined(RAYLIB_CMAKE)

View file

@ -48,7 +48,10 @@
* Mouse gestures are directly mapped like touches and processed by gestures system. * Mouse gestures are directly mapped like touches and processed by gestures system.
* *
* #define SUPPORT_BUSY_WAIT_LOOP * #define SUPPORT_BUSY_WAIT_LOOP
* Use busy wait loop for timming sync, if not defined, a high-resolution timer is setup and used * Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
*
* #define SUPPORT_SCREEN_CAPTURE
* Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
* *
* #define SUPPORT_GIF_RECORDING * #define SUPPORT_GIF_RECORDING
* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() * Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
@ -81,30 +84,20 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features) #include "config.h" // Defines module configuration flags
//------------------------------------------------- #include "raylib.h" // Declares module functions
#define SUPPORT_DEFAULT_FONT
#define SUPPORT_MOUSE_GESTURES
#define SUPPORT_CAMERA_SYSTEM
#define SUPPORT_GESTURES_SYSTEM
//#define SUPPORT_BUSY_WAIT_LOOP
#define SUPPORT_GIF_RECORDING
//-------------------------------------------------
#include "raylib.h"
#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L #if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
#undef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#endif #endif
#define RAYMATH_IMPLEMENTATION // Define external out-of-line implementation of raymath here
#include "raymath.h" // Required for: Vector3 and Matrix functions
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
#include "utils.h" // Required for: fopen() Android mapping #include "utils.h" // Required for: fopen() Android mapping
#define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation)
#define RAYMATH_EXTERN_INLINE // Compile raymath functions as static inline (remember, it's a compiler hint)
#include "raymath.h" // Required for: Vector3 and Matrix functions
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM)
#define GESTURES_IMPLEMENTATION #define GESTURES_IMPLEMENTATION
#include "gestures.h" // Gestures detection functionality #include "gestures.h" // Gestures detection functionality
@ -124,9 +117,10 @@
#include <stdlib.h> // Required for: malloc(), free(), rand(), atexit() #include <stdlib.h> // Required for: malloc(), free(), rand(), atexit()
#include <stdint.h> // Required for: typedef unsigned long long int uint64_t, used by hi-res timer #include <stdint.h> // Required for: typedef unsigned long long int uint64_t, used by hi-res timer
#include <time.h> // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!) #include <time.h> // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!)
#include <math.h> // Required for: tan() [Used in Begin3dMode() to set perspective] #include <math.h> // Required for: tan() [Used in BeginMode3D() to set perspective]
#include <string.h> // Required for: strrchr(), strcmp() #include <string.h> // Required for: strrchr(), strcmp()
//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes //#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
#include <ctype.h> // Required for: tolower() [Used in IsFileExtension()]
#if defined(_WIN32) #if defined(_WIN32)
#include <direct.h> // Required for: _getch(), _chdir() #include <direct.h> // Required for: _getch(), _chdir()
@ -147,13 +141,7 @@
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
//#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
#include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
// NOTE: GLFW3 already includes gl.h (OpenGL) headers
#if defined(__linux__)
#define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
#define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window
#include <GLFW/glfw3native.h> // which are required for hiding mouse
#endif
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
// NOTE: Those functions require linking with winmm library // NOTE: Those functions require linking with winmm library
@ -238,9 +226,10 @@ static GLFWwindow *window; // Native window (graphic device
static bool windowReady = false; // Check if window has been initialized successfully static bool windowReady = false; // Check if window has been initialized successfully
static bool windowMinimized = false; // Check if window has been minimized static bool windowMinimized = false; // Check if window has been minimized
static const char *windowTitle = NULL; // Window text title...
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
static struct android_app *app; // Android activity static struct android_app *androidApp; // Android activity
static struct android_poll_source *source; // Android events polling source static struct android_poll_source *source; // Android events polling source
static int ident, events; // Android ALooper_pollAll() variables static int ident, events; // Android ALooper_pollAll() variables
static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files) static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files)
@ -283,10 +272,10 @@ static bool windowShouldClose = false; // Flag to set window for closing
#endif #endif
#if defined(PLATFORM_UWP) #if defined(PLATFORM_UWP)
static EGLNativeWindowType uwpWindow; extern EGLNativeWindowType uwpWindow; // Native EGL window handler for UWP (external, defined in UWP App)
#endif #endif
// Display size-related data // Screen related variables
static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...)
static int screenWidth, screenHeight; // Screen width and height (used render area) static int screenWidth, screenHeight; // Screen width and height (used render area)
static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required) static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required)
@ -294,13 +283,11 @@ static int renderOffsetX = 0; // Offset X from render area (must b
static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2) static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2)
static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP)
static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
static bool cursorHidden = false; // Track if cursor is hidden static bool cursorHidden = false; // Track if cursor is hidden
static bool cursorOnScreen = false; // Tracks if cursor is inside client area static bool cursorOnScreen = false; // Tracks if cursor is inside client area
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
static const char *windowTitle = NULL; // Window text title...
static int screenshotCounter = 0; // Screenshots counter
// Register mouse states // Register mouse states
static char previousMouseState[3] = { 0 }; // Registers previous mouse button state static char previousMouseState[3] = { 0 }; // Registers previous mouse button state
static char currentMouseState[3] = { 0 }; // Registers current mouse button state static char currentMouseState[3] = { 0 }; // Registers current mouse button state
@ -326,6 +313,7 @@ static int lastGamepadButtonPressed = -1; // Register last gamepad button pres
static int gamepadAxisCount = 0; // Register number of available gamepad axis static int gamepadAxisCount = 0; // Register number of available gamepad axis
static Vector2 mousePosition; // Mouse position on screen static Vector2 mousePosition; // Mouse position on screen
static float mouseScale = 1.0f; // Mouse default scale
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click
@ -338,17 +326,23 @@ static char **dropFilesPath; // Store dropped files paths as stri
static int dropFilesCount = 0; // Count stored strings static int dropFilesCount = 0; // Count stored strings
#endif #endif
static double currentTime, previousTime; // Used to track timmings static double currentTime = 0.0; // Current time measure
static double updateTime, drawTime; // Time measures for update and draw static double previousTime = 0.0; // Previous time measure
static double updateTime = 0.0; // Time measure for frame update
static double drawTime = 0.0; // Time measure for frame draw
static double frameTime = 0.0; // Time measure for one frame static double frameTime = 0.0; // Time measure for one frame
static double targetTime = 0.0; // Desired time for one frame, if 0 not applied static double targetTime = 0.0; // Desired time for one frame, if 0 not applied
static unsigned char configFlags = 0; // Configuration flags (bit based) static unsigned char configFlags = 0; // Configuration flags (bit based)
static bool showLogo = false; // Track if showing logo at init is enabled static bool showLogo = false; // Track if showing logo at init is enabled
#if defined(SUPPORT_SCREEN_CAPTURE)
static int screenshotCounter = 0; // Screenshots counter
#endif
#if defined(SUPPORT_GIF_RECORDING) #if defined(SUPPORT_GIF_RECORDING)
static int gifFramesCounter = 0; static int gifFramesCounter = 0; // GIF frames counter
static bool gifRecording = false; static bool gifRecording = false; // GIF recording state
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -415,7 +409,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread
#endif #endif
#if defined(PLATFORM_UWP) #if defined(PLATFORM_UWP)
// Define functions required to manage inputs // TODO: Define functions required to manage inputs
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
@ -426,29 +420,97 @@ static void *GamepadThread(void *arg); // Mouse reading thread
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions // Module Functions Definition - Window and OpenGL Context Functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
#if defined(PLATFORM_ANDROID)
// To allow easier porting to android, we allow the user to define a
// main function which we call from android_main, defined by ourselves
extern int main(int argc, char *argv[]);
void android_main(struct android_app *app)
{
char arg0[] = "raylib"; // NOTE: argv[] are mutable
androidApp = app;
// TODO: Should we maybe report != 0 return codes somewhere?
(void)main(1, (char*[]) { arg0, NULL });
}
// TODO: Add this to header (if apps really need it)
struct android_app *GetAndroidApp(void)
{
return androidApp;
}
#endif
// Initialize window and OpenGL context // Initialize window and OpenGL context
// NOTE: data parameter could be used to pass any kind of required data to the initialization // NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, void *data) void InitWindow(int width, int height, const char *title)
{ {
TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)"); TraceLog(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
#if defined(PLATFORM_DESKTOP) windowTitle = title;
windowTitle = (char *)data; #if defined(PLATFORM_ANDROID)
#endif screenWidth = width;
screenHeight = height;
#if defined(PLATFORM_UWP) // Input data is android app pointer
uwpWindow = (EGLNativeWindowType)data; internalDataPath = androidApp->activity->internalDataPath;
#endif
// Init hi-res timer // Set desired windows flags before initializing anything
InitTimer(); ANativeActivity_setWindowFlags(androidApp->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
//ANativeActivity_setWindowFlags(androidApp->activity, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN, AWINDOW_FLAG_FULLSCREEN);
int orientation = AConfiguration_getOrientation(androidApp->config);
if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(LOG_INFO, "PORTRAIT window orientation");
else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(LOG_INFO, "LANDSCAPE window orientation");
// TODO: Automatic orientation doesn't seem to work
if (width <= height)
{
AConfiguration_setOrientation(androidApp->config, ACONFIGURATION_ORIENTATION_PORT);
TraceLog(LOG_WARNING, "Window set to portraid mode");
}
else
{
AConfiguration_setOrientation(androidApp->config, ACONFIGURATION_ORIENTATION_LAND);
TraceLog(LOG_WARNING, "Window set to landscape mode");
}
//AConfiguration_getDensity(androidApp->config);
//AConfiguration_getKeyboard(androidApp->config);
//AConfiguration_getScreenSize(androidApp->config);
//AConfiguration_getScreenLong(androidApp->config);
androidApp->onAppCmd = AndroidCommandCallback;
androidApp->onInputEvent = AndroidInputCallback;
InitAssetManager(androidApp->activity->assetManager);
TraceLog(LOG_INFO, "Android app initialized successfully");
// Wait for window to be initialized (display and context)
while (!windowReady)
{
// Process events loop
while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0)
{
// Process this event
if (source != NULL) source->process(androidApp, source);
// NOTE: Never close window, native activity is controlled by the system!
//if (androidApp->destroyRequested != 0) windowShouldClose = true;
}
}
#else
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
// NOTE: returns true if window and graphic device has been initialized successfully // NOTE: returns true if window and graphic device has been initialized successfully
windowReady = InitGraphicsDevice(width, height); windowReady = InitGraphicsDevice(width, height);
if (!windowReady) return; if (!windowReady) return;
// Init hi-res timer
InitTimer();
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
// NOTE: External function (defined in module: text) // NOTE: External function (defined in module: text)
@ -494,71 +556,8 @@ void InitWindow(int width, int height, void *data)
SetTargetFPS(60); SetTargetFPS(60);
LogoAnimation(); LogoAnimation();
} }
#endif // defined(PLATFORM_ANDROID)
} }
#endif
#if defined(PLATFORM_ANDROID)
// Initialize window and OpenGL context (and Android activity)
// NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, void *data)
{
TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)");
screenWidth = width;
screenHeight = height;
// Input data is android app pointer
app = (struct android_app *)data;
internalDataPath = app->activity->internalDataPath;
// Set desired windows flags before initializing anything
ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
//ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN, AWINDOW_FLAG_FULLSCREEN);
int orientation = AConfiguration_getOrientation(app->config);
if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(LOG_INFO, "PORTRAIT window orientation");
else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(LOG_INFO, "LANDSCAPE window orientation");
// TODO: Automatic orientation doesn't seem to work
if (width <= height)
{
AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_PORT);
TraceLog(LOG_WARNING, "Window set to portraid mode");
}
else
{
AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_LAND);
TraceLog(LOG_WARNING, "Window set to landscape mode");
}
//AConfiguration_getDensity(app->config);
//AConfiguration_getKeyboard(app->config);
//AConfiguration_getScreenSize(app->config);
//AConfiguration_getScreenLong(app->config);
app->onAppCmd = AndroidCommandCallback;
app->onInputEvent = AndroidInputCallback;
InitAssetManager(app->activity->assetManager);
TraceLog(LOG_INFO, "Android app initialized successfully");
// Wait for window to be initialized (display and context)
while (!windowReady)
{
// Process events loop
while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0)
{
// Process this event
if (source != NULL) source->process(app, source);
// NOTE: Never close window, native activity is controlled by the system!
//if (app->destroyRequested != 0) windowShouldClose = true;
}
}
}
#endif
// Close window and unload OpenGL context // Close window and unload OpenGL context
void CloseWindow(void) void CloseWindow(void)
@ -736,6 +735,14 @@ void SetWindowMinSize(int width, int height)
#endif #endif
} }
// Set window dimensions
void SetWindowSize(int width, int height)
{
#if defined(PLATFORM_DESKTOP)
glfwSetWindowSize(window, width, height);
#endif
}
// Get current screen width // Get current screen width
int GetScreenWidth(void) int GetScreenWidth(void)
{ {
@ -752,11 +759,7 @@ int GetScreenHeight(void)
void ShowCursor() void ShowCursor()
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
#if defined(__linux__) && defined(_GLFW_X11)
XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window));
#else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
#endif
#endif #endif
cursorHidden = false; cursorHidden = false;
} }
@ -765,18 +768,7 @@ void ShowCursor()
void HideCursor() void HideCursor()
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
#if defined(__linux__) && defined(_GLFW_X11)
XColor col;
const char nil[] = {0};
Pixmap pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), nil, 1, 1);
Cursor cur = XCreatePixmapCursor(glfwGetX11Display(), pix, pix, &col, &col, 0, 0);
XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), cur);
XFreeCursor(glfwGetX11Display(), cur);
#else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
#endif
#endif #endif
cursorHidden = true; cursorHidden = true;
} }
@ -890,7 +882,7 @@ void EndDrawing(void)
} }
// Initialize 2D mode with custom camera (2D) // Initialize 2D mode with custom camera (2D)
void Begin2dMode(Camera2D camera) void BeginMode2D(Camera2D camera)
{ {
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
@ -908,7 +900,7 @@ void Begin2dMode(Camera2D camera)
} }
// Ends 2D mode with custom camera // Ends 2D mode with custom camera
void End2dMode(void) void EndMode2D(void)
{ {
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
@ -916,7 +908,7 @@ void End2dMode(void)
} }
// Initializes 3D mode with custom camera (3D) // Initializes 3D mode with custom camera (3D)
void Begin3dMode(Camera camera) void BeginMode3D(Camera3D camera)
{ {
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
@ -924,13 +916,26 @@ void Begin3dMode(Camera camera)
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
rlLoadIdentity(); // Reset current matrix (PROJECTION) rlLoadIdentity(); // Reset current matrix (PROJECTION)
// Setup perspective projection
float aspect = (float)screenWidth/(float)screenHeight; float aspect = (float)screenWidth/(float)screenHeight;
if (camera.type == CAMERA_PERSPECTIVE)
{
// Setup perspective projection
double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); double top = 0.01*tan(camera.fovy*0.5*DEG2RAD);
double right = top*aspect; double right = top*aspect;
// NOTE: zNear and zFar values are important when computing depth buffer values
rlFrustum(-right, right, -top, top, 0.01, 1000.0); rlFrustum(-right, right, -top, top, 0.01, 1000.0);
}
else if (camera.type == CAMERA_ORTHOGRAPHIC)
{
// Setup orthographic projection
double top = camera.fovy/2.0;
double right = top*aspect;
rlOrtho(-right,right,-top,top, 0.01, 1000.0);
}
// NOTE: zNear and zFar values are important when computing depth buffer values
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
@ -943,7 +948,7 @@ void Begin3dMode(Camera camera)
} }
// Ends 3D mode and returns to default 2D orthographic mode // Ends 3D mode and returns to default 2D orthographic mode
void End3dMode(void) void EndMode3D(void)
{ {
rlglDraw(); // Process internal buffers (update + draw) rlglDraw(); // Process internal buffers (update + draw)
@ -1018,22 +1023,41 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
TraceLog(LOG_DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); TraceLog(LOG_DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z);
// Calculate projection matrix from perspective
Matrix matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
// Calculate view matrix from camera look at // Calculate view matrix from camera look at
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
Matrix matProj;
if (camera.type == CAMERA_PERSPECTIVE)
{
// Calculate projection matrix from perspective
matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
}
else if (camera.type == CAMERA_ORTHOGRAPHIC)
{
float aspect = (float)screenWidth/(float)screenHeight;
double top = camera.fovy/2.0;
double right = top*aspect;
// Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0);
}
// Unproject far/near points // Unproject far/near points
Vector3 nearPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); Vector3 nearPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
Vector3 farPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); Vector3 farPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
// Unproject the mouse cursor in the near plane.
// We need this as the source position because orthographic projects, compared to perspect doesn't have a
// convergence point, meaning that the "eye" of the camera is more like a plane than a point.
Vector3 cameraPlanePointerPos = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
// Calculate normalized direction vector // Calculate normalized direction vector
Vector3 direction = Vector3Subtract(farPoint, nearPoint); Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint));
Vector3Normalize(&direction);
if (camera.type == CAMERA_PERSPECTIVE) ray.position = camera.position;
else if (camera.type == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos;
// Apply calculated vectors to ray // Apply calculated vectors to ray
ray.position = camera.position;
ray.direction = direction; ray.direction = direction;
return ray; return ray;
@ -1043,7 +1067,21 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
Vector2 GetWorldToScreen(Vector3 position, Camera camera) Vector2 GetWorldToScreen(Vector3 position, Camera camera)
{ {
// Calculate projection matrix (from perspective instead of frustum // Calculate projection matrix (from perspective instead of frustum
Matrix matProj = MatrixPerspective(camera.fovy*DEG2RAD, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0); Matrix matProj;
if(camera.type == CAMERA_PERSPECTIVE)
{
// Calculate projection matrix from perspective
matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0);
}
else if(camera.type == CAMERA_ORTHOGRAPHIC)
{
float aspect = (float)screenWidth/(float)screenHeight;
double top = camera.fovy/2.0;
double right = top*aspect;
// Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0);
}
// Calculate view matrix from camera look at (and transpose it) // Calculate view matrix from camera look at (and transpose it)
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
@ -1052,10 +1090,10 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
Quaternion worldPos = { position.x, position.y, position.z, 1.0f }; Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
// Transform world position to view // Transform world position to view
QuaternionTransform(&worldPos, matView); worldPos = QuaternionTransform(worldPos, matView);
// Transform result to projection (clip space position) // Transform result to projection (clip space position)
QuaternionTransform(&worldPos, matProj); worldPos = QuaternionTransform(worldPos, matProj);
// Calculate normalized device coordinates (inverted y) // Calculate normalized device coordinates (inverted y)
Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w }; Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
@ -1112,25 +1150,25 @@ double GetTime(void)
#endif #endif
} }
// Returns normalized float array for a Color
float *ColorToFloat(Color color)
{
static float buffer[4];
buffer[0] = (float)color.r/255;
buffer[1] = (float)color.g/255;
buffer[2] = (float)color.b/255;
buffer[3] = (float)color.a/255;
return buffer;
}
// Returns hexadecimal value for a Color // Returns hexadecimal value for a Color
int ColorToInt(Color color) int ColorToInt(Color color)
{ {
return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
} }
// Returns color normalized as float [0..1]
Vector4 ColorNormalize(Color color)
{
Vector4 result;
result.x = (float)color.r/255.0f;
result.y = (float)color.g/255.0f;
result.z = (float)color.b/255.0f;
result.w = (float)color.a/255.0f;
return result;
}
// Returns HSV values for a Color // Returns HSV values for a Color
// NOTE: Hue is returned as degrees [0..360] // NOTE: Hue is returned as degrees [0..360]
Vector3 ColorToHSV(Color color) Vector3 ColorToHSV(Color color)
@ -1257,7 +1295,24 @@ bool IsFileExtension(const char *fileName, const char *ext)
if ((fileExt = strrchr(fileName, '.')) != NULL) if ((fileExt = strrchr(fileName, '.')) != NULL)
{ {
#if defined(_WIN32)
result = true;
int extLen = strlen(ext);
if (strlen(fileExt) == extLen)
{
for (int i = 0; i < extLen; i++)
{
if (tolower(fileExt[i]) != tolower(ext[i]))
{
result = false;
break;
}
}
}
#else
if (strcmp(fileExt, ext) == 0) result = true; if (strcmp(fileExt, ext) == 0) result = true;
#endif
} }
return result; return result;
@ -1268,7 +1323,7 @@ const char *GetExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); const char *dot = strrchr(fileName, '.');
if (!dot || dot == fileName) return ""; if (!dot || dot == fileName) return NULL;
return (dot + 1); return (dot + 1);
} }
@ -1315,24 +1370,32 @@ bool ChangeDirectory(const char *dir)
return (CHDIR(dir) == 0); return (CHDIR(dir) == 0);
} }
#if defined(PLATFORM_DESKTOP)
// Check if a file has been dropped into window // Check if a file has been dropped into window
bool IsFileDropped(void) bool IsFileDropped(void)
{ {
#if defined(PLATFORM_DESKTOP)
if (dropFilesCount > 0) return true; if (dropFilesCount > 0) return true;
else return false; else return false;
#else
return false;
#endif
} }
// Get dropped files names // Get dropped files names
char **GetDroppedFiles(int *count) char **GetDroppedFiles(int *count)
{ {
#if defined(PLATFORM_DESKTOP)
*count = dropFilesCount; *count = dropFilesCount;
return dropFilesPath; return dropFilesPath;
#else
return NULL;
#endif
} }
// Clear dropped files paths buffer // Clear dropped files paths buffer
void ClearDroppedFiles(void) void ClearDroppedFiles(void)
{ {
#if defined(PLATFORM_DESKTOP)
if (dropFilesCount > 0) if (dropFilesCount > 0)
{ {
for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]); for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]);
@ -1341,8 +1404,8 @@ void ClearDroppedFiles(void)
dropFilesCount = 0; dropFilesCount = 0;
} }
}
#endif #endif
}
// Save integer value to storage file (to defined position) // Save integer value to storage file (to defined position)
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) // NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
@ -1663,7 +1726,7 @@ int GetMouseX(void)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
return (int)touchPosition[0].x; return (int)touchPosition[0].x;
#else #else
return (int)mousePosition.x; return (int)(mousePosition.x*mouseScale);
#endif #endif
} }
@ -1673,7 +1736,7 @@ int GetMouseY(void)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
return (int)touchPosition[0].x; return (int)touchPosition[0].x;
#else #else
return (int)mousePosition.y; return (int)(mousePosition.y*mouseScale);
#endif #endif
} }
@ -1683,7 +1746,7 @@ Vector2 GetMousePosition(void)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
return GetTouchPosition(0); return GetTouchPosition(0);
#else #else
return mousePosition; return (Vector2){ mousePosition.x*mouseScale, mousePosition.y*mouseScale };
#endif #endif
} }
@ -1697,6 +1760,15 @@ void SetMousePosition(Vector2 position)
#endif #endif
} }
// Set mouse scaling
// NOTE: Useful when rendering to different size targets
void SetMouseScale(float scale)
{
#if !defined(PLATFORM_ANDROID)
mouseScale = scale;
#endif
}
// Returns mouse wheel movement Y // Returns mouse wheel movement Y
int GetMouseWheelMove(void) int GetMouseWheelMove(void)
{ {
@ -2219,8 +2291,8 @@ static bool InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
EGLint displayFormat; EGLint displayFormat;
displayWidth = ANativeWindow_getWidth(app->window); displayWidth = ANativeWindow_getWidth(androidApp->window);
displayHeight = ANativeWindow_getHeight(app->window); displayHeight = ANativeWindow_getHeight(androidApp->window);
// EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
// As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
@ -2230,10 +2302,10 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView
SetupFramebufferSize(displayWidth, displayHeight); SetupFramebufferSize(displayWidth, displayHeight);
ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat); ANativeWindow_setBuffersGeometry(androidApp->window, renderWidth, renderHeight, displayFormat);
//ANativeWindow_setBuffersGeometry(app->window, 0, 0, displayFormat); // Force use of native display size //ANativeWindow_setBuffersGeometry(androidApp->window, 0, 0, displayFormat); // Force use of native display size
surface = eglCreateWindowSurface(display, config, app->window, NULL); surface = eglCreateWindowSurface(display, config, androidApp->window, NULL);
#endif // defined(PLATFORM_ANDROID) #endif // defined(PLATFORM_ANDROID)
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
@ -2639,14 +2711,14 @@ static void PollInputEvents(void)
while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0)
{ {
// Process this event // Process this event
if (source != NULL) source->process(app, source); if (source != NULL) source->process(androidApp, source);
// NOTE: Never close window, native activity is controlled by the system! // NOTE: Never close window, native activity is controlled by the system!
if (app->destroyRequested != 0) if (androidApp->destroyRequested != 0)
{ {
//TraceLog(LOG_INFO, "Closing Window..."); //TraceLog(LOG_INFO, "Closing Window...");
//windowShouldClose = true; //windowShouldClose = true;
//ANativeActivity_finish(app->activity); //ANativeActivity_finish(androidApp->activity);
} }
} }
#endif #endif
@ -2724,10 +2796,12 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
} }
else else
#endif // SUPPORT_GIF_RECORDING #endif // SUPPORT_GIF_RECORDING
#if defined(SUPPORT_SCREEN_CAPTURE)
{ {
TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter)); TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter));
screenshotCounter++; screenshotCounter++;
} }
#endif // SUPPORT_SCREEN_CAPTURE
} }
#endif // PLATFORM_DESKTOP #endif // PLATFORM_DESKTOP
else else
@ -2832,7 +2906,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
rlClearScreenBuffers(); // Clear screen buffers (color and depth) rlClearScreenBuffers(); // Clear screen buffers (color and depth)
// Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode()) // Window size must be updated to be used on 3D mode to get new aspect ratio (BeginMode3D())
// NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor, // NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor,
// for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported) // for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported)
screenWidth = width; screenWidth = width;
@ -2983,14 +3057,14 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
case APP_CMD_DESTROY: case APP_CMD_DESTROY:
{ {
// TODO: Finish activity? // TODO: Finish activity?
//ANativeActivity_finish(app->activity); //ANativeActivity_finish(androidApp->activity);
TraceLog(LOG_INFO, "APP_CMD_DESTROY"); TraceLog(LOG_INFO, "APP_CMD_DESTROY");
} break; } break;
case APP_CMD_CONFIG_CHANGED: case APP_CMD_CONFIG_CHANGED:
{ {
//AConfiguration_fromAssetManager(app->config, app->activity->assetManager); //AConfiguration_fromAssetManager(androidApp->config, androidApp->activity->assetManager);
//print_cur_config(app); //print_cur_config(androidApp);
// Check screen orientation here! // Check screen orientation here!
@ -3389,12 +3463,14 @@ static void ProcessKeyboard(void)
// Check exit key (same functionality as GLFW3 KeyCallback()) // Check exit key (same functionality as GLFW3 KeyCallback())
if (currentKeyState[exitKey] == 1) windowShouldClose = true; if (currentKeyState[exitKey] == 1) windowShouldClose = true;
#if defined(SUPPORT_SCREEN_CAPTURE)
// Check screen capture key (raylib key: KEY_F12) // Check screen capture key (raylib key: KEY_F12)
if (currentKeyState[301] == 1) if (currentKeyState[301] == 1)
{ {
TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter)); TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter));
screenshotCounter++; screenshotCounter++;
} }
#endif
} }
// Restore default keyboard input // Restore default keyboard input

View file

@ -55,6 +55,13 @@ func CloseWindow() {
C.CloseWindow() C.CloseWindow()
} }
// IsWindowReady - Check if window has been initialized successfully
func IsWindowReady() bool {
ret := C.IsWindowReady()
v := bool(int(ret) == 1)
return v
}
// WindowShouldClose - Detect if KEY_ESCAPE pressed or Close icon pressed // WindowShouldClose - Detect if KEY_ESCAPE pressed or Close icon pressed
func WindowShouldClose() bool { func WindowShouldClose() bool {
ret := C.WindowShouldClose() ret := C.WindowShouldClose()
@ -100,6 +107,20 @@ func SetWindowMonitor(monitor int32) {
C.SetWindowMonitor(cmonitor) C.SetWindowMonitor(cmonitor)
} }
// SetWindowMinSize - Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
func SetWindowMinSize(w, h int32) {
cw := (C.int)(w)
ch := (C.int)(h)
C.SetWindowMinSize(cw, ch)
}
// SetWindowSize - Set window dimensions
func SetWindowSize(w, h int32) {
cw := (C.int)(w)
ch := (C.int)(h)
C.SetWindowSize(cw, ch)
}
// GetScreenWidth - Get current screen width // GetScreenWidth - Get current screen width
func GetScreenWidth() int32 { func GetScreenWidth() int32 {
ret := C.GetScreenWidth() ret := C.GetScreenWidth()
@ -130,26 +151,26 @@ func EndDrawing() {
C.EndDrawing() C.EndDrawing()
} }
// Begin2dMode - Initialize 2D mode with custom camera // BeginMode2D - Initialize 2D mode with custom camera
func Begin2dMode(camera Camera2D) { func BeginMode2D(camera Camera2D) {
ccamera := camera.cptr() ccamera := camera.cptr()
C.Begin2dMode(*ccamera) C.BeginMode2D(*ccamera)
} }
// End2dMode - Ends 2D mode custom camera usage // EndMode2D - Ends 2D mode custom camera usage
func End2dMode() { func EndMode2D() {
C.End2dMode() C.EndMode2D()
} }
// Begin3dMode - Initializes 3D mode for drawing (Camera setup) // BeginMode3D - Initializes 3D mode for drawing (Camera setup)
func Begin3dMode(camera Camera) { func BeginMode3D(camera Camera) {
ccamera := camera.cptr() ccamera := camera.cptr()
C.Begin3dMode(*ccamera) C.BeginMode3D(*ccamera)
} }
// End3dMode - Ends 3D mode and returns to default 2D orthographic mode // EndMode3D - Ends 3D mode and returns to default 2D orthographic mode
func End3dMode() { func EndMode3D() {
C.End3dMode() C.EndMode3D()
} }
// BeginTextureMode - Initializes render texture for drawing // BeginTextureMode - Initializes render texture for drawing
@ -241,15 +262,15 @@ func ColorToHSV(color Color) Vector3 {
return v return v
} }
// ColorToFloat - Converts Color to float32 slice and normalizes // ColorNormalize - Returns color normalized as float [0..1]
func ColorToFloat(color Color) []float32 { func ColorNormalize(color Color) Vector4 {
data := make([]float32, 0) result := Vector4{}
data[0] = float32(color.R) / 255 result.X = float32(color.R) / 255
data[0] = float32(color.G) / 255 result.Y = float32(color.G) / 255
data[0] = float32(color.B) / 255 result.Z = float32(color.B) / 255
data[0] = float32(color.A) / 255 result.W = float32(color.A) / 255
return data return result
} }
// Vector3ToFloat - Converts Vector3 to float32 slice // Vector3ToFloat - Converts Vector3 to float32 slice
@ -527,6 +548,12 @@ func SetMousePosition(position Vector2) {
C.SetMousePosition(*cposition) C.SetMousePosition(*cposition)
} }
// SetMouseScale - Set mouse scaling
func SetMouseScale(scale float32) {
cscale := (C.float)(scale)
C.SetMouseScale(cscale)
}
// GetMouseWheelMove - Returns mouse wheel movement Y // GetMouseWheelMove - Returns mouse wheel movement Y
func GetMouseWheelMove() int32 { func GetMouseWheelMove() int32 {
ret := C.GetMouseWheelMove() ret := C.GetMouseWheelMove()

2841
raylib/external/dr_mp3.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -493,17 +493,37 @@ extern "C" {
* @{ */ * @{ */
/*! @brief If this bit is set one or more Shift keys were held down. /*! @brief If this bit is set one or more Shift keys were held down.
*
* If this bit is set one or more Shift keys were held down.
*/ */
#define GLFW_MOD_SHIFT 0x0001 #define GLFW_MOD_SHIFT 0x0001
/*! @brief If this bit is set one or more Control keys were held down. /*! @brief If this bit is set one or more Control keys were held down.
*
* If this bit is set one or more Control keys were held down.
*/ */
#define GLFW_MOD_CONTROL 0x0002 #define GLFW_MOD_CONTROL 0x0002
/*! @brief If this bit is set one or more Alt keys were held down. /*! @brief If this bit is set one or more Alt keys were held down.
*
* If this bit is set one or more Alt keys were held down.
*/ */
#define GLFW_MOD_ALT 0x0004 #define GLFW_MOD_ALT 0x0004
/*! @brief If this bit is set one or more Super keys were held down. /*! @brief If this bit is set one or more Super keys were held down.
*
* If this bit is set one or more Super keys were held down.
*/ */
#define GLFW_MOD_SUPER 0x0008 #define GLFW_MOD_SUPER 0x0008
/*! @brief If this bit is set the Caps Lock key is enabled.
*
* If this bit is set the Caps Lock key is enabled and the @ref
* GLFW_LOCK_KEY_MODS input mode is set.
*/
#define GLFW_MOD_CAPS_LOCK 0x0010
/*! @brief If this bit is set the Num Lock key is enabled.
*
* If this bit is set the Num Lock key is enabled and the @ref
* GLFW_LOCK_KEY_MODS input mode is set.
*/
#define GLFW_MOD_NUM_LOCK 0x0020
/*! @} */ /*! @} */
@ -794,6 +814,11 @@ extern "C" {
* [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib).
*/ */
#define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A #define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A
/*! @brief Mouse cursor hover window attribute.
*
* Mouse cursor hover [window attribute](@ref GLFW_HOVERED_attrib).
*/
#define GLFW_HOVERED 0x0002000B
/*! @brief Framebuffer bit depth hint. /*! @brief Framebuffer bit depth hint.
* *
@ -944,8 +969,11 @@ extern "C" {
#define GLFW_CONTEXT_CREATION_API 0x0002200B #define GLFW_CONTEXT_CREATION_API 0x0002200B
#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001
#define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002 #define GLFW_COCOA_FRAME_NAME 0x00023002
#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003
#define GLFW_X11_CLASS_NAME 0x00024001
#define GLFW_X11_INSTANCE_NAME 0x00024002
/*! @} */ /*! @} */
#define GLFW_NO_API 0 #define GLFW_NO_API 0
@ -963,6 +991,7 @@ extern "C" {
#define GLFW_CURSOR 0x00033001 #define GLFW_CURSOR 0x00033001
#define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_KEYS 0x00033002
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
#define GLFW_LOCK_KEY_MODS 0x00033004
#define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_NORMAL 0x00034001
#define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_HIDDEN 0x00034002
@ -1025,9 +1054,6 @@ extern "C" {
#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001
#define GLFW_COCOA_MENUBAR 0x00051002 #define GLFW_COCOA_MENUBAR 0x00051002
#define GLFW_X11_WM_CLASS_NAME 0x00052001
#define GLFW_X11_WM_CLASS_CLASS 0x00052002
/*! @} */ /*! @} */
#define GLFW_DONT_CARE -1 #define GLFW_DONT_CARE -1
@ -1046,7 +1072,7 @@ extern "C" {
* @sa @ref glfwGetProcAddress * @sa @ref glfwGetProcAddress
* *
* @since Added in version 3.0. * @since Added in version 3.0.
*
* @ingroup context * @ingroup context
*/ */
typedef void (*GLFWglproc)(void); typedef void (*GLFWglproc)(void);
@ -1257,6 +1283,24 @@ typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int);
*/ */
typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
/*! @brief The function signature for window content scale callbacks.
*
* This is the function signature for window content scale callback
* functions.
*
* @param[in] window The window whose content scale changed.
* @param[in] xscale The new x-axis content scale of the window.
* @param[in] yscale The new y-axis content scale of the window.
*
* @sa @ref window_scale
* @sa @ref glfwSetWindowContentScaleCallback
*
* @since Added in version 3.3.
*
* @ingroup window
*/
typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float);
/*! @brief The function signature for mouse button callbacks. /*! @brief The function signature for mouse button callbacks.
* *
* This is the function signature for mouse button callback functions. * This is the function signature for mouse button callback functions.
@ -1414,7 +1458,8 @@ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**);
* This is the function signature for monitor configuration callback functions. * This is the function signature for monitor configuration callback functions.
* *
* @param[in] monitor The monitor that was connected or disconnected. * @param[in] monitor The monitor that was connected or disconnected.
* @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Remaining
* values reserved for future use.
* *
* @sa @ref monitor_event * @sa @ref monitor_event
* @sa @ref glfwSetMonitorCallback * @sa @ref glfwSetMonitorCallback
@ -1431,7 +1476,8 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
* functions. * functions.
* *
* @param[in] jid The joystick that was connected or disconnected. * @param[in] jid The joystick that was connected or disconnected.
* @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Remaining
* values reserved for future use.
* *
* @sa @ref joystick_event * @sa @ref joystick_event
* @sa @ref glfwSetJoystickCallback * @sa @ref glfwSetJoystickCallback
@ -1623,8 +1669,7 @@ GLFWAPI void glfwTerminate(void);
/*! @brief Sets the specified init hint to the desired value. /*! @brief Sets the specified init hint to the desired value.
* *
* This function sets hints for the next initialization of GLFW. Only integer * This function sets hints for the next initialization of GLFW.
* type hints can be set with this function.
* *
* The values you set hints to are never reset by GLFW, but they only take * The values you set hints to are never reset by GLFW, but they only take
* effect during initialization. Once GLFW has been initialized, any values * effect during initialization. Once GLFW has been initialized, any values
@ -1647,7 +1692,6 @@ GLFWAPI void glfwTerminate(void);
* *
* @sa init_hints * @sa init_hints
* @sa glfwInit * @sa glfwInit
* @sa glfwInitHintString
* *
* @since Added in version 3.3. * @since Added in version 3.3.
* *
@ -1655,40 +1699,6 @@ GLFWAPI void glfwTerminate(void);
*/ */
GLFWAPI void glfwInitHint(int hint, int value); GLFWAPI void glfwInitHint(int hint, int value);
/*! @brief Sets the specified init hint to the desired value.
*
* This function sets hints for the next initialization of GLFW. Only string
* type hints can be set with this function.
*
* The values you set hints to are never reset by GLFW, but they only take
* effect during initialization. Once GLFW has been initialized, any values
* you set will be ignored until the library is terminated and initialized
* again.
*
* Some hints are platform specific. These may be set on any platform but they
* will only affect their specific platform. Other platforms will ignore them.
* Setting these hints requires no platform specific headers or functions.
*
* @param[in] hint The [init hint](@ref init_hints) to set.
* @param[in] value The new value of the init hint.
*
* @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref
* GLFW_INVALID_VALUE.
*
* @remarks This function may be called before @ref glfwInit.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa init_hints
* @sa glfwInit
* @sa glfwInitHint
*
* @since Added in version 3.3.
*
* @ingroup init
*/
GLFWAPI void glfwInitHintString(int hint, const char* value);
/*! @brief Retrieves the version of the GLFW library. /*! @brief Retrieves the version of the GLFW library.
* *
* This function retrieves the major, minor and revision numbers of the GLFW * This function retrieves the major, minor and revision numbers of the GLFW
@ -1985,6 +1995,56 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, flo
*/ */
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
/*! @brief Sets the user pointer of the specified monitor.
*
* This function sets the user-defined pointer of the specified monitor. The
* current value is retained until the monitor is disconnected. The initial
* value is `NULL`.
*
* This function may be called from the monitor callback, even for a monitor
* that is being disconnected.
*
* @param[in] monitor The monitor whose pointer to set.
* @param[in] pointer The new value.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @sa @ref monitor_userptr
* @sa @ref glfwGetMonitorUserPointer
*
* @since Added in version 3.3.
*
* @ingroup monitor
*/
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer);
/*! @brief Returns the user pointer of the specified monitor.
*
* This function returns the current value of the user-defined pointer of the
* specified monitor. The initial value is `NULL`.
*
* This function may be called from the monitor callback, even for a monitor
* that is being disconnected.
*
* @param[in] monitor The monitor whose pointer to return.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @sa @ref monitor_userptr
* @sa @ref glfwSetMonitorUserPointer
*
* @since Added in version 3.3.
*
* @ingroup monitor
*/
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor);
/*! @brief Sets the monitor configuration callback. /*! @brief Sets the monitor configuration callback.
* *
* This function sets the monitor configuration callback, or removes the * This function sets the monitor configuration callback, or removes the
@ -2184,6 +2244,7 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
* *
* @sa @ref window_hints * @sa @ref window_hints
* @sa @ref glfwWindowHint * @sa @ref glfwWindowHint
* @sa @ref glfwWindowHintString
* *
* @since Added in version 3.0. * @since Added in version 3.0.
* *
@ -2194,14 +2255,20 @@ GLFWAPI void glfwDefaultWindowHints(void);
/*! @brief Sets the specified window hint to the desired value. /*! @brief Sets the specified window hint to the desired value.
* *
* This function sets hints for the next call to @ref glfwCreateWindow. The * This function sets hints for the next call to @ref glfwCreateWindow. The
* hints, once set, retain their values until changed by a call to @ref * hints, once set, retain their values until changed by a call to this
* glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is * function or @ref glfwDefaultWindowHints, or until the library is terminated.
* terminated. *
* Only integer value hints can be set with this function. String value hints
* are set with @ref glfwWindowHintString.
* *
* This function does not check whether the specified hint values are valid. * This function does not check whether the specified hint values are valid.
* If you set hints to invalid values this will instead be reported by the next * If you set hints to invalid values this will instead be reported by the next
* call to @ref glfwCreateWindow. * call to @ref glfwCreateWindow.
* *
* Some hints are platform specific. These may be set on any platform but they
* will only affect their specific platform. Other platforms will ignore them.
* Setting these hints requires no platform specific headers or functions.
*
* @param[in] hint The [window hint](@ref window_hints) to set. * @param[in] hint The [window hint](@ref window_hints) to set.
* @param[in] value The new value of the window hint. * @param[in] value The new value of the window hint.
* *
@ -2211,6 +2278,7 @@ GLFWAPI void glfwDefaultWindowHints(void);
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_hints * @sa @ref window_hints
* @sa @ref glfwWindowHintString
* @sa @ref glfwDefaultWindowHints * @sa @ref glfwDefaultWindowHints
* *
* @since Added in version 3.0. Replaces `glfwOpenWindowHint`. * @since Added in version 3.0. Replaces `glfwOpenWindowHint`.
@ -2219,6 +2287,44 @@ GLFWAPI void glfwDefaultWindowHints(void);
*/ */
GLFWAPI void glfwWindowHint(int hint, int value); GLFWAPI void glfwWindowHint(int hint, int value);
/*! @brief Sets the specified window hint to the desired value.
*
* This function sets hints for the next call to @ref glfwCreateWindow. The
* hints, once set, retain their values until changed by a call to this
* function or @ref glfwDefaultWindowHints, or until the library is terminated.
*
* Only string type hints can be set with this function. Integer value hints
* are set with @ref glfwWindowHint.
*
* This function does not check whether the specified hint values are valid.
* If you set hints to invalid values this will instead be reported by the next
* call to @ref glfwCreateWindow.
*
* Some hints are platform specific. These may be set on any platform but they
* will only affect their specific platform. Other platforms will ignore them.
* Setting these hints requires no platform specific headers or functions.
*
* @param[in] hint The [window hint](@ref window_hints) to set.
* @param[in] value The new value of the window hint.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_ENUM.
*
* @pointer_lifetime The specified string is copied before this function
* returns.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_hints
* @sa @ref glfwWindowHint
* @sa @ref glfwDefaultWindowHints
*
* @since Added in version 3.3.
*
* @ingroup window
*/
GLFWAPI void glfwWindowHintString(int hint, const char* value);
/*! @brief Creates a window and its associated context. /*! @brief Creates a window and its associated context.
* *
* This function creates a window and its associated OpenGL or OpenGL ES * This function creates a window and its associated OpenGL or OpenGL ES
@ -2329,9 +2435,8 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* `CMake/MacOSXBundleInfo.plist.in` in the source tree. * `CMake/MacOSXBundleInfo.plist.in` in the source tree.
* *
* @remark @macos When activating frame autosaving with * @remark @macos When activating frame autosaving with
* [GLFW_COCOA_FRAME_AUTOSAVE](@ref GLFW_COCOA_FRAME_AUTOSAVE_hint), the * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified
* specified window size may be overriden by a previously saved size and * window size and position may be overriden by previously saved values.
* position.
* *
* @remark @x11 Some window managers will not respect the placement of * @remark @x11 Some window managers will not respect the placement of
* initially hidden windows. * initially hidden windows.
@ -2341,23 +2446,22 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* query the final size, position or other attributes directly after window * query the final size, position or other attributes directly after window
* creation. * creation.
* *
* @remark @x11 The name and class of the `WM_CLASS` window property will by * @remark @x11 The class part of the `WM_CLASS` window property will by
* default be set to the window title passed to this function. Set the @ref * default be set to the window title passed to this function. The instance
* GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before * part will use the contents of the `RESOURCE_NAME` environment variable, if
* initialization to override this. * present and not empty, or fall back to the window title. Set the @ref
* GLFW_X11_CLASS_NAME and @ref GLFW_X11_INSTANCE_NAME window hints to override
* this.
* *
* @remark @wayland The window frame is currently unimplemented, as if * @remark @wayland The window frame is currently very simple, only allowing
* [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`. * window resize or move. A compositor can still emit close, maximize or
* A compositor can still emit close, resize or maximize events, using for * fullscreen events, using for example a keybind mechanism. Additionally,
* example a keybind mechanism. * the wp_viewporter protocol is required for this feature, otherwise the
* window will not be decorated.
* *
* @remark @wayland A full screen window will not attempt to change the mode, * @remark @wayland A full screen window will not attempt to change the mode,
* no matter what the requested size or refresh rate. * no matter what the requested size or refresh rate.
* *
* @remark @wayland The wl_shell protocol does not support window
* icons, the window will inherit the one defined in the application's
* desktop file, so this function emits @ref GLFW_PLATFORM_ERROR.
*
* @remark @wayland Screensaver inhibition requires the idle-inhibit protocol * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol
* to be implemented in the user's compositor. * to be implemented in the user's compositor.
* *
@ -2501,9 +2605,9 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
* in the Mac Developer Library. * in the Mac Developer Library.
* *
* @remark @wayland The wl_shell protocol does not support icons, the window * @remark @wayland There is no existing protocol to change an icon, the
* will inherit the one defined in the application's desktop file, so this * window will thus inherit the one defined in the application's desktop file.
* function emits @ref GLFW_PLATFORM_ERROR. * This function always emits @ref GLFW_PLATFORM_ERROR.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -2795,10 +2899,6 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height)
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland The window frame is currently unimplemented, as if
* [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`,
* so the returned values will always be zero.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_size * @sa @ref window_size
@ -2831,6 +2931,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_scale * @sa @ref window_scale
* @sa @ref glfwSetWindowContentScaleCallback
* @sa @ref glfwGetMonitorContentScale * @sa @ref glfwGetMonitorContentScale
* *
* @since Added in version 3.3. * @since Added in version 3.3.
@ -2910,7 +3011,8 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland There is no concept of iconification in wl_shell, this * @remark @wayland There is no concept of iconification in wl_shell, this
* function will always emit @ref GLFW_PLATFORM_ERROR. * function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated
* protocol.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -3435,7 +3537,7 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
* @remark @wayland The wl_shell protocol has no concept of iconification, * @remark @wayland The wl_shell protocol has no concept of iconification,
* this callback will never be called. * this callback will never be called when using this deprecated protocol.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
@ -3493,6 +3595,30 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window,
*/ */
GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun);
/*! @brief Sets the window content scale callback for the specified window.
*
* This function sets the window content scale callback of the specified window,
* which is called when the content scale of the specified window changes.
*
* @param[in] window The window whose callback to set.
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_scale
* @sa @ref glfwGetWindowContentScale
*
* @since Added in version 3.3.
*
* @ingroup window
*/
GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun cbfun);
/*! @brief Processes all pending events. /*! @brief Processes all pending events.
* *
* This function processes only those events that are already in the event * This function processes only those events that are already in the event
@ -3657,12 +3783,12 @@ GLFWAPI void glfwPostEmptyEvent(void);
/*! @brief Returns the value of an input option for the specified window. /*! @brief Returns the value of an input option for the specified window.
* *
* This function returns the value of an input option for the specified window. * This function returns the value of an input option for the specified window.
* The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
* @ref GLFW_STICKY_MOUSE_BUTTONS. * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
* *
* @param[in] window The window to query. * @param[in] window The window to query.
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
* `GLFW_STICKY_MOUSE_BUTTONS`. * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_ENUM. * GLFW_INVALID_ENUM.
@ -3680,8 +3806,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
/*! @brief Sets an input option for the specified window. /*! @brief Sets an input option for the specified window.
* *
* This function sets an input mode option for the specified window. The mode * This function sets an input mode option for the specified window. The mode
* must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
* @ref GLFW_STICKY_MOUSE_BUTTONS. * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
* *
* If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
* modes: * modes:
@ -3707,9 +3833,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* you are only interested in whether mouse buttons have been pressed but not * you are only interested in whether mouse buttons have been pressed but not
* when or in which order. * when or in which order.
* *
* If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to
* enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled,
* callbacks that receive modifier bits will also have the @ref
* GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on,
* and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on.
*
* @param[in] window The window whose input mode to set. * @param[in] window The window whose input mode to set.
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
* `GLFW_STICKY_MOUSE_BUTTONS`. * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
* @param[in] value The new value of the specified input mode. * @param[in] value The new value of the specified input mode.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
@ -4556,6 +4688,56 @@ GLFWAPI const char* glfwGetJoystickName(int jid);
*/ */
GLFWAPI const char* glfwGetJoystickGUID(int jid); GLFWAPI const char* glfwGetJoystickGUID(int jid);
/*! @brief Sets the user pointer of the specified joystick.
*
* This function sets the user-defined pointer of the specified joystick. The
* current value is retained until the joystick is disconnected. The initial
* value is `NULL`.
*
* This function may be called from the joystick callback, even for a joystick
* that is being disconnected.
*
* @param[in] joystick The joystick whose pointer to set.
* @param[in] pointer The new value.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @sa @ref joystick_userptr
* @sa @ref glfwGetJoystickUserPointer
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer);
/*! @brief Returns the user pointer of the specified joystick.
*
* This function returns the current value of the user-defined pointer of the
* specified joystick. The initial value is `NULL`.
*
* This function may be called from the joystick callback, even for a joystick
* that is being disconnected.
*
* @param[in] joystick The joystick whose pointer to return.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @sa @ref joystick_userptr
* @sa @ref glfwSetJoystickUserPointer
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI void* glfwGetJoystickUserPointer(int jid);
/*! @brief Returns whether the specified joystick has a gamepad mapping. /*! @brief Returns whether the specified joystick has a gamepad mapping.
* *
* This function returns whether the specified joystick is both present and has * This function returns whether the specified joystick is both present and has
@ -4969,7 +5151,7 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window);
* is sometimes called _vertical synchronization_, _vertical retrace * is sometimes called _vertical synchronization_, _vertical retrace
* synchronization_ or just _vsync_. * synchronization_ or just _vsync_.
* *
* A context that support either of the `WGL_EXT_swap_control_tear` and * A context that supports either of the `WGL_EXT_swap_control_tear` and
* `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap
* intervals, which allows the driver to swap immediately even if a frame * intervals, which allows the driver to swap immediately even if a frame
* arrives a little bit late. You can check for these extensions with @ref * arrives a little bit late. You can check for these extensions with @ref
@ -5258,6 +5440,11 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys
* glfwGetRequiredInstanceExtensions to check what instance extensions are * glfwGetRequiredInstanceExtensions to check what instance extensions are
* required. * required.
* *
* The window surface cannot be shared with another API so the window must
* have been created with the [client api hint](@ref GLFW_CLIENT_API_attrib)
* set to `GLFW_NO_API` otherwise it generates a @ref GLFW_INVALID_VALUE error
* and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`.
*
* The window surface must be destroyed before the specified Vulkan instance. * The window surface must be destroyed before the specified Vulkan instance.
* It is the responsibility of the caller to destroy the window surface. GLFW * It is the responsibility of the caller to destroy the window surface. GLFW
* does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the
@ -5273,7 +5460,7 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys
* [error](@ref error_handling) occurred. * [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * GLFW_API_UNAVAILABLE, @ref GLFW_PLATFORM_ERROR and @ref GLFW_INVALID_VALUE
* *
* @remark If an error occurs before the creation call is made, GLFW returns * @remark If an error occurs before the creation call is made, GLFW returns
* the Vulkan error code most appropriate for the error. Appropriate use of * the Vulkan error code most appropriate for the error. Appropriate use of

View file

@ -264,7 +264,7 @@ void _glfwPollMonitorsNS(void)
const CGSize size = CGDisplayScreenSize(displays[i]); const CGSize size = CGDisplayScreenSize(displays[i]);
char* name = getDisplayName(displays[i]); char* name = getDisplayName(displays[i]);
if (!name) if (!name)
name = strdup("Unknown"); name = _glfw_strdup("Unknown");
monitor = _glfwAllocMonitor(name, size.width, size.height); monitor = _glfwAllocMonitor(name, size.width, size.height);
monitor->ns.displayID = displays[i]; monitor->ns.displayID = displays[i];
@ -287,7 +287,7 @@ void _glfwPollMonitorsNS(void)
// Change the current video mode // Change the current video mode
// //
GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{ {
CFArrayRef modes; CFArrayRef modes;
CFIndex count, i; CFIndex count, i;
@ -299,7 +299,7 @@ GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
best = _glfwChooseVideoMode(monitor, desired); best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current); _glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0) if (_glfwCompareVideoModes(&current, best) == 0)
return GLFW_TRUE; return;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
@ -332,15 +332,6 @@ GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
CFRelease(modes); CFRelease(modes);
CVDisplayLinkRelease(link); CVDisplayLinkRelease(link);
if (!native)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Monitor mode list changed");
return GLFW_FALSE;
}
return GLFW_TRUE;
} }
// Restore the previously saved (original) video mode // Restore the previously saved (original) video mode
@ -364,6 +355,10 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);

View file

@ -88,9 +88,10 @@ typedef struct _GLFWwindowNS
GLFWbool maximized; GLFWbool maximized;
// Cached window and framebuffer sizes used to filter out duplicate events // Cached window properties to filter out duplicate events
int width, height; int width, height;
int fbWidth, fbHeight; int fbWidth, fbHeight;
float xscale, yscale;
// The total sum of the distances the cursor has been warped // The total sum of the distances the cursor has been warped
// since the last cursor motion event was processed // since the last cursor motion event was processed
@ -163,6 +164,6 @@ typedef struct _GLFWtimerNS
void _glfwInitTimerNS(void); void _glfwInitTimerNS(void);
void _glfwPollMonitorsNS(void); void _glfwPollMonitorsNS(void);
GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);

View file

@ -43,6 +43,7 @@
#define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagControl NSControlKeyMask
#define NSEventModifierFlagOption NSAlternateKeyMask #define NSEventModifierFlagOption NSAlternateKeyMask
#define NSEventModifierFlagShift NSShiftKeyMask #define NSEventModifierFlagShift NSShiftKeyMask
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
#define NSEventMaskAny NSAnyEventMask #define NSEventMaskAny NSAnyEventMask
#define NSEventTypeApplicationDefined NSApplicationDefined #define NSEventTypeApplicationDefined NSApplicationDefined
@ -137,9 +138,9 @@ static float transformY(float y)
// Make the specified window and its video mode active on its monitor // Make the specified window and its video mode active on its monitor
// //
static GLFWbool acquireMonitor(_GLFWwindow* window) static void acquireMonitor(_GLFWwindow* window)
{ {
const GLFWbool status = _glfwSetVideoModeNS(window->monitor, &window->videoMode); _glfwSetVideoModeNS(window->monitor, &window->videoMode);
const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
const NSRect frame = NSMakeRect(bounds.origin.x, const NSRect frame = NSMakeRect(bounds.origin.x,
transformY(bounds.origin.y + bounds.size.height), transformY(bounds.origin.y + bounds.size.height),
@ -149,7 +150,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
[window->ns.object setFrame:frame display:YES]; [window->ns.object setFrame:frame display:YES];
_glfwInputMonitorWindow(window->monitor, window); _glfwInputMonitorWindow(window->monitor, window);
return status;
} }
// Remove the window and restore the original video mode // Remove the window and restore the original video mode
@ -177,6 +177,8 @@ static int translateFlags(NSUInteger flags)
mods |= GLFW_MOD_ALT; mods |= GLFW_MOD_ALT;
if (flags & NSEventModifierFlagCommand) if (flags & NSEventModifierFlagCommand)
mods |= GLFW_MOD_SUPER; mods |= GLFW_MOD_SUPER;
if (flags & NSEventModifierFlagCapsLock)
mods |= GLFW_MOD_CAPS_LOCK;
return mods; return mods;
} }
@ -571,6 +573,16 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
window->ns.fbHeight = fbRect.size.height; window->ns.fbHeight = fbRect.size.height;
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
} }
const float xscale = fbRect.size.width / contentRect.size.width;
const float yscale = fbRect.size.height / contentRect.size.height;
if (xscale != window->ns.xscale || yscale != window->ns.yscale)
{
window->ns.xscale = xscale;
window->ns.yscale = yscale;
_glfwInputWindowContentScale(window, xscale, yscale);
}
} }
- (void)drawRect:(NSRect)rect - (void)drawRect:(NSRect)rect
@ -694,7 +706,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
NSUInteger i; NSUInteger i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
paths[i] = strdup([[e nextObject] UTF8String]); paths[i] = _glfw_strdup([[e nextObject] UTF8String]);
_glfwInputDrop(window, (int) count, (const char**) paths); _glfwInputDrop(window, (int) count, (const char**) paths);
@ -1093,8 +1105,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
[window->ns.object zoom:nil]; [window->ns.object zoom:nil];
} }
if (wndconfig->ns.frame) if (strlen(wndconfig->ns.frameName))
[window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->title]]; [window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->ns.frameName]];
window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
@ -1165,11 +1177,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
_glfwPlatformFocusWindow(window); _glfwPlatformFocusWindow(window);
if (!acquireMonitor(window)) acquireMonitor(window);
return GLFW_FALSE;
if (wndconfig->centerCursor)
centerCursor(window);
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1405,6 +1413,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
const NSUInteger styleMask = getStyleMask(window); const NSUInteger styleMask = getStyleMask(window);
[window->ns.object setStyleMask:styleMask]; [window->ns.object setStyleMask:styleMask];
// HACK: Changing the style mask can cause the first responder to be cleared
[window->ns.object makeFirstResponder:window->ns.view]; [window->ns.object makeFirstResponder:window->ns.view];
if (monitor) if (monitor)
@ -1475,6 +1484,20 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return [window->ns.object isZoomed]; return [window->ns.object isZoomed];
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
const NSPoint point = [NSEvent mouseLocation];
if ([NSWindow windowNumberAtPoint:point belowWindowWithWindowNumber:0] !=
[window->ns.object windowNumber])
{
return GLFW_FALSE;
}
return NSPointInRect(point,
[window->ns.object convertRectToScreen:[window->ns.view bounds]]);
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
@ -1511,6 +1534,9 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
if (!initializeAppKit())
return;
for (;;) for (;;)
{ {
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
@ -1786,7 +1812,7 @@ const char* _glfwPlatformGetClipboardString(void)
} }
free(_glfw.ns.clipboardString); free(_glfw.ns.clipboardString);
_glfw.ns.clipboardString = strdup([object UTF8String]); _glfw.ns.clipboardString = _glfw_strdup([object UTF8String]);
return _glfw.ns.clipboardString; return _glfw.ns.clipboardString;
} }

View file

@ -38,8 +38,24 @@
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Checks whether the desired context attributes are valid
//
// This function checks things like whether the specified client API version
// exists and whether all relevant options have supported and non-conflicting
// values
//
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
{ {
if (ctxconfig->share)
{
if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->share->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return GLFW_FALSE;
}
}
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
ctxconfig->source != GLFW_EGL_CONTEXT_API && ctxconfig->source != GLFW_EGL_CONTEXT_API &&
ctxconfig->source != GLFW_OSMESA_CONTEXT_API) ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
@ -155,6 +171,8 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
return GLFW_TRUE; return GLFW_TRUE;
} }
// Chooses the framebuffer config that best matches the desired one
//
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives, const _GLFWfbconfig* alternatives,
unsigned int count) unsigned int count)
@ -321,10 +339,13 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
return closest; return closest;
} }
GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) // Retrieves the attributes of the current context
//
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig)
{ {
int i; int i;
_GLFWwindow* window; _GLFWwindow* previous;
const char* version; const char* version;
const char* prefixes[] = const char* prefixes[] =
{ {
@ -334,11 +355,12 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
NULL NULL
}; };
window = _glfwPlatformGetTls(&_glfw.contextSlot);
window->context.source = ctxconfig->source; window->context.source = ctxconfig->source;
window->context.client = GLFW_OPENGL_API; window->context.client = GLFW_OPENGL_API;
previous = _glfwPlatformGetTls(&_glfw.contextSlot);;
glfwMakeContextCurrent((GLFWwindow*) window);
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
window->context.getProcAddress("glGetIntegerv"); window->context.getProcAddress("glGetIntegerv");
window->context.GetString = (PFNGLGETSTRINGPROC) window->context.GetString = (PFNGLGETSTRINGPROC)
@ -346,6 +368,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
if (!window->context.GetIntegerv || !window->context.GetString) if (!window->context.GetIntegerv || !window->context.GetString)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -363,6 +386,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
"OpenGL ES version string retrieval is broken"); "OpenGL ES version string retrieval is broken");
} }
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -394,6 +418,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
"No version found in OpenGL ES version string"); "No version found in OpenGL ES version string");
} }
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -423,6 +448,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
window->context.major, window->context.minor); window->context.major, window->context.minor);
} }
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -438,6 +464,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Entry point retrieval is broken"); "Entry point retrieval is broken");
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE; return GLFW_FALSE;
} }
} }
@ -544,9 +571,12 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
window->context.swapBuffers(window); window->context.swapBuffers(window);
} }
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_TRUE; return GLFW_TRUE;
} }
// Searches an extension string for the specified extension
//
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
{ {
const char* start = extensions; const char* start = extensions;
@ -587,7 +617,8 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
if (window && window->context.client == GLFW_NO_API) if (window && window->context.client == GLFW_NO_API)
{ {
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
"Cannot make current with a window that has no OpenGL or OpenGL ES context");
return; return;
} }
@ -616,7 +647,8 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
if (window->context.client == GLFW_NO_API) if (window->context.client == GLFW_NO_API)
{ {
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
"Cannot swap buffers of a window that has no OpenGL or OpenGL ES context");
return; return;
} }
@ -632,7 +664,8 @@ GLFWAPI void glfwSwapInterval(int interval)
window = _glfwPlatformGetTls(&_glfw.contextSlot); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot set swap interval without a current OpenGL or OpenGL ES context");
return; return;
} }
@ -649,13 +682,14 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
window = _glfwPlatformGetTls(&_glfw.contextSlot); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot query extension without a current OpenGL or OpenGL ES context");
return GLFW_FALSE; return GLFW_FALSE;
} }
if (*extension == '\0') if (*extension == '\0')
{ {
_glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string"); _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -714,7 +748,8 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
window = _glfwPlatformGetTls(&_glfw.contextSlot); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot query entry point without a current OpenGL or OpenGL ES context");
return NULL; return NULL;
} }

View file

@ -223,7 +223,7 @@ static GLFWglproc getProcAddressGLX(const char* procname)
else if (_glfw.glx.GetProcAddressARB) else if (_glfw.glx.GetProcAddressARB)
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
else else
return dlsym(_glfw.glx.handle, procname); return _glfw_dlsym(_glfw.glx.handle, procname);
} }
// Destroy the OpenGL context // Destroy the OpenGL context
@ -271,7 +271,7 @@ GLFWbool _glfwInitGLX(void)
for (i = 0; sonames[i]; i++) for (i = 0; sonames[i]; i++)
{ {
_glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); _glfw.glx.handle = _glfw_dlopen(sonames[i]);
if (_glfw.glx.handle) if (_glfw.glx.handle)
break; break;
} }
@ -283,35 +283,35 @@ GLFWbool _glfwInitGLX(void)
} }
_glfw.glx.GetFBConfigs = _glfw.glx.GetFBConfigs =
dlsym(_glfw.glx.handle, "glXGetFBConfigs"); _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs");
_glfw.glx.GetFBConfigAttrib = _glfw.glx.GetFBConfigAttrib =
dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
_glfw.glx.GetClientString = _glfw.glx.GetClientString =
dlsym(_glfw.glx.handle, "glXGetClientString"); _glfw_dlsym(_glfw.glx.handle, "glXGetClientString");
_glfw.glx.QueryExtension = _glfw.glx.QueryExtension =
dlsym(_glfw.glx.handle, "glXQueryExtension"); _glfw_dlsym(_glfw.glx.handle, "glXQueryExtension");
_glfw.glx.QueryVersion = _glfw.glx.QueryVersion =
dlsym(_glfw.glx.handle, "glXQueryVersion"); _glfw_dlsym(_glfw.glx.handle, "glXQueryVersion");
_glfw.glx.DestroyContext = _glfw.glx.DestroyContext =
dlsym(_glfw.glx.handle, "glXDestroyContext"); _glfw_dlsym(_glfw.glx.handle, "glXDestroyContext");
_glfw.glx.MakeCurrent = _glfw.glx.MakeCurrent =
dlsym(_glfw.glx.handle, "glXMakeCurrent"); _glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent");
_glfw.glx.SwapBuffers = _glfw.glx.SwapBuffers =
dlsym(_glfw.glx.handle, "glXSwapBuffers"); _glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers");
_glfw.glx.QueryExtensionsString = _glfw.glx.QueryExtensionsString =
dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); _glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
_glfw.glx.CreateNewContext = _glfw.glx.CreateNewContext =
dlsym(_glfw.glx.handle, "glXCreateNewContext"); _glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext");
_glfw.glx.CreateWindow = _glfw.glx.CreateWindow =
dlsym(_glfw.glx.handle, "glXCreateWindow"); _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
_glfw.glx.DestroyWindow = _glfw.glx.DestroyWindow =
dlsym(_glfw.glx.handle, "glXDestroyWindow"); _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
_glfw.glx.GetProcAddress = _glfw.glx.GetProcAddress =
dlsym(_glfw.glx.handle, "glXGetProcAddress"); _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB = _glfw.glx.GetProcAddressARB =
dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
_glfw.glx.GetVisualFromFBConfig = _glfw.glx.GetVisualFromFBConfig =
dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
if (!_glfw.glx.GetFBConfigs || if (!_glfw.glx.GetFBConfigs ||
!_glfw.glx.GetFBConfigAttrib || !_glfw.glx.GetFBConfigAttrib ||
@ -428,7 +428,7 @@ void _glfwTerminateGLX(void)
if (_glfw.glx.handle) if (_glfw.glx.handle)
{ {
dlclose(_glfw.glx.handle); _glfw_dlclose(_glfw.glx.handle);
_glfw.glx.handle = NULL; _glfw.glx.handle = NULL;
} }
} }

View file

@ -35,8 +35,9 @@
#include <assert.h> #include <assert.h>
// The global variables below comprise all global data in GLFW. // The global variables below comprise all mutable global data in GLFW
// Any other global variable is a bug. //
// Any other global variable is a bug
// Global state shared between compilation units of GLFW // Global state shared between compilation units of GLFW
// //
@ -53,10 +54,6 @@ static _GLFWinitconfig _glfwInitHints =
{ {
GLFW_TRUE, // macOS menu bar GLFW_TRUE, // macOS menu bar
GLFW_TRUE // macOS bundle chdir GLFW_TRUE // macOS bundle chdir
},
{
"", // X11 WM_CLASS name
"" // X11 WM_CLASS class
} }
}; };
@ -141,10 +138,25 @@ static void terminate(void)
} }
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
char* _glfw_strdup(const char* source)
{
const size_t length = strlen(source);
char* result = calloc(length + 1, 1);
strcpy(result, source);
return result;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Notifies shared code of an error
//
void _glfwInputError(int code, const char* format, ...) void _glfwInputError(int code, const char* format, ...)
{ {
_GLFWerror* error; _GLFWerror* error;
@ -260,27 +272,7 @@ GLFWAPI void glfwInitHint(int hint, int value)
} }
_glfwInputError(GLFW_INVALID_ENUM, _glfwInputError(GLFW_INVALID_ENUM,
"Invalid integer type init hint 0x%08X", hint); "Invalid init hint 0x%08X", hint);
}
GLFWAPI void glfwInitHintString(int hint, const char* value)
{
assert(value != NULL);
switch (hint)
{
case GLFW_X11_WM_CLASS_NAME:
strncpy(_glfwInitHints.x11.className, value,
sizeof(_glfwInitHints.x11.className) - 1);
return;
case GLFW_X11_WM_CLASS_CLASS:
strncpy(_glfwInitHints.x11.classClass, value,
sizeof(_glfwInitHints.x11.classClass) - 1);
return;
}
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid string type init hint 0x%08X", hint);
} }
GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)

View file

@ -57,6 +57,58 @@ static _GLFWmapping* findMapping(const char* guid)
return NULL; return NULL;
} }
// Checks whether a gamepad mapping element is present in the hardware
//
static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e,
const _GLFWjoystick* js)
{
if (e->type == _GLFW_JOYSTICK_HATBIT && (e->index >> 4) >= js->hatCount)
return GLFW_FALSE;
else if (e->type == _GLFW_JOYSTICK_BUTTON && e->index >= js->buttonCount)
return GLFW_FALSE;
else if (e->type == _GLFW_JOYSTICK_AXIS && e->index >= js->axisCount)
return GLFW_FALSE;
return GLFW_TRUE;
}
// Finds a mapping based on joystick GUID and verifies element indices
//
static _GLFWmapping* findValidMapping(const _GLFWjoystick* js)
{
_GLFWmapping* mapping = findMapping(js->guid);
if (mapping)
{
int i;
for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
{
if (!isValidElementForJoystick(mapping->buttons + i, js))
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid button in gamepad mapping %s (%s)",
mapping->guid,
mapping->name);
return NULL;
}
}
for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
{
if (!isValidElementForJoystick(mapping->axes + i, js))
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid axis in gamepad mapping %s (%s)",
mapping->guid,
mapping->name);
return NULL;
}
}
}
return mapping;
}
// Parses an SDL_GameControllerDB line and adds it to the mapping list // Parses an SDL_GameControllerDB line and adds it to the mapping list
// //
static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
@ -115,6 +167,10 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
while (*c) while (*c)
{ {
// TODO: Implement output modifiers
if (*c == '+' || *c == '-')
return GLFW_FALSE;
for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++)
{ {
length = strlen(fields[i].name); length = strlen(fields[i].name);
@ -125,23 +181,50 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
if (fields[i].element) if (fields[i].element)
{ {
_GLFWmapelement* e = fields[i].element;
int8_t minimum = -1;
int8_t maximum = 1;
if (*c == '+')
{
minimum = 0;
c += 1;
}
else if (*c == '-')
{
maximum = 0;
c += 1;
}
if (*c == 'a') if (*c == 'a')
fields[i].element->type = _GLFW_JOYSTICK_AXIS; e->type = _GLFW_JOYSTICK_AXIS;
else if (*c == 'b') else if (*c == 'b')
fields[i].element->type = _GLFW_JOYSTICK_BUTTON; e->type = _GLFW_JOYSTICK_BUTTON;
else if (*c == 'h') else if (*c == 'h')
fields[i].element->type = _GLFW_JOYSTICK_HATBIT; e->type = _GLFW_JOYSTICK_HATBIT;
else else
break; break;
if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) if (e->type == _GLFW_JOYSTICK_HATBIT)
{ {
const unsigned long hat = strtoul(c + 1, (char**) &c, 10); const unsigned long hat = strtoul(c + 1, (char**) &c, 10);
const unsigned long bit = strtoul(c + 1, (char**) &c, 10); const unsigned long bit = strtoul(c + 1, (char**) &c, 10);
fields[i].element->value = (uint8_t) ((hat << 4) | bit); e->index = (uint8_t) ((hat << 4) | bit);
} }
else else
fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); e->index = (uint8_t) strtoul(c + 1, (char**) &c, 10);
if (e->type == _GLFW_JOYSTICK_AXIS)
{
e->axisScale = 2 / (maximum - minimum);
e->axisOffset = -(maximum + minimum);
if (*c == '~')
{
e->axisScale = -e->axisScale;
e->axisOffset = -e->axisOffset;
}
}
} }
else else
{ {
@ -172,6 +255,8 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Notifies shared code of a physical key event
//
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
if (key >= 0 && key <= GLFW_KEY_LAST) if (key >= 0 && key <= GLFW_KEY_LAST)
@ -193,15 +278,24 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
action = GLFW_REPEAT; action = GLFW_REPEAT;
} }
if (!window->lockKeyMods)
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
if (window->callbacks.key) if (window->callbacks.key)
window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
} }
// Notifies shared code of a Unicode codepoint input event
// The 'plain' parameter determines whether to emit a regular character event
//
void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain) void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
{ {
if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
return; return;
if (!window->lockKeyMods)
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
if (window->callbacks.charmods) if (window->callbacks.charmods)
window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
@ -212,17 +306,24 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb
} }
} }
// Notifies shared code of a scroll event
//
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
{ {
if (window->callbacks.scroll) if (window->callbacks.scroll)
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
} }
// Notifies shared code of a mouse button click event
//
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
{ {
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
return; return;
if (!window->lockKeyMods)
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
if (action == GLFW_RELEASE && window->stickyMouseButtons) if (action == GLFW_RELEASE && window->stickyMouseButtons)
window->mouseButtons[button] = _GLFW_STICK; window->mouseButtons[button] = _GLFW_STICK;
else else
@ -232,6 +333,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
} }
// Notifies shared code of a cursor motion event
// The position is specified in client-area relative screen coordinates
//
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
{ {
if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
@ -244,18 +348,24 @@ void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos); window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
} }
// Notifies shared code of a cursor enter/leave event
//
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
{ {
if (window->callbacks.cursorEnter) if (window->callbacks.cursorEnter)
window->callbacks.cursorEnter((GLFWwindow*) window, entered); window->callbacks.cursorEnter((GLFWwindow*) window, entered);
} }
// Notifies shared code of files or directories dropped on a window
//
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
{ {
if (window->callbacks.drop) if (window->callbacks.drop)
window->callbacks.drop((GLFWwindow*) window, count, paths); window->callbacks.drop((GLFWwindow*) window, count, paths);
} }
// Notifies shared code of a joystick connection or disconnection
//
void _glfwInputJoystick(_GLFWjoystick* js, int event) void _glfwInputJoystick(_GLFWjoystick* js, int event)
{ {
const int jid = (int) (js - _glfw.joysticks); const int jid = (int) (js - _glfw.joysticks);
@ -264,16 +374,22 @@ void _glfwInputJoystick(_GLFWjoystick* js, int event)
_glfw.callbacks.joystick(jid, event); _glfw.callbacks.joystick(jid, event);
} }
// Notifies shared code of the new value of a joystick axis
//
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
{ {
js->axes[axis] = value; js->axes[axis] = value;
} }
// Notifies shared code of the new value of a joystick button
//
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
{ {
js->buttons[button] = value; js->buttons[button] = value;
} }
// Notifies shared code of the new value of a joystick hat
//
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
{ {
const int base = js->buttonCount + hat * 4; const int base = js->buttonCount + hat * 4;
@ -291,6 +407,8 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Returns an available joystick object with arrays and name allocated
//
_GLFWjoystick* _glfwAllocJoystick(const char* name, _GLFWjoystick* _glfwAllocJoystick(const char* name,
const char* guid, const char* guid,
int axisCount, int axisCount,
@ -311,20 +429,22 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
js = _glfw.joysticks + jid; js = _glfw.joysticks + jid;
js->present = GLFW_TRUE; js->present = GLFW_TRUE;
js->name = strdup(name); js->name = _glfw_strdup(name);
js->axes = calloc(axisCount, sizeof(float)); js->axes = calloc(axisCount, sizeof(float));
js->buttons = calloc(buttonCount + hatCount * 4, 1); js->buttons = calloc(buttonCount + hatCount * 4, 1);
js->hats = calloc(hatCount, 1); js->hats = calloc(hatCount, 1);
js->axisCount = axisCount; js->axisCount = axisCount;
js->buttonCount = buttonCount; js->buttonCount = buttonCount;
js->hatCount = hatCount; js->hatCount = hatCount;
js->mapping = findMapping(guid);
strcpy(js->guid, guid); strcpy(js->guid, guid);
js->mapping = findValidMapping(js);
return js; return js;
} }
// Frees arrays and name and flags the joystick object as unused
//
void _glfwFreeJoystick(_GLFWjoystick* js) void _glfwFreeJoystick(_GLFWjoystick* js)
{ {
free(js->name); free(js->name);
@ -354,6 +474,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
return window->stickyKeys; return window->stickyKeys;
case GLFW_STICKY_MOUSE_BUTTONS: case GLFW_STICKY_MOUSE_BUTTONS:
return window->stickyMouseButtons; return window->stickyMouseButtons;
case GLFW_LOCK_KEY_MODS:
return window->lockKeyMods;
} }
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@ -409,7 +531,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
} }
} }
window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; window->stickyKeys = value;
} }
else if (mode == GLFW_STICKY_MOUSE_BUTTONS) else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
{ {
@ -429,8 +551,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
} }
} }
window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; window->stickyMouseButtons = value;
} }
else if (mode == GLFW_LOCK_KEY_MODS)
window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE;
else else
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
} }
@ -914,6 +1038,38 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid)
return js->guid; return js->guid;
} }
GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
{
_GLFWjoystick* js;
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
_GLFW_REQUIRE_INIT();
js = _glfw.joysticks + jid;
if (!js->present)
return;
js->userPointer = pointer;
}
GLFWAPI void* glfwGetJoystickUserPointer(int jid)
{
_GLFWjoystick* js;
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
js = _glfw.joysticks + jid;
if (!js->present)
return NULL;
return js->userPointer;
}
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@ -973,7 +1129,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string)
{ {
_GLFWjoystick* js = _glfw.joysticks + jid; _GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present) if (js->present)
js->mapping = findMapping(js->guid); js->mapping = findValidMapping(js);
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1063,35 +1219,41 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
{ {
if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_AXIS) const _GLFWmapelement* e = js->mapping->buttons + i;
if (e->type == _GLFW_JOYSTICK_AXIS)
{ {
if (fabs(js->axes[js->mapping->buttons[i].value]) > 0.5) const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
if (value > 0.f)
state->buttons[i] = GLFW_PRESS; state->buttons[i] = GLFW_PRESS;
} }
else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) else if (e->type == _GLFW_JOYSTICK_HATBIT)
{ {
const unsigned int hat = js->mapping->buttons[i].value >> 4; const unsigned int hat = e->index >> 4;
const unsigned int bit = js->mapping->buttons[i].value & 0xf; const unsigned int bit = e->index & 0xf;
if (js->hats[hat] & bit) if (js->hats[hat] & bit)
state->buttons[i] = GLFW_PRESS; state->buttons[i] = GLFW_PRESS;
} }
else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) else if (e->type == _GLFW_JOYSTICK_BUTTON)
state->buttons[i] = js->buttons[js->mapping->buttons[i].value]; state->buttons[i] = js->buttons[e->index];
} }
for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
{ {
if (js->mapping->axes[i].type == _GLFW_JOYSTICK_AXIS) const _GLFWmapelement* e = js->mapping->axes + i;
state->axes[i] = js->axes[js->mapping->axes[i].value]; if (e->type == _GLFW_JOYSTICK_AXIS)
else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT)
{ {
const unsigned int hat = js->mapping->buttons[i].value >> 4; const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
const unsigned int bit = js->mapping->buttons[i].value & 0xf; state->axes[i] = fminf(fmaxf(value, -1.f), 1.f);
}
else if (e->type == _GLFW_JOYSTICK_HATBIT)
{
const unsigned int hat = e->index >> 4;
const unsigned int bit = e->index & 0xf;
if (js->hats[hat] & bit) if (js->hats[hat] & bit)
state->axes[i] = 1.f; state->axes[i] = 1.f;
} }
else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) else if (e->type == _GLFW_JOYSTICK_BUTTON)
state->axes[i] = (float) js->buttons[js->mapping->axes[i].value]; state->axes[i] = (float) js->buttons[e->index];
} }
return GLFW_TRUE; return GLFW_TRUE;

View file

@ -196,38 +196,6 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
#error "No supported window creation API selected" #error "No supported window creation API selected"
#endif #endif
//========================================================================
// Doxygen group definitions
//========================================================================
/*! @defgroup platform Platform interface
* @brief The interface implemented by the platform-specific code.
*
* The platform API is the interface exposed by the platform-specific code for
* each platform and is called by the shared code of the public API It mirrors
* the public API except it uses objects instead of handles.
*/
/*! @defgroup event Event interface
* @brief The interface used by the platform-specific code to report events.
*
* The event API is used by the platform-specific code to notify the shared
* code of events that can be translated into state changes and/or callback
* calls.
*/
/*! @defgroup utility Utility functions
* @brief Various utility functions for internal use.
*
* These functions are shared code and may be used by any part of GLFW
* Each platform may add its own utility functions, but those must only be
* called by the platform-specific code
*/
//========================================================================
// Helper macros
//========================================================================
// Constructs a version number string from the public header macros // Constructs a version number string from the public header macros
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r #define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) #define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
@ -258,11 +226,8 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
y = t; \ y = t; \
} }
// Per-thread error structure
//======================================================================== //
// Platform-independent structures
//========================================================================
struct _GLFWerror struct _GLFWerror
{ {
_GLFWerror* next; _GLFWerror* next;
@ -270,10 +235,10 @@ struct _GLFWerror
char description[_GLFW_MESSAGE_SIZE]; char description[_GLFW_MESSAGE_SIZE];
}; };
/*! @brief Initialization configuration. // Initialization configuration
* //
* Parameters relating to the initialization of the library. // Parameters relating to the initialization of the library
*/ //
struct _GLFWinitconfig struct _GLFWinitconfig
{ {
GLFWbool hatButtons; GLFWbool hatButtons;
@ -281,18 +246,14 @@ struct _GLFWinitconfig
GLFWbool menubar; GLFWbool menubar;
GLFWbool chdir; GLFWbool chdir;
} ns; } ns;
struct {
char className[256];
char classClass[256];
} x11;
}; };
/*! @brief Window configuration. // Window configuration
* //
* Parameters relating to the creation of the window but not directly related // Parameters relating to the creation of the window but not directly related
* to the framebuffer. This is used to pass window creation parameters from // to the framebuffer. This is used to pass window creation parameters from
* shared code to the platform API. // shared code to the platform API.
*/ //
struct _GLFWwndconfig struct _GLFWwndconfig
{ {
int width; int width;
@ -308,16 +269,20 @@ struct _GLFWwndconfig
GLFWbool centerCursor; GLFWbool centerCursor;
struct { struct {
GLFWbool retina; GLFWbool retina;
GLFWbool frame; char frameName[256];
} ns; } ns;
struct {
char className[256];
char instanceName[256];
} x11;
}; };
/*! @brief Context configuration. // Context configuration
* //
* Parameters relating to the creation of the context but not directly related // Parameters relating to the creation of the context but not directly related
* to the framebuffer. This is used to pass context creation parameters from // to the framebuffer. This is used to pass context creation parameters from
* shared code to the platform API. // shared code to the platform API.
*/ //
struct _GLFWctxconfig struct _GLFWctxconfig
{ {
int client; int client;
@ -336,14 +301,14 @@ struct _GLFWctxconfig
} nsgl; } nsgl;
}; };
/*! @brief Framebuffer configuration. // Framebuffer configuration
* //
* This describes buffers and their sizes. It also contains // This describes buffers and their sizes. It also contains
* a platform-specific ID used to map back to the backend API object. // a platform-specific ID used to map back to the backend API object.
* //
* It is used to pass framebuffer parameters from shared code to the platform // It is used to pass framebuffer parameters from shared code to the platform
* API and also to enumerate and select available framebuffer configs. // API and also to enumerate and select available framebuffer configs.
*/ //
struct _GLFWfbconfig struct _GLFWfbconfig
{ {
int redBits; int redBits;
@ -365,8 +330,8 @@ struct _GLFWfbconfig
uintptr_t handle; uintptr_t handle;
}; };
/*! @brief Context structure. // Context structure
*/ //
struct _GLFWcontext struct _GLFWcontext
{ {
int client; int client;
@ -396,8 +361,8 @@ struct _GLFWcontext
_GLFW_OSMESA_CONTEXT_STATE; _GLFW_OSMESA_CONTEXT_STATE;
}; };
/*! @brief Window and context structure. // Window and context structure
*/ //
struct _GLFWwindow struct _GLFWwindow
{ {
struct _GLFWwindow* next; struct _GLFWwindow* next;
@ -419,6 +384,7 @@ struct _GLFWwindow
GLFWbool stickyKeys; GLFWbool stickyKeys;
GLFWbool stickyMouseButtons; GLFWbool stickyMouseButtons;
GLFWbool lockKeyMods;
int cursorMode; int cursorMode;
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
char keys[GLFW_KEY_LAST + 1]; char keys[GLFW_KEY_LAST + 1];
@ -436,6 +402,7 @@ struct _GLFWwindow
GLFWwindowiconifyfun iconify; GLFWwindowiconifyfun iconify;
GLFWwindowmaximizefun maximize; GLFWwindowmaximizefun maximize;
GLFWframebuffersizefun fbsize; GLFWframebuffersizefun fbsize;
GLFWwindowcontentscalefun scale;
GLFWmousebuttonfun mouseButton; GLFWmousebuttonfun mouseButton;
GLFWcursorposfun cursorPos; GLFWcursorposfun cursorPos;
GLFWcursorenterfun cursorEnter; GLFWcursorenterfun cursorEnter;
@ -450,11 +417,12 @@ struct _GLFWwindow
_GLFW_PLATFORM_WINDOW_STATE; _GLFW_PLATFORM_WINDOW_STATE;
}; };
/*! @brief Monitor structure. // Monitor structure
*/ //
struct _GLFWmonitor struct _GLFWmonitor
{ {
char* name; char* name;
void* userPointer;
// Physical dimensions in millimeters. // Physical dimensions in millimeters.
int widthMM, heightMM; int widthMM, heightMM;
@ -473,8 +441,8 @@ struct _GLFWmonitor
_GLFW_PLATFORM_MONITOR_STATE; _GLFW_PLATFORM_MONITOR_STATE;
}; };
/*! @brief Cursor structure // Cursor structure
*/ //
struct _GLFWcursor struct _GLFWcursor
{ {
_GLFWcursor* next; _GLFWcursor* next;
@ -483,16 +451,18 @@ struct _GLFWcursor
_GLFW_PLATFORM_CURSOR_STATE; _GLFW_PLATFORM_CURSOR_STATE;
}; };
/*! @brief Gamepad mapping element structure // Gamepad mapping element structure
*/ //
struct _GLFWmapelement struct _GLFWmapelement
{ {
uint8_t type; uint8_t type;
uint8_t value; uint8_t index;
int8_t axisScale;
int8_t axisOffset;
}; };
/*! @brief Gamepad mapping structure // Gamepad mapping structure
*/ //
struct _GLFWmapping struct _GLFWmapping
{ {
char name[128]; char name[128];
@ -501,8 +471,8 @@ struct _GLFWmapping
_GLFWmapelement axes[6]; _GLFWmapelement axes[6];
}; };
/*! @brief Joystick structure // Joystick structure
*/ //
struct _GLFWjoystick struct _GLFWjoystick
{ {
GLFWbool present; GLFWbool present;
@ -513,6 +483,7 @@ struct _GLFWjoystick
unsigned char* hats; unsigned char* hats;
int hatCount; int hatCount;
char* name; char* name;
void* userPointer;
char guid[33]; char guid[33];
_GLFWmapping* mapping; _GLFWmapping* mapping;
@ -520,24 +491,24 @@ struct _GLFWjoystick
_GLFW_PLATFORM_JOYSTICK_STATE; _GLFW_PLATFORM_JOYSTICK_STATE;
}; };
/*! @brief Thread local storage structure. // Thread local storage structure
*/ //
struct _GLFWtls struct _GLFWtls
{ {
// This is defined in the platform's thread.h // This is defined in the platform's thread.h
_GLFW_PLATFORM_TLS_STATE; _GLFW_PLATFORM_TLS_STATE;
}; };
/*! @brief Mutex structure. // Mutex structure
*/ //
struct _GLFWmutex struct _GLFWmutex
{ {
// This is defined in the platform's thread.h // This is defined in the platform's thread.h
_GLFW_PLATFORM_MUTEX_STATE; _GLFW_PLATFORM_MUTEX_STATE;
}; };
/*! @brief Library global data. // Library global data
*/ //
struct _GLFWlibrary struct _GLFWlibrary
{ {
GLFWbool initialized; GLFWbool initialized;
@ -611,21 +582,14 @@ struct _GLFWlibrary
_GLFW_OSMESA_LIBRARY_CONTEXT_STATE; _GLFW_OSMESA_LIBRARY_CONTEXT_STATE;
}; };
//========================================================================
// Global state shared between compilation units of GLFW // Global state shared between compilation units of GLFW
//======================================================================== //
/*! @brief All global data shared between compilation units.
*/
extern _GLFWlibrary _glfw; extern _GLFWlibrary _glfw;
//======================================================================== //////////////////////////////////////////////////////////////////////////
// Platform API functions ////// GLFW platform API //////
//======================================================================== //////////////////////////////////////////////////////////////////////////
/*! @addtogroup platform @{ */
int _glfwPlatformInit(void); int _glfwPlatformInit(void);
void _glfwPlatformTerminate(void); void _glfwPlatformTerminate(void);
@ -634,7 +598,8 @@ const char* _glfwPlatformGetVersionString(void);
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image, int xhot, int yhot);
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape);
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
@ -642,8 +607,10 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
const char* _glfwPlatformGetScancodeName(int scancode); const char* _glfwPlatformGetScancodeName(int scancode);
int _glfwPlatformGetKeyScancode(int key); int _glfwPlatformGetKeyScancode(int key);
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale); void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale);
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
@ -664,16 +631,22 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
void _glfwPlatformDestroyWindow(_GLFWwindow* window); void _glfwPlatformDestroyWindow(_GLFWwindow* window);
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images); void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
int count, const GLFWimage* images);
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos);
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos);
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height);
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height);
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight);
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height);
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); int* left, int* top,
int* right, int* bottom);
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
float* xscale, float* yscale);
void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformIconifyWindow(_GLFWwindow* window);
void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window);
void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
@ -681,11 +654,14 @@ void _glfwPlatformShowWindow(_GLFWwindow* window);
void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window);
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformRequestWindowAttention(_GLFWwindow* window);
void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window);
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
int xpos, int ypos, int width, int height,
int refreshRate);
int _glfwPlatformWindowFocused(_GLFWwindow* window); int _glfwPlatformWindowFocused(_GLFWwindow* window);
int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowIconified(_GLFWwindow* window);
int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window);
int _glfwPlatformWindowMaximized(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window);
int _glfwPlatformWindowHovered(_GLFWwindow* window);
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window);
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
@ -699,8 +675,13 @@ void _glfwPlatformWaitEventsTimeout(double timeout);
void _glfwPlatformPostEmptyEvent(void); void _glfwPlatformPostEmptyEvent(void);
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); VkPhysicalDevice device,
uint32_t queuefamily);
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface);
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
void _glfwPlatformDestroyTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls);
@ -712,307 +693,79 @@ void _glfwPlatformDestroyMutex(_GLFWmutex* mutex);
void _glfwPlatformLockMutex(_GLFWmutex* mutex); void _glfwPlatformLockMutex(_GLFWmutex* mutex);
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
/*! @} */
//////////////////////////////////////////////////////////////////////////
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
//========================================================================
// Event API functions
//========================================================================
/*! @brief Notifies shared code that a window has lost or received input focus.
* @param[in] window The window that received the event.
* @param[in] focused `GLFW_TRUE` if the window received focus, or `GLFW_FALSE`
* if it lost focus.
* @ingroup event
*/
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
/*! @brief Notifies shared code that a window has moved.
* @param[in] window The window that received the event.
* @param[in] xpos The new x-coordinate of the client area of the window.
* @param[in] ypos The new y-coordinate of the client area of the window.
* @ingroup event
*/
void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos);
/*! @brief Notifies shared code that a window has been resized.
* @param[in] window The window that received the event.
* @param[in] width The new width of the client area of the window.
* @param[in] height The new height of the client area of the window.
* @ingroup event
*/
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); void _glfwInputWindowSize(_GLFWwindow* window, int width, int height);
/*! @brief Notifies shared code that a window framebuffer has been resized.
* @param[in] window The window that received the event.
* @param[in] width The new width, in pixels, of the framebuffer.
* @param[in] height The new height, in pixels, of the framebuffer.
* @ingroup event
*/
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height);
void _glfwInputWindowContentScale(_GLFWwindow* window,
/*! @brief Notifies shared code that a window has been iconified or restored. float xscale, float yscale);
* @param[in] window The window that received the event.
* @param[in] iconified `GLFW_TRUE` if the window was iconified, or
* `GLFW_FALSE` if it was restored.
* @ingroup event
*/
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified);
/*! @brief Notifies shared code that a window has been maximized or restored.
* @param[in] window The window that received the event.
* @param[in] maximized `GLFW_TRUE` if the window was maximized, or
* `GLFW_FALSE` if it was restored.
* @ingroup event
*/
void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized); void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized);
/*! @brief Notifies shared code that a window's contents needs updating.
* @param[in] window The window that received the event.
*/
void _glfwInputWindowDamage(_GLFWwindow* window); void _glfwInputWindowDamage(_GLFWwindow* window);
/*! @brief Notifies shared code that the user wishes to close a window.
* @param[in] window The window that received the event.
* @ingroup event
*/
void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window);
/*! @brief Notifies shared code that a window has changed its desired monitor.
* @param[in] window The window that received the event.
* @param[in] monitor The new desired monitor, or `NULL`.
* @ingroup event
*/
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
/*! @brief Notifies shared code of a physical key event. void _glfwInputKey(_GLFWwindow* window,
* @param[in] window The window that received the event. int key, int scancode, int action, int mods);
* @param[in] key The key that was pressed or released. void _glfwInputChar(_GLFWwindow* window,
* @param[in] scancode The system-specific scan code of the key. unsigned int codepoint, int mods, GLFWbool plain);
* @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE.
* @param[in] mods The modifiers pressed when the event was generated.
* @ingroup event
*/
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods);
/*! @brief Notifies shared code of a Unicode character input event.
* @param[in] window The window that received the event.
* @param[in] codepoint The Unicode code point of the input character.
* @param[in] mods Bit field describing which modifier keys were held down.
* @param[in] plain `GLFW_TRUE` if the character is regular text input, or
* `GLFW_FALSE` otherwise.
* @ingroup event
*/
void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain);
/*! @brief Notifies shared code of a scroll event.
* @param[in] window The window that received the event.
* @param[in] xoffset The scroll offset along the x-axis.
* @param[in] yoffset The scroll offset along the y-axis.
* @ingroup event
*/
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
/*! @brief Notifies shared code of a mouse button click event.
* @param[in] window The window that received the event.
* @param[in] button The button that was pressed or released.
* @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE.
* @param[in] mods The modifiers pressed when the event was generated.
* @ingroup event
*/
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
/*! @brief Notifies shared code of a cursor motion event.
* @param[in] window The window that received the event.
* @param[in] xpos The new x-coordinate of the cursor, relative to the left
* edge of the client area of the window.
* @param[in] ypos The new y-coordinate of the cursor, relative to the top edge
* of the client area of the window.
* @ingroup event
*/
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
/*! @brief Notifies shared code of a cursor enter/leave event.
* @param[in] window The window that received the event.
* @param[in] entered `GLFW_TRUE` if the cursor entered the client area of the
* window, or `GLFW_FALSE` if it left it.
* @ingroup event
*/
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
void _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
/*! @brief Notifies shared code of a monitor connection or disconnection.
* @param[in] monitor The monitor that was connected or disconnected.
* @param[in] action One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
* @param[in] placement `_GLFW_INSERT_FIRST` or `_GLFW_INSERT_LAST`.
* @ingroup event
*/
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
/*! @brief Notifies shared code that a full screen window has acquired or
* released a monitor.
* @param[in] monitor The monitor that was acquired or released.
* @param[in] window The window that acquired the monitor, or `NULL`.
* @ingroup event
*/
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
/*! @brief Notifies shared code of an error.
* @param[in] code The error code most suitable for the error.
* @param[in] format The `printf` style format string of the error
* description.
* @ingroup event
*/
#if defined(__GNUC__) #if defined(__GNUC__)
void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); void _glfwInputError(int code, const char* format, ...)
__attribute__((format(printf, 2, 3)));
#else #else
void _glfwInputError(int code, const char* format, ...); void _glfwInputError(int code, const char* format, ...);
#endif #endif
/*! @brief Notifies shared code of files or directories dropped on a window.
* @param[in] window The window that received the event.
* @param[in] count The number of dropped objects.
* @param[in] names The names of the dropped objects.
* @ingroup event
*/
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
/*! @brief Notifies shared code of a joystick connection or disconnection. //////////////////////////////////////////////////////////////////////////
* @param[in] js The joystick that was connected or disconnected. ////// GLFW internal API //////
* @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. //////////////////////////////////////////////////////////////////////////
* @ingroup event
*/
void _glfwInputJoystick(_GLFWjoystick* js, int event);
/*! @brief Notifies shared code of the new value of a joystick axis.
* @param[in] js The joystick whose axis to update.
* @param[in] axis The index of the axis to update.
* @param[in] value The new value of the axis.
*/
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
/*! @brief Notifies shared code of the new value of a joystick button.
* @param[in] js The joystick whose button to update.
* @param[in] button The index of the button to update.
* @param[in] value The new value of the button.
*/
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
/*! @brief Notifies shared code of the new value of a joystick hat.
* @param[in] js The joystick whose hat to update.
* @param[in] button The index of the hat to update.
* @param[in] value The new value of the hat.
*/
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
//========================================================================
// Utility functions
//========================================================================
/*! @brief Chooses the video mode most closely matching the desired one.
* @ingroup utility
*/
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
const GLFWvidmode* desired);
/*! @brief Performs lexical comparison between two @ref GLFWvidmode structures.
* @ingroup utility
*/
int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second);
/*! @brief Splits a color depth into red, green and blue bit depths.
* @ingroup utility
*/
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
/*! @brief Searches an extension string for the specified extension.
* @param[in] string The extension string to search.
* @param[in] extensions The extension to search for.
* @return `GLFW_TRUE` if the extension was found, or `GLFW_FALSE` otherwise.
* @ingroup utility
*/
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions); GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions);
/*! @brief Chooses the framebuffer config that best matches the desired one.
* @param[in] desired The desired framebuffer config.
* @param[in] alternatives The framebuffer configs supported by the system.
* @param[in] count The number of entries in the alternatives array.
* @return The framebuffer config most closely matching the desired one, or @c
* NULL if none fulfilled the hard constraints of the desired values.
* @ingroup utility
*/
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives, const _GLFWfbconfig* alternatives,
unsigned int count); unsigned int count);
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
/*! @brief Retrieves the attributes of the current context. const _GLFWctxconfig* ctxconfig);
* @param[in] ctxconfig The desired context attributes.
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if the context is
* unusable.
* @ingroup utility
*/
GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig);
/*! @brief Checks whether the desired context attributes are valid.
* @param[in] ctxconfig The context attributes to check.
* @return `GLFW_TRUE` if the context attributes are valid, or `GLFW_FALSE`
* otherwise.
* @ingroup utility
*
* This function checks things like whether the specified client API version
* exists and whether all relevant options have supported and non-conflicting
* values.
*/
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
/*! @brief Allocates red, green and blue value arrays of the specified size. const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
* @ingroup utility const GLFWvidmode* desired);
*/ int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second);
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size);
/*! @brief Frees the red, green and blue value arrays and clears the struct.
* @ingroup utility
*/
void _glfwFreeGammaArrays(GLFWgammaramp* ramp);
/*! @brief Allocates and returns a monitor object with the specified name
* and dimensions.
* @param[in] name The name of the monitor.
* @param[in] widthMM The width, in mm, of the monitor's display area.
* @param[in] heightMM The height, in mm, of the monitor's display area.
* @return The newly created object.
* @ingroup utility
*/
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM);
/*! @brief Frees a monitor object and any data associated with it.
* @ingroup utility
*/
void _glfwFreeMonitor(_GLFWmonitor* monitor); void _glfwFreeMonitor(_GLFWmonitor* monitor);
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size);
void _glfwFreeGammaArrays(GLFWgammaramp* ramp);
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
/*! @brief Returns an available joystick object with arrays and name allocated.
* @ingroup utility
*/
_GLFWjoystick* _glfwAllocJoystick(const char* name, _GLFWjoystick* _glfwAllocJoystick(const char* name,
const char* guid, const char* guid,
int axisCount, int axisCount,
int buttonCount, int buttonCount,
int hatCount); int hatCount);
/*! @brief Frees arrays and name and flags the joystick object as unused.
* @ingroup utility
*/
void _glfwFreeJoystick(_GLFWjoystick* js); void _glfwFreeJoystick(_GLFWjoystick* js);
/*! @ingroup utility
*/
GLFWbool _glfwInitVulkan(int mode); GLFWbool _glfwInitVulkan(int mode);
/*! @ingroup utility
*/
void _glfwTerminateVulkan(void); void _glfwTerminateVulkan(void);
/*! @ingroup utility
*/
const char* _glfwGetVulkanResultString(VkResult result); const char* _glfwGetVulkanResultString(VkResult result);
char* _glfw_strdup(const char* source);

View file

@ -38,6 +38,11 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#ifndef SYN_DROPPED // < v2.6.39 kernel headers
// Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32
#define SYN_DROPPED 3
#endif
// Apply an EV_KEY event to the specified joystick // Apply an EV_KEY event to the specified joystick
// //
static void handleKeyEvent(_GLFWjoystick* js, int code, int value) static void handleKeyEvent(_GLFWjoystick* js, int code, int value)

View file

@ -60,243 +60,411 @@
const char* _glfwDefaultMappings[] = const char* _glfwDefaultMappings[] =
{ {
"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,", "03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,", "030000008f0e00001200000000000000,Acme,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
"d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,platform:Windows,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"5e048e02000000000000504944564944,Controller (XBOX 360 For Windows),platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,righttrigger:a2,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",
"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000006b1400000055000000000000,bigben ps3padstreetnew,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", "0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f8500000000000000504944564944,Fighting Commander 2016 PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,",
"0d0f5f00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"0d0f5e00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:a3,platform:Windows,", "030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"0d0f8400000000000000504944564944,Fighting Commander 5,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,",
"0d0f8700000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f8800000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b9,guide:b12,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"0d0f2700000000000000504944564944,FIGHTING STICK V3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000004f04000023b3000000000000,Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", "030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
"45130010000000000000504944564944,Generic USB Joystick,a:b0,b:b1,x:b2,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"d8140862000000000000504944564944,HitBox Edition Cthulhu+,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", "78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
"0d0f4000000000000000504944564944,Hori Fighting Stick Mini 3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", "03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
"0d0f4d00000000000000504944564944,HORIPAD3 A,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"25090017000000000000504944564944,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b5,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b6,platform:Windows,", "03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000451300000010000000000000,Generic USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,", "03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"6f0e2401000000000000504944564944,INJUSTICE FightStick for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Windows", "030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,", "03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"38075032000000000000504944564944,Mad Catz FightPad PRO PS3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"38075082000000000000504944564944,Mad Catz FightPad PRO PS4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b13,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", "030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"38078433000000000000504944564944,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"38078483000000000000504944564944,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:b6,platform:Windows,", "030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"38078134000000000000504944564944,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b7,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b4,platform:Windows,", "030000000d0f00004d00000000000000,HORIPAD3 A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"38078184000000000000504944564944,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:b7,platform:Windows,", "03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,",
"38078034000000000000504944564944,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,",
"38078084000000000000504944564944,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", "03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"38078532000000000000504944564944,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"38073888000000000000504944564944,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,",
"38071888000000000000504944564944,MadCatz SFIV FightStick PS3,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b6,platform:Windows,", "03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000006f0e00002401000000000000,INJUSTICE FightStick for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"25090128000000000000504944564944,Mayflash Arcade Stick,a:b1,b:b2,x:b5,y:b6,back:b8,start:b9,leftshoulder:b0,rightshoulder:b3,leftx:a0,lefty:a1,rightx:h0.4,righty:h0.0,lefttrigger:b4,righttrigger:b7,platform:Windows,", "03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,",
"8f0e1030000000000000504944564944,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b6,rightshoulder:b2,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b5,righttrigger:b7,platform:Windows,", "030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,", "03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"bd1215d0000000000000504944564944,Nintendo Retrolink USB Super SNES Classic Controller,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,start:b9,back:b8,leftx:a0,lefty:a1,platform:Windows,", "03000000380700008433000000000000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000380700008483000000000000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,", "03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"120cf60e000000000000504944564944,P4 Wired Gamepad,a:b1,b:b2,x:b0,y:b3,back:b12,guide:b8,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.0,lefttrigger:b7,righttrigger:b6,platform:Windows,", "03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,", "03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", "03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,", "03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,", "030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"10008200000000000000504944564944,PS360+ v1.66,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,",
"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"300f0011000000000000504944564944,QanBa Arcade JoyStick 1008,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b10,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", "03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"300f1611000000000000504944564944,QanBa Arcade JoyStick 4018,a:b1,b:b2,x:b0,y:b3,back:b10,guide:b9,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,",
"222c0020000000000000504944564944,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:a3,righttrigger:a4,platform:Windows,", "0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
"300f1210000000000000504944564944,QanBa Joystick Plus,a:b0,b:b1,x:b2,y:b3,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,", "03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"341a0104000000000000504944564944,QanBa Joystick Q4RAF,a:b5,b:b6,x:b1,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b0,rightshoulder:b3,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b7,platform:Windows,", "030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,",
"222c0223000000000000504944564944,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
"222c0023000000000000504944564944,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,x:b0,y:b3,back:b13,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"0d0f1100000000000000504944564944,REAL ARCADE PRO.3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,start:b9,x:b2,y:b3,platform:Windows,",
"0d0f8b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,",
"0d0f8a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", "03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f6b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"0d0f6a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", "03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f7000000000000000504944564944,REAL ARCADE PRO.4 VLX,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "030000008f0e00007530000000000000,PS (R) Gamepad,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f2200000000000000504944564944,REAL ARCADE Pro.V3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", "03000000100800000100000000000000,PS1 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", "03000000100800000300000000000000,PS2 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
"300f1201000000000000504944564944,Saitek Dual Analog Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", "030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", "03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", "03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"9b280500000000000000504944564944,Saturn_Adapter_2.0,a:b1,b:b2,x:b0,y:b3,start:b9,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Windows,", "030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"79001100000000000000504944564944,Sega Saturn Gamepad,a:b1,b:b2,x:b4,y:b5,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a4,lefttrigger:b3,righttrigger:b0,platform:Windows,", "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", "030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", "03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,",
"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,", "03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",
"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,", "03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
"66660488000000000000504944564944,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,platform:Windows,", "03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,",
"38076652000000000000504944564944,UnKnown,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"79001b18000000000000504944564944,Venom Arcade Joystick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", "03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", "030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", "030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", "030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,", "030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", "030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", "0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", "0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,", "030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,", "030000006f0e00001e01000000000000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", "03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", "03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,", "03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,", "03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows,",
"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,", "03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", "03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", "03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", "03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
"4c05000000000000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", "03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,", "030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", "03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
"10080000000000000100000000000000,Twin USB Joystick,a:b4,b:b2,x:b6,y:b0,back:b16,start:b18,leftstick:b20,rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,righty:a4,lefttrigger:b8,righttrigger:b10,platform:Mac OS X,", "030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,", "03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,",
"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,", "03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", "03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,",
"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", "03000000380700006652000000000000,UnKnown,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,", "03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,", "03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", "03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", "03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
"03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
"06000000adde0000efbe000002010000,Hidromancer Game Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,", "03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,", "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,", "030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7", "030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,", "030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", "030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", "030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,", "030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", "030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,",
"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,", "030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,",
"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,",
"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,",
"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,",
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,",
"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,",
"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,",
"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,",
"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
"05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
"05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,",
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,",
"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006f0e00001f01000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,",
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,",
"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,",
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,",
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,",
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,",
"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,", "030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",
"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,", "03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", "03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,", "03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", "03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,", "03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,", "03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,", "03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", "030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", "030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,", "030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,",
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,",
"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", "060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", "05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", "050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,platform:Linux,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", "050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", "050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", "030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,", "030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", "03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,",
"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,", "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,platform:Linux,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", "03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", "03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", "03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", "0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", "0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,", "030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,", "03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", "03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", "03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,",
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", "03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", "03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,", "03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,",
"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", "03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", "03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", "030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", "030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,",
"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",
"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e040000a102000000010000,X360 Wireless Controller,platform:Linux,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,platform:Linux,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,", "050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,",
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,",
"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,",
"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,",
"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,",
"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,",
"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,",
"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",

View file

@ -80,6 +80,10 @@ void _glfwPollMonitorsMir(void)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
if (xpos) if (xpos)

View file

@ -117,12 +117,16 @@ static int mirModToGLFWMod(uint32_t mods)
if (mods & mir_input_event_modifier_alt) if (mods & mir_input_event_modifier_alt)
publicMods |= GLFW_MOD_ALT; publicMods |= GLFW_MOD_ALT;
else if (mods & mir_input_event_modifier_shift) if (mods & mir_input_event_modifier_shift)
publicMods |= GLFW_MOD_SHIFT; publicMods |= GLFW_MOD_SHIFT;
else if (mods & mir_input_event_modifier_ctrl) if (mods & mir_input_event_modifier_ctrl)
publicMods |= GLFW_MOD_CONTROL; publicMods |= GLFW_MOD_CONTROL;
else if (mods & mir_input_event_modifier_meta) if (mods & mir_input_event_modifier_meta)
publicMods |= GLFW_MOD_SUPER; publicMods |= GLFW_MOD_SUPER;
if (mods & mir_input_event_modifier_caps_lock)
publicMods |= GLFW_MOD_CAPS_LOCK;
if (mods & mir_input_event_modifier_num_lock)
publicMods |= GLFW_MOD_NUM_LOCK;
return publicMods; return publicMods;
} }
@ -623,6 +627,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return mir_window_get_state(window->mir.window) == mir_window_state_maximized; return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View file

@ -86,6 +86,8 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Notifies shared code of a monitor connection or disconnection
//
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
{ {
if (action == GLFW_CONNECTED) if (action == GLFW_CONNECTED)
@ -141,6 +143,9 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
_glfwFreeMonitor(monitor); _glfwFreeMonitor(monitor);
} }
// Notifies shared code that a full screen window has acquired or released
// a monitor
//
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
{ {
monitor->window = window; monitor->window = window;
@ -151,6 +156,8 @@ void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Allocates and returns a monitor object with the specified name and dimensions
//
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
{ {
_GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
@ -158,16 +165,20 @@ _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
monitor->heightMM = heightMM; monitor->heightMM = heightMM;
if (name) if (name)
monitor->name = strdup(name); monitor->name = _glfw_strdup(name);
return monitor; return monitor;
} }
// Frees a monitor object and any data associated with it
//
void _glfwFreeMonitor(_GLFWmonitor* monitor) void _glfwFreeMonitor(_GLFWmonitor* monitor)
{ {
if (monitor == NULL) if (monitor == NULL)
return; return;
_glfwPlatformFreeMonitor(monitor);
_glfwFreeGammaArrays(&monitor->originalRamp); _glfwFreeGammaArrays(&monitor->originalRamp);
_glfwFreeGammaArrays(&monitor->currentRamp); _glfwFreeGammaArrays(&monitor->currentRamp);
@ -176,6 +187,8 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor)
free(monitor); free(monitor);
} }
// Allocates red, green and blue value arrays of the specified size
//
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
{ {
ramp->red = calloc(size, sizeof(unsigned short)); ramp->red = calloc(size, sizeof(unsigned short));
@ -184,6 +197,8 @@ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
ramp->size = size; ramp->size = size;
} }
// Frees the red, green and blue value arrays and clears the struct
//
void _glfwFreeGammaArrays(GLFWgammaramp* ramp) void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
{ {
free(ramp->red); free(ramp->red);
@ -193,6 +208,8 @@ void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
memset(ramp, 0, sizeof(GLFWgammaramp)); memset(ramp, 0, sizeof(GLFWgammaramp));
} }
// Chooses the video mode most closely matching the desired one
//
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
const GLFWvidmode* desired) const GLFWvidmode* desired)
{ {
@ -243,11 +260,15 @@ const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
return closest; return closest;
} }
// Performs lexical comparison between two @ref GLFWvidmode structures
//
int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm) int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
{ {
return compareVideoModes(fm, sm); return compareVideoModes(fm, sm);
} }
// Splits a color depth into red, green and blue bit depths
//
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
{ {
int delta; int delta;
@ -351,6 +372,24 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
return monitor->name; return monitor->name;
} }
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT();
monitor->userPointer = pointer;
}
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->userPointer;
}
GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@ -406,16 +445,16 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
{ {
double value; float value;
// Calculate intensity // Calculate intensity
value = i / 255.0; value = i / 255.f;
// Apply gamma curve // Apply gamma curve
value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
// Clamp to value range // Clamp to value range
if (value > 65535.0) if (value > 65535.f)
value = 65535.0; value = 65535.f;
values[i] = (unsigned short) value; values[i] = (unsigned short) value;
} }

View file

@ -32,6 +32,10 @@
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
} }

View file

@ -165,6 +165,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return GLFW_FALSE; return GLFW_FALSE;
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
return GLFW_FALSE; return GLFW_FALSE;

View file

@ -54,7 +54,7 @@ GLFWbool _glfwInitVulkan(int mode)
#elif defined(_GLFW_WIN32) #elif defined(_GLFW_WIN32)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA) #elif defined(_GLFW_COCOA)
_glfw.vk.handle = _glfw_dlopen("libMoltenVK.dylib"); _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
#else #else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif #endif
@ -317,6 +317,13 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
return VK_ERROR_EXTENSION_NOT_PRESENT; return VK_ERROR_EXTENSION_NOT_PRESENT;
} }
if (window->context.client != GLFW_NO_API)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
}
return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
} }

View file

@ -329,21 +329,52 @@ static void destroyContextWGL(_GLFWwindow* window)
} }
} }
// Initialize WGL-specific extensions
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize WGL
// //
static void loadWGLExtensions(void) GLFWbool _glfwInitWGL(void)
{ {
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
HGLRC rc; HGLRC prc, rc;
HDC dc = GetDC(_glfw.win32.helperWindowHandle);; HDC pdc, dc;
_glfw.wgl.extensionsLoaded = GLFW_TRUE; if (_glfw.wgl.instance)
return GLFW_TRUE;
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
if (!_glfw.wgl.instance)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to load opengl32.dll");
return GLFW_FALSE;
}
_glfw.wgl.CreateContext = (PFN_wglCreateContext)
GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
_glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
_glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
_glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
_glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext");
_glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
_glfw.wgl.ShareLists = (PFN_wglShareLists)
GetProcAddress(_glfw.wgl.instance, "wglShareLists");
// NOTE: A dummy context has to be created for opengl32.dll to load the // NOTE: A dummy context has to be created for opengl32.dll to load the
// OpenGL ICD, from which we can then query WGL extensions // OpenGL ICD, from which we can then query WGL extensions
// NOTE: This code will accept the Microsoft GDI ICD; accelerated context // NOTE: This code will accept the Microsoft GDI ICD; accelerated context
// creation failure occurs during manual pixel format enumeration // creation failure occurs during manual pixel format enumeration
dc = GetDC(_glfw.win32.helperWindowHandle);;
ZeroMemory(&pfd, sizeof(pfd)); ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd); pfd.nSize = sizeof(pfd);
pfd.nVersion = 1; pfd.nVersion = 1;
@ -355,7 +386,7 @@ static void loadWGLExtensions(void)
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to set pixel format for dummy context"); "WGL: Failed to set pixel format for dummy context");
return; return GLFW_FALSE;
} }
rc = wglCreateContext(dc); rc = wglCreateContext(dc);
@ -363,15 +394,19 @@ static void loadWGLExtensions(void)
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to create dummy context"); "WGL: Failed to create dummy context");
return; return GLFW_FALSE;
} }
pdc = wglGetCurrentDC();
prc = wglGetCurrentContext();
if (!wglMakeCurrent(dc, rc)) if (!wglMakeCurrent(dc, rc))
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to make dummy context current"); "WGL: Failed to make dummy context current");
wglMakeCurrent(pdc, prc);
wglDeleteContext(rc); wglDeleteContext(rc);
return; return GLFW_FALSE;
} }
// NOTE: Functions must be loaded first as they're needed to retrieve the // NOTE: Functions must be loaded first as they're needed to retrieve the
@ -414,43 +449,8 @@ static void loadWGLExtensions(void)
_glfw.wgl.ARB_context_flush_control = _glfw.wgl.ARB_context_flush_control =
extensionSupportedWGL("WGL_ARB_context_flush_control"); extensionSupportedWGL("WGL_ARB_context_flush_control");
wglMakeCurrent(dc, NULL); wglMakeCurrent(pdc, prc);
wglDeleteContext(rc); wglDeleteContext(rc);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize WGL
//
GLFWbool _glfwInitWGL(void)
{
if (_glfw.wgl.instance)
return GLFW_TRUE;
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
if (!_glfw.wgl.instance)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to load opengl32.dll");
return GLFW_FALSE;
}
_glfw.wgl.CreateContext = (PFN_wglCreateContext)
GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
_glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
_glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
_glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
_glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
_glfw.wgl.ShareLists = (PFN_wglShareLists)
GetProcAddress(_glfw.wgl.instance, "wglShareLists");
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -480,9 +480,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
HGLRC share = NULL; HGLRC share = NULL;
if (!_glfw.wgl.extensionsLoaded)
loadWGLExtensions();
if (ctxconfig->share) if (ctxconfig->share)
share = ctxconfig->share->context.wgl.handle; share = ctxconfig->share->context.wgl.handle;

View file

@ -86,6 +86,7 @@ typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void);
typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
@ -94,6 +95,7 @@ typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
#define wglDeleteContext _glfw.wgl.DeleteContext #define wglDeleteContext _glfw.wgl.DeleteContext
#define wglGetProcAddress _glfw.wgl.GetProcAddress #define wglGetProcAddress _glfw.wgl.GetProcAddress
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC #define wglGetCurrentDC _glfw.wgl.GetCurrentDC
#define wglGetCurrentContext _glfw.wgl.GetCurrentContext
#define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglMakeCurrent _glfw.wgl.MakeCurrent
#define wglShareLists _glfw.wgl.ShareLists #define wglShareLists _glfw.wgl.ShareLists
@ -124,11 +126,10 @@ typedef struct _GLFWlibraryWGL
PFN_wglDeleteContext DeleteContext; PFN_wglDeleteContext DeleteContext;
PFN_wglGetProcAddress GetProcAddress; PFN_wglGetProcAddress GetProcAddress;
PFN_wglGetCurrentDC GetCurrentDC; PFN_wglGetCurrentDC GetCurrentDC;
PFN_wglGetCurrentContext GetCurrentContext;
PFN_wglMakeCurrent MakeCurrent; PFN_wglMakeCurrent MakeCurrent;
PFN_wglShareLists ShareLists; PFN_wglShareLists ShareLists;
GLFWbool extensionsLoaded;
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT;

View file

@ -351,6 +351,7 @@ static HWND createHelperWindow(void)
dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
_glfw.win32.deviceNotificationHandle =
RegisterDeviceNotificationW(window, RegisterDeviceNotificationW(window,
(DEV_BROADCAST_HDR*) &dbi, (DEV_BROADCAST_HDR*) &dbi,
DEVICE_NOTIFY_WINDOW_HANDLE); DEVICE_NOTIFY_WINDOW_HANDLE);
@ -543,6 +544,9 @@ int _glfwPlatformInit(void)
void _glfwPlatformTerminate(void) void _glfwPlatformTerminate(void)
{ {
if (_glfw.win32.deviceNotificationHandle)
UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
if (_glfw.win32.helperWindowHandle) if (_glfw.win32.helperWindowHandle)
DestroyWindow(_glfw.win32.helperWindowHandle); DestroyWindow(_glfw.win32.helperWindowHandle);

View file

@ -241,7 +241,7 @@ void _glfwPollMonitorsWin32(void)
// Change the current video mode // Change the current video mode
// //
GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{ {
GLFWvidmode current; GLFWvidmode current;
const GLFWvidmode* best; const GLFWvidmode* best;
@ -251,7 +251,7 @@ GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desire
best = _glfwChooseVideoMode(monitor, desired); best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current); _glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0) if (_glfwCompareVideoModes(&current, best) == 0)
return GLFW_TRUE; return;
ZeroMemory(&dm, sizeof(dm)); ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm); dm.dmSize = sizeof(dm);
@ -270,7 +270,9 @@ GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desire
NULL, NULL,
CDS_FULLSCREEN, CDS_FULLSCREEN,
NULL); NULL);
if (result != DISP_CHANGE_SUCCESSFUL) if (result == DISP_CHANGE_SUCCESSFUL)
monitor->win32.modeChanged = GLFW_TRUE;
else
{ {
const char* description = "Unknown error"; const char* description = "Unknown error";
@ -292,12 +294,7 @@ GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desire
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to set video mode: %s", "Win32: Failed to set video mode: %s",
description); description);
return GLFW_FALSE;
} }
monitor->win32.modeChanged = GLFW_TRUE;
return GLFW_TRUE;
} }
// Restore the previously saved (original) video mode // Restore the previously saved (original) video mode
@ -337,6 +334,10 @@ void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* ysc
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
DEVMODEW dm; DEVMODEW dm;

View file

@ -67,11 +67,6 @@
#include <xinput.h> #include <xinput.h>
#include <dbt.h> #include <dbt.h>
#if defined(_MSC_VER)
#include <malloc.h>
#define strdup _strdup
#endif
// HACK: Define macros that some windows.h variants don't // HACK: Define macros that some windows.h variants don't
#ifndef WM_MOUSEHWHEEL #ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E #define WM_MOUSEHWHEEL 0x020E
@ -105,12 +100,11 @@
#endif #endif
#if WINVER < 0x0601 #if WINVER < 0x0601
typedef struct tagCHANGEFILTERSTRUCT typedef struct
{ {
DWORD cbSize; DWORD cbSize;
DWORD ExtStatus; DWORD ExtStatus;
} CHANGEFILTERSTRUCT;
} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
#ifndef MSGFLT_ALLOW #ifndef MSGFLT_ALLOW
#define MSGFLT_ALLOW 1 #define MSGFLT_ALLOW 1
#endif #endif
@ -129,13 +123,13 @@ typedef struct
#endif /*Windows Vista*/ #endif /*Windows Vista*/
#ifndef DPI_ENUMS_DECLARED #ifndef DPI_ENUMS_DECLARED
typedef enum PROCESS_DPI_AWARENESS typedef enum
{ {
PROCESS_DPI_UNAWARE = 0, PROCESS_DPI_UNAWARE = 0,
PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_SYSTEM_DPI_AWARE = 1,
PROCESS_PER_MONITOR_DPI_AWARE = 2 PROCESS_PER_MONITOR_DPI_AWARE = 2
} PROCESS_DPI_AWARENESS; } PROCESS_DPI_AWARENESS;
typedef enum MONITOR_DPI_TYPE typedef enum
{ {
MDT_EFFECTIVE_DPI = 0, MDT_EFFECTIVE_DPI = 0,
MDT_ANGULAR_DPI = 1, MDT_ANGULAR_DPI = 1,
@ -209,7 +203,7 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*
// user32.dll function pointer typedefs // user32.dll function pointer typedefs
typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
@ -289,6 +283,7 @@ typedef struct _GLFWwindowWin32
typedef struct _GLFWlibraryWin32 typedef struct _GLFWlibraryWin32
{ {
HWND helperWindowHandle; HWND helperWindowHandle;
HDEVNOTIFY deviceNotificationHandle;
DWORD foregroundLockTimeout; DWORD foregroundLockTimeout;
int acquiredMonitorCount; int acquiredMonitorCount;
char* clipboardString; char* clipboardString;
@ -403,7 +398,7 @@ void _glfwUpdateKeyNamesWin32(void);
void _glfwInitTimerWin32(void); void _glfwInitTimerWin32(void);
void _glfwPollMonitorsWin32(void); void _glfwPollMonitorsWin32(void);
GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale);

View file

@ -384,14 +384,18 @@ static int getKeyMods(void)
{ {
int mods = 0; int mods = 0;
if (GetKeyState(VK_SHIFT) & (1 << 31)) if (GetKeyState(VK_SHIFT) & 0x8000)
mods |= GLFW_MOD_SHIFT; mods |= GLFW_MOD_SHIFT;
if (GetKeyState(VK_CONTROL) & (1 << 31)) if (GetKeyState(VK_CONTROL) & 0x8000)
mods |= GLFW_MOD_CONTROL; mods |= GLFW_MOD_CONTROL;
if (GetKeyState(VK_MENU) & (1 << 31)) if (GetKeyState(VK_MENU) & 0x8000)
mods |= GLFW_MOD_ALT; mods |= GLFW_MOD_ALT;
if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
mods |= GLFW_MOD_SUPER; mods |= GLFW_MOD_SUPER;
if (GetKeyState(VK_CAPITAL) & 1)
mods |= GLFW_MOD_CAPS_LOCK;
if (GetKeyState(VK_NUMLOCK) & 1)
mods |= GLFW_MOD_NUM_LOCK;
return mods; return mods;
} }
@ -402,14 +406,18 @@ static int getAsyncKeyMods(void)
{ {
int mods = 0; int mods = 0;
if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
mods |= GLFW_MOD_SHIFT; mods |= GLFW_MOD_SHIFT;
if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
mods |= GLFW_MOD_CONTROL; mods |= GLFW_MOD_CONTROL;
if (GetAsyncKeyState(VK_MENU) & (1 << 31)) if (GetAsyncKeyState(VK_MENU) & 0x8000)
mods |= GLFW_MOD_ALT; mods |= GLFW_MOD_ALT;
if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
mods |= GLFW_MOD_SUPER; mods |= GLFW_MOD_SUPER;
if (GetAsyncKeyState(VK_CAPITAL) & 1)
mods |= GLFW_MOD_CAPS_LOCK;
if (GetAsyncKeyState(VK_NUMLOCK) & 1)
mods |= GLFW_MOD_NUM_LOCK;
return mods; return mods;
} }
@ -463,30 +471,29 @@ static int translateKey(WPARAM wParam, LPARAM lParam)
return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF]; return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF];
} }
static void fitToMonitor(_GLFWwindow* window)
{
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
}
// Make the specified window and its video mode active on its monitor // Make the specified window and its video mode active on its monitor
// //
static GLFWbool acquireMonitor(_GLFWwindow* window) static void acquireMonitor(_GLFWwindow* window)
{ {
GLFWvidmode mode;
GLFWbool status;
int xpos, ypos;
if (!_glfw.win32.acquiredMonitorCount) if (!_glfw.win32.acquiredMonitorCount)
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
if (!window->monitor->window) if (!window->monitor->window)
_glfw.win32.acquiredMonitorCount++; _glfw.win32.acquiredMonitorCount++;
status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode); _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
_glfwPlatformGetVideoMode(window->monitor, &mode);
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
SetWindowPos(window->win32.handle, HWND_TOPMOST,
xpos, ypos, mode.width, mode.height,
SWP_NOACTIVATE | SWP_NOCOPYBITS);
_glfwInputMonitorWindow(window->monitor, window); _glfwInputMonitorWindow(window->monitor, window);
return status;
} }
// Remove the window and restore the original video mode // Remove the window and restore the original video mode
@ -893,7 +900,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (iconified) if (iconified)
releaseMonitor(window); releaseMonitor(window);
else else
{
acquireMonitor(window); acquireMonitor(window);
fitToMonitor(window);
}
} }
window->win32.iconified = iconified; window->win32.iconified = iconified;
@ -988,6 +998,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
return 0; return 0;
} }
case WM_DPICHANGED:
{
const float xscale = HIWORD(wParam) / 96.f;
const float yscale = LOWORD(wParam) / 96.f;
_glfwInputWindowContentScale(window, xscale, yscale);
break;
}
case WM_SETCURSOR: case WM_SETCURSOR:
{ {
if (LOWORD(lParam) == HTCLIENT) if (LOWORD(lParam) == HTCLIENT)
@ -1224,11 +1242,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
_glfwPlatformFocusWindow(window); _glfwPlatformFocusWindow(window);
if (!acquireMonitor(window)) acquireMonitor(window);
return GLFW_FALSE; fitToMonitor(window);
if (wndconfig->centerCursor)
centerCursor(window);
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1344,7 +1359,10 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
if (window->monitor) if (window->monitor)
{ {
if (window->monitor->window == window) if (window->monitor->window == window)
{
acquireMonitor(window); acquireMonitor(window);
fitToMonitor(window);
}
} }
else else
{ {
@ -1443,7 +1461,7 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
void _glfwPlatformShowWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
ShowWindow(window->win32.handle, SW_SHOW); ShowWindow(window->win32.handle, SW_SHOWNA);
} }
void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformHideWindow(_GLFWwindow* window)
@ -1474,7 +1492,10 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
if (monitor) if (monitor)
{ {
if (monitor->window == window) if (monitor->window == window)
{
acquireMonitor(window); acquireMonitor(window);
fitToMonitor(window);
}
} }
else else
{ {
@ -1497,20 +1518,27 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
if (monitor) if (monitor)
{ {
MONITORINFO mi = { sizeof(mi) };
UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
if (window->decorated) if (window->decorated)
{ {
DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
UINT flags = SWP_FRAMECHANGED | SWP_SHOWWINDOW |
SWP_NOACTIVATE | SWP_NOCOPYBITS |
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE;
style &= ~WS_OVERLAPPEDWINDOW; style &= ~WS_OVERLAPPEDWINDOW;
style |= getWindowStyle(window); style |= getWindowStyle(window);
SetWindowLongW(window->win32.handle, GWL_STYLE, style); SetWindowLongW(window->win32.handle, GWL_STYLE, style);
SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, flags); flags |= SWP_FRAMECHANGED;
} }
acquireMonitor(window); acquireMonitor(window);
GetMonitorInfo(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
flags);
} }
else else
{ {
@ -1562,6 +1590,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return IsZoomed(window->win32.handle); return IsZoomed(window->win32.handle);
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
return cursorInClientArea(window);
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
return window->win32.transparent && _glfwIsCompositionEnabledWin32(); return window->win32.transparent && _glfwIsCompositionEnabledWin32();

View file

@ -38,6 +38,8 @@
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Notifies shared code that a window has lost or received input focus
//
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
{ {
if (window->callbacks.focus) if (window->callbacks.focus)
@ -64,42 +66,68 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
} }
} }
// Notifies shared code that a window has moved
// The position is specified in client-area relative screen coordinates
//
void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) void _glfwInputWindowPos(_GLFWwindow* window, int x, int y)
{ {
if (window->callbacks.pos) if (window->callbacks.pos)
window->callbacks.pos((GLFWwindow*) window, x, y); window->callbacks.pos((GLFWwindow*) window, x, y);
} }
// Notifies shared code that a window has been resized
// The size is specified in screen coordinates
//
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) void _glfwInputWindowSize(_GLFWwindow* window, int width, int height)
{ {
if (window->callbacks.size) if (window->callbacks.size)
window->callbacks.size((GLFWwindow*) window, width, height); window->callbacks.size((GLFWwindow*) window, width, height);
} }
// Notifies shared code that a window has been iconified or restored
//
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
{ {
if (window->callbacks.iconify) if (window->callbacks.iconify)
window->callbacks.iconify((GLFWwindow*) window, iconified); window->callbacks.iconify((GLFWwindow*) window, iconified);
} }
// Notifies shared code that a window has been maximized or restored
//
void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized)
{ {
if (window->callbacks.maximize) if (window->callbacks.maximize)
window->callbacks.maximize((GLFWwindow*) window, maximized); window->callbacks.maximize((GLFWwindow*) window, maximized);
} }
// Notifies shared code that a window framebuffer has been resized
// The size is specified in pixels
//
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height)
{ {
if (window->callbacks.fbsize) if (window->callbacks.fbsize)
window->callbacks.fbsize((GLFWwindow*) window, width, height); window->callbacks.fbsize((GLFWwindow*) window, width, height);
} }
// Notifies shared code that a window content scale has changed
// The scale is specified as the ratio between the current and default DPI
//
void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale)
{
if (window->callbacks.scale)
window->callbacks.scale((GLFWwindow*) window, xscale, yscale);
}
// Notifies shared code that the window contents needs updating
//
void _glfwInputWindowDamage(_GLFWwindow* window) void _glfwInputWindowDamage(_GLFWwindow* window)
{ {
if (window->callbacks.refresh) if (window->callbacks.refresh)
window->callbacks.refresh((GLFWwindow*) window); window->callbacks.refresh((GLFWwindow*) window);
} }
// Notifies shared code that the user wishes to close a window
//
void _glfwInputWindowCloseRequest(_GLFWwindow* window) void _glfwInputWindowCloseRequest(_GLFWwindow* window)
{ {
window->shouldClose = GLFW_TRUE; window->shouldClose = GLFW_TRUE;
@ -108,6 +136,8 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window)
window->callbacks.close((GLFWwindow*) window); window->callbacks.close((GLFWwindow*) window);
} }
// Notifies shared code that a window has changed its desired monitor
//
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor)
{ {
window->monitor = monitor; window->monitor = monitor;
@ -127,7 +157,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
_GLFWctxconfig ctxconfig; _GLFWctxconfig ctxconfig;
_GLFWwndconfig wndconfig; _GLFWwndconfig wndconfig;
_GLFWwindow* window; _GLFWwindow* window;
_GLFWwindow* previous;
assert(title != NULL); assert(title != NULL);
assert(width >= 0); assert(width >= 0);
@ -153,16 +182,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
wndconfig.title = title; wndconfig.title = title;
ctxconfig.share = (_GLFWwindow*) share; ctxconfig.share = (_GLFWwindow*) share;
if (ctxconfig.share)
{
if (ctxconfig.client == GLFW_NO_API ||
ctxconfig.share->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
}
if (!_glfwIsValidContextConfig(&ctxconfig)) if (!_glfwIsValidContextConfig(&ctxconfig))
return NULL; return NULL;
@ -191,36 +210,32 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->numer = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE;
window->denom = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE;
// Save the currently current context so it can be restored later
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
if (ctxconfig.client != GLFW_NO_API)
glfwMakeContextCurrent(NULL);
// Open the actual window and create its context // Open the actual window and create its context
if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig))
{ {
glfwMakeContextCurrent((GLFWwindow*) previous);
glfwDestroyWindow((GLFWwindow*) window); glfwDestroyWindow((GLFWwindow*) window);
return NULL; return NULL;
} }
if (ctxconfig.client != GLFW_NO_API) if (ctxconfig.client != GLFW_NO_API)
{ {
window->context.makeCurrent(window); if (!_glfwRefreshContextAttribs(window, &ctxconfig))
// Retrieve the actual (as opposed to requested) context attributes
if (!_glfwRefreshContextAttribs(&ctxconfig))
{ {
glfwMakeContextCurrent((GLFWwindow*) previous);
glfwDestroyWindow((GLFWwindow*) window); glfwDestroyWindow((GLFWwindow*) window);
return NULL; return NULL;
} }
// Restore the previously current context (or NULL)
glfwMakeContextCurrent((GLFWwindow*) previous);
} }
if (!window->monitor) if (window->monitor)
{
if (wndconfig.centerCursor)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
}
}
else
{ {
if (wndconfig.visible) if (wndconfig.visible)
{ {
@ -349,9 +364,6 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_RETINA_FRAMEBUFFER: case GLFW_COCOA_RETINA_FRAMEBUFFER:
_glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
case GLFW_COCOA_FRAME_AUTOSAVE:
_glfw.hints.window.ns.frame = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_COCOA_GRAPHICS_SWITCHING: case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
@ -396,6 +408,31 @@ GLFWAPI void glfwWindowHint(int hint, int value)
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint);
} }
GLFWAPI void glfwWindowHintString(int hint, const char* value)
{
assert(value != NULL);
_GLFW_REQUIRE_INIT();
switch (hint)
{
case GLFW_COCOA_FRAME_NAME:
strncpy(_glfw.hints.window.ns.frameName, value,
sizeof(_glfw.hints.window.ns.frameName) - 1);
return;
case GLFW_X11_CLASS_NAME:
strncpy(_glfw.hints.window.x11.className, value,
sizeof(_glfw.hints.window.x11.className) - 1);
return;
case GLFW_X11_INSTANCE_NAME:
strncpy(_glfw.hints.window.x11.instanceName, value,
sizeof(_glfw.hints.window.x11.instanceName) - 1);
return;
}
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);
}
GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
@ -771,6 +808,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return _glfwPlatformWindowVisible(window); return _glfwPlatformWindowVisible(window);
case GLFW_MAXIMIZED: case GLFW_MAXIMIZED:
return _glfwPlatformWindowMaximized(window); return _glfwPlatformWindowMaximized(window);
case GLFW_HOVERED:
return _glfwPlatformWindowHovered(window);
case GLFW_TRANSPARENT_FRAMEBUFFER: case GLFW_TRANSPARENT_FRAMEBUFFER:
return _glfwPlatformFramebufferTransparent(window); return _glfwPlatformFramebufferTransparent(window);
case GLFW_RESIZABLE: case GLFW_RESIZABLE:
@ -1005,6 +1044,17 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle
return cbfun; return cbfun;
} }
GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle,
GLFWwindowcontentscalefun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun);
return cbfun;
}
GLFWAPI void glfwPollEvents(void) GLFWAPI void glfwPollEvents(void)
{ {
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();

View file

@ -32,9 +32,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/timerfd.h>
#include <unistd.h> #include <unistd.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-cursor.h>
static inline int min(int n1, int n2) static inline int min(int n1, int n2)
@ -42,6 +42,39 @@ static inline int min(int n1, int n2)
return n1 < n2 ? n1 : n2; return n1 < n2 ? n1 : n2;
} }
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which)
{
int focus;
_GLFWwindow* window = _glfw.windowListHead;
if (!which)
which = &focus;
while (window)
{
if (surface == window->wl.decorations.top.surface)
{
*which = topDecoration;
break;
}
if (surface == window->wl.decorations.left.surface)
{
*which = leftDecoration;
break;
}
if (surface == window->wl.decorations.right.surface)
{
*which = rightDecoration;
break;
}
if (surface == window->wl.decorations.bottom.surface)
{
*which = bottomDecoration;
break;
}
window = window->next;
}
return window;
}
static void pointerHandleEnter(void* data, static void pointerHandleEnter(void* data,
struct wl_pointer* pointer, struct wl_pointer* pointer,
uint32_t serial, uint32_t serial,
@ -49,11 +82,25 @@ static void pointerHandleEnter(void* data,
wl_fixed_t sx, wl_fixed_t sx,
wl_fixed_t sy) wl_fixed_t sy)
{ {
_GLFWwindow* window = wl_surface_get_user_data(surface); // Happens in the case we just destroyed the surface.
if (!surface)
return;
int focus = 0;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, &focus);
if (!window)
return;
}
window->wl.decorations.focus = focus;
_glfw.wl.pointerSerial = serial; _glfw.wl.pointerSerial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
window->wl.hovered = GLFW_TRUE;
_glfwPlatformSetCursor(window, window->wl.currentCursor); _glfwPlatformSetCursor(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE); _glfwInputCursorEnter(window, GLFW_TRUE);
} }
@ -68,11 +115,46 @@ static void pointerHandleLeave(void* data,
if (!window) if (!window)
return; return;
window->wl.hovered = GLFW_FALSE;
_glfw.wl.pointerSerial = serial; _glfw.wl.pointerSerial = serial;
_glfw.wl.pointerFocus = NULL; _glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE); _glfwInputCursorEnter(window, GLFW_FALSE);
} }
static void setCursor(const char* name)
{
struct wl_buffer* buffer;
struct wl_cursor* cursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
name);
if (!cursor)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor not found");
return;
}
image = cursor->images[0];
if (!image)
return;
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
image->hotspot_x,
image->hotspot_y);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
}
static void pointerHandleMotion(void* data, static void pointerHandleMotion(void* data,
struct wl_pointer* pointer, struct wl_pointer* pointer,
uint32_t time, uint32_t time,
@ -80,6 +162,7 @@ static void pointerHandleMotion(void* data,
wl_fixed_t sy) wl_fixed_t sy)
{ {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
const char* cursorName;
if (!window) if (!window)
return; return;
@ -92,13 +175,47 @@ static void pointerHandleMotion(void* data,
window->wl.cursorPosY = wl_fixed_to_double(sy); window->wl.cursorPosY = wl_fixed_to_double(sy);
} }
switch (window->wl.decorations.focus)
{
case mainWindow:
_glfwInputCursorPos(window, _glfwInputCursorPos(window,
wl_fixed_to_double(sx), wl_fixed_to_double(sx),
wl_fixed_to_double(sy)); wl_fixed_to_double(sy));
return;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "n-resize";
else
cursorName = "left_ptr";
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
cursorName = "sw-resize";
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
cursorName = "se-resize";
else
cursorName = "s-resize";
break;
default:
assert(0);
}
setCursor(cursorName);
} }
static void pointerHandleButton(void* data, static void pointerHandleButton(void* data,
struct wl_pointer* wl_pointer, struct wl_pointer* pointer,
uint32_t serial, uint32_t serial,
uint32_t time, uint32_t time,
uint32_t button, uint32_t button,
@ -107,8 +224,76 @@ static void pointerHandleButton(void* data,
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton; int glfwButton;
// Both xdg-shell and wl_shell use the same values.
uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE;
if (!window) if (!window)
return; return;
if (button == BTN_LEFT)
{
switch (window->wl.decorations.focus)
{
case mainWindow:
break;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP;
else
{
if (window->wl.xdg.toplevel)
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
else
wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);
}
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
else
edges = WL_SHELL_SURFACE_RESIZE_LEFT;
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_RIGHT;
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM;
break;
default:
assert(0);
}
if (edges != WL_SHELL_SURFACE_RESIZE_NONE)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
else
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
serial, edges);
}
}
else if (button == BTN_RIGHT)
{
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
return;
}
}
// Dont pass the button to the user if it was related to a decoration.
if (window->wl.decorations.focus != mainWindow)
return;
_glfw.wl.pointerSerial = serial; _glfw.wl.pointerSerial = serial;
@ -125,37 +310,28 @@ static void pointerHandleButton(void* data,
} }
static void pointerHandleAxis(void* data, static void pointerHandleAxis(void* data,
struct wl_pointer* wl_pointer, struct wl_pointer* pointer,
uint32_t time, uint32_t time,
uint32_t axis, uint32_t axis,
wl_fixed_t value) wl_fixed_t value)
{ {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
double scrollFactor; double x = 0.0, y = 0.0;
double x, y; // Wayland scroll events are in pointer motion coordinate space (think two
// finger scroll). The factor 10 is commonly used to convert to "scroll
// step means 1.0.
const double scrollFactor = 1.0 / 10.0;
if (!window) if (!window)
return; return;
/* Wayland scroll events are in pointer motion coordinate space (think assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
* two finger scroll). The factor 10 is commonly used to convert to axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
* "scroll step means 1.0. */
scrollFactor = 1.0/10.0;
switch (axis) if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
{
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
x = wl_fixed_to_double(value) * scrollFactor; x = wl_fixed_to_double(value) * scrollFactor;
y = 0.0; else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
break;
case WL_POINTER_AXIS_VERTICAL_SCROLL:
x = 0.0;
y = wl_fixed_to_double(value) * scrollFactor; y = wl_fixed_to_double(value) * scrollFactor;
break;
default:
assert(GLFW_FALSE);
break;
}
_glfwInputScroll(window, x, y); _glfwInputScroll(window, x, y);
} }
@ -264,6 +440,10 @@ static void keyboardHandleKeymap(void* data,
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
_glfw.wl.xkb.superMask = _glfw.wl.xkb.superMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
_glfw.wl.xkb.capsLockMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
_glfw.wl.xkb.numLockMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
} }
static void keyboardHandleEnter(void* data, static void keyboardHandleEnter(void* data,
@ -272,7 +452,17 @@ static void keyboardHandleEnter(void* data,
struct wl_surface* surface, struct wl_surface* surface,
struct wl_array* keys) struct wl_array* keys)
{ {
// Happens in the case we just destroyed the surface.
if (!surface)
return;
_GLFWwindow* window = wl_surface_get_user_data(surface); _GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, NULL);
if (!window)
return;
}
_glfw.wl.keyboardFocus = window; _glfw.wl.keyboardFocus = window;
_glfwInputWindowFocus(window, GLFW_TRUE); _glfwInputWindowFocus(window, GLFW_TRUE);
@ -322,7 +512,7 @@ static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
} }
#endif #endif
static void inputChar(_GLFWwindow* window, uint32_t key) static GLFWbool inputChar(_GLFWwindow* window, uint32_t key)
{ {
uint32_t code, numSyms; uint32_t code, numSyms;
long cp; long cp;
@ -347,6 +537,8 @@ static void inputChar(_GLFWwindow* window, uint32_t key)
_glfwInputChar(window, cp, mods, plain); _glfwInputChar(window, cp, mods, plain);
} }
} }
return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]);
} }
static void keyboardHandleKey(void* data, static void keyboardHandleKey(void* data,
@ -359,6 +551,8 @@ static void keyboardHandleKey(void* data,
int keyCode; int keyCode;
int action; int action;
_GLFWwindow* window = _glfw.wl.keyboardFocus; _GLFWwindow* window = _glfw.wl.keyboardFocus;
GLFWbool shouldRepeat;
struct itimerspec timer = {};
if (!window) if (!window)
return; return;
@ -371,7 +565,20 @@ static void keyboardHandleKey(void* data,
_glfw.wl.xkb.modifiers); _glfw.wl.xkb.modifiers);
if (action == GLFW_PRESS) if (action == GLFW_PRESS)
inputChar(window, key); {
shouldRepeat = inputChar(window, key);
if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
{
_glfw.wl.keyboardLastKey = keyCode;
_glfw.wl.keyboardLastScancode = key;
timer.it_interval.tv_sec = _glfw.wl.keyboardRepeatRate / 1000;
timer.it_interval.tv_nsec = (_glfw.wl.keyboardRepeatRate % 1000) * 1000000;
timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;
timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;
}
}
timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
} }
static void keyboardHandleModifiers(void* data, static void keyboardHandleModifiers(void* data,
@ -409,15 +616,36 @@ static void keyboardHandleModifiers(void* data,
modifiers |= GLFW_MOD_SHIFT; modifiers |= GLFW_MOD_SHIFT;
if (mask & _glfw.wl.xkb.superMask) if (mask & _glfw.wl.xkb.superMask)
modifiers |= GLFW_MOD_SUPER; modifiers |= GLFW_MOD_SUPER;
if (mask & _glfw.wl.xkb.capsLockMask)
modifiers |= GLFW_MOD_CAPS_LOCK;
if (mask & _glfw.wl.xkb.numLockMask)
modifiers |= GLFW_MOD_NUM_LOCK;
_glfw.wl.xkb.modifiers = modifiers; _glfw.wl.xkb.modifiers = modifiers;
} }
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
static void keyboardHandleRepeatInfo(void* data,
struct wl_keyboard* keyboard,
int32_t rate,
int32_t delay)
{
if (keyboard != _glfw.wl.keyboard)
return;
_glfw.wl.keyboardRepeatRate = rate;
_glfw.wl.keyboardRepeatDelay = delay;
}
#endif
static const struct wl_keyboard_listener keyboardListener = { static const struct wl_keyboard_listener keyboardListener = {
keyboardHandleKeymap, keyboardHandleKeymap,
keyboardHandleEnter, keyboardHandleEnter,
keyboardHandleLeave, keyboardHandleLeave,
keyboardHandleKey, keyboardHandleKey,
keyboardHandleModifiers, keyboardHandleModifiers,
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
keyboardHandleRepeatInfo,
#endif
}; };
static void seatHandleCapabilities(void* data, static void seatHandleCapabilities(void* data,
@ -447,8 +675,26 @@ static void seatHandleCapabilities(void* data,
} }
} }
static void seatHandleName(void* data,
struct wl_seat* seat,
const char* name)
{
}
static const struct wl_seat_listener seatListener = { static const struct wl_seat_listener seatListener = {
seatHandleCapabilities seatHandleCapabilities,
seatHandleName,
};
static void wmBaseHandlePing(void* data,
struct xdg_wm_base* wmBase,
uint32_t serial)
{
xdg_wm_base_pong(wmBase, serial);
}
static const struct xdg_wm_base_listener wmBaseListener = {
wmBaseHandlePing
}; };
static void registryHandleGlobal(void* data, static void registryHandleGlobal(void* data,
@ -464,6 +710,11 @@ static void registryHandleGlobal(void* data,
wl_registry_bind(registry, name, &wl_compositor_interface, wl_registry_bind(registry, name, &wl_compositor_interface,
_glfw.wl.compositorVersion); _glfw.wl.compositorVersion);
} }
else if (strcmp(interface, "wl_subcompositor") == 0)
{
_glfw.wl.subcompositor =
wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);
}
else if (strcmp(interface, "wl_shm") == 0) else if (strcmp(interface, "wl_shm") == 0)
{ {
_glfw.wl.shm = _glfw.wl.shm =
@ -482,11 +733,24 @@ static void registryHandleGlobal(void* data,
{ {
if (!_glfw.wl.seat) if (!_glfw.wl.seat)
{ {
_glfw.wl.seatVersion = min(4, version);
_glfw.wl.seat = _glfw.wl.seat =
wl_registry_bind(registry, name, &wl_seat_interface, 1); wl_registry_bind(registry, name, &wl_seat_interface,
_glfw.wl.seatVersion);
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
} }
} }
else if (strcmp(interface, "xdg_wm_base") == 0)
{
_glfw.wl.wmBase =
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
}
else if (strcmp(interface, "wp_viewporter") == 0)
{
_glfw.wl.viewporter =
wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
{ {
_glfw.wl.relativePointerManager = _glfw.wl.relativePointerManager =
@ -514,6 +778,18 @@ static void registryHandleGlobalRemove(void *data,
struct wl_registry *registry, struct wl_registry *registry,
uint32_t name) uint32_t name)
{ {
int i;
_GLFWmonitor* monitor;
for (i = 0; i < _glfw.monitorCount; ++i)
{
monitor = _glfw.monitors[i];
if (monitor->wl.name == name)
{
_glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);
return;
}
}
} }
@ -663,50 +939,84 @@ static void createKeyTables(void)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
_glfw.wl.xkb.handle = dlopen("libxkbcommon.so.0", RTLD_LAZY | RTLD_GLOBAL); _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
if (!_glfw.wl.cursor.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-cursor");
return GLFW_FALSE;
}
_glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
_glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
_glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
_glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
_glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
if (!_glfw.wl.egl.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-egl");
return GLFW_FALSE;
}
_glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");
_glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");
_glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");
_glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");
if (!_glfw.wl.xkb.handle) if (!_glfw.wl.xkb.handle)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libxkbcommon."); "Wayland: Failed to open libxkbcommon");
return GLFW_FALSE; return GLFW_FALSE;
} }
_glfw.wl.xkb.context_new = (PFN_xkb_context_new) _glfw.wl.xkb.context_new = (PFN_xkb_context_new)
dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");
_glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)
dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");
_glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)
dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");
_glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)
dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");
_glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)
dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");
_glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)
_glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");
_glfw.wl.xkb.state_new = (PFN_xkb_state_new) _glfw.wl.xkb.state_new = (PFN_xkb_state_new)
dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");
_glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)
dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");
_glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)
dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");
_glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)
dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");
_glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)
dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");
#ifdef HAVE_XKBCOMMON_COMPOSE_H #ifdef HAVE_XKBCOMMON_COMPOSE_H
_glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");
_glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");
_glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");
_glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");
_glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");
_glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
_glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
#endif #endif
_glfw.wl.display = wl_display_connect(NULL); _glfw.wl.display = wl_display_connect(NULL);
@ -741,13 +1051,17 @@ int _glfwPlatformInit(void)
_glfwInitTimerPOSIX(); _glfwInitTimerPOSIX();
_glfw.wl.timerfd = -1;
if (_glfw.wl.seatVersion >= 4)
_glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (_glfw.wl.pointer && _glfw.wl.shm) if (_glfw.wl.pointer && _glfw.wl.shm)
{ {
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
if (!_glfw.wl.cursorTheme) if (!_glfw.wl.cursorTheme)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load default cursor theme\n"); "Wayland: Unable to load default cursor theme");
return GLFW_FALSE; return GLFW_FALSE;
} }
_glfw.wl.cursorSurface = _glfw.wl.cursorSurface =
@ -759,30 +1073,52 @@ int _glfwPlatformInit(void)
void _glfwPlatformTerminate(void) void _glfwPlatformTerminate(void)
{ {
_glfwTerminateEGL();
_glfwTerminateJoysticksLinux(); _glfwTerminateJoysticksLinux();
_glfwTerminateEGL();
if (_glfw.wl.egl.handle)
{
_glfw_dlclose(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
#ifdef HAVE_XKBCOMMON_COMPOSE_H #ifdef HAVE_XKBCOMMON_COMPOSE_H
if (_glfw.wl.xkb.composeState)
xkb_compose_state_unref(_glfw.wl.xkb.composeState); xkb_compose_state_unref(_glfw.wl.xkb.composeState);
#endif #endif
if (_glfw.wl.xkb.keymap)
xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_keymap_unref(_glfw.wl.xkb.keymap);
if (_glfw.wl.xkb.state)
xkb_state_unref(_glfw.wl.xkb.state); xkb_state_unref(_glfw.wl.xkb.state);
if (_glfw.wl.xkb.context)
xkb_context_unref(_glfw.wl.xkb.context); xkb_context_unref(_glfw.wl.xkb.context);
if (_glfw.wl.xkb.handle)
dlclose(_glfw.wl.xkb.handle); {
_glfw_dlclose(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL; _glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursorTheme) if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme); wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursor.handle)
{
_glfw_dlclose(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
if (_glfw.wl.cursorSurface) if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface); wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.subcompositor)
wl_subcompositor_destroy(_glfw.wl.subcompositor);
if (_glfw.wl.compositor) if (_glfw.wl.compositor)
wl_compositor_destroy(_glfw.wl.compositor); wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm) if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm); wl_shm_destroy(_glfw.wl.shm);
if (_glfw.wl.shell) if (_glfw.wl.shell)
wl_shell_destroy(_glfw.wl.shell); wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.pointer) if (_glfw.wl.pointer)
wl_pointer_destroy(_glfw.wl.pointer); wl_pointer_destroy(_glfw.wl.pointer);
if (_glfw.wl.keyboard) if (_glfw.wl.keyboard)

View file

@ -52,7 +52,7 @@ static void geometry(void* data,
monitor->heightMM = physicalHeight; monitor->heightMM = physicalHeight;
snprintf(name, sizeof(name), "%s %s", make, model); snprintf(name, sizeof(name), "%s %s", make, model);
monitor->name = strdup(name); monitor->name = _glfw_strdup(name);
} }
static void mode(void* data, static void mode(void* data,
@ -136,6 +136,7 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
monitor->wl.scale = 1; monitor->wl.scale = 1;
monitor->wl.output = output; monitor->wl.output = output;
monitor->wl.name = name;
wl_output_add_listener(output, &outputListener, monitor); wl_output_add_listener(output, &outputListener, monitor);
} }
@ -145,6 +146,12 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
if (monitor->wl.output)
wl_output_destroy(monitor->wl.output);
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
if (xpos) if (xpos)

View file

@ -52,6 +52,8 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#include "egl_context.h" #include "egl_context.h"
#include "osmesa_context.h" #include "osmesa_context.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
@ -71,11 +73,40 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#define _GLFW_PLATFORM_CONTEXT_STATE #define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
struct wl_cursor_image {
uint32_t width;
uint32_t height;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t delay;
};
struct wl_cursor {
unsigned int image_count;
struct wl_cursor_image** images;
char* name;
};
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
typedef struct wl_buffer* (* PFN_wl_cursor_image_get_buffer)(struct wl_cursor_image*);
#define wl_cursor_theme_load _glfw.wl.cursor.theme_load
#define wl_cursor_theme_destroy _glfw.wl.cursor.theme_destroy
#define wl_cursor_theme_get_cursor _glfw.wl.cursor.theme_get_cursor
#define wl_cursor_image_get_buffer _glfw.wl.cursor.image_get_buffer
typedef struct wl_egl_window* (* PFN_wl_egl_window_create)(struct wl_surface*, int, int);
typedef void (* PFN_wl_egl_window_destroy)(struct wl_egl_window*);
typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int, int);
#define wl_egl_window_create _glfw.wl.egl.window_create
#define wl_egl_window_destroy _glfw.wl.egl.window_destroy
#define wl_egl_window_resize _glfw.wl.egl.window_resize
typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags); typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags);
typedef void (* PFN_xkb_context_unref)(struct xkb_context*); typedef void (* PFN_xkb_context_unref)(struct xkb_context*);
typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*);
typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*);
typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t);
typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*);
typedef void (* PFN_xkb_state_unref)(struct xkb_state*); typedef void (* PFN_xkb_state_unref)(struct xkb_state*);
typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
@ -86,6 +117,7 @@ typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum
#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string
#define xkb_keymap_unref _glfw.wl.xkb.keymap_unref #define xkb_keymap_unref _glfw.wl.xkb.keymap_unref
#define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index #define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index
#define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats
#define xkb_state_new _glfw.wl.xkb.state_new #define xkb_state_new _glfw.wl.xkb.state_new
#define xkb_state_unref _glfw.wl.xkb.state_unref #define xkb_state_unref _glfw.wl.xkb.state_unref
#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms #define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms
@ -109,6 +141,28 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st
#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
#endif #endif
#define _GLFW_DECORATION_WIDTH 4
#define _GLFW_DECORATION_TOP 24
#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)
typedef enum _GLFWdecorationSideWayland
{
mainWindow,
topDecoration,
leftDecoration,
rightDecoration,
bottomDecoration,
} _GLFWdecorationSideWayland;
typedef struct _GLFWdecorationWayland
{
struct wl_surface* surface;
struct wl_subsurface* subsurface;
struct wp_viewport* viewport;
} _GLFWdecorationWayland;
// Wayland-specific per-window data // Wayland-specific per-window data
// //
@ -117,12 +171,18 @@ typedef struct _GLFWwindowWayland
int width, height; int width, height;
GLFWbool visible; GLFWbool visible;
GLFWbool maximized; GLFWbool maximized;
GLFWbool hovered;
GLFWbool transparent; GLFWbool transparent;
struct wl_surface* surface; struct wl_surface* surface;
struct wl_egl_window* native; struct wl_egl_window* native;
struct wl_shell_surface* shellSurface; struct wl_shell_surface* shellSurface;
struct wl_callback* callback; struct wl_callback* callback;
struct {
struct xdg_surface* surface;
struct xdg_toplevel* toplevel;
} xdg;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
double cursorPosX, cursorPosY; double cursorPosX, cursorPosY;
@ -142,6 +202,15 @@ typedef struct _GLFWwindowWayland
struct zwp_idle_inhibitor_v1* idleInhibitor; struct zwp_idle_inhibitor_v1* idleInhibitor;
// This is a hack to prevent auto-iconification on creation.
GLFWbool justCreated;
struct {
struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom;
int focus;
} decorations;
} _GLFWwindowWayland; } _GLFWwindowWayland;
// Wayland-specific global data // Wayland-specific global data
@ -151,21 +220,30 @@ typedef struct _GLFWlibraryWayland
struct wl_display* display; struct wl_display* display;
struct wl_registry* registry; struct wl_registry* registry;
struct wl_compositor* compositor; struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_shell* shell; struct wl_shell* shell;
struct wl_shm* shm; struct wl_shm* shm;
struct wl_seat* seat; struct wl_seat* seat;
struct wl_pointer* pointer; struct wl_pointer* pointer;
struct wl_keyboard* keyboard; struct wl_keyboard* keyboard;
struct xdg_wm_base* wmBase;
struct wp_viewporter* viewporter;
struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager; struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
int compositorVersion; int compositorVersion;
int seatVersion;
struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorTheme;
struct wl_surface* cursorSurface; struct wl_surface* cursorSurface;
uint32_t pointerSerial; uint32_t pointerSerial;
int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay;
int keyboardLastKey;
int keyboardLastScancode;
int timerfd;
short int keycodes[256]; short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1]; short int scancodes[GLFW_KEY_LAST + 1];
@ -183,6 +261,8 @@ typedef struct _GLFWlibraryWayland
xkb_mod_mask_t altMask; xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask; xkb_mod_mask_t shiftMask;
xkb_mod_mask_t superMask; xkb_mod_mask_t superMask;
xkb_mod_mask_t capsLockMask;
xkb_mod_mask_t numLockMask;
unsigned int modifiers; unsigned int modifiers;
PFN_xkb_context_new context_new; PFN_xkb_context_new context_new;
@ -190,6 +270,7 @@ typedef struct _GLFWlibraryWayland
PFN_xkb_keymap_new_from_string keymap_new_from_string; PFN_xkb_keymap_new_from_string keymap_new_from_string;
PFN_xkb_keymap_unref keymap_unref; PFN_xkb_keymap_unref keymap_unref;
PFN_xkb_keymap_mod_get_index keymap_mod_get_index; PFN_xkb_keymap_mod_get_index keymap_mod_get_index;
PFN_xkb_keymap_key_repeats keymap_key_repeats;
PFN_xkb_state_new state_new; PFN_xkb_state_new state_new;
PFN_xkb_state_unref state_unref; PFN_xkb_state_unref state_unref;
PFN_xkb_state_key_get_syms state_key_get_syms; PFN_xkb_state_key_get_syms state_key_get_syms;
@ -210,6 +291,23 @@ typedef struct _GLFWlibraryWayland
_GLFWwindow* pointerFocus; _GLFWwindow* pointerFocus;
_GLFWwindow* keyboardFocus; _GLFWwindow* keyboardFocus;
struct {
void* handle;
PFN_wl_cursor_theme_load theme_load;
PFN_wl_cursor_theme_destroy theme_destroy;
PFN_wl_cursor_theme_get_cursor theme_get_cursor;
PFN_wl_cursor_image_get_buffer image_get_buffer;
} cursor;
struct {
void* handle;
PFN_wl_egl_window_create window_create;
PFN_wl_egl_window_destroy window_destroy;
PFN_wl_egl_window_resize window_resize;
} egl;
} _GLFWlibraryWayland; } _GLFWlibraryWayland;
// Wayland-specific per-monitor data // Wayland-specific per-monitor data
@ -217,6 +315,7 @@ typedef struct _GLFWlibraryWayland
typedef struct _GLFWmonitorWayland typedef struct _GLFWmonitorWayland
{ {
struct wl_output* output; struct wl_output* output;
int name;
int currentMode; int currentMode;
int x; int x;
@ -237,3 +336,4 @@ typedef struct _GLFWcursorWayland
void _glfwAddOutputWayland(uint32_t name, uint32_t version); void _glfwAddOutputWayland(uint32_t name, uint32_t version);

View file

@ -35,11 +35,9 @@
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/timerfd.h>
#include <poll.h> #include <poll.h>
#include <wayland-egl.h>
#include <wayland-cursor.h>
static void handlePing(void* data, static void handlePing(void* data,
struct wl_shell_surface* shellSurface, struct wl_shell_surface* shellSurface,
@ -60,6 +58,16 @@ static void handleConfigure(void* data,
if (!window->monitor) if (!window->monitor)
{ {
if (_glfw.wl.viewporter && window->decorated)
{
width -= _GLFW_DECORATION_HORIZONTAL;
height -= _GLFW_DECORATION_VERTICAL;
}
if (width < 1)
width = 1;
if (height < 1)
height = 1;
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{ {
aspectRatio = (float)width / (float)height; aspectRatio = (float)width / (float)height;
@ -97,9 +105,265 @@ static const struct wl_shell_surface_listener shellSurfaceListener = {
handlePopupDone handlePopupDone
}; };
static int
createTmpfileCloexec(char* tmpname)
{
int fd;
fd = mkostemp(tmpname, O_CLOEXEC);
if (fd >= 0)
unlink(tmpname);
return fd;
}
/*
* Create a new, unique, anonymous file of the given size, and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*
* posix_fallocate() is used to guarantee that disk space is available
* for the file at the given size. If disk space is insufficent, errno
* is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead.
*/
static int
createAnonymousFile(off_t size)
{
static const char template[] = "/glfw-shared-XXXXXX";
const char* path;
char* name;
int fd;
int ret;
path = getenv("XDG_RUNTIME_DIR");
if (!path)
{
errno = ENOENT;
return -1;
}
name = calloc(strlen(path) + sizeof(template), 1);
strcpy(name, path);
strcat(name, template);
fd = createTmpfileCloexec(name);
free(name);
if (fd < 0)
return -1;
ret = posix_fallocate(fd, 0, size);
if (ret != 0)
{
close(fd);
errno = ret;
return -1;
}
return fd;
}
static struct wl_buffer* createShmBuffer(const GLFWimage* image)
{
struct wl_shm_pool* pool;
struct wl_buffer* buffer;
int stride = image->width * 4;
int length = image->width * image->height * 4;
void* data;
int fd, i;
fd = createAnonymousFile(length);
if (fd < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Creating a buffer file for %d B failed: %m",
length);
return GLFW_FALSE;
}
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: mmap failed: %m");
close(fd);
return GLFW_FALSE;
}
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
close(fd);
unsigned char* source = (unsigned char*) image->pixels;
unsigned char* target = data;
for (i = 0; i < image->width * image->height; i++, source += 4)
{
unsigned int alpha = source[3];
*target++ = (unsigned char) ((source[2] * alpha) / 255);
*target++ = (unsigned char) ((source[1] * alpha) / 255);
*target++ = (unsigned char) ((source[0] * alpha) / 255);
*target++ = (unsigned char) alpha;
}
buffer =
wl_shm_pool_create_buffer(pool, 0,
image->width,
image->height,
stride, WL_SHM_FORMAT_ARGB8888);
munmap(data, length);
wl_shm_pool_destroy(pool);
return buffer;
}
static void createDecoration(_GLFWdecorationWayland* decoration,
struct wl_surface* parent,
struct wl_buffer* buffer, GLFWbool opaque,
int x, int y,
int width, int height)
{
struct wl_region* region;
decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);
decoration->subsurface =
wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
decoration->surface, parent);
wl_subsurface_set_position(decoration->subsurface, x, y);
decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
decoration->surface);
wp_viewport_set_destination(decoration->viewport, width, height);
wl_surface_attach(decoration->surface, buffer, 0, 0);
if (opaque)
{
region = wl_compositor_create_region(_glfw.wl.compositor);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_opaque_region(decoration->surface, region);
wl_surface_commit(decoration->surface);
wl_region_destroy(region);
}
else
wl_surface_commit(decoration->surface);
}
static void createDecorations(_GLFWwindow* window)
{
unsigned char data[] = { 224, 224, 224, 255 };
const GLFWimage image = { 1, 1, data };
GLFWbool opaque = (data[3] == 255);
if (!_glfw.wl.viewporter)
return;
if (!window->wl.decorations.buffer)
window->wl.decorations.buffer = createShmBuffer(&image);
createDecoration(&window->wl.decorations.top, window->wl.surface,
window->wl.decorations.buffer, opaque,
0, -_GLFW_DECORATION_TOP,
window->wl.width, _GLFW_DECORATION_TOP);
createDecoration(&window->wl.decorations.left, window->wl.surface,
window->wl.decorations.buffer, opaque,
-_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP,
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
createDecoration(&window->wl.decorations.right, window->wl.surface,
window->wl.decorations.buffer, opaque,
window->wl.width, -_GLFW_DECORATION_TOP,
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
createDecoration(&window->wl.decorations.bottom, window->wl.surface,
window->wl.decorations.buffer, opaque,
-_GLFW_DECORATION_WIDTH, window->wl.height,
window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);
}
static void destroyDecoration(_GLFWdecorationWayland* decoration)
{
if (decoration->surface)
wl_surface_destroy(decoration->surface);
if (decoration->subsurface)
wl_subsurface_destroy(decoration->subsurface);
if (decoration->viewport)
wp_viewport_destroy(decoration->viewport);
decoration->surface = NULL;
decoration->subsurface = NULL;
decoration->viewport = NULL;
}
static void destroyDecorations(_GLFWwindow* window)
{
destroyDecoration(&window->wl.decorations.top);
destroyDecoration(&window->wl.decorations.left);
destroyDecoration(&window->wl.decorations.right);
destroyDecoration(&window->wl.decorations.bottom);
}
// Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window)
{
struct wl_region* region;
region = wl_compositor_create_region(_glfw.wl.compositor);
if (!region)
return;
wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
wl_surface_set_opaque_region(window->wl.surface, region);
wl_surface_commit(window->wl.surface);
wl_region_destroy(region);
}
static void resizeWindow(_GLFWwindow* window)
{
int scale = window->wl.scale;
int scaledWidth = window->wl.width * scale;
int scaledHeight = window->wl.height * scale;
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
if (!window->wl.transparent)
setOpaqueRegion(window);
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
_glfwInputWindowContentScale(window, scale, scale);
if (!window->wl.decorations.top.surface)
return;
// Top decoration.
wp_viewport_set_destination(window->wl.decorations.top.viewport,
window->wl.width, _GLFW_DECORATION_TOP);
wl_surface_commit(window->wl.decorations.top.surface);
// Left decoration.
wp_viewport_set_destination(window->wl.decorations.left.viewport,
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
wl_surface_commit(window->wl.decorations.left.surface);
// Right decoration.
wl_subsurface_set_position(window->wl.decorations.right.subsurface,
window->wl.width, -_GLFW_DECORATION_TOP);
wp_viewport_set_destination(window->wl.decorations.right.viewport,
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
wl_surface_commit(window->wl.decorations.right.surface);
// Bottom decoration.
wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,
-_GLFW_DECORATION_WIDTH, window->wl.height);
wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);
wl_surface_commit(window->wl.decorations.bottom.surface);
}
static void checkScaleChange(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window)
{ {
int scaledWidth, scaledHeight;
int scale = 1; int scale = 1;
int i; int i;
int monitorScale; int monitorScale;
@ -120,11 +384,8 @@ static void checkScaleChange(_GLFWwindow* window)
if (scale != window->wl.scale) if (scale != window->wl.scale)
{ {
window->wl.scale = scale; window->wl.scale = scale;
scaledWidth = window->wl.width * scale;
scaledHeight = window->wl.height * scale;
wl_surface_set_buffer_scale(window->wl.surface, scale); wl_surface_set_buffer_scale(window->wl.surface, scale);
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); resizeWindow(window);
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
} }
} }
@ -174,21 +435,6 @@ static const struct wl_surface_listener surfaceListener = {
handleLeave handleLeave
}; };
// Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window)
{
struct wl_region* region;
region = wl_compositor_create_region(_glfw.wl.compositor);
if (!region)
return;
wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
wl_surface_set_opaque_region(window->wl.surface, region);
wl_surface_commit(window->wl.surface);
wl_region_destroy(region);
}
static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
{ {
if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager) if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)
@ -233,15 +479,49 @@ static GLFWbool createSurface(_GLFWwindow* window,
if (!window->wl.transparent) if (!window->wl.transparent)
setOpaqueRegion(window); setOpaqueRegion(window);
if (window->decorated && !window->monitor)
createDecorations(window);
return GLFW_TRUE; return GLFW_TRUE;
} }
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate)
{
if (window->wl.xdg.toplevel)
{
xdg_toplevel_set_fullscreen(
window->wl.xdg.toplevel,
monitor->wl.output);
}
else if (window->wl.shellSurface)
{
wl_shell_surface_set_fullscreen(
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
refreshRate * 1000, // Convert Hz to mHz.
monitor->wl.output);
}
setIdleInhibitor(window, GLFW_TRUE);
destroyDecorations(window);
}
static GLFWbool createShellSurface(_GLFWwindow* window) static GLFWbool createShellSurface(_GLFWwindow* window)
{ {
if (!_glfw.wl.shell)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: wl_shell protocol not available");
return GLFW_FALSE;
}
window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell, window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,
window->wl.surface); window->wl.surface);
if (!window->wl.shellSurface) if (!window->wl.shellSurface)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Shell surface creation failed");
return GLFW_FALSE; return GLFW_FALSE;
}
wl_shell_surface_add_listener(window->wl.shellSurface, wl_shell_surface_add_listener(window->wl.shellSurface,
&shellSurfaceListener, &shellSurfaceListener,
@ -252,12 +532,7 @@ static GLFWbool createShellSurface(_GLFWwindow* window)
if (window->monitor) if (window->monitor)
{ {
wl_shell_surface_set_fullscreen( setFullscreen(window, window->monitor, 0);
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0,
window->monitor->wl.output);
setIdleInhibitor(window, GLFW_TRUE);
} }
else if (window->wl.maximized) else if (window->wl.maximized)
{ {
@ -275,16 +550,144 @@ static GLFWbool createShellSurface(_GLFWwindow* window)
return GLFW_TRUE; return GLFW_TRUE;
} }
static int static void xdgToplevelHandleConfigure(void* data,
createTmpfileCloexec(char* tmpname) struct xdg_toplevel* toplevel,
int32_t width,
int32_t height,
struct wl_array* states)
{ {
int fd; _GLFWwindow* window = data;
float aspectRatio;
float targetRatio;
uint32_t* state;
GLFWbool maximized = GLFW_FALSE;
GLFWbool fullscreen = GLFW_FALSE;
GLFWbool activated = GLFW_FALSE;
fd = mkostemp(tmpname, O_CLOEXEC); wl_array_for_each(state, states)
if (fd >= 0) {
unlink(tmpname); switch (*state)
{
case XDG_TOPLEVEL_STATE_MAXIMIZED:
maximized = GLFW_TRUE;
break;
case XDG_TOPLEVEL_STATE_FULLSCREEN:
fullscreen = GLFW_TRUE;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
activated = GLFW_TRUE;
break;
}
}
return fd; if (width != 0 && height != 0)
{
if (!maximized && !fullscreen)
{
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
aspectRatio = (float)width / (float)height;
targetRatio = (float)window->numer / (float)window->denom;
if (aspectRatio < targetRatio)
height = width / targetRatio;
else if (aspectRatio > targetRatio)
width = height * targetRatio;
}
}
_glfwInputWindowSize(window, width, height);
_glfwPlatformSetWindowSize(window, width, height);
_glfwInputWindowDamage(window);
}
if (!window->wl.justCreated && !activated && window->autoIconify)
_glfwPlatformIconifyWindow(window);
_glfwInputWindowFocus(window, activated);
window->wl.justCreated = GLFW_FALSE;
}
static void xdgToplevelHandleClose(void* data,
struct xdg_toplevel* toplevel)
{
_GLFWwindow* window = data;
_glfwInputWindowCloseRequest(window);
}
static const struct xdg_toplevel_listener xdgToplevelListener = {
xdgToplevelHandleConfigure,
xdgToplevelHandleClose
};
static void xdgSurfaceHandleConfigure(void* data,
struct xdg_surface* surface,
uint32_t serial)
{
xdg_surface_ack_configure(surface, serial);
}
static const struct xdg_surface_listener xdgSurfaceListener = {
xdgSurfaceHandleConfigure
};
static GLFWbool createXdgSurface(_GLFWwindow* window)
{
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
window->wl.surface);
if (!window->wl.xdg.surface)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: xdg-surface creation failed");
return GLFW_FALSE;
}
xdg_surface_add_listener(window->wl.xdg.surface,
&xdgSurfaceListener,
window);
window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface);
if (!window->wl.xdg.toplevel)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: xdg-toplevel creation failed");
return GLFW_FALSE;
}
xdg_toplevel_add_listener(window->wl.xdg.toplevel,
&xdgToplevelListener,
window);
if (window->wl.title)
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)
xdg_toplevel_set_min_size(window->wl.xdg.toplevel,
window->minwidth, window->minheight);
if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
xdg_toplevel_set_max_size(window->wl.xdg.toplevel,
window->maxwidth, window->maxheight);
if (window->monitor)
{
xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,
window->monitor->wl.output);
setIdleInhibitor(window, GLFW_TRUE);
}
else if (window->wl.maximized)
{
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE);
}
else
{
setIdleInhibitor(window, GLFW_FALSE);
}
wl_surface_commit(window->wl.surface);
wl_display_roundtrip(_glfw.wl.display);
return GLFW_TRUE;
} }
static void static void
@ -293,7 +696,10 @@ handleEvents(int timeout)
struct wl_display* display = _glfw.wl.display; struct wl_display* display = _glfw.wl.display;
struct pollfd fds[] = { struct pollfd fds[] = {
{ wl_display_get_fd(display), POLLIN }, { wl_display_get_fd(display), POLLIN },
{ _glfw.wl.timerfd, POLLIN },
}; };
ssize_t read_ret;
uint64_t repeats, i;
while (wl_display_prepare_read(display) != 0) while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display); wl_display_dispatch_pending(display);
@ -313,7 +719,9 @@ handleEvents(int timeout)
return; return;
} }
if (poll(fds, 1, timeout) > 0) if (poll(fds, 2, timeout) > 0)
{
if (fds[0].revents & POLLIN)
{ {
wl_display_read_events(display); wl_display_read_events(display);
wl_display_dispatch_pending(display); wl_display_dispatch_pending(display);
@ -322,62 +730,23 @@ handleEvents(int timeout)
{ {
wl_display_cancel_read(display); wl_display_cancel_read(display);
} }
}
/* if (fds[1].revents & POLLIN)
* Create a new, unique, anonymous file of the given size, and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*
* posix_fallocate() is used to guarantee that disk space is available
* for the file at the given size. If disk space is insufficent, errno
* is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead.
*/
int
createAnonymousFile(off_t size)
{
static const char template[] = "/glfw-shared-XXXXXX";
const char* path;
char* name;
int fd;
int ret;
path = getenv("XDG_RUNTIME_DIR");
if (!path)
{ {
errno = ENOENT; read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats));
return -1; if (read_ret != 8)
return;
for (i = 0; i < repeats; ++i)
_glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey,
_glfw.wl.keyboardLastScancode, GLFW_REPEAT,
_glfw.wl.xkb.modifiers);
} }
}
name = calloc(strlen(path) + sizeof(template), 1); else
strcpy(name, path);
strcat(name, template);
fd = createTmpfileCloexec(name);
free(name);
if (fd < 0)
return -1;
ret = posix_fallocate(fd, 0, size);
if (ret != 0)
{ {
close(fd); wl_display_cancel_read(display);
errno = ret;
return -1;
} }
return fd;
} }
// Translates a GLFW standard cursor to a theme cursor name // Translates a GLFW standard cursor to a theme cursor name
@ -411,6 +780,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
{ {
window->wl.justCreated = GLFW_TRUE;
window->wl.transparent = fbconfig->transparent; window->wl.transparent = fbconfig->transparent;
if (!createSurface(window, wndconfig)) if (!createSurface(window, wndconfig))
@ -436,17 +806,27 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
} }
if (wndconfig->title) if (wndconfig->title)
window->wl.title = strdup(wndconfig->title); window->wl.title = _glfw_strdup(wndconfig->title);
if (wndconfig->visible) if (wndconfig->visible)
{
if (_glfw.wl.wmBase)
{
if (!createXdgSurface(window))
return GLFW_FALSE;
}
else
{ {
if (!createShellSurface(window)) if (!createShellSurface(window))
return GLFW_FALSE; return GLFW_FALSE;
}
window->wl.visible = GLFW_TRUE; window->wl.visible = GLFW_TRUE;
} }
else else
{ {
window->wl.xdg.surface = NULL;
window->wl.xdg.toplevel = NULL;
window->wl.shellSurface = NULL; window->wl.shellSurface = NULL;
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
} }
@ -479,12 +859,22 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->context.destroy) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
destroyDecorations(window);
if (window->wl.decorations.buffer)
wl_buffer_destroy(window->wl.decorations.buffer);
if (window->wl.native) if (window->wl.native)
wl_egl_window_destroy(window->wl.native); wl_egl_window_destroy(window->wl.native);
if (window->wl.shellSurface) if (window->wl.shellSurface)
wl_shell_surface_destroy(window->wl.shellSurface); wl_shell_surface_destroy(window->wl.shellSurface);
if (window->wl.xdg.toplevel)
xdg_toplevel_destroy(window->wl.xdg.toplevel);
if (window->wl.xdg.surface)
xdg_surface_destroy(window->wl.xdg.surface);
if (window->wl.surface) if (window->wl.surface)
wl_surface_destroy(window->wl.surface); wl_surface_destroy(window->wl.surface);
@ -496,8 +886,10 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{ {
if (window->wl.title) if (window->wl.title)
free(window->wl.title); free(window->wl.title);
window->wl.title = strdup(title); window->wl.title = _glfw_strdup(title);
if (window->wl.shellSurface) if (window->wl.xdg.toplevel)
xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
else if (window->wl.shellSurface)
wl_shell_surface_set_title(window->wl.shellSurface, title); wl_shell_surface_set_title(window->wl.shellSurface, title);
} }
@ -535,22 +927,33 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{ {
int scaledWidth = width * window->wl.scale;
int scaledHeight = height * window->wl.scale;
window->wl.width = width; window->wl.width = width;
window->wl.height = height; window->wl.height = height;
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); resizeWindow(window);
if (!window->wl.transparent)
setOpaqueRegion(window);
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
} }
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
if (_glfw.wl.wmBase)
{
if (window->wl.xdg.toplevel)
{
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
wl_surface_commit(window->wl.surface);
}
}
else
{
// TODO: find out how to trigger a resize. // TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler. // The actual limits are checked in the wl_shell_surface::configure handler.
}
} }
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
@ -570,8 +973,17 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
// TODO: will need a proper implementation once decorations are if (window->decorated && !window->monitor)
// implemented, but for now just leave everything as 0. {
if (top)
*top = _GLFW_DECORATION_TOP;
if (left)
*left = _GLFW_DECORATION_WIDTH;
if (right)
*right = _GLFW_DECORATION_WIDTH;
if (bottom)
*bottom = _GLFW_DECORATION_WIDTH;
}
} }
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
@ -585,41 +997,59 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{ {
// TODO: move to xdg_shell instead of wl_shell. if (_glfw.wl.wmBase)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Iconify window not supported"); "Wayland: Iconify window not supported on wl_shell");
}
} }
void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{ {
// TODO: also do the same for iconified. if (window->wl.xdg.toplevel)
if (window->monitor || window->wl.maximized)
{ {
if (window->wl.shellSurface) if (window->monitor)
wl_shell_surface_set_toplevel(window->wl.shellSurface); xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
if (window->wl.maximized)
window->wl.maximized = GLFW_FALSE; xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
// There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do here.
} }
else if (window->wl.shellSurface)
{
if (window->monitor || window->wl.maximized)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
}
_glfwInputWindowMonitor(window, NULL);
window->wl.maximized = GLFW_FALSE;
} }
void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{ {
if (!window->monitor && !window->wl.maximized) if (window->wl.xdg.toplevel)
{ {
if (window->wl.shellSurface) xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
}
else if (window->wl.shellSurface)
{ {
// Let the compositor select the best output. // Let the compositor select the best output.
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
} }
window->wl.maximized = GLFW_TRUE; window->wl.maximized = GLFW_TRUE;
}
} }
void _glfwPlatformShowWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
if (!window->monitor) if (!window->wl.visible)
{ {
if (!window->wl.shellSurface) if (_glfw.wl.wmBase)
createXdgSurface(window);
else if (!window->wl.shellSurface)
createShellSurface(window); createShellSurface(window);
window->wl.visible = GLFW_TRUE; window->wl.visible = GLFW_TRUE;
} }
@ -627,12 +1057,19 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformHideWindow(_GLFWwindow* window)
{ {
if (!window->monitor) if (window->wl.xdg.toplevel)
{ {
if (window->wl.shellSurface) xdg_toplevel_destroy(window->wl.xdg.toplevel);
wl_shell_surface_destroy(window->wl.shellSurface); xdg_surface_destroy(window->wl.xdg.surface);
window->wl.visible = GLFW_FALSE; window->wl.xdg.toplevel = NULL;
window->wl.xdg.surface = NULL;
} }
else if (window->wl.shellSurface)
{
wl_shell_surface_destroy(window->wl.shellSurface);
window->wl.shellSurface = NULL;
}
window->wl.visible = GLFW_FALSE;
} }
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
@ -656,17 +1093,17 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
{ {
if (monitor) if (monitor)
{ {
wl_shell_surface_set_fullscreen( setFullscreen(window, monitor, refreshRate);
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
refreshRate * 1000, // Convert Hz to mHz.
monitor->wl.output);
setIdleInhibitor(window, GLFW_TRUE);
} }
else else
{ {
if (window->wl.xdg.toplevel)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
else if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface); wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (window->decorated)
createDecorations(window);
} }
_glfwInputWindowMonitor(window, monitor); _glfwInputWindowMonitor(window, monitor);
} }
@ -678,7 +1115,8 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
int _glfwPlatformWindowIconified(_GLFWwindow* window) int _glfwPlatformWindowIconified(_GLFWwindow* window)
{ {
// TODO: move to xdg_shell, wl_shell doesn't have any iconified concept. // wl_shell doesn't have any iconified concept, and xdg-shell doesnt give
// any way to request whether a surface is iconified.
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -692,6 +1130,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return window->wl.maximized; return window->wl.maximized;
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
return window->wl.hovered;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
return window->wl.transparent; return window->wl.transparent;
@ -706,9 +1149,13 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{ {
// TODO if (!window->monitor)
_glfwInputError(GLFW_PLATFORM_ERROR, {
"Wayland: Window attribute setting not implemented yet"); if (enabled)
createDecorations(window);
else
destroyDecorations(window);
}
} }
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
@ -788,53 +1235,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image, const GLFWimage* image,
int xhot, int yhot) int xhot, int yhot)
{ {
struct wl_shm_pool* pool; cursor->wl.buffer = createShmBuffer(image);
int stride = image->width * 4;
int length = image->width * image->height * 4;
void* data;
int fd, i;
fd = createAnonymousFile(length);
if (fd < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Creating a buffer file for %d B failed: %m",
length);
return GLFW_FALSE;
}
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Cursor mmap failed: %m");
close(fd);
return GLFW_FALSE;
}
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
close(fd);
unsigned char* source = (unsigned char*) image->pixels;
unsigned char* target = data;
for (i = 0; i < image->width * image->height; i++, source += 4)
{
unsigned int alpha = source[3];
*target++ = (unsigned char) ((source[2] * alpha) / 255);
*target++ = (unsigned char) ((source[1] * alpha) / 255);
*target++ = (unsigned char) ((source[0] * alpha) / 255);
*target++ = (unsigned char) alpha;
}
cursor->wl.buffer =
wl_shm_pool_create_buffer(pool, 0,
image->width,
image->height,
stride, WL_SHM_FORMAT_ARGB8888);
munmap(data, length);
wl_shm_pool_destroy(pool);
cursor->wl.width = image->width; cursor->wl.width = image->width;
cursor->wl.height = image->height; cursor->wl.height = image->height;
cursor->wl.xhot = xhot; cursor->wl.xhot = xhot;

View file

@ -461,17 +461,17 @@ static void detectEWMH(void)
// //
static GLFWbool initExtensions(void) static GLFWbool initExtensions(void)
{ {
_glfw.x11.vidmode.handle = dlopen("libXxf86vm.so.1", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
if (_glfw.x11.vidmode.handle) if (_glfw.x11.vidmode.handle)
{ {
_glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension) _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
_glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
_glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
_glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
_glfw.x11.vidmode.available = _glfw.x11.vidmode.available =
XF86VidModeQueryExtension(_glfw.x11.display, XF86VidModeQueryExtension(_glfw.x11.display,
@ -479,13 +479,13 @@ static GLFWbool initExtensions(void)
&_glfw.x11.vidmode.errorBase); &_glfw.x11.vidmode.errorBase);
} }
_glfw.x11.xi.handle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6");
if (_glfw.x11.xi.handle) if (_glfw.x11.xi.handle)
{ {
_glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
_glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
dlsym(_glfw.x11.xi.handle, "XISelectEvents"); _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents");
if (XQueryExtension(_glfw.x11.display, if (XQueryExtension(_glfw.x11.display,
"XInputExtension", "XInputExtension",
@ -505,45 +505,45 @@ static GLFWbool initExtensions(void)
} }
} }
_glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2");
if (_glfw.x11.randr.handle) if (_glfw.x11.randr.handle)
{ {
_glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma");
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
_glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
_glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
_glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources");
_glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
_glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
_glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
_glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo");
_glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
_glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
_glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension");
_glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion");
_glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput");
_glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
_glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
_glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration");
if (XRRQueryExtension(_glfw.x11.display, if (XRRQueryExtension(_glfw.x11.display,
&_glfw.x11.randr.eventBase, &_glfw.x11.randr.eventBase,
@ -593,26 +593,26 @@ static GLFWbool initExtensions(void)
RROutputChangeNotifyMask); RROutputChangeNotifyMask);
} }
_glfw.x11.xcursor.handle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1");
if (_glfw.x11.xcursor.handle) if (_glfw.x11.xcursor.handle)
{ {
_glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate");
_glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
} }
_glfw.x11.xinerama.handle = dlopen("libXinerama.so.1", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1");
if (_glfw.x11.xinerama.handle) if (_glfw.x11.xinerama.handle)
{ {
_glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive");
_glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
_glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
if (XineramaQueryExtension(_glfw.x11.display, if (XineramaQueryExtension(_glfw.x11.display,
&_glfw.x11.xinerama.major, &_glfw.x11.xinerama.major,
@ -644,22 +644,22 @@ static GLFWbool initExtensions(void)
} }
} }
_glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so.1", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1");
if (_glfw.x11.x11xcb.handle) if (_glfw.x11.x11xcb.handle)
{ {
_glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection)
dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
} }
_glfw.x11.xrender.handle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1");
if (_glfw.x11.xrender.handle) if (_glfw.x11.xrender.handle)
{ {
_glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
_glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
_glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
if (XRenderQueryExtension(_glfw.x11.display, if (XRenderQueryExtension(_glfw.x11.display,
&_glfw.x11.xrender.errorBase, &_glfw.x11.xrender.errorBase,
@ -994,8 +994,6 @@ void _glfwPlatformTerminate(void)
_glfw.x11.im = NULL; _glfw.x11.im = NULL;
} }
_glfwTerminateEGL();
if (_glfw.x11.display) if (_glfw.x11.display)
{ {
XCloseDisplay(_glfw.x11.display); XCloseDisplay(_glfw.x11.display);
@ -1004,30 +1002,31 @@ void _glfwPlatformTerminate(void)
if (_glfw.x11.x11xcb.handle) if (_glfw.x11.x11xcb.handle)
{ {
dlclose(_glfw.x11.x11xcb.handle); _glfw_dlclose(_glfw.x11.x11xcb.handle);
_glfw.x11.x11xcb.handle = NULL; _glfw.x11.x11xcb.handle = NULL;
} }
if (_glfw.x11.xcursor.handle) if (_glfw.x11.xcursor.handle)
{ {
dlclose(_glfw.x11.xcursor.handle); _glfw_dlclose(_glfw.x11.xcursor.handle);
_glfw.x11.xcursor.handle = NULL; _glfw.x11.xcursor.handle = NULL;
} }
if (_glfw.x11.randr.handle) if (_glfw.x11.randr.handle)
{ {
dlclose(_glfw.x11.randr.handle); _glfw_dlclose(_glfw.x11.randr.handle);
_glfw.x11.randr.handle = NULL; _glfw.x11.randr.handle = NULL;
} }
if (_glfw.x11.xinerama.handle) if (_glfw.x11.xinerama.handle)
{ {
dlclose(_glfw.x11.xinerama.handle); _glfw_dlclose(_glfw.x11.xinerama.handle);
_glfw.x11.xinerama.handle = NULL; _glfw.x11.xinerama.handle = NULL;
} }
// NOTE: This needs to be done after XCloseDisplay, as libGL registers // NOTE: These need to be unloaded after XCloseDisplay, as they register
// cleanup callbacks that get called by it // cleanup callbacks that get called by that function
_glfwTerminateEGL();
_glfwTerminateGLX(); _glfwTerminateGLX();
#if defined(__linux__) #if defined(__linux__)

View file

@ -203,8 +203,7 @@ void _glfwPollMonitorsX11(void)
free(disconnected); free(disconnected);
} }
else
if (!_glfw.monitorCount)
{ {
const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
@ -217,7 +216,7 @@ void _glfwPollMonitorsX11(void)
// Set the current video mode for the specified monitor // Set the current video mode for the specified monitor
// //
GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{ {
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{ {
@ -232,7 +231,7 @@ GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
best = _glfwChooseVideoMode(monitor, desired); best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current); _glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0) if (_glfwCompareVideoModes(&current, best) == 0)
return GLFW_TRUE; return;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
@ -270,16 +269,7 @@ GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
XRRFreeOutputInfo(oi); XRRFreeOutputInfo(oi);
XRRFreeCrtcInfo(ci); XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr); XRRFreeScreenResources(sr);
if (!native)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Monitor mode list changed");
return GLFW_FALSE;
} }
}
return GLFW_TRUE;
} }
// Restore the saved (original) video mode for the specified monitor // Restore the saved (original) video mode for the specified monitor
@ -318,6 +308,10 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)

View file

@ -425,7 +425,7 @@ typedef struct _GLFWcursorX11
void _glfwPollMonitorsX11(void); void _glfwPollMonitorsX11(void);
GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot);

View file

@ -212,6 +212,10 @@ static int translateState(int state)
mods |= GLFW_MOD_ALT; mods |= GLFW_MOD_ALT;
if (state & Mod4Mask) if (state & Mod4Mask)
mods |= GLFW_MOD_SUPER; mods |= GLFW_MOD_SUPER;
if (state & LockMask)
mods |= GLFW_MOD_CAPS_LOCK;
if (state & Mod2Mask)
mods |= GLFW_MOD_NUM_LOCK;
return mods; return mods;
} }
@ -707,20 +711,25 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
{ {
XClassHint* hint = XAllocClassHint(); XClassHint* hint = XAllocClassHint();
if (strlen(_glfw.hints.init.x11.className) && if (strlen(wndconfig->x11.instanceName) &&
strlen(_glfw.hints.init.x11.classClass)) strlen(wndconfig->x11.className))
{ {
hint->res_name = (char*) _glfw.hints.init.x11.className; hint->res_name = (char*) wndconfig->x11.instanceName;
hint->res_class = (char*) _glfw.hints.init.x11.classClass; hint->res_class = (char*) wndconfig->x11.className;
}
else if (strlen(wndconfig->title))
{
hint->res_name = (char*) wndconfig->title;
hint->res_class = (char*) wndconfig->title;
} }
else else
{ {
const char* resourceName = getenv("RESOURCE_NAME");
if (resourceName && strlen(resourceName))
hint->res_name = (char*) resourceName;
else if (strlen(wndconfig->title))
hint->res_name = (char*) wndconfig->title;
else
hint->res_name = (char*) "glfw-application"; hint->res_name = (char*) "glfw-application";
if (strlen(wndconfig->title))
hint->res_class = (char*) wndconfig->title;
else
hint->res_class = (char*) "GLFW-Application"; hint->res_class = (char*) "GLFW-Application";
} }
@ -1047,7 +1056,7 @@ static const char* getSelectionString(Atom selection)
if (targets[i] == XA_STRING) if (targets[i] == XA_STRING)
*selectionString = convertLatin1toUTF8(data); *selectionString = convertLatin1toUTF8(data);
else else
*selectionString = strdup(data); *selectionString = _glfw_strdup(data);
} }
XFree(data); XFree(data);
@ -1067,10 +1076,8 @@ static const char* getSelectionString(Atom selection)
// Make the specified window and its video mode active on its monitor // Make the specified window and its video mode active on its monitor
// //
static GLFWbool acquireMonitor(_GLFWwindow* window) static void acquireMonitor(_GLFWwindow* window)
{ {
GLFWbool status;
if (_glfw.x11.saver.count == 0) if (_glfw.x11.saver.count == 0)
{ {
// Remember old screen saver settings // Remember old screen saver settings
@ -1088,7 +1095,7 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
if (!window->monitor->window) if (!window->monitor->window)
_glfw.x11.saver.count++; _glfw.x11.saver.count++;
status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); _glfwSetVideoModeX11(window->monitor, &window->videoMode);
if (window->x11.overrideRedirect) if (window->x11.overrideRedirect)
{ {
@ -1104,7 +1111,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
} }
_glfwInputMonitorWindow(window->monitor, window); _glfwInputMonitorWindow(window->monitor, window);
return status;
} }
// Remove the window and restore the original video mode // Remove the window and restore the original video mode
@ -1968,11 +1974,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
updateWindowMode(window); updateWindowMode(window);
if (!acquireMonitor(window)) acquireMonitor(window);
return GLFW_FALSE;
if (wndconfig->centerCursor)
centerCursor(window);
} }
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);
@ -2444,6 +2446,28 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return maximized; return maximized;
} }
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
Window w = _glfw.x11.root;
while (w)
{
Window root;
int rootX, rootY, childX, childY;
unsigned int mask;
if (!XQueryPointer(_glfw.x11.display, w,
&root, &w, &rootX, &rootY, &childX, &childY, &mask))
{
return GLFW_FALSE;
}
if (w == window->x11.handle)
return GLFW_TRUE;
}
return GLFW_FALSE;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{ {
if (!window->x11.transparent) if (!window->x11.transparent)
@ -2803,7 +2827,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetClipboardString(const char* string) void _glfwPlatformSetClipboardString(const char* string)
{ {
free(_glfw.x11.clipboardString); free(_glfw.x11.clipboardString);
_glfw.x11.clipboardString = strdup(string); _glfw.x11.clipboardString = _glfw_strdup(string);
XSetSelectionOwner(_glfw.x11.display, XSetSelectionOwner(_glfw.x11.display,
_glfw.x11.CLIPBOARD, _glfw.x11.CLIPBOARD,
@ -2995,7 +3019,7 @@ GLFWAPI void glfwSetX11SelectionString(const char* string)
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
free(_glfw.x11.primarySelectionString); free(_glfw.x11.primarySelectionString);
_glfw.x11.primarySelectionString = strdup(string); _glfw.x11.primarySelectionString = _glfw_strdup(string);
XSetSelectionOwner(_glfw.x11.display, XSetSelectionOwner(_glfw.x11.display,
_glfw.x11.PRIMARY, _glfw.x11.PRIMARY,

View file

@ -86,7 +86,6 @@
//#include <stdbool.h> //#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View file

@ -612,6 +612,8 @@ int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t
return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate); return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate);
} }
#define ALIGN(x, b) (((x) + ((b) - 1)) & ~((b) - 1))
#define ALIGN_PTR(x, b) (void*)(((uintptr_t)(x) + ((b) - 1)) & ~((b) - 1))
int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) { int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) {
#if JAR_XM_DEFENSIVE #if JAR_XM_DEFENSIVE
int ret; int ret;
@ -644,9 +646,11 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
ctx->rate = rate; ctx->rate = rate;
mempool = jar_xm_load_module(ctx, moddata, moddata_length, mempool); mempool = jar_xm_load_module(ctx, moddata, moddata_length, mempool);
mempool = ALIGN_PTR(mempool, 16);
ctx->channels = (jar_xm_channel_context_t*)mempool; ctx->channels = (jar_xm_channel_context_t*)mempool;
mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t); mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t);
mempool = ALIGN_PTR(mempool, 16);
ctx->global_volume = 1.f; ctx->global_volume = 1.f;
ctx->amplification = .25f; /* XXX: some bad modules may still clip. Find out something better. */ ctx->amplification = .25f; /* XXX: some bad modules may still clip. Find out something better. */
@ -671,6 +675,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
ch->actual_panning = .5f; ch->actual_panning = .5f;
} }
mempool = ALIGN_PTR(mempool, 16);
ctx->row_loop_count = (uint8_t*)mempool; ctx->row_loop_count = (uint8_t*)mempool;
mempool += MAX_NUM_ROWS * sizeof(uint8_t); mempool += MAX_NUM_ROWS * sizeof(uint8_t);
@ -850,15 +855,15 @@ size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_
uint16_t num_instruments; uint16_t num_instruments;
/* Read the module header */ /* Read the module header */
num_channels = READ_U16(offset + 8);
num_channels = READ_U16(offset + 8); num_channels = READ_U16(offset + 8);
num_patterns = READ_U16(offset + 10); num_patterns = READ_U16(offset + 10);
memory_needed += num_patterns * sizeof(jar_xm_pattern_t); memory_needed += num_patterns * sizeof(jar_xm_pattern_t);
memory_needed = ALIGN(memory_needed, 16);
num_instruments = READ_U16(offset + 12); num_instruments = READ_U16(offset + 12);
memory_needed += num_instruments * sizeof(jar_xm_instrument_t); memory_needed += num_instruments * sizeof(jar_xm_instrument_t);
memory_needed = ALIGN(memory_needed, 16);
memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * sizeof(uint8_t); /* Module length */ memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * sizeof(uint8_t); /* Module length */
@ -875,6 +880,7 @@ size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_
/* Pattern header length + packed pattern data size */ /* Pattern header length + packed pattern data size */
offset += READ_U32(offset) + READ_U16(offset + 7); offset += READ_U32(offset) + READ_U16(offset + 7);
} }
memory_needed = ALIGN(memory_needed, 16);
/* Read instrument headers */ /* Read instrument headers */
for(uint16_t i = 0; i < num_instruments; ++i) { for(uint16_t i = 0; i < num_instruments; ++i) {
@ -940,9 +946,11 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd
mod->patterns = (jar_xm_pattern_t*)mempool; mod->patterns = (jar_xm_pattern_t*)mempool;
mempool += mod->num_patterns * sizeof(jar_xm_pattern_t); mempool += mod->num_patterns * sizeof(jar_xm_pattern_t);
mempool = ALIGN_PTR(mempool, 16);
mod->instruments = (jar_xm_instrument_t*)mempool; mod->instruments = (jar_xm_instrument_t*)mempool;
mempool += mod->num_instruments * sizeof(jar_xm_instrument_t); mempool += mod->num_instruments * sizeof(jar_xm_instrument_t);
mempool = ALIGN_PTR(mempool, 16);
uint16_t flags = READ_U32(offset + 14); uint16_t flags = READ_U32(offset + 14);
mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES; mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES;
@ -1032,6 +1040,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd
offset += packed_patterndata_size; offset += packed_patterndata_size;
} }
mempool = ALIGN_PTR(mempool, 16);
/* Read instruments */ /* Read instruments */
for(uint16_t i = 0; i < ctx->module.num_instruments; ++i) { for(uint16_t i = 0; i < ctx->module.num_instruments; ++i) {
@ -2562,16 +2571,10 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx)
return total; return total;
} }
//-------------------------------------------- //--------------------------------------------
//FILE LOADER - TODO - NEEDS TO BE CLEANED UP //FILE LOADER - TODO - NEEDS TO BE CLEANED UP
//-------------------------------------------- //--------------------------------------------
#undef DEBUG #undef DEBUG
#define DEBUG(...) do { \ #define DEBUG(...) do { \
fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, __VA_ARGS__); \
@ -2599,6 +2602,7 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx)
int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const char* filename) { int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const char* filename) {
FILE* xmf; FILE* xmf;
int size; int size;
int ret;
xmf = fopen(filename, "rb"); xmf = fopen(filename, "rb");
if(xmf == NULL) { if(xmf == NULL) {
@ -2618,16 +2622,20 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
} }
char* data = malloc(size + 1); char* data = malloc(size + 1);
if(fread(data, 1, size, xmf) < size) { if(!data || fread(data, 1, size, xmf) < size) {
fclose(xmf); fclose(xmf);
DEBUG_ERR("fread() failed"); DEBUG_ERR(data ? "fread() failed" : "malloc() failed");
free(data);
*ctx = NULL; *ctx = NULL;
return 5; return 5;
} }
fclose(xmf); fclose(xmf);
switch(jar_xm_create_context_safe(ctx, data, size, rate)) { ret = jar_xm_create_context_safe(ctx, data, size, rate);
free(data);
switch(ret) {
case 0: case 0:
break; break;
@ -2652,13 +2660,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
return 0; return 0;
} }
#endif//end of JAR_XM_IMPLEMENTATION #endif//end of JAR_XM_IMPLEMENTATION
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
#endif//end of INCLUDE_JAR_XM_H #endif//end of INCLUDE_JAR_XM_H

View file

@ -2037,7 +2037,7 @@ static inline float mal_mix_f32(float x, float y, float a)
// Atomics // Atomics
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#if defined(_WIN32) && defined(_MSC_VER) #if defined(_WIN32) && !defined(__GNUC__)
#define mal_memory_barrier() MemoryBarrier() #define mal_memory_barrier() MemoryBarrier()
#define mal_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b) #define mal_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b)
#define mal_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b) #define mal_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b)
@ -6412,6 +6412,7 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t
free(NAME); free(NAME);
free(DESC); free(DESC);
free(IOID); free(IOID);
ppNextDeviceHint += 1;
if (foundDevice) { if (foundDevice) {
break; break;
@ -6974,7 +6975,7 @@ static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type ty
// When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do // When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do
// everything by the size of a fragment. // everything by the size of a fragment.
pDevice->oss.pIntermediaryBuffer = mal_malloc(fragmentSizeInBytes); pDevice->oss.pIntermediaryBuffer = mal_malloc(actualFragmentSizeInBytes);
if (pDevice->oss.pIntermediaryBuffer == NULL) { if (pDevice->oss.pIntermediaryBuffer == NULL) {
close(pDevice->oss.fd); close(pDevice->oss.fd);
return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY);

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* rgif.h original implementation by Charlie Tangora [ctangora -at- gmail -dot- com] * rgif.h original implementation (gif.h) by Charlie Tangora [ctangora -at- gmail -dot- com]
* adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5) * adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5)
* *
* This file offers a simple, very limited way to create animated GIFs directly in code. * This file offers a simple, very limited way to create animated GIFs directly in code.
@ -28,7 +28,32 @@
* 3) Finally, call GifEnd() to close the file handle and free memory. * 3) Finally, call GifEnd() to close the file handle and free memory.
* *
* *
* LICENSE: public domain (www.unlicense.org) * LICENSE: This software is available under 2 licenses -- choose whichever you prefer
*
* ALTERNATIVE A - MIT License
*
* Copyright (c) 2017 Ramon Santamaria
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ------------------------------------------------------------------------------
*
* ALTERNATIVE B - public domain (www.unlicense.org)
* *
* This is free and unencumbered software released into the public domain. * This is free and unencumbered software released into the public domain.
* Anyone is free to copy, modify, publish, use, compile, sell, or distribute this * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
@ -886,7 +911,6 @@ static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, u
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
memset(codetree, 0, sizeof(GifLzwNode)*4096); memset(codetree, 0, sizeof(GifLzwNode)*4096);
curCode = -1;
codeSize = minCodeSize + 1; codeSize = minCodeSize + 1;
maxCode = clearCode + 1; maxCode = clearCode + 1;
} }

View file

@ -1,4 +1,4 @@
/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.18 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -48,6 +48,8 @@ LICENSE
RECENT REVISION HISTORY: RECENT REVISION HISTORY:
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
@ -74,11 +76,11 @@ RECENT REVISION HISTORY:
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments) github:urraka (animated gif) Junggon Kim (PNM comments)
Daniel Gibson (16-bit TGA) Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG) socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs) Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
Fabian "ryg" Giesen Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
Arseny Kapoulkine Arseny Kapoulkine
John-Mark Allen John-Mark Allen
@ -87,16 +89,17 @@ RECENT REVISION HISTORY:
Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
Dave Moore Roy Eltham Hayaki Saito Nathan Reed Dave Moore Roy Eltham Hayaki Saito Nathan Reed
Won Chun Luke Graham Johan Duparc Nick Verigakis Won Chun Luke Graham Johan Duparc Nick Verigakis
the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh
Janez Zemva John Bartholomew Michal Cichon github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou
Jonathan Blow Ken Hamada Tero Hanninen github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar
Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex
Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex Ryamond Barbiero Paul Du Bois Engin Manap github:grim210
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210 Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
Blazej Dariusz Roszkowski Gregory Mullen github:phprus Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
Christian Floisand Kevin Schmidt github:poppolopoppo Christian Floisand Kevin Schmidt github:darealshinji
Blazej Dariusz Roszkowski github:Michaelangel007
*/ */
#ifndef STBI_INCLUDE_STB_IMAGE_H #ifndef STBI_INCLUDE_STB_IMAGE_H
@ -105,10 +108,8 @@ RECENT REVISION HISTORY:
// DOCUMENTATION // DOCUMENTATION
// //
// Limitations: // Limitations:
// - no 16-bit-per-channel PNG
// - no 12-bit-per-channel JPEG // - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding // - no JPEGs with arithmetic coding
// - no 1-bit BMP
// - GIF always returns *comp=4 // - GIF always returns *comp=4
// //
// Basic usage (see HDR discussion below for HDR usage): // Basic usage (see HDR discussion below for HDR usage):
@ -353,6 +354,10 @@ typedef struct
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
#endif
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
@ -416,11 +421,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding // get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit (char const *filename);
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif #endif
@ -504,7 +512,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#include <limits.h> #include <limits.h>
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
#include <math.h> // ldexp #include <math.h> // ldexp, pow
#endif #endif
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
@ -784,6 +792,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__png_test(stbi__context *s); static int stbi__png_test(stbi__context *s);
static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__png_is16(stbi__context *s);
#endif #endif
#ifndef STBI_NO_BMP #ifndef STBI_NO_BMP
@ -802,6 +811,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__psd_test(stbi__context *s); static int stbi__psd_test(stbi__context *s);
static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__psd_is16(stbi__context *s);
#endif #endif
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
@ -819,6 +829,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
#ifndef STBI_NO_GIF #ifndef STBI_NO_GIF
static int stbi__gif_test(stbi__context *s); static int stbi__gif_test(stbi__context *s);
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
#endif #endif
@ -893,11 +904,13 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add)
} }
// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
{ {
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
} }
#endif
// mallocs with size overflow checking // mallocs with size overflow checking
static void *stbi__malloc_mad2(int a, int b, int add) static void *stbi__malloc_mad2(int a, int b, int add)
@ -912,11 +925,13 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add)
return stbi__malloc(a*b*c + add); return stbi__malloc(a*b*c + add);
} }
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
{ {
if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
return stbi__malloc(a*b*c*d + add); return stbi__malloc(a*b*c*d + add);
} }
#endif
// stbi__err - error // stbi__err - error
// stbi__errpf - error returning pointer to float // stbi__errpf - error returning pointer to float
@ -1054,6 +1069,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
} }
} }
static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
{
int slice;
int slice_size = w * h * bytes_per_pixel;
stbi_uc *bytes = (stbi_uc *)image;
for (slice = 0; slice < z; ++slice) {
stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
bytes += slice_size;
}
}
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
stbi__result_info ri; stbi__result_info ri;
@ -1103,7 +1130,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
return (stbi__uint16 *) result; return (stbi__uint16 *) result;
} }
#ifndef STBI_NO_HDR #if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR)
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
{ {
if (stbi__vertically_flip_on_load && result != NULL) { if (stbi__vertically_flip_on_load && result != NULL) {
@ -1205,6 +1232,22 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
} }
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
unsigned char *result;
stbi__context s;
stbi__start_mem(&s,buffer,len);
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
if (stbi__vertically_flip_on_load) {
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
}
return result;
}
#endif
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
@ -1291,9 +1334,13 @@ STBIDEF int stbi_is_hdr (char const *filename)
STBIDEF int stbi_is_hdr_from_file(FILE *f) STBIDEF int stbi_is_hdr_from_file(FILE *f)
{ {
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
long pos = ftell(f);
int res;
stbi__context s; stbi__context s;
stbi__start_file(&s,f); stbi__start_file(&s,f);
return stbi__hdr_test(&s); res = stbi__hdr_test(&s);
fseek(f, pos, SEEK_SET);
return res;
#else #else
STBI_NOTUSED(f); STBI_NOTUSED(f);
return 0; return 0;
@ -1705,7 +1752,8 @@ typedef struct
static int stbi__build_huffman(stbi__huffman *h, int *count) static int stbi__build_huffman(stbi__huffman *h, int *count)
{ {
int i,j,k=0,code; int i,j,k=0;
unsigned int code;
// build size list for each symbol (from JPEG spec) // build size list for each symbol (from JPEG spec)
for (i=0; i < 16; ++i) for (i=0; i < 16; ++i)
for (j=0; j < count[i]; ++j) for (j=0; j < count[i]; ++j)
@ -1721,7 +1769,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
if (h->size[k] == j) { if (h->size[k] == j) {
while (h->size[k] == j) while (h->size[k] == j)
h->code[k++] = (stbi__uint16) (code++); h->code[k++] = (stbi__uint16) (code++);
if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
} }
// compute largest code + 1 for this size, preshifted as needed later // compute largest code + 1 for this size, preshifted as needed later
h->maxcode[j] = code << (16-j); h->maxcode[j] = code << (16-j);
@ -1765,7 +1813,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
if (k < m) k += (~0U << magbits) + 1; if (k < m) k += (~0U << magbits) + 1;
// if the result is small enough, we can fit it in fast_ac table // if the result is small enough, we can fit it in fast_ac table
if (k >= -128 && k <= 127) if (k >= -128 && k <= 127)
fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
} }
} }
} }
@ -1774,7 +1822,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
static void stbi__grow_buffer_unsafe(stbi__jpeg *j) static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
{ {
do { do {
int b = j->nomore ? 0 : stbi__get8(j->s); unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
if (b == 0xff) { if (b == 0xff) {
int c = stbi__get8(j->s); int c = stbi__get8(j->s);
while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
@ -1790,7 +1838,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
} }
// (1 << n) - 1 // (1 << n) - 1
static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
// decode a jpeg huffman value from the bitstream // decode a jpeg huffman value from the bitstream
stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
@ -1843,7 +1891,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
} }
// bias[n] = (-1<<n) + 1 // bias[n] = (-1<<n) + 1
static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
// combined JPEG 'receive' and JPEG 'extend', since baseline // combined JPEG 'receive' and JPEG 'extend', since baseline
// always extends everything it receives. // always extends everything it receives.
@ -1886,7 +1934,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
// given a value that's at position X in the zigzag stream, // given a value that's at position X in the zigzag stream,
// where does it appear in the 8x8 matrix coded as row-major? // where does it appear in the 8x8 matrix coded as row-major?
static stbi_uc stbi__jpeg_dezigzag[64+15] = static const stbi_uc stbi__jpeg_dezigzag[64+15] =
{ {
0, 1, 8, 16, 9, 2, 3, 10, 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5, 17, 24, 32, 25, 18, 11, 4, 5,
@ -2112,7 +2160,7 @@ stbi_inline static stbi_uc stbi__clamp(int x)
} }
#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) #define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
#define stbi__fsh(x) ((x) << 12) #define stbi__fsh(x) ((x) * 4096)
// derived from jidctint -- DCT_ISLOW // derived from jidctint -- DCT_ISLOW
#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ #define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
@ -2167,7 +2215,7 @@ static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
// (1|2|3|4|5|6|7)==0 0 seconds // (1|2|3|4|5|6|7)==0 0 seconds
// all separate -0.047 seconds // all separate -0.047 seconds
// 1 && 2|3 && 4|5 && 6|7: -0.047 seconds // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
int dcterm = d[0] << 2; int dcterm = d[0]*4;
v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
} else { } else {
STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
@ -2968,7 +3016,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
z->rgb = 0; z->rgb = 0;
for (i=0; i < s->img_n; ++i) { for (i=0; i < s->img_n; ++i) {
static unsigned char rgb[3] = { 'R', 'G', 'B' }; static const unsigned char rgb[3] = { 'R', 'G', 'B' };
z->img_comp[i].id = stbi__get8(s); z->img_comp[i].id = stbi__get8(s);
if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
++z->rgb; ++z->rgb;
@ -3093,8 +3141,8 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
} else if (stbi__DNL(m)) { } else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s); int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s);
if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG"); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
} else { } else {
if (!stbi__process_marker(j, m)) return 0; if (!stbi__process_marker(j, m)) return 0;
} }
@ -3912,18 +3960,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room
return 1; return 1;
} }
static int stbi__zlength_base[31] = { static const int stbi__zlength_base[31] = {
3,4,5,6,7,8,9,10,11,13, 3,4,5,6,7,8,9,10,11,13,
15,17,19,23,27,31,35,43,51,59, 15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0 }; 67,83,99,115,131,163,195,227,258,0,0 };
static int stbi__zlength_extra[31]= static const int stbi__zlength_extra[31]=
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static int stbi__zdist_extra[32] = static const int stbi__zdist_extra[32] =
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static int stbi__parse_huffman_block(stbi__zbuf *a) static int stbi__parse_huffman_block(stbi__zbuf *a)
@ -3970,7 +4018,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
static int stbi__compute_huffman_codes(stbi__zbuf *a) static int stbi__compute_huffman_codes(stbi__zbuf *a)
{ {
static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
stbi__zhuffman z_codelength; stbi__zhuffman z_codelength;
stbi_uc lencodes[286+32+137];//padding for maximum single op stbi_uc lencodes[286+32+137];//padding for maximum single op
stbi_uc codelength_sizes[19]; stbi_uc codelength_sizes[19];
@ -4229,7 +4277,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
static int stbi__check_png_header(stbi__context *s) static int stbi__check_png_header(stbi__context *s)
{ {
static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
int i; int i;
for (i=0; i < 8; ++i) for (i=0; i < 8; ++i)
if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
@ -4275,7 +4323,7 @@ static int stbi__paeth(int a, int b, int c)
return c; return c;
} }
static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
// create the png data from post-deflated data // create the png data from post-deflated data
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
@ -4295,8 +4343,10 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory"); if (!a->out) return stbi__err("outofmem", "Out of memory");
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_width_bytes = (((img_n * x * depth) + 7) >> 3);
img_len = (img_width_bytes + 1) * y; img_len = (img_width_bytes + 1) * y;
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs, // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
// but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
// so just check for raw_len < img_len always. // so just check for raw_len < img_len always.
@ -4675,7 +4725,7 @@ static void stbi__de_iphone(stbi__png *z)
} }
} }
#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) #define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
{ {
@ -4912,6 +4962,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
p.s = s; p.s = s;
return stbi__png_info_raw(&p, x, y, comp); return stbi__png_info_raw(&p, x, y, comp);
} }
static int stbi__png_is16(stbi__context *s)
{
stbi__png p;
p.s = s;
if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
return 0;
if (p.depth != 16) {
stbi__rewind(p.s);
return 0;
}
return 1;
}
#endif #endif
// Microsoft/Windows BMP image // Microsoft/Windows BMP image
@ -4963,21 +5026,27 @@ static int stbi__bitcount(unsigned int a)
return a & 0xff; return a & 0xff;
} }
// extract an arbitrarily-aligned N-bit value (N=bits)
// from v, and then make it 8-bits long and fractionally
// extend it to full full range.
static int stbi__shiftsigned(int v, int shift, int bits) static int stbi__shiftsigned(int v, int shift, int bits)
{ {
int result; static unsigned int mul_table[9] = {
int z=0; 0,
0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
if (shift < 0) v <<= -shift; 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
else v >>= shift; };
result = v; static unsigned int shift_table[9] = {
0, 0,0,1,0,2,4,6,0,
z = bits; };
while (z < 8) { if (shift < 0)
result += v >> z; v <<= -shift;
z += bits; else
} v >>= shift;
return result; STBI_ASSERT(v >= 0 && v < 256);
v >>= (8-bits);
STBI_ASSERT(bits >= 0 && bits <= 8);
return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
} }
typedef struct typedef struct
@ -5007,7 +5076,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
} }
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
info->bpp = stbi__get16le(s); info->bpp = stbi__get16le(s);
if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
if (hsz != 12) { if (hsz != 12) {
int compress = stbi__get32le(s); int compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
@ -5125,10 +5193,27 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (info.bpp == 4) width = (s->img_x + 1) >> 1; if (info.bpp == 1) width = (s->img_x + 7) >> 3;
else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (info.bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
pad = (-width)&3; pad = (-width)&3;
if (info.bpp == 1) {
for (j=0; j < (int) s->img_y; ++j) {
int bit_offset = 7, v = stbi__get8(s);
for (i=0; i < (int) s->img_x; ++i) {
int color = (v>>bit_offset)&0x1;
out[z++] = pal[color][0];
out[z++] = pal[color][1];
out[z++] = pal[color][2];
if((--bit_offset) < 0) {
bit_offset = 7;
v = stbi__get8(s);
}
}
stbi__skip(s, pad);
}
} else {
for (j=0; j < (int) s->img_y; ++j) { for (j=0; j < (int) s->img_y; ++j) {
for (i=0; i < (int) s->img_x; i += 2) { for (i=0; i < (int) s->img_x; i += 2) {
int v=stbi__get8(s),v2=0; int v=stbi__get8(s),v2=0;
@ -5149,6 +5234,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
} }
stbi__skip(s, pad); stbi__skip(s, pad);
} }
}
} else { } else {
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
@ -5188,7 +5274,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
int bpp = info.bpp; int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) { for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
int a; unsigned int a;
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
@ -5236,14 +5322,14 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
{ {
// only RGB or RGBA (incl. 16bit) or grey allowed // only RGB or RGBA (incl. 16bit) or grey allowed
if(is_rgb16) *is_rgb16 = 0; if (is_rgb16) *is_rgb16 = 0;
switch(bits_per_pixel) { switch(bits_per_pixel) {
case 8: return STBI_grey; case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha; case 16: if(is_grey) return STBI_grey_alpha;
// else: fall-through // fallthrough
case 15: if(is_rgb16) *is_rgb16 = 1; case 15: if(is_rgb16) *is_rgb16 = 1;
return STBI_rgb; return STBI_rgb;
case 24: // fall-through case 24: // fallthrough
case 32: return bits_per_pixel/8; case 32: return bits_per_pixel/8;
default: return 0; default: return 0;
} }
@ -6038,11 +6124,13 @@ typedef struct
typedef struct typedef struct
{ {
int w,h; int w,h;
stbi_uc *out, *old_out; // output buffer (always 4 components) stbi_uc *out; // output buffer (always 4 components)
int flags, bgindex, ratio, transparent, eflags, delay; stbi_uc *background; // The current "background" as far as a gif is concerned
stbi_uc *history;
int flags, bgindex, ratio, transparent, eflags;
stbi_uc pal[256][4]; stbi_uc pal[256][4];
stbi_uc lpal[256][4]; stbi_uc lpal[256][4];
stbi__gif_lzw codes[4096]; stbi__gif_lzw codes[8192];
stbi_uc *color_table; stbi_uc *color_table;
int parse, step; int parse, step;
int lflags; int lflags;
@ -6050,6 +6138,7 @@ typedef struct
int max_x, max_y; int max_x, max_y;
int cur_x, cur_y; int cur_x, cur_y;
int line_size; int line_size;
int delay;
} stbi__gif; } stbi__gif;
static int stbi__gif_test_raw(stbi__context *s) static int stbi__gif_test_raw(stbi__context *s)
@ -6125,6 +6214,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{ {
stbi_uc *p, *c; stbi_uc *p, *c;
int idx;
// recurse to decode the prefixes, since the linked-list is backwards, // recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty // and working backwards through an interleaved image would be nasty
@ -6133,10 +6223,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
if (g->cur_y >= g->max_y) return; if (g->cur_y >= g->max_y) return;
p = &g->out[g->cur_x + g->cur_y]; idx = g->cur_x + g->cur_y;
c = &g->color_table[g->codes[code].suffix * 4]; p = &g->out[idx];
g->history[idx / 4] = 1;
if (c[3] >= 128) { c = &g->color_table[g->codes[code].suffix * 4];
if (c[3] > 128) { // don't render transparent pixels;
p[0] = c[2]; p[0] = c[2];
p[1] = c[1]; p[1] = c[1];
p[2] = c[0]; p[2] = c[0];
@ -6210,11 +6302,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
stbi__skip(s,len); stbi__skip(s,len);
return g->out; return g->out;
} else if (code <= avail) { } else if (code <= avail) {
if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); if (first) {
return stbi__errpuc("no clear code", "Corrupt GIF");
}
if (oldcode >= 0) { if (oldcode >= 0) {
p = &g->codes[avail++]; p = &g->codes[avail++];
if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); if (avail > 8192) {
return stbi__errpuc("too many codes", "Corrupt GIF");
}
p->prefix = (stbi__int16) oldcode; p->prefix = (stbi__int16) oldcode;
p->first = g->codes[oldcode].first; p->first = g->codes[oldcode].first;
p->suffix = (code == avail) ? p->first : g->codes[code].first; p->suffix = (code == avail) ? p->first : g->codes[code].first;
@ -6236,62 +6333,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
} }
} }
static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
{
int x, y;
stbi_uc *c = g->pal[g->bgindex];
for (y = y0; y < y1; y += 4 * g->w) {
for (x = x0; x < x1; x += 4) {
stbi_uc *p = &g->out[y + x];
p[0] = c[2];
p[1] = c[1];
p[2] = c[0];
p[3] = 0;
}
}
}
// this function is designed to support animated gifs, although stb_image doesn't support it // this function is designed to support animated gifs, although stb_image doesn't support it
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) // two back is the image from two frames ago, used for a very specific disposal format
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
{ {
int i; int dispose;
stbi_uc *prev_out = 0; int first_frame;
int pi;
int pcount;
if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) // on first frame, any non-written pixels get the background colour (non-transparent)
return 0; // stbi__g_failure_reason set by stbi__gif_header first_frame = 0;
if (g->out == 0) {
if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
return stbi__errpuc("too large", "GIF too large"); g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
prev_out = g->out; g->history = (stbi_uc *) stbi__malloc(g->w * g->h);
g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
switch ((g->eflags & 0x1C) >> 2) { // image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
case 0: // unspecified (also always used on 1st frame) // background colour is only used for pixels that are not rendered first frame, after that "background"
stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); // color refers to teh color that was there the previous frame.
break; memset( g->out, 0x00, 4 * g->w * g->h );
case 1: // do not dispose memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent)
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
g->old_out = prev_out; first_frame = 1;
break; } else {
case 2: // dispose to background // second frame - how do we dispoase of the previous one?
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); dispose = (g->eflags & 0x1C) >> 2;
stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); pcount = g->w * g->h;
break;
case 3: // dispose to previous if ((dispose == 3) && (two_back == 0)) {
if (g->old_out) { dispose = 2; // if I don't have an image to revert back to, default to the old background
for (i = g->start_y; i < g->max_y; i += 4 * g->w)
memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
}
break;
} }
if (dispose == 3) { // use previous graphic
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
}
}
} else if (dispose == 2) {
// restore what was changed last frame to background before that frame;
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
}
}
} else {
// This is a non-disposal case eithe way, so just
// leave the pixels as is, and they will become the new background
// 1: do not dispose
// 0: not specified.
}
// background is what out is after the undoing of the previou frame;
memcpy( g->background, g->out, 4 * g->w * g->h );
}
// clear my history;
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
for (;;) { for (;;) {
switch (stbi__get8(s)) { int tag = stbi__get8(s);
switch (tag) {
case 0x2C: /* Image Descriptor */ case 0x2C: /* Image Descriptor */
{ {
int prev_trans = -1;
stbi__int32 x, y, w, h; stbi__int32 x, y, w, h;
stbi_uc *o; stbi_uc *o;
@ -6324,10 +6431,6 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
g->color_table = (stbi_uc *) g->lpal; g->color_table = (stbi_uc *) g->lpal;
} else if (g->flags & 0x80) { } else if (g->flags & 0x80) {
if (g->transparent >= 0 && (g->eflags & 0x01)) {
prev_trans = g->pal[g->transparent][3];
g->pal[g->transparent][3] = 0;
}
g->color_table = (stbi_uc *) g->pal; g->color_table = (stbi_uc *) g->pal;
} else } else
return stbi__errpuc("missing color table", "Corrupt GIF"); return stbi__errpuc("missing color table", "Corrupt GIF");
@ -6335,8 +6438,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
o = stbi__process_gif_raster(s, g); o = stbi__process_gif_raster(s, g);
if (o == NULL) return NULL; if (o == NULL) return NULL;
if (prev_trans != -1) // if this was the first frame,
g->pal[g->transparent][3] = (stbi_uc) prev_trans; pcount = g->w * g->h;
if (first_frame && (g->bgindex > 0)) {
// if first frame, any pixel not drawn to gets the background color
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi] == 0) {
g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
}
}
}
return o; return o;
} }
@ -6344,19 +6456,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case 0x21: // Comment Extension. case 0x21: // Comment Extension.
{ {
int len; int len;
if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. int ext = stbi__get8(s);
if (ext == 0xF9) { // Graphic Control Extension.
len = stbi__get8(s); len = stbi__get8(s);
if (len == 4) { if (len == 4) {
g->eflags = stbi__get8(s); g->eflags = stbi__get8(s);
g->delay = stbi__get16le(s); g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
// unset old transparent
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 255;
}
if (g->eflags & 0x01) {
g->transparent = stbi__get8(s); g->transparent = stbi__get8(s);
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 0;
}
} else {
// don't need transparent
stbi__skip(s, 1);
g->transparent = -1;
}
} else { } else {
stbi__skip(s, len); stbi__skip(s, len);
break; break;
} }
} }
while ((len = stbi__get8(s)) != 0) while ((len = stbi__get8(s)) != 0) {
stbi__skip(s, len); stbi__skip(s, len);
}
break; break;
} }
@ -6367,28 +6495,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
return stbi__errpuc("unknown code", "Corrupt GIF"); return stbi__errpuc("unknown code", "Corrupt GIF");
} }
} }
}
STBI_NOTUSED(req_comp); static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
if (stbi__gif_test(s)) {
int layers = 0;
stbi_uc *u = 0;
stbi_uc *out = 0;
stbi_uc *two_back = 0;
stbi__gif g;
int stride;
memset(&g, 0, sizeof(g));
if (delays) {
*delays = 0;
}
do {
u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
if (u) {
*x = g.w;
*y = g.h;
++layers;
stride = g.w * g.h * 4;
if (out) {
out = (stbi_uc*) STBI_REALLOC( out, layers * stride );
if (delays) {
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
}
} else {
out = (stbi_uc*)stbi__malloc( layers * stride );
if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) );
}
}
memcpy( out + ((layers - 1) * stride), u, stride );
if (layers >= 2) {
two_back = out - 2 * stride;
}
if (delays) {
(*delays)[layers - 1U] = g.delay;
}
}
} while (u != 0);
// free temp buffer;
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
// do the final conversion after loading everything;
if (req_comp && req_comp != 4)
out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
*z = layers;
return out;
} else {
return stbi__errpuc("not GIF", "Image was not as a gif type.");
}
} }
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{ {
stbi_uc *u = 0; stbi_uc *u = 0;
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); stbi__gif g;
memset(g, 0, sizeof(*g)); memset(&g, 0, sizeof(g));
STBI_NOTUSED(ri);
u = stbi__gif_load_next(s, g, comp, req_comp); u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
if (u) { if (u) {
*x = g->w; *x = g.w;
*y = g->h; *y = g.h;
// moved conversion to after successful load so that the same
// can be done for multiple frames.
if (req_comp && req_comp != 4) if (req_comp && req_comp != 4)
u = stbi__convert_format(u, 4, req_comp, g->w, g->h); u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
} }
else if (g->out)
STBI_FREE(g->out); // free buffers needed for multiple frame loading;
STBI_FREE(g); STBI_FREE(g.history);
STBI_FREE(g.background);
return u; return u;
} }
@ -6667,7 +6859,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_PSD #ifndef STBI_NO_PSD
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int channelCount, dummy; int channelCount, dummy, depth;
if (!x) x = &dummy; if (!x) x = &dummy;
if (!y) y = &dummy; if (!y) y = &dummy;
if (!comp) comp = &dummy; if (!comp) comp = &dummy;
@ -6687,7 +6879,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
} }
*y = stbi__get32be(s); *y = stbi__get32be(s);
*x = stbi__get32be(s); *x = stbi__get32be(s);
if (stbi__get16be(s) != 8) { depth = stbi__get16be(s);
if (depth != 8 && depth != 16) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
@ -6698,6 +6891,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
*comp = 4; *comp = 4;
return 1; return 1;
} }
static int stbi__psd_is16(stbi__context *s)
{
int channelCount, dummy, depth;
if (stbi__get32be(s) != 0x38425053) {
stbi__rewind( s );
return 0;
}
if (stbi__get16be(s) != 1) {
stbi__rewind( s );
return 0;
}
stbi__skip(s, 6);
channelCount = stbi__get16be(s);
if (channelCount < 0 || channelCount > 16) {
stbi__rewind( s );
return 0;
}
dummy = stbi__get32be(s);
dummy = stbi__get32be(s);
depth = stbi__get16be(s);
if (depth != 16) {
stbi__rewind( s );
return 0;
}
return 1;
}
#endif #endif
#ifndef STBI_NO_PIC #ifndef STBI_NO_PIC
@ -6928,6 +7148,19 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
return stbi__err("unknown image type", "Image not of any known type, or corrupt"); return stbi__err("unknown image type", "Image not of any known type, or corrupt");
} }
static int stbi__is_16_main(stbi__context *s)
{
#ifndef STBI_NO_PNG
if (stbi__png_is16(s)) return 1;
#endif
#ifndef STBI_NO_PSD
if (stbi__psd_is16(s)) return 1;
#endif
return 0;
}
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
{ {
@ -6949,6 +7182,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
fseek(f,pos,SEEK_SET); fseek(f,pos,SEEK_SET);
return r; return r;
} }
STBIDEF int stbi_is_16_bit(char const *filename)
{
FILE *f = stbi__fopen(filename, "rb");
int result;
if (!f) return stbi__err("can't fopen", "Unable to open file");
result = stbi_is_16_bit_from_file(f);
fclose(f);
return result;
}
STBIDEF int stbi_is_16_bit_from_file(FILE *f)
{
int r;
stbi__context s;
long pos = ftell(f);
stbi__start_file(&s, f);
r = stbi__is_16_main(&s);
fseek(f,pos,SEEK_SET);
return r;
}
#endif // !STBI_NO_STDIO #endif // !STBI_NO_STDIO
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
@ -6965,10 +7219,28 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
return stbi__info_main(&s,x,y,comp); return stbi__info_main(&s,x,y,comp);
} }
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
{
stbi__context s;
stbi__start_mem(&s,buffer,len);
return stbi__is_16_main(&s);
}
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
return stbi__is_16_main(&s);
}
#endif // STB_IMAGE_IMPLEMENTATION #endif // STB_IMAGE_IMPLEMENTATION
/* /*
revision history: revision history:
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
1-bit BMP
*_is_16_bit api
avoid warnings
2.16 (2017-07-23) all functions have 16-bit variants; 2.16 (2017-07-23) all functions have 16-bit variants;
STBI_NO_STDIO works again; STBI_NO_STDIO works again;
compilation fixes; compilation fixes;

View file

@ -1,4 +1,4 @@
/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.08 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -10,34 +10,47 @@
Will probably not work correctly with strict-aliasing optimizations. Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT: ABOUT:
This header file is a library for writing images to C stdio. It could be This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know. adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed written by a decent optimizing implementation; though providing a custom
for source code compactness and simplicity, not optimal image file size zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
or run-time performance. This library is designed for source code compactness and simplicity,
not optimal image file size or run-time performance.
BUILDING: BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free. malloc,realloc,free.
You can define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_MEMMOVE() to replace memmove()
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
for PNG compression (instead of the builtin one), it must have the following signature:
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
The returned data will be freed with STBIW_FREE() (free() by default),
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
USAGE: USAGE:
There are four functions, one for each image file format: There are five functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data); int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data, int quality);
There are also four equivalent functions that use an arbitrary write function. You are void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
There are also five equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
@ -49,6 +62,12 @@ USAGE:
where the callback is: where the callback is:
void stbi_write_func(void *context, void *data, int size); void stbi_write_func(void *context, void *data, int size);
You can configure it with these global variables:
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
You can define STBI_WRITE_NO_STDIO to disable the file variant of these You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output. also disable HDR writing, because it requires stdio for formatted output.
@ -75,6 +94,9 @@ USAGE:
writer, both because it is in BGR order and because it may have padding writer, both because it is in BGR order and because it may have padding
at the end of the line.) at the end of the line.)
PNG allows you to set the deflate compression level by setting the global
variable 'stbi_write_png_level' (it defaults to 8).
HDR expects linear float data. Since the format is always 32-bit rgb(e) HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels. replicated across all three channels.
@ -88,21 +110,17 @@ USAGE:
CREDITS: CREDITS:
PNG/BMP/TGA
Sean Barrett Sean Barrett - PNG/BMP/TGA
HDR Baldur Karlsson - HDR
Baldur Karlsson Jean-Sebastien Guay - TGA monochrome
TGA monochrome: Tim Kelsey - misc enhancements
Jean-Sebastien Guay Alan Hickman - TGA RLE
misc enhancements: Emmanuel Julien - initial file IO callback implementation
Tim Kelsey Jon Olick - original jo_jpeg.cpp code
TGA RLE Daniel Gibson - integrate JPEG, allow external zlib
Alan Hickman Aarni Koskela - allow choosing PNG filter
initial file IO callback implementation
Emmanuel Julien
JPEG
Jon Olick (original jo_jpeg.cpp code)
Daniel Gibson
bugfixes: bugfixes:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
@ -114,6 +132,7 @@ CREDITS:
Thatcher Ulrich Thatcher Ulrich
github:poppolopoppo github:poppolopoppo
Patrick Boettcher Patrick Boettcher
github:xeekworx
LICENSE LICENSE
@ -132,9 +151,12 @@ extern "C" {
#define STBIWDEF static #define STBIWDEF static
#else #else
#define STBIWDEF extern #define STBIWDEF extern
extern int stbi_write_tga_with_rle;
#endif #endif
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_comperssion_level;
STBIWDEF int stbi_write_force_png_filter;
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
@ -151,6 +173,8 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w,
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -208,6 +232,23 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
}
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -230,7 +271,13 @@ static void stbi__stdio_write(void *context, void *data, int size)
static int stbi__start_write_file(stbi__write_context *s, const char *filename) static int stbi__start_write_file(stbi__write_context *s, const char *filename)
{ {
FILE *f = fopen(filename, "wb"); FILE *f;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb");
#endif
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL; return f != NULL;
} }
@ -245,12 +292,6 @@ static void stbi__end_write_file(stbi__write_context *s)
typedef unsigned int stbiw_uint32; typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
{ {
while (*fmt) { while (*fmt) {
@ -341,6 +382,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (y <= 0) if (y <= 0)
return; return;
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0) if (vdir < 0)
j_end = -1, j = y-1; j_end = -1, j = y-1;
else else
@ -412,10 +456,20 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
} else { } else {
int i,j,k; int i,j,k;
int jend, jdir;
stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
for (j = y - 1; j >= 0; --j) { if (stbi__flip_vertically_on_write) {
j = 0;
jend = y;
jdir = 1;
} else {
j = y-1;
jend = -1;
jdir = -1;
}
for (; j != jend; j += jdir) {
unsigned char *row = (unsigned char *) data + j * x * comp; unsigned char *row = (unsigned char *) data + j * x * comp;
int len; int len;
@ -626,11 +680,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len); s->func(s->context, buffer, len);
for(i=0; i < y; i++) for(i=0; i < y; i++)
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x);
STBIW_FREE(scratch); STBIW_FREE(scratch);
return 1; return 1;
} }
@ -662,6 +720,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
// PNG writer // PNG writer
// //
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbm(a) stbiw__sbraw(a)[0]
@ -742,8 +801,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__ZHASH 16384 #define stbiw__ZHASH 16384
#endif // STBIW_ZLIB_COMPRESS
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{ {
#ifdef STBIW_ZLIB_COMPRESS
// user provided a zlib compress implementation, use that
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
#else // use builtin
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
@ -752,6 +817,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
int i,j, bitcount=0; int i,j, bitcount=0;
unsigned char *out = NULL; unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5; if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window stbiw__sbpush(out, 0x78); // DEFLATE 32K window
@ -845,6 +912,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
// make returned pointer freeable // make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
#endif // STBIW_ZLIB_COMPRESS
} }
static unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@ -911,29 +979,15 @@ static unsigned char stbiw__paeth(int a, int b, int c)
} }
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
{ {
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 }; static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 }; static int firstmap[] = { 0,1,0,5,6 };
int *mymap = (j != 0) ? mapping : firstmap; int *mymap = (y != 0) ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff; int i;
for (p=0; p < 2; ++p) { int type = mymap[filter_type];
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int type = mymap[k],est=0; for (i = 0; i < n; ++i) {
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) { switch (type) {
case 0: line_buffer[i] = z[i]; break; case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break;
@ -943,7 +997,8 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
case 5: line_buffer[i] = z[i]; break; case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break; case 6: line_buffer[i] = z[i]; break;
} }
for (i=n; i < x*n; ++i) { }
for (i=n; i < width*n; ++i) {
switch (type) { switch (type) {
case 0: line_buffer[i] = z[i]; break; case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break; case 1: line_buffer[i] = z[i] - z[i-n]; break;
@ -954,18 +1009,57 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
} }
} }
if (p) break; }
for (i=0; i < x*n; ++i)
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int force_filter = stbi_write_force_png_filter;
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int j,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
if (force_filter >= 5) {
force_filter = -1;
}
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) {
int filter_type;
if (force_filter > -1) {
filter_type = force_filter;
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
} else { // Estimate the best filter by running through all of them:
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
for (filter_type = 0; filter_type < 5; filter_type++) {
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
// Estimate the entropy of the line using this filter; the less, the better.
est = 0;
for (i = 0; i < x*n; ++i) {
est += abs((signed char) line_buffer[i]); est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; } }
if (est < best_filter_val) {
best_filter_val = est;
best_filter = filter_type;
} }
} }
// when we get here, best contains the filter type, and line_buffer contains the data if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
filt[j*(x*n+1)] = (unsigned char) best; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer);
filter_type = best_filter;
}
}
// when we get here, filter_type contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
} }
STBIW_FREE(line_buffer); STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
STBIW_FREE(filt); STBIW_FREE(filt);
if (!zlib) return 0; if (!zlib) return 0;
@ -1010,7 +1104,12 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const
int len; int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0; if (png == NULL) return 0;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb"); f = fopen(filename, "wb");
#endif
if (!f) { STBIW_FREE(png); return 0; } if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f); fwrite(png, 1, len, f);
fclose(f); fclose(f);
@ -1318,7 +1417,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
float YDU[64], UDU[64], VDU[64]; float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) { for(row = y, pos = 0; row < y+8; ++row) {
for(col = x; col < x+8; ++col, ++pos) { for(col = x; col < x+8; ++col, ++pos) {
int p = row*width*comp + col*comp; int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp;
float r, g, b; float r, g, b;
if(row >= height) { if(row >= height) {
p -= width*comp*(row+1 - height); p -= width*comp*(row+1 - height);
@ -1377,6 +1476,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.08 (2018-01-29)
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
1.07 (2017-07-24) 1.07 (2017-07-24)
doc fix doc fix
1.06 (2017-07-23) 1.06 (2017-07-23)

View file

@ -1,4 +1,4 @@
// stb_truetype.h - v1.17 - public domain // stb_truetype.h - v1.18 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools // authored from 2009-2016 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -30,33 +30,24 @@
// Imanol Celaya // Imanol Celaya
// //
// Bug/warning reports/fixes: // Bug/warning reports/fixes:
// "Zer" on mollyrocket // "Zer" on mollyrocket Fabian "ryg" Giesen
// Cass Everitt // Cass Everitt Martins Mozeiko
// stoiko (Haemimont Games) // stoiko (Haemimont Games) Cap Petschulat
// Brian Hook // Brian Hook Omar Cornut
// Walter van Niftrik // Walter van Niftrik github:aloucks
// David Gow // David Gow Peter LaValle
// David Given // David Given Sergey Popov
// Ivan-Assen Ivanov // Ivan-Assen Ivanov Giumo X. Clanjor
// Anthony Pesch // Anthony Pesch Higor Euripedes
// Johan Duparc // Johan Duparc Thomas Fields
// Hou Qiming // Hou Qiming Derek Vinyard
// Fabian "ryg" Giesen // Rob Loach Cort Stratton
// Martins Mozeiko // Kenney Phillis Jr. github:oyvindjam
// Cap Petschulat // Brian Costabile github:vassvik
// Omar Cornut
// github:aloucks
// Peter LaValle
// Sergey Popov
// Giumo X. Clanjor
// Higor Euripedes
// Thomas Fields
// Derek Vinyard
// Cort Stratton
// github:oyvindjam
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix // 1.17 (2017-07-23) make more arguments const; doc fix
// 1.16 (2017-07-12) SDF support // 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const // 1.15 (2017-03-03) make more arguments const
@ -171,7 +162,7 @@
// measurement for describing font size, defined as 72 points per inch. // measurement for describing font size, defined as 72 points per inch.
// stb_truetype provides a point API for compatibility. However, true // stb_truetype provides a point API for compatibility. However, true
// "per inch" conventions don't make much sense on computer displays // "per inch" conventions don't make much sense on computer displays
// since they different monitors have different number of pixels per // since different monitors have different number of pixels per
// inch. For example, Windows traditionally uses a convention that // inch. For example, Windows traditionally uses a convention that
// there are 96 pixels per inch, thus making 'inch' measurements have // there are 96 pixels per inch, thus making 'inch' measurements have
// nothing to do with inches, and thus effectively defining a point to // nothing to do with inches, and thus effectively defining a point to
@ -181,6 +172,39 @@
// for non-commercial fonts, thus making fonts scaled in points // for non-commercial fonts, thus making fonts scaled in points
// according to the TrueType spec incoherently sized in practice. // according to the TrueType spec incoherently sized in practice.
// //
// DETAILED USAGE:
//
// Scale:
// Select how high you want the font to be, in points or pixels.
// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
// a scale factor SF that will be used by all other functions.
//
// Baseline:
// You need to select a y-coordinate that is the baseline of where
// your text will appear. Call GetFontBoundingBox to get the baseline-relative
// bounding box for all characters. SF*-y0 will be the distance in pixels
// that the worst-case character could extend above the baseline, so if
// you want the top edge of characters to appear at the top of the
// screen where y=0, then you would set the baseline to SF*-y0.
//
// Current point:
// Set the current point where the first character will appear. The
// first character could extend left of the current point; this is font
// dependent. You can either choose a current point that is the leftmost
// point and hope, or add some padding, or check the bounding box or
// left-side-bearing of the first character to be displayed and set
// the current point based on that.
//
// Displaying a character:
// Compute the bounding box of the character. It will contain signed values
// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
// then the character should be displayed in the rectangle from
// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
//
// Advancing for the next character:
// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
//
//
// ADVANCED USAGE // ADVANCED USAGE
// //
// Quality: // Quality:
@ -427,11 +451,6 @@ int main(int arg, char **argv)
#define STBTT_fabs(x) fabs(x) #define STBTT_fabs(x) fabs(x)
#endif #endif
#ifndef STBTT_fabs
#include <math.h>
#define STBTT_fabs(x) fabs(x)
#endif
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
#ifndef STBTT_malloc #ifndef STBTT_malloc
#include <stdlib.h> #include <stdlib.h>
@ -2172,7 +2191,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
// push immediate // push immediate
if (b0 == 255) { if (b0 == 255) {
f = (float)stbtt__buf_get32(&b) / 0x10000; f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
} else { } else {
stbtt__buf_skip(&b, -1); stbtt__buf_skip(&b, -1);
f = (float)(stbtt_int16)stbtt__cff_int(&b); f = (float)(stbtt_int16)stbtt__cff_int(&b);
@ -2210,12 +2229,10 @@ static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, in
{ {
stbtt__csctx c = STBTT__CSCTX_INIT(1); stbtt__csctx c = STBTT__CSCTX_INIT(1);
int r = stbtt__run_charstring(info, glyph_index, &c); int r = stbtt__run_charstring(info, glyph_index, &c);
if (x0) { if (x0) *x0 = r ? c.min_x : 0;
*x0 = r ? c.min_x : 0; if (y0) *y0 = r ? c.min_y : 0;
*y0 = r ? c.min_y : 0; if (x1) *x1 = r ? c.max_x : 0;
*x1 = r ? c.max_x : 0; if (y1) *y1 = r ? c.max_y : 0;
*y1 = r ? c.max_y : 0;
}
return r ? c.num_vertices : 0; return r ? c.num_vertices : 0;
} }
@ -2395,7 +2412,7 @@ static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
hh->num_remaining_in_head_chunk = count; hh->num_remaining_in_head_chunk = count;
} }
--hh->num_remaining_in_head_chunk; --hh->num_remaining_in_head_chunk;
return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk; return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
} }
} }
@ -3230,7 +3247,8 @@ error:
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
{ {
float scale = scale_x > scale_y ? scale_y : scale_x; float scale = scale_x > scale_y ? scale_y : scale_x;
int winding_count, *winding_lengths; int winding_count = 0;
int *winding_lengths = NULL;
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
if (windings) { if (windings) {
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
@ -3318,6 +3336,11 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
} }
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
{
stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
}
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
{ {
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));

View file

@ -193,9 +193,7 @@
#undef __forceinline #undef __forceinline
#endif #endif
#define __forceinline #define __forceinline
#ifndef alloca
#define alloca __builtin_alloca #define alloca __builtin_alloca
#endif
#elif !defined(_MSC_VER) #elif !defined(_MSC_VER)
#if __GNUC__ #if __GNUC__
#define __forceinline inline #define __forceinline inline
@ -1660,6 +1658,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
return TRUE; return TRUE;
} }
// n is 1/2 of the blocksize --
// specification: "Correct per-vector decode length is [n]/2"
static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
{ {
int i,j,pass; int i,j,pass;
@ -1667,7 +1667,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int rtype = f->residue_types[rn]; int rtype = f->residue_types[rn];
int c = r->classbook; int c = r->classbook;
int classwords = f->codebooks[c].dimensions; int classwords = f->codebooks[c].dimensions;
int n_read = r->end - r->begin; unsigned int actual_size = rtype == 2 ? n*2 : n;
unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
int temp_alloc_point = temp_alloc_save(f); int temp_alloc_point = temp_alloc_save(f);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -3009,7 +3012,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->last_seg_which == f->end_seg_with_known_loc) { if (f->last_seg_which == f->end_seg_with_known_loc) {
// if we have a valid current loc, and this is final: // if we have a valid current loc, and this is final:
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end); uint32 current_end = f->known_loc_for_packet;
// then let's infer the size of the (probably) short final frame // then let's infer the size of the (probably) short final frame
if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
@ -3018,7 +3021,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
} else { } else {
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start; // this doesn't seem right, but has no ill effect on my test files
if (*len > right_end) *len = right_end; // this should never happen if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
@ -3695,7 +3698,10 @@ static int start_decoder(vorb *f)
int i,max_part_read=0; int i,max_part_read=0;
for (i=0; i < f->residue_count; ++i) { for (i=0; i < f->residue_count; ++i) {
Residue *r = f->residue_config + i; Residue *r = f->residue_config + i;
int n_read = r->end - r->begin; unsigned int actual_size = f->blocksize_1 / 2;
unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
if (part_read > max_part_read) if (part_read > max_part_read)
max_part_read = part_read; max_part_read = part_read;
@ -3706,6 +3712,8 @@ static int start_decoder(vorb *f)
classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
#endif #endif
// maximum reasonable partition size is f->blocksize_1
f->temp_memory_required = classify_mem; f->temp_memory_required = classify_mem;
if (imdct_mem > f->temp_memory_required) if (imdct_mem > f->temp_memory_required)
f->temp_memory_required = imdct_mem; f->temp_memory_required = imdct_mem;
@ -4969,6 +4977,8 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
1.11 - 2017/07/23 - fix MinGW compilation
1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version 1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version
1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks;

View file

@ -1,11 +1,11 @@
// Ogg Vorbis audio decoder - v1.11 - public domain // Ogg Vorbis audio decoder - v1.13b - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
// //
// Originally sponsored by RAD Game Tools. Seeking sponsored // Originally sponsored by RAD Game Tools. Seeking implementation
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, // sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
// Aras Pranckevicius, and Sean Barrett. // Elias Software, Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -32,6 +32,8 @@
// manxorist@github saga musix github:infatum // manxorist@github saga musix github:infatum
// //
// Partial history: // Partial history:
// 1.13 - 2018/01/29 - fix truncation of last frame (hopefully)
// 1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
// 1.11 - 2017/07/23 - fix MinGW compilation // 1.11 - 2017/07/23 - fix MinGW compilation
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory // 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version // 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version

View file

@ -493,7 +493,7 @@ float GetGesturePinchAngle(void)
// Returns angle from two-points vector with X-axis // Returns angle from two-points vector with X-axis
static float Vector2Angle(Vector2 v1, Vector2 v2) static float Vector2Angle(Vector2 v1, Vector2 v2)
{ {
float angle = angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
if (angle < 0) angle += 360.0f; if (angle < 0) angle += 360.0f;

View file

@ -36,12 +36,7 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features) #include "config.h"
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_OBJ
#define SUPPORT_FILEFORMAT_MTL
#define SUPPORT_MESH_GENERATION
//-------------------------------------------------
#include "raylib.h" #include "raylib.h"
@ -636,11 +631,13 @@ Mesh LoadMesh(const char *fileName)
TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName); TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName);
#endif #endif
if (mesh.vertexCount == 0) TraceLog(LOG_WARNING, "Mesh could not be loaded"); if (mesh.vertexCount == 0)
{
TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!");
mesh = GenMeshCube(1.0f, 1.0f, 1.0f);
}
else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
// TODO: Initialize default mesh data in case loading fails, maybe a cube?
return mesh; return mesh;
} }
@ -650,6 +647,47 @@ void UnloadMesh(Mesh *mesh)
rlUnloadMesh(mesh); rlUnloadMesh(mesh);
} }
// Export mesh as an OBJ file
void ExportMesh(const char *fileName, Mesh mesh)
{
FILE *objFile = fopen(fileName, "wt");
fprintf(objFile, "# raylib Mesh OBJ exporter v1.0\n\n");
fprintf(objFile, "# Mesh exported as triangle faces and not optimized.\n");
fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount);
fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount);
fprintf(objFile, "# LICENSE: zlib/libpng\n");
fprintf(objFile, "# Copyright (c) 2018 Ramon Santamaria (@raysan5)\n\n");
fprintf(objFile, "g mesh\n");
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{
fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
}
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
{
fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
}
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{
fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
}
for (int i = 0; i < mesh.triangleCount; i += 3)
{
fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
}
fprintf(objFile, "\n");
fclose(objFile);
TraceLog(LOG_INFO, "Mesh saved: %s", fileName);
}
#if defined(SUPPORT_MESH_GENERATION) #if defined(SUPPORT_MESH_GENERATION)
// Generate plane mesh (with subdivisions) // Generate plane mesh (with subdivisions)
Mesh GenMeshPlane(float width, float length, int resX, int resZ) Mesh GenMeshPlane(float width, float length, int resX, int resZ)
@ -1179,9 +1217,9 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Color *pixels = GetImageData(heightmap); Color *pixels = GetImageData(heightmap);
// NOTE: One vertex per pixel // NOTE: One vertex per pixel
int triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels mesh.triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
mesh.vertexCount = triangleCount*3; mesh.vertexCount = mesh.triangleCount*3;
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
@ -1584,6 +1622,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
// Move data from mapVertices temp arays to vertices float array // Move data from mapVertices temp arays to vertices float array
mesh.vertexCount = vCounter; mesh.vertexCount = vCounter;
mesh.triangleCount = vCounter/3;
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
@ -1671,14 +1710,13 @@ Material LoadMaterialDefault(void)
// Unload material from memory // Unload material from memory
void UnloadMaterial(Material material) void UnloadMaterial(Material material)
{ {
// Unload material shader // Unload material shader (avoid unloading default shader, managed by raylib)
UnloadShader(material.shader); if (material.shader.id != GetShaderDefault().id) UnloadShader(material.shader);
// Unload loaded texture maps // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
for (int i = 0; i < MAX_MATERIAL_MAPS; i++) for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
{ {
// NOTE: We already check for (tex.id > 0) inside function if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id);
rlDeleteTextures(material.maps[i].texture.id);
} }
} }
@ -1759,8 +1797,8 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
| | | |
d-------c d-------c
*/ */
Vector3Scale(&right, sizeRatio.x/2); right = Vector3Scale(right, sizeRatio.x/2);
Vector3Scale(&up, sizeRatio.y/2); up = Vector3Scale(up, sizeRatio.y/2);
Vector3 p1 = Vector3Add(right, up); Vector3 p1 = Vector3Add(right, up);
Vector3 p2 = Vector3Subtract(right, up); Vector3 p2 = Vector3Subtract(right, up);
@ -1889,16 +1927,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
if (d >= 0.0f) collision = true; if (d >= 0.0f) collision = true;
// Calculate collision point // Check if ray origin is inside the sphere to calculate the correct collision point
Vector3 offset = ray.direction;
float collisionDistance = 0; float collisionDistance = 0;
// Check if ray origin is inside the sphere to calculate the correct collision point
if (distance < sphereRadius) collisionDistance = vector + sqrtf(d); if (distance < sphereRadius) collisionDistance = vector + sqrtf(d);
else collisionDistance = vector - sqrtf(d); else collisionDistance = vector - sqrtf(d);
Vector3Scale(&offset, collisionDistance); // Calculate collision point
Vector3 cPoint = Vector3Add(ray.position, offset); Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance));
collisionPoint->x = cPoint.x; collisionPoint->x = cPoint.x;
collisionPoint->y = cPoint.y; collisionPoint->y = cPoint.y;
@ -1927,28 +1963,28 @@ bool CheckCollisionRayBox(Ray ray, BoundingBox box)
return collision; return collision;
} }
// Get collision info between ray and mesh // Get collision info between ray and model
RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh) RayHitInfo GetCollisionRayModel(Ray ray, Model *model)
{ {
RayHitInfo result = { 0 }; RayHitInfo result = { 0 };
// If mesh doesn't have vertex data on CPU, can't test it. // If mesh doesn't have vertex data on CPU, can't test it.
if (!mesh->vertices) return result; if (!model->mesh.vertices) return result;
// mesh->triangleCount may not be set, vertexCount is more reliable // model->mesh.triangleCount may not be set, vertexCount is more reliable
int triangleCount = mesh->vertexCount/3; int triangleCount = model->mesh.vertexCount/3;
// Test against all triangles in mesh // Test against all triangles in mesh
for (int i = 0; i < triangleCount; i++) for (int i = 0; i < triangleCount; i++)
{ {
Vector3 a, b, c; Vector3 a, b, c;
Vector3 *vertdata = (Vector3 *)mesh->vertices; Vector3 *vertdata = (Vector3 *)model->mesh.vertices;
if (mesh->indices) if (model->mesh.indices)
{ {
a = vertdata[mesh->indices[i*3 + 0]]; a = vertdata[model->mesh.indices[i*3 + 0]];
b = vertdata[mesh->indices[i*3 + 1]]; b = vertdata[model->mesh.indices[i*3 + 1]];
c = vertdata[mesh->indices[i*3 + 2]]; c = vertdata[model->mesh.indices[i*3 + 2]];
} }
else else
{ {
@ -1957,6 +1993,10 @@ RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh)
c = vertdata[i*3 + 2]; c = vertdata[i*3 + 2];
} }
a = Vector3Transform(a, model->transform);
b = Vector3Transform(b, model->transform);
c = Vector3Transform(c, model->transform);
RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c);
if (triHitInfo.hit) if (triHitInfo.hit)
@ -2021,11 +2061,8 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
result.hit = true; result.hit = true;
result.distance = t; result.distance = t;
result.hit = true; result.hit = true;
result.normal = Vector3CrossProduct(edge1, edge2); result.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
Vector3Normalize(&result.normal); result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
Vector3 rayDir = ray.direction;
Vector3Scale(&rayDir, t);
result.position = Vector3Add(ray.position, rayDir);
} }
return result; return result;
@ -2040,25 +2077,23 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
if (fabsf(ray.direction.y) > EPSILON) if (fabsf(ray.direction.y) > EPSILON)
{ {
float t = (ray.position.y - groundHeight)/-ray.direction.y; float distance = (ray.position.y - groundHeight)/-ray.direction.y;
if (t >= 0.0) if (distance >= 0.0)
{ {
Vector3 rayDir = ray.direction;
Vector3Scale(&rayDir, t);
result.hit = true; result.hit = true;
result.distance = t; result.distance = distance;
result.normal = (Vector3){ 0.0, 1.0, 0.0 }; result.normal = (Vector3){ 0.0, 1.0, 0.0 };
result.position = Vector3Add(ray.position, rayDir); result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, distance));
} }
} }
return result; return result;
} }
// Calculate mesh bounding box limits // Compute mesh bounding box limits
// NOTE: minVertex and maxVertex should be transformed by model transform matrix // NOTE: minVertex and maxVertex should be transformed by model transform matrix
BoundingBox CalculateBoundingBox(Mesh mesh) BoundingBox MeshBoundingBox(Mesh mesh)
{ {
// Get min and max vertex to construct bounds (AABB) // Get min and max vertex to construct bounds (AABB)
Vector3 minVertex = { 0 }; Vector3 minVertex = { 0 };
@ -2084,6 +2119,100 @@ BoundingBox CalculateBoundingBox(Mesh mesh)
return box; return box;
} }
// Compute mesh tangents
// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
void MeshTangents(Mesh *mesh)
{
if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float));
else TraceLog(LOG_WARNING, "Mesh tangents already exist");
Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3));
Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3));
for (int i = 0; i < mesh->vertexCount; i += 3)
{
// Get triangle vertices
Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
// Get triangle texcoords
Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
float x1 = v2.x - v1.x;
float y1 = v2.y - v1.y;
float z1 = v2.z - v1.z;
float x2 = v3.x - v1.x;
float y2 = v3.y - v1.y;
float z2 = v3.z - v1.z;
float s1 = uv2.x - uv1.x;
float t1 = uv2.y - uv1.y;
float s2 = uv3.x - uv1.x;
float t2 = uv3.y - uv1.y;
float div = s1*t2 - s2*t1;
float r = (div == 0.0f) ? 0.0f : 1.0f/div;
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
tan1[i + 0] = sdir;
tan1[i + 1] = sdir;
tan1[i + 2] = sdir;
tan2[i + 0] = tdir;
tan2[i + 1] = tdir;
tan2[i + 2] = tdir;
}
// Compute tangents considering normals
for (int i = 0; i < mesh->vertexCount; ++i)
{
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
Vector3 tangent = tan1[i];
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
#if defined(COMPUTE_TANGENTS_METHOD_01)
Vector3 tmp = Vector3Subtract(tangent, Vector3Multiply(normal, Vector3DotProduct(normal, tangent)));
tmp = Vector3Normalize(tmp);
mesh->tangents[i*4 + 0] = tmp.x;
mesh->tangents[i*4 + 1] = tmp.y;
mesh->tangents[i*4 + 2] = tmp.z;
mesh->tangents[i*4 + 3] = 1.0f;
#else
Vector3OrthoNormalize(&normal, &tangent);
mesh->tangents[i*4 + 0] = tangent.x;
mesh->tangents[i*4 + 1] = tangent.y;
mesh->tangents[i*4 + 2] = tangent.z;
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f) ? -1.0f : 1.0f;
#endif
}
free(tan1);
free(tan2);
TraceLog(LOG_INFO, "Tangents computed for mesh");
}
// Compute mesh binormals (aka bitangent)
void MeshBinormals(Mesh *mesh)
{
for (int i = 0; i < mesh->vertexCount; i++)
{
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
float tangentW = mesh->tangents[i*4 + 3];
Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW);
// TODO: Register computed binormal in mesh->binormal ?
}
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -2288,7 +2417,7 @@ static Mesh LoadOBJ(const char *fileName)
{ {
// If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)] // If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)]
Vector3 norm = Vector3CrossProduct(Vector3Subtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), Vector3Subtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1])); Vector3 norm = Vector3CrossProduct(Vector3Subtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), Vector3Subtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1]));
Vector3Normalize(&norm); norm = Vector3Normalize(norm);
mesh.normals[nCounter] = norm.x; mesh.normals[nCounter] = norm.x;
mesh.normals[nCounter + 1] = norm.y; mesh.normals[nCounter + 1] = norm.y;
@ -2325,79 +2454,6 @@ static Mesh LoadOBJ(const char *fileName)
fclose(objFile); fclose(objFile);
// Security check, just in case no normals or no texcoords defined in OBJ
if (texcoordCount == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f;
else
{
// Attempt to calculate mesh tangents and binormals using positions and texture coordinates
mesh.tangents = (float *)malloc(mesh.vertexCount*3*sizeof(float));
// mesh.binormals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
int vCount = 0;
int uvCount = 0;
while (vCount < mesh.vertexCount*3)
{
// Calculate mesh vertex positions as Vector3
Vector3 v0 = { mesh.vertices[vCount], mesh.vertices[vCount + 1], mesh.vertices[vCount + 2] };
Vector3 v1 = { mesh.vertices[vCount + 3], mesh.vertices[vCount + 4], mesh.vertices[vCount + 5] };
Vector3 v2 = { mesh.vertices[vCount + 6], mesh.vertices[vCount + 7], mesh.vertices[vCount + 8] };
// Calculate mesh texture coordinates as Vector2
Vector2 uv0 = { mesh.texcoords[uvCount + 0], mesh.texcoords[uvCount + 1] };
Vector2 uv1 = { mesh.texcoords[uvCount + 2], mesh.texcoords[uvCount + 3] };
Vector2 uv2 = { mesh.texcoords[uvCount + 4], mesh.texcoords[uvCount + 5] };
// Calculate edges of the triangle (position delta)
Vector3 deltaPos1 = Vector3Subtract(v1, v0);
Vector3 deltaPos2 = Vector3Subtract(v2, v0);
// UV delta
Vector2 deltaUV1 = { uv1.x - uv0.x, uv1.y - uv0.y };
Vector2 deltaUV2 = { uv2.x - uv0.x, uv2.y - uv0.y };
float r = 1.0f/(deltaUV1.x*deltaUV2.y - deltaUV1.y*deltaUV2.x);
Vector3 t1 = { deltaPos1.x*deltaUV2.y, deltaPos1.y*deltaUV2.y, deltaPos1.z*deltaUV2.y };
Vector3 t2 = { deltaPos2.x*deltaUV1.y, deltaPos2.y*deltaUV1.y, deltaPos2.z*deltaUV1.y };
// Vector3 b1 = { deltaPos2.x*deltaUV1.x, deltaPos2.y*deltaUV1.x, deltaPos2.z*deltaUV1.x };
// Vector3 b2 = { deltaPos1.x*deltaUV2.x, deltaPos1.y*deltaUV2.x, deltaPos1.z*deltaUV2.x };
// Calculate vertex tangent
Vector3 tangent = Vector3Subtract(t1, t2);
Vector3Scale(&tangent, r);
// Apply calculated tangents data to mesh struct
mesh.tangents[vCount + 0] = tangent.x;
mesh.tangents[vCount + 1] = tangent.y;
mesh.tangents[vCount + 2] = tangent.z;
mesh.tangents[vCount + 3] = tangent.x;
mesh.tangents[vCount + 4] = tangent.y;
mesh.tangents[vCount + 5] = tangent.z;
mesh.tangents[vCount + 6] = tangent.x;
mesh.tangents[vCount + 7] = tangent.y;
mesh.tangents[vCount + 8] = tangent.z;
// TODO: add binormals to mesh struct and assign buffers id and locations properly
/* // Calculate vertex binormal
Vector3 binormal = Vector3Subtract(b1, b2);
Vector3Scale(&binormal, r);
// Apply calculated binormals data to mesh struct
mesh.binormals[vCount + 0] = binormal.x;
mesh.binormals[vCount + 1] = binormal.y;
mesh.binormals[vCount + 2] = binormal.z;
mesh.binormals[vCount + 3] = binormal.x;
mesh.binormals[vCount + 4] = binormal.y;
mesh.binormals[vCount + 5] = binormal.z;
mesh.binormals[vCount + 6] = binormal.x;
mesh.binormals[vCount + 7] = binormal.y;
mesh.binormals[vCount + 8] = binormal.z; */
// Update vertex position and texture coordinates counters
vCount += 9;
uvCount += 6;
}
}
// Now we can free temp mid* arrays // Now we can free temp mid* arrays
free(midVertices); free(midVertices);
free(midNormals); free(midNormals);
@ -2443,7 +2499,7 @@ static Material LoadMTL(const char *fileName)
case 'n': // newmtl string Material name. Begins a new material description. case 'n': // newmtl string Material name. Begins a new material description.
{ {
// TODO: Support multiple materials in a single .mtl // TODO: Support multiple materials in a single .mtl
sscanf(buffer, "newmtl %s", mapFileName); sscanf(buffer, "newmtl %127s", mapFileName);
TraceLog(LOG_INFO, "[%s] Loading material...", mapFileName); TraceLog(LOG_INFO, "[%s] Loading material...", mapFileName);
} }
@ -2508,12 +2564,12 @@ static Material LoadMTL(const char *fileName)
{ {
if (buffer[5] == 'd') // map_Kd string Diffuse color texture map. if (buffer[5] == 'd') // map_Kd string Diffuse color texture map.
{ {
result = sscanf(buffer, "map_Kd %s", mapFileName); result = sscanf(buffer, "map_Kd %127s", mapFileName);
if (result != EOF) material.maps[MAP_DIFFUSE].texture = LoadTexture(mapFileName); if (result != EOF) material.maps[MAP_DIFFUSE].texture = LoadTexture(mapFileName);
} }
else if (buffer[5] == 's') // map_Ks string Specular color texture map. else if (buffer[5] == 's') // map_Ks string Specular color texture map.
{ {
result = sscanf(buffer, "map_Ks %s", mapFileName); result = sscanf(buffer, "map_Ks %127s", mapFileName);
if (result != EOF) material.maps[MAP_SPECULAR].texture = LoadTexture(mapFileName); if (result != EOF) material.maps[MAP_SPECULAR].texture = LoadTexture(mapFileName);
} }
else if (buffer[5] == 'a') // map_Ka string Ambient color texture map. else if (buffer[5] == 'a') // map_Ka string Ambient color texture map.
@ -2523,12 +2579,12 @@ static Material LoadMTL(const char *fileName)
} break; } break;
case 'B': // map_Bump string Bump texture map. case 'B': // map_Bump string Bump texture map.
{ {
result = sscanf(buffer, "map_Bump %s", mapFileName); result = sscanf(buffer, "map_Bump %127s", mapFileName);
if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName);
} break; } break;
case 'b': // map_bump string Bump texture map. case 'b': // map_bump string Bump texture map.
{ {
result = sscanf(buffer, "map_bump %s", mapFileName); result = sscanf(buffer, "map_bump %127s", mapFileName);
if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName);
} break; } break;
case 'd': // map_d string Opacity texture map. case 'd': // map_d string Opacity texture map.
@ -2553,7 +2609,7 @@ static Material LoadMTL(const char *fileName)
} break; } break;
case 'b': // bump string Bump texture map case 'b': // bump string Bump texture map
{ {
result = sscanf(buffer, "bump %s", mapFileName); result = sscanf(buffer, "bump %127s", mapFileName);
if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName);
} break; } break;
case 'T': // Tr float Transparency Tr (alpha). Tr is inverse of d case 'T': // Tr float Transparency Tr (alpha). Tr is inverse of d

View file

@ -200,6 +200,14 @@ func UnloadMesh(mesh *Mesh) {
C.UnloadMesh(cmesh) C.UnloadMesh(cmesh)
} }
// ExportMesh - Export mesh as an OBJ file
func ExportMesh(fileName string, mesh Mesh) {
cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName))
cmesh := mesh.cptr()
C.ExportMesh(cfileName, *cmesh)
}
// GenMeshPlane - Generate plane mesh (with subdivisions) // GenMeshPlane - Generate plane mesh (with subdivisions)
func GenMeshPlane(width, length float32, resX, resZ int) Mesh { func GenMeshPlane(width, length float32, resX, resZ int) Mesh {
cwidth := (C.float)(width) cwidth := (C.float)(width)
@ -390,10 +398,10 @@ func DrawBillboardRec(camera Camera, texture Texture2D, sourceRec Rectangle, cen
C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, csize, *ctint) C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, csize, *ctint)
} }
// CalculateBoundingBox - Calculate mesh bounding box limits // MeshBoundingBox - Compute mesh bounding box limits
func CalculateBoundingBox(mesh Mesh) BoundingBox { func MeshBoundingBox(mesh Mesh) BoundingBox {
cmesh := mesh.cptr() cmesh := mesh.cptr()
ret := C.CalculateBoundingBox(*cmesh) ret := C.MeshBoundingBox(*cmesh)
v := newBoundingBoxFromPointer(unsafe.Pointer(&ret)) v := newBoundingBoxFromPointer(unsafe.Pointer(&ret))
return v return v
} }

View file

@ -21,9 +21,8 @@ func InitWindow(width int32, height int32, t interface{}) {
title, ok := t.(string) title, ok := t.(string)
if ok { if ok {
ctitle := C.CString(title) ctitle := C.CString(title)
cptitle := unsafe.Pointer(ctitle) defer C.free(unsafe.Pointer(ctitle))
defer C.free(cptitle) C.InitWindow(cwidth, cheight, ctitle)
C.InitWindow(cwidth, cheight, cptitle)
} }
} }

View file

@ -151,6 +151,15 @@ const (
CameraThirdPerson CameraThirdPerson
) )
// CameraType type
type CameraType int32
// Camera projection modes
const (
CameraPerspective CameraType = iota
CameraOrthographic
)
// Some basic Defines // Some basic Defines
const ( const (
Pi = 3.1415927 Pi = 3.1415927
@ -213,6 +222,9 @@ const (
KeyRightShift = 344 KeyRightShift = 344
KeyRightControl = 345 KeyRightControl = 345
KeyRightAlt = 346 KeyRightAlt = 346
KeyGrave = 96
KeySlash = 47
KeyBackSlash = 92
// Keyboard Alpha Numeric Keys // Keyboard Alpha Numeric Keys
KeyZero = 48 KeyZero = 48
@ -421,6 +433,24 @@ func newVector3FromPointer(ptr unsafe.Pointer) Vector3 {
return *(*Vector3)(ptr) return *(*Vector3)(ptr)
} }
// Vector4 type
type Vector4 struct {
X float32
Y float32
Z float32
W float32
}
// NewVector4 - Returns new Vector4
func NewVector4(X, Y, Z, W float32) Vector4 {
return Vector4{X, Y, Z, W}
}
// newVector4FromPointer - Returns new Vector4 from pointer
func newVector4FromPointer(ptr unsafe.Pointer) Vector4 {
return *(*Vector4)(ptr)
}
// Matrix type (OpenGL style 4x4 - right handed, column major) // Matrix type (OpenGL style 4x4 - right handed, column major)
type Matrix struct { type Matrix struct {
M0, M4, M8, M12 float32 M0, M4, M8, M12 float32
@ -485,14 +515,14 @@ func newColorFromPointer(ptr unsafe.Pointer) Color {
// Rectangle type // Rectangle type
type Rectangle struct { type Rectangle struct {
X int32 X float32
Y int32 Y float32
Width int32 Width float32
Height int32 Height float32
} }
// NewRectangle - Returns new Rectangle // NewRectangle - Returns new Rectangle
func NewRectangle(x, y, width, height int32) Rectangle { func NewRectangle(x, y, width, height float32) Rectangle {
return Rectangle{x, y, width, height} return Rectangle{x, y, width, height}
} }
@ -501,26 +531,61 @@ func newRectangleFromPointer(ptr unsafe.Pointer) Rectangle {
return *(*Rectangle)(ptr) return *(*Rectangle)(ptr)
} }
// Camera type, defines a camera position/orientation in 3d space // ToInt32 converts rectangle to int32 variant
type Camera struct { func (r *Rectangle) ToInt32() RectangleInt32 {
rect := RectangleInt32{}
rect.X = int32(r.X)
rect.Y = int32(r.Y)
rect.Width = int32(r.Width)
rect.Height = int32(r.Height)
return rect
}
// RectangleInt32 type
type RectangleInt32 struct {
X int32
Y int32
Width int32
Height int32
}
// ToFloat32 converts rectangle to float32 variant
func (r *RectangleInt32) ToFloat32() Rectangle {
rect := Rectangle{}
rect.X = float32(r.X)
rect.Y = float32(r.Y)
rect.Width = float32(r.Width)
rect.Height = float32(r.Height)
return rect
}
// Camera3D type, defines a camera position/orientation in 3d space
type Camera3D struct {
// Camera position // Camera position
Position Vector3 Position Vector3
// Camera target it looks-at // Camera target it looks-at
Target Vector3 Target Vector3
// Camera up vector (rotation over its axis) // Camera up vector (rotation over its axis)
Up Vector3 Up Vector3
// Camera field-of-view apperture in Y (degrees) // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
Fovy float32 Fovy float32
// Camera type, controlling projection type, either CameraPerspective or CameraOrthographic.
Type CameraType
} }
// NewCamera - Returns new Camera // Camera type fallback, defaults to Camera3D
func NewCamera(pos, target, up Vector3, fovy float32) Camera { type Camera = Camera3D
return Camera{pos, target, up, fovy}
// NewCamera3D - Returns new Camera3D
func NewCamera3D(pos, target, up Vector3, fovy float32, ct CameraType) Camera3D {
return Camera3D{pos, target, up, fovy, ct}
} }
// newCameraFromPointer - Returns new Camera from pointer // newCamera3DFromPointer - Returns new Camera3D from pointer
func newCameraFromPointer(ptr unsafe.Pointer) Camera { func newCamera3DFromPointer(ptr unsafe.Pointer) Camera3D {
return *(*Camera)(ptr) return *(*Camera3D)(ptr)
} }
// Camera2D type, defines a 2d camera // Camera2D type, defines a 2d camera
@ -608,7 +673,7 @@ const (
LocMapMetalness LocMapMetalness
LocMapNormal LocMapNormal
LocMapRoughness LocMapRoughness
LocMapOccusion LocMapOcclusion
LocMapEmission LocMapEmission
LocMapHeight LocMapHeight
LocMapCubemap LocMapCubemap
@ -838,7 +903,7 @@ func newShaderFromPointer(ptr unsafe.Pointer) Shader {
return *(*Shader)(ptr) return *(*Shader)(ptr)
} }
// CharInfo - SpriteFont character info // CharInfo - Font character info
type CharInfo struct { type CharInfo struct {
// Character value (Unicode) // Character value (Unicode)
Value int32 Value int32
@ -852,18 +917,18 @@ type CharInfo struct {
AdvanceX int32 AdvanceX int32
} }
// NewCharInfo - Returns new SpriteFont // NewCharInfo - Returns new CharInfo
func NewCharInfo(value int32, rec Rectangle, offsetX, offsetY, advanceX int32) CharInfo { func NewCharInfo(value int32, rec Rectangle, offsetX, offsetY, advanceX int32) CharInfo {
return CharInfo{value, rec, offsetX, offsetY, advanceX} return CharInfo{value, rec, offsetX, offsetY, advanceX}
} }
// newCharInfoFromPointer - Returns new SpriteFont from pointer // newCharInfoFromPointer - Returns new CharInfo from pointer
func newCharInfoFromPointer(ptr unsafe.Pointer) CharInfo { func newCharInfoFromPointer(ptr unsafe.Pointer) CharInfo {
return *(*CharInfo)(ptr) return *(*CharInfo)(ptr)
} }
// SpriteFont type, includes texture and charSet array data // Font type, includes texture and charSet array data
type SpriteFont struct { type Font struct {
// Font texture // Font texture
Texture Texture2D Texture Texture2D
// Base size (default chars height) // Base size (default chars height)
@ -874,14 +939,14 @@ type SpriteFont struct {
Chars *CharInfo Chars *CharInfo
} }
// NewSpriteFont - Returns new SpriteFont // NewFont - Returns new Font
func NewSpriteFont(texture Texture2D, baseSize, charsCount int32, chars *CharInfo) SpriteFont { func NewFont(texture Texture2D, baseSize, charsCount int32, chars *CharInfo) Font {
return SpriteFont{texture, baseSize, charsCount, chars} return Font{texture, baseSize, charsCount, chars}
} }
// newSpriteFontFromPointer - Returns new SpriteFont from pointer // newFontFromPointer - Returns new Font from pointer
func newSpriteFontFromPointer(ptr unsafe.Pointer) SpriteFont { func newFontFromPointer(ptr unsafe.Pointer) Font {
return *(*SpriteFont)(ptr) return *(*Font)(ptr)
} }
// PixelFormat - Texture format // PixelFormat - Texture format

View file

@ -1,14 +1,12 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib v1.9.4-dev * raylib - A simple and easy-to-use library to learn videogames programming (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming (www.raylib.com)
* *
* FEATURES: * FEATURES:
* - Written in plain C code (C99) in PascalCase/camelCase notation * - Written in plain C code (C99) in PascalCase/camelCase notation
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile) * - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile)
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
* - Powerful fonts module with SpriteFonts support (XNA fonts, AngelCode fonts, TTF) * - Powerful fonts module with Fonts support (XNA fonts, AngelCode fonts, TTF)
* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) * - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC)
* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more!
* - Flexible Materials system, supporting classic maps and PBR maps * - Flexible Materials system, supporting classic maps and PBR maps
@ -138,6 +136,9 @@
#define KEY_RIGHT_SHIFT 344 #define KEY_RIGHT_SHIFT 344
#define KEY_RIGHT_CONTROL 345 #define KEY_RIGHT_CONTROL 345
#define KEY_RIGHT_ALT 346 #define KEY_RIGHT_ALT 346
#define KEY_GRAVE 96
#define KEY_SLASH 47
#define KEY_BACKSLASH 92
// Keyboard Alpha Numeric Keys // Keyboard Alpha Numeric Keys
#define KEY_ZERO 48 #define KEY_ZERO 48
@ -322,6 +323,14 @@ typedef struct Vector3 {
float z; float z;
} Vector3; } Vector3;
// Vector4 type
typedef struct Vector4 {
float x;
float y;
float z;
float w;
} Vector4;
// Matrix type (OpenGL style 4x4 - right handed, column major) // Matrix type (OpenGL style 4x4 - right handed, column major)
typedef struct Matrix { typedef struct Matrix {
float m0, m4, m8, m12; float m0, m4, m8, m12;
@ -340,10 +349,10 @@ typedef struct Color {
// Rectangle type // Rectangle type
typedef struct Rectangle { typedef struct Rectangle {
int x; float x;
int y; float y;
int width; float width;
int height; float height;
} Rectangle; } Rectangle;
// Image type, bpp always RGBA (32bit) // Image type, bpp always RGBA (32bit)
@ -373,7 +382,7 @@ typedef struct RenderTexture2D {
Texture2D depth; // Depth buffer attachment texture Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D; } RenderTexture2D;
// SpriteFont character info // Font character info
typedef struct CharInfo { typedef struct CharInfo {
int value; // Character value (Unicode) int value; // Character value (Unicode)
Rectangle rec; // Character rectangle in sprite font Rectangle rec; // Character rectangle in sprite font
@ -382,21 +391,26 @@ typedef struct CharInfo {
int advanceX; // Character advance position X int advanceX; // Character advance position X
} CharInfo; } CharInfo;
// SpriteFont type, includes texture and charSet array data // Font type, includes texture and charSet array data
typedef struct SpriteFont { typedef struct Font {
Texture2D texture; // Font texture Texture2D texture; // Font texture
int baseSize; // Base size (default chars height) int baseSize; // Base size (default chars height)
int charsCount; // Number of characters int charsCount; // Number of characters
CharInfo *chars; // Characters info data CharInfo *chars; // Characters info data
} SpriteFont; } Font;
#define SpriteFont Font // SpriteFont type fallback, defaults to Font
// Camera type, defines a camera position/orientation in 3d space // Camera type, defines a camera position/orientation in 3d space
typedef struct Camera { typedef struct Camera3D {
Vector3 position; // Camera position Vector3 position; // Camera position
Vector3 target; // Camera target it looks-at Vector3 target; // Camera target it looks-at
Vector3 up; // Camera up vector (rotation over its axis) Vector3 up; // Camera up vector (rotation over its axis)
float fovy; // Camera field-of-view apperture in Y (degrees) float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
} Camera; int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
} Camera3D;
#define Camera Camera3D // Camera type fallback, defaults to Camera3D
// Camera2D type, defines a 2d camera // Camera2D type, defines a 2d camera
typedef struct Camera2D { typedef struct Camera2D {
@ -422,7 +436,7 @@ typedef struct Mesh {
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5) float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // Vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// Vertex indices (in case vertex data comes indexed) unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
@ -553,7 +567,7 @@ typedef enum {
LOC_MAP_METALNESS, // LOC_MAP_SPECULAR LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
LOC_MAP_NORMAL, LOC_MAP_NORMAL,
LOC_MAP_ROUGHNESS, LOC_MAP_ROUGHNESS,
LOC_MAP_OCCUSION, LOC_MAP_OCCLUSION,
LOC_MAP_EMISSION, LOC_MAP_EMISSION,
LOC_MAP_HEIGHT, LOC_MAP_HEIGHT,
LOC_MAP_CUBEMAP, LOC_MAP_CUBEMAP,
@ -660,6 +674,12 @@ typedef enum {
CAMERA_THIRD_PERSON CAMERA_THIRD_PERSON
} CameraMode; } CameraMode;
// Camera projection modes
typedef enum {
CAMERA_PERSPECTIVE = 0,
CAMERA_ORTHOGRAPHIC
} CameraType;
// Head Mounted Display devices // Head Mounted Display devices
typedef enum { typedef enum {
HMD_DEFAULT_DEVICE = 0, HMD_DEFAULT_DEVICE = 0,
@ -684,7 +704,7 @@ extern "C" { // Prevents name mangling of functions
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Window-related functions // Window-related functions
RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context
RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
@ -695,6 +715,7 @@ RLAPI void SetWindowTitle(const char *title); // Set title f
RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
RLAPI void SetWindowSize(int width, int height); // Set window dimensions
RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height RLAPI int GetScreenHeight(void); // Get current screen height
@ -709,10 +730,10 @@ RLAPI void DisableCursor(void); // Disables cu
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing
RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering) RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering)
RLAPI void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera (2D) RLAPI void BeginMode2D(Camera2D camera); // Initialize 2D mode with custom camera (2D)
RLAPI void End2dMode(void); // Ends 2D mode with custom camera RLAPI void EndMode2D(void); // Ends 2D mode with custom camera
RLAPI void Begin3dMode(Camera camera); // Initializes 3D mode with custom camera (3D) RLAPI void BeginMode3D(Camera3D camera); // Initializes 3D mode with custom camera (3D)
RLAPI void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
RLAPI void EndTextureMode(void); // Ends drawing to render texture RLAPI void EndTextureMode(void); // Ends drawing to render texture
@ -728,19 +749,12 @@ RLAPI float GetFrameTime(void); // Returns tim
RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow()
// Color-related functions // Color-related functions
RLAPI float *ColorToFloat(Color color); // Returns normalized float array for a Color
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
RLAPI Vector4 ColorNormalize(Color color); // Returns color normalized as float [0..1]
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
// Math useful functions (available from raymath.h)
RLAPI float *Vector3ToFloat(Vector3 vec); // Returns Vector3 as float array
RLAPI float *MatrixToFloat(Matrix mat); // Returns Matrix as float array
RLAPI Vector3 Vector3Zero(void); // Vector with components value 0.0f
RLAPI Vector3 Vector3One(void); // Vector with components value 1.0f
RLAPI Matrix MatrixIdentity(void); // Returns identity matrix
// Misc. functions // Misc. functions
RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags)
RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS) RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS)
@ -797,6 +811,7 @@ RLAPI int GetMouseX(void); // Returns mouse p
RLAPI int GetMouseY(void); // Returns mouse position Y RLAPI int GetMouseY(void); // Returns mouse position Y
RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY
RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY
RLAPI void SetMouseScale(float scale); // Set mouse scaling
RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y
// Input-related functions: touch // Input-related functions: touch
@ -826,9 +841,7 @@ RLAPI void UpdateCamera(Camera *camera); // Update came
RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera)
RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera)
RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera)
RLAPI void SetCameraMoveControls(int frontKey, int backKey, RLAPI void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
int rightKey, int leftKey,
int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Basic Shapes Drawing Functions (Module: shapes) // Basic Shapes Drawing Functions (Module: shapes)
@ -878,6 +891,7 @@ RLAPI Image LoadImage(const char *fileName);
RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit) RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit)
RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI void ExportImage(const char *fileName, Image image); // Export image as a PNG file
RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM) RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM)
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
@ -888,7 +902,6 @@ RLAPI Color *GetImageData(Image image);
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file
// Image manipulation functions // Image manipulation functions
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations)
@ -904,11 +917,11 @@ RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight);
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image
RLAPI void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color); // Draw rectangle within an image
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination)
float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination)
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally
RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint
@ -937,31 +950,30 @@ RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
float rotation, Color tint);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text) // Font Loading and Text Drawing Functions (Module: text)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// SpriteFont loading/unloading functions // Font loading/unloading functions
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI Font GetDefaultFont(void); // Get the default Font
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) RLAPI Font LoadFont(const char *fileName); // Load Font from file into GPU memory (VRAM)
RLAPI SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from file with extended parameters RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load Font from file with extended parameters
RLAPI void UnloadSpriteFont(SpriteFont font); // Unload SpriteFont from GPU memory (VRAM) RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM)
// Text drawing functions // Text drawing functions
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS RLAPI void DrawFPS(int posX, int posY); // Shows current FPS
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(SpriteFont font, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using Font and additional parameters
float fontSize, int spacing, Color tint);
// Text misc. functions // Text misc. functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed'
RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string
RLAPI int GetGlyphIndex(SpriteFont font, int character); // Returns index position for a unicode character on sprite font RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models) // Basic 3d Shapes Drawing Functions (Module: models)
@ -997,6 +1009,12 @@ RLAPI void UnloadModel(Model model);
// Mesh loading/unloading functions // Mesh loading/unloading functions
RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM) RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
RLAPI void ExportMesh(const char *fileName, Mesh mesh); // Export mesh as an OBJ file
// Mesh manipulation functions
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
// Mesh generation functions // Mesh generation functions
RLAPI Mesh GenMeshPlane(float width, float length, int resX, int resZ); // Generate plane mesh (with subdivisions) RLAPI Mesh GenMeshPlane(float width, float length, int resX, int resZ); // Generate plane mesh (with subdivisions)
@ -1016,26 +1034,21 @@ RLAPI void UnloadMaterial(Material material);
// Model drawing functions // Model drawing functions
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set)
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec
Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec
// Collision detection functions // Collision detection functions
RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits
RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere
RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere
RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh); // Get collision info between ray and mesh RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model *model); // Get collision info between ray and model
RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane) RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
@ -1134,8 +1147,7 @@ RLAPI float GetMusicTimeLength(Music music); // Get mus
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
// AudioStream management functions // AudioStream management functions
RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
unsigned int channels); // Init audio stream (to stream raw audio pcm data)
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill

File diff suppressed because it is too large Load diff

View file

@ -54,11 +54,7 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features) #include "config.h"
//-------------------------------------------------
#define SUPPORT_VR_SIMULATOR
#define SUPPORT_DISTORTION_SHADER
//-------------------------------------------------
#include "rlgl.h" #include "rlgl.h"
@ -470,8 +466,7 @@ void rlRotatef(float angleDeg, float x, float y, float z)
Matrix matRotation = MatrixIdentity(); Matrix matRotation = MatrixIdentity();
Vector3 axis = (Vector3){ x, y, z }; Vector3 axis = (Vector3){ x, y, z };
Vector3Normalize(&axis); matRotation = MatrixRotate(Vector3Normalize(axis), angleDeg*DEG2RAD);
matRotation = MatrixRotate(axis, angleDeg*DEG2RAD);
// NOTE: We transpose matrix with multiplication order // NOTE: We transpose matrix with multiplication order
*currentMatrix = MatrixMultiply(matRotation, *currentMatrix); *currentMatrix = MatrixMultiply(matRotation, *currentMatrix);
@ -570,7 +565,7 @@ void rlEnd(void)
// This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1 // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1
// Apply transformation matrix to all temp vertices // Apply transformation matrix to all temp vertices
for (int i = 0; i < tempBufferCount; i++) Vector3Transform(&tempBuffer[i], *currentMatrix); for (int i = 0; i < tempBufferCount; i++) tempBuffer[i] = Vector3Transform(tempBuffer[i], *currentMatrix);
// Deactivate tempBuffer usage to allow rlVertex3f do its job // Deactivate tempBuffer usage to allow rlVertex3f do its job
useTempBuffer = false; useTempBuffer = false;
@ -1356,13 +1351,13 @@ Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view)
// Calculate unproject matrix (multiply view patrix by projection matrix) and invert it // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
Matrix matViewProj = MatrixMultiply(view, proj); Matrix matViewProj = MatrixMultiply(view, proj);
MatrixInvert(&matViewProj); matViewProj = MatrixInvert(matViewProj);
// Create quaternion from source point // Create quaternion from source point
Quaternion quat = { source.x, source.y, source.z, 1.0f }; Quaternion quat = { source.x, source.y, source.z, 1.0f };
// Multiply quat point by unproject matrix // Multiply quat point by unproject matrix
QuaternionTransform(&quat, matViewProj); quat = QuaternionTransform(quat, matViewProj);
// Normalized world points in vectors // Normalized world points in vectors
result.x = quat.x/quat.w; result.x = quat.x/quat.w;
@ -1782,14 +1777,14 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{ {
glGenBuffers(1, &mesh->vboId[4]); glGenBuffers(1, &mesh->vboId[4]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[4]); glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[4]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, drawHint); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh->vertexCount, mesh->tangents, drawHint);
glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(4, 4, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(4); glEnableVertexAttribArray(4);
} }
else else
{ {
// Default tangents vertex attribute // Default tangents vertex attribute
glVertexAttrib3f(4, 0.0f, 0.0f, 0.0f); glVertexAttrib4f(4, 0.0f, 0.0f, 0.0f, 0.0f);
glDisableVertexAttribArray(4); glDisableVertexAttribArray(4);
} }
@ -1804,7 +1799,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
} }
else else
{ {
// Default tangents vertex attribute // Default texcoord2 vertex attribute
glVertexAttrib2f(5, 0.0f, 0.0f); glVertexAttrib2f(5, 0.0f, 0.0f);
glDisableVertexAttribArray(5); glDisableVertexAttribArray(5);
} }
@ -1868,8 +1863,8 @@ void rlUpdateMesh(Mesh mesh, int buffer, int numVertex)
case 4: // Update tangents (vertex tangents) case 4: // Update tangents (vertex tangents)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]); glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.tangents, GL_DYNAMIC_DRAW); if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.tangents, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.tangents); else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*numVertex, mesh.tangents);
} break; } break;
case 5: // Update texcoords2 (vertex second texture coordinates) case 5: // Update texcoords2 (vertex second texture coordinates)
{ {
@ -1952,7 +1947,7 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
if (material.shader.locs[LOC_MATRIX_PROJECTION] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_PROJECTION], projection); if (material.shader.locs[LOC_MATRIX_PROJECTION] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_PROJECTION], projection);
// At this point the modelview matrix just contains the view matrix (camera) // At this point the modelview matrix just contains the view matrix (camera)
// That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix() // That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matView = modelview; // View matrix (camera) Matrix matView = modelview; // View matrix (camera)
Matrix matProjection = projection; // Projection matrix (perspective) Matrix matProjection = projection; // Projection matrix (perspective)
@ -2019,7 +2014,7 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
if (material.shader.locs[LOC_VERTEX_TANGENT] != -1) if (material.shader.locs[LOC_VERTEX_TANGENT] != -1)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]); glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TANGENT], 3, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TANGENT], 4, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TANGENT]); glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TANGENT]);
} }
@ -3374,9 +3369,9 @@ static void LoadBuffersDefault(void)
quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad
quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
quads.indices = (unsigned int *)malloc(sizeof(int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) quads.indices = (unsigned int *)malloc(sizeof(unsigned int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices)
#elif defined(GRAPHICS_API_OPENGL_ES2) #elif defined(GRAPHICS_API_OPENGL_ES2)
quads.indices = (unsigned short *)malloc(sizeof(short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) quads.indices = (unsigned short *)malloc(sizeof(unsigned short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices)
#endif #endif
for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f; for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f;

View file

@ -24,7 +24,7 @@
* #define RLGL_STANDALONE * #define RLGL_STANDALONE
* Use rlgl as standalone library (no raylib dependency) * Use rlgl as standalone library (no raylib dependency)
* *
* #define SUPPORT_VR_SIMULATION / SUPPORT_STEREO_RENDERING * #define SUPPORT_VR_SIMULATOR
* Support VR simulation functionality (stereo rendering) * Support VR simulation functionality (stereo rendering)
* *
* #define SUPPORT_DISTORTION_SHADER * #define SUPPORT_DISTORTION_SHADER
@ -187,7 +187,7 @@ typedef unsigned char byte;
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) float *tangents; // vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed) unsigned short *indices;// vertex indices (in case vertex data comes indexed)
@ -321,7 +321,7 @@ typedef unsigned char byte;
LOC_MAP_METALNESS, // LOC_MAP_SPECULAR LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
LOC_MAP_NORMAL, LOC_MAP_NORMAL,
LOC_MAP_ROUGHNESS, LOC_MAP_ROUGHNESS,
LOC_MAP_OCCUSION, LOC_MAP_OCCLUSION,
LOC_MAP_EMISSION, LOC_MAP_EMISSION,
LOC_MAP_HEIGHT, LOC_MAP_HEIGHT,
LOC_MAP_CUBEMAP, LOC_MAP_CUBEMAP,

View file

@ -4,16 +4,13 @@
* *
* CONFIGURATION: * CONFIGURATION:
* *
* #define SUPPORT_QUADS_ONLY * #define SUPPORT_FONT_TEXTURE
* Draw shapes using only QUADS, vertex are accumulated in QUADS arrays (like textures)
*
* #define SUPPORT_TRIANGLES_ONLY
* Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays
*
* #define USE_DEFAULT_FONT_TEXTURE
* Draw rectangle shapes using font texture white character instead of default white texture * Draw rectangle shapes using font texture white character instead of default white texture
* Allows drawing rectangles and text with a single draw call, very useful for GUI systems! * Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
* *
* #define SUPPORT_QUADS_DRAW_MODE
* Use QUADS instead of TRIANGLES for drawing when possible.
* Some lines-based shapes could still use lines
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
@ -36,13 +33,12 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#define USE_DEFAULT_FONT_TEXTURE #include "config.h" // Defines module configuration flags
#include "raylib.h" // Declares module functions
#include "raylib.h"
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include <stdlib.h> // Required for: abs() #include <stdlib.h> // Required for: abs(), fabs()
#include <math.h> // Required for: sinf(), cosf(), sqrtf() #include <math.h> // Required for: sinf(), cosf(), sqrtf()
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -194,21 +190,7 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawCircleV(Vector2 center, float radius, Color color) void DrawCircleV(Vector2 center, float radius, Color color)
{ {
if (rlGetVersion() == OPENGL_11) #if defined(SUPPORT_QUADS_DRAW_MODE)
{
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetTextureDefault().id); // Default white texture rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
@ -224,7 +206,18 @@ void DrawCircleV(Vector2 center, float radius, Color color)
rlEnd(); rlEnd();
rlDisableTexture(); rlDisableTexture();
#else
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
} }
rlEnd();
#endif
} }
// Draw circle outline // Draw circle outline
@ -255,23 +248,8 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleV(Vector2 position, Vector2 size, Color color) void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{ {
if (rlGetVersion() == OPENGL_11) #if defined(SUPPORT_QUADS_DRAW_MODE)
{ #if defined(SUPPORT_FONT_TEXTURE)
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y);
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
#if defined(USE_DEFAULT_FONT_TEXTURE)
// Draw rectangle using font texture white character // Draw rectangle using font texture white character
rlEnableTexture(GetDefaultFont().texture.id); rlEnableTexture(GetDefaultFont().texture.id);
@ -298,7 +276,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
rlEnd(); rlEnd();
rlDisableTexture(); rlDisableTexture();
#else #else
rlEnableTexture(GetTextureDefault().id); // Default white texture rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
@ -319,8 +297,20 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
rlEnd(); rlEnd();
rlDisableTexture(); rlDisableTexture();
#endif #endif // SUPPORT_FONT_TEXTURE
} #else
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y);
rlEnd();
#endif // SUPPORT_QUADS_DRAW_MODE
} }
// Draw a color-filled rectangle // Draw a color-filled rectangle
@ -334,7 +324,7 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlEnableTexture(GetTextureDefault().id); rlEnableTexture(GetTextureDefault().id);
rlPushMatrix(); rlPushMatrix();
rlTranslatef((float)rec.x, (float)rec.y, 0); rlTranslatef(rec.x, rec.y, 0);
rlRotatef(rotation, 0, 0, 1); rlRotatef(rotation, 0, 0, 1);
rlTranslatef(-origin.x, -origin.y, 0); rlTranslatef(-origin.x, -origin.y, 0);
@ -343,9 +333,9 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
rlVertex2f(0.0f, 0.0f); rlVertex2f(0.0f, 0.0f);
rlVertex2f(0.0f, (float)rec.height); rlVertex2f(0.0f, rec.height);
rlVertex2f((float)rec.width, (float)rec.height); rlVertex2f(rec.width, rec.height);
rlVertex2f((float)rec.width, 0.0f); rlVertex2f(rec.width, 0.0f);
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
@ -370,7 +360,7 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col
// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise // NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{ {
#if defined(USE_DEFAULT_FONT_TEXTURE) #if defined(SUPPORT_FONT_TEXTURE)
// Draw rectangle using font texture white character // Draw rectangle using font texture white character
rlEnableTexture(GetDefaultFont().texture.id); rlEnableTexture(GetDefaultFont().texture.id);
@ -379,23 +369,23 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
// NOTE: Default raylib font character 95 is a white square // NOTE: Default raylib font character 95 is a white square
rlColor4ub(col1.r, col1.g, col1.b, col1.a); rlColor4ub(col1.r, col1.g, col1.b, col1.a);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, rlTexCoord2f(GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y); rlVertex2f(rec.x, rec.y);
rlColor4ub(col2.r, col2.g, col2.b, col2.a); rlColor4ub(col2.r, col2.g, col2.b, col2.a);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, rlTexCoord2f(GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); (GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y + rec.height); rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(col3.r, col3.g, col3.b, col3.a); rlColor4ub(col3.r, col3.g, col3.b, col3.a);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, rlTexCoord2f((GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); (GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height); rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(col4.r, col4.g, col4.b, col4.a); rlColor4ub(col4.r, col4.g, col4.b, col4.a);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, rlTexCoord2f((GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y); rlVertex2f(rec.x + rec.width, rec.y);
rlEnd(); rlEnd();
@ -431,8 +421,12 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleLines(int posX, int posY, int width, int height, Color color) void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{ {
if (rlGetVersion() == OPENGL_11) #if defined(SUPPORT_QUADS_DRAW_MODE)
{ DrawRectangle(posX, posY, width, 1, color);
DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
DrawRectangle(posX, posY + height - 1, width, 1, color);
DrawRectangle(posX, posY + 1, 1, height - 2, color);
#else
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX + 1, posY + 1); rlVertex2i(posX + 1, posY + 1);
@ -447,14 +441,7 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
rlVertex2i(posX + 1, posY + height); rlVertex2i(posX + 1, posY + height);
rlVertex2i(posX + 1, posY + 1); rlVertex2i(posX + 1, posY + 1);
rlEnd(); rlEnd();
} #endif
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
DrawRectangle(posX, posY, width, 1, color);
DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
DrawRectangle(posX, posY + height - 1, width, 1, color);
DrawRectangle(posX, posY + 1, 1, height - 2, color);
}
} }
// Draw rectangle outline with extended parameters // Draw rectangle outline with extended parameters
@ -475,17 +462,7 @@ void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
// Draw a triangle // Draw a triangle
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{ {
if (rlGetVersion() == OPENGL_11) #if defined(SUPPORT_QUADS_DRAW_MODE)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetTextureDefault().id); // Default white texture rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
@ -497,9 +474,17 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlEnd(); rlEnd();
rlDisableTexture(); rlDisableTexture();
} #else
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlEnd();
#endif
} }
// Draw a triangle using lines
void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color) void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
@ -524,6 +509,22 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlTranslatef(center.x, center.y, 0.0); rlTranslatef(center.x, center.y, 0.0);
rlRotatef(rotation, 0, 0, 1); rlRotatef(rotation, 0, 0, 1);
#if defined(SUPPORT_QUADS_DRAW_MODE)
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
for (int i = 0; i < 360; i += 360/sides)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(0, 0);
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
}
rlEnd();
rlDisableTexture();
#else
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
@ -534,38 +535,54 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
} }
rlEnd(); rlEnd();
#endif
rlPopMatrix(); rlPopMatrix();
} }
// Draw a closed polygon defined by points // Draw a closed polygon defined by points
// NOTE: Array num elements MUST be passed as parameter to function void DrawPolyEx(Vector2 *points, int pointsCount, Color color)
void DrawPolyEx(Vector2 *points, int numPoints, Color color)
{ {
if (numPoints >= 3) if (pointsCount >= 3)
{ {
#if defined(SUPPORT_QUADS_DRAW_MODE)
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 1; i < pointsCount - 1; i++)
{
rlVertex2f(points[0].x, points[0].y);
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
rlDisableTexture();
#else
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 1; i < numPoints - 1; i++) for (int i = 1; i < pointsCount - 1; i++)
{ {
rlVertex2f(points[0].x, points[0].y); rlVertex2f(points[0].x, points[0].y);
rlVertex2f(points[i].x, points[i].y); rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y); rlVertex2f(points[i + 1].x, points[i + 1].y);
} }
rlEnd(); rlEnd();
#endif
} }
} }
// Draw polygon lines // Draw polygon using lines
// NOTE: Array num elements MUST be passed as parameter to function void DrawPolyExLines(Vector2 *points, int pointsCount, Color color)
void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
{ {
if (numPoints >= 2) if (pointsCount >= 2)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints - 1; i++) for (int i = 0; i < pointsCount - 1; i++)
{ {
rlVertex2f(points[i].x, points[i].y); rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y); rlVertex2f(points[i + 1].x, points[i + 1].y);
@ -650,14 +667,14 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
float dx = fabsf(center.x - recCenterX); float dx = fabsf(center.x - recCenterX);
float dy = fabsf(center.y - recCenterY); float dy = fabsf(center.y - recCenterY);
if (dx > ((float)rec.width/2.0f + radius)) { return false; } if (dx > (rec.width/2.0f + radius)) { return false; }
if (dy > ((float)rec.height/2.0f + radius)) { return false; } if (dy > (rec.height/2.0f + radius)) { return false; }
if (dx <= ((float)rec.width/2.0f)) { return true; } if (dx <= (rec.width/2.0f)) { return true; }
if (dy <= ((float)rec.height/2.0f)) { return true; } if (dy <= (rec.height/2.0f)) { return true; }
float cornerDistanceSq = (dx - (float)rec.width/2.0f)*(dx - (float)rec.width/2.0f) + float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
(dy - (float)rec.height/2.0f)*(dy - (float)rec.height/2.0f); (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
return (cornerDistanceSq <= (radius*radius)); return (cornerDistanceSq <= (radius*radius));
} }

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.text - Basic functions to load SpriteFonts and draw Text * raylib.text - Basic functions to load Fonts and draw Text
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -36,12 +36,7 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default supported features #include "config.h"
//-------------------------------------
#define SUPPORT_DEFAULT_FONT
#define SUPPORT_FILEFORMAT_FNT
#define SUPPORT_FILEFORMAT_TTF
//-------------------------------------
#include "raylib.h" #include "raylib.h"
@ -78,7 +73,7 @@
// Global variables // Global variables
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
static SpriteFont defaultFont; // Default font provided by raylib static Font defaultFont; // Default font provided by raylib
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core] // NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core]
#endif #endif
@ -90,12 +85,12 @@ static SpriteFont defaultFont; // Default font provided by raylib
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static Font LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif #endif
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data
#endif #endif
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
@ -111,7 +106,7 @@ extern void UnloadDefaultFont(void);
// Load raylib default font // Load raylib default font
extern void LoadDefaultFont(void) extern void LoadDefaultFont(void)
{ {
#define BIT_CHECK(a,b) ((a) & (1 << (b))) #define BIT_CHECK(a,b) ((a) & (1u << (b)))
// NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
// http://www.utf8-chartable.de/unicode-utf8-table.pl // http://www.utf8-chartable.de/unicode-utf8-table.pl
@ -119,7 +114,7 @@ extern void LoadDefaultFont(void)
defaultFont.charsCount = 224; // Number of chars included in our default font defaultFont.charsCount = 224; // Number of chars included in our default font
// Default font is directly defined here (data generated from a sprite font image) // Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables // This way, we reconstruct Font without creating large global variables
// This data is automatically allocated to Stack and automatically deallocated at the end of this function // This data is automatically allocated to Stack and automatically deallocated at the end of this function
int defaultFontData[512] = { int defaultFontData[512] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f,
@ -266,28 +261,28 @@ extern void UnloadDefaultFont(void)
#endif // SUPPORT_DEFAULT_FONT #endif // SUPPORT_DEFAULT_FONT
// Get the default font, useful to be used with extended parameters // Get the default font, useful to be used with extended parameters
SpriteFont GetDefaultFont() Font GetDefaultFont()
{ {
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
return defaultFont; return defaultFont;
#else #else
SpriteFont font = { 0 }; Font font = { 0 };
return font; return font;
#endif #endif
} }
// Load SpriteFont from file into GPU memory (VRAM) // Load Font from file into GPU memory (VRAM)
SpriteFont LoadSpriteFont(const char *fileName) Font LoadFont(const char *fileName)
{ {
// Default hardcoded values for ttf file loading // Default hardcoded values for ttf file loading
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space)
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont
SpriteFont spriteFont = { 0 }; Font spriteFont = { 0 };
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
else else
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
@ -302,7 +297,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
if (spriteFont.texture.id == 0) if (spriteFont.texture.id == 0)
{ {
TraceLog(LOG_WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName);
spriteFont = GetDefaultFont(); spriteFont = GetDefaultFont();
} }
else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance)
@ -310,12 +305,12 @@ SpriteFont LoadSpriteFont(const char *fileName)
return spriteFont; return spriteFont;
} }
// Load SpriteFont from TTF font file with generation parameters // Load Font from TTF font file with generation parameters
// NOTE: You can pass an array with desired characters, those characters should be available in the font // NOTE: You can pass an array with desired characters, those characters should be available in the font
// if array is NULL, default char set is selected 32..126 // if array is NULL, default char set is selected 32..126
SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars)
{ {
SpriteFont spriteFont = { 0 }; Font spriteFont = { 0 };
int totalChars = 95; // Default charset [32..126] int totalChars = 95; // Default charset [32..126]
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
@ -335,15 +330,15 @@ SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount,
if (spriteFont.texture.id == 0) if (spriteFont.texture.id == 0)
{ {
TraceLog(LOG_WARNING, "[%s] SpriteFont could not be generated, using default font", fileName); TraceLog(LOG_WARNING, "[%s] Font could not be generated, using default font", fileName);
spriteFont = GetDefaultFont(); spriteFont = GetDefaultFont();
} }
return spriteFont; return spriteFont;
} }
// Unload SpriteFont from GPU memory (VRAM) // Unload Font from GPU memory (VRAM)
void UnloadSpriteFont(SpriteFont font) void UnloadFont(Font font)
{ {
// NOTE: Make sure spriteFont is not default font (fallback) // NOTE: Make sure spriteFont is not default font (fallback)
if (font.texture.id != GetDefaultFont().texture.id) if (font.texture.id != GetDefaultFont().texture.id)
@ -369,13 +364,13 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
if (fontSize < defaultFontSize) fontSize = defaultFontSize; if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize/defaultFontSize; int spacing = fontSize/defaultFontSize;
DrawTextEx(GetDefaultFont(), text, position, (float)fontSize, spacing, color); DrawTextEx(GetDefaultFont(), text, position, (float)fontSize, (float)spacing, color);
} }
} }
// Draw text using SpriteFont // Draw text using Font
// NOTE: chars spacing is NOT proportional to fontSize // NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(SpriteFont font, const char *text, Vector2 position, float fontSize, int spacing, Color tint) void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
{ {
int length = strlen(text); int length = strlen(text);
int textOffsetX = 0; // Offset between characters int textOffsetX = 0; // Offset between characters
@ -481,14 +476,14 @@ int MeasureText(const char *text, int fontSize)
if (fontSize < defaultFontSize) fontSize = defaultFontSize; if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize/defaultFontSize; int spacing = fontSize/defaultFontSize;
vec = MeasureTextEx(GetDefaultFont(), text, (float)fontSize, spacing); vec = MeasureTextEx(GetDefaultFont(), text, (float)fontSize, (float)spacing);
} }
return (int)vec.x; return (int)vec.x;
} }
// Measure string size for SpriteFont // Measure string size for Font
Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spacing) Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
{ {
int len = strlen(text); int len = strlen(text);
int tempLen = 0; // Used to count longer text line num chars int tempLen = 0; // Used to count longer text line num chars
@ -532,7 +527,7 @@ Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spa
} }
// Returns index position for a unicode character on spritefont // Returns index position for a unicode character on spritefont
int GetGlyphIndex(SpriteFont font, int character) int GetGlyphIndex(Font font, int character)
{ {
#define UNORDERED_CHARSET #define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET) #if defined(UNORDERED_CHARSET)
@ -580,7 +575,7 @@ void DrawFPS(int posX, int posY)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Load an Image font file (XNA style) // Load an Image font file (XNA style)
static SpriteFont LoadImageFont(Image image, Color key, int firstChar) static Font LoadImageFont(Image image, Color key, int firstChar)
{ {
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
@ -653,7 +648,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
xPosToRead = charSpacing; xPosToRead = charSpacing;
} }
TraceLog(LOG_DEBUG, "SpriteFont data parsed correctly from image"); TraceLog(LOG_DEBUG, "Font data parsed correctly from image");
// NOTE: We need to remove key color borders from image to avoid weird // NOTE: We need to remove key color borders from image to avoid weird
// artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR // artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR
@ -665,7 +660,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
free(pixels); // Free pixels array memory free(pixels); // Free pixels array memory
// Create spritefont with all data parsed from image // Create spritefont with all data parsed from image
SpriteFont spriteFont = { 0 }; Font spriteFont = { 0 };
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
spriteFont.charsCount = index; spriteFont.charsCount = index;
@ -689,18 +684,18 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
spriteFont.baseSize = spriteFont.chars[0].rec.height; spriteFont.baseSize = spriteFont.chars[0].rec.height;
TraceLog(LOG_INFO, "Image file loaded correctly as SpriteFont"); TraceLog(LOG_INFO, "Image file loaded correctly as Font");
return spriteFont; return spriteFont;
} }
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
// Load a BMFont file (AngelCode font file) // Load a BMFont file (AngelCode font file)
static SpriteFont LoadBMFont(const char *fileName) static Font LoadBMFont(const char *fileName)
{ {
#define MAX_BUFFER_SIZE 256 #define MAX_BUFFER_SIZE 256
SpriteFont font = { 0 }; Font font = { 0 };
font.texture.id = 0; font.texture.id = 0;
char buffer[MAX_BUFFER_SIZE]; char buffer[MAX_BUFFER_SIZE];
@ -708,7 +703,7 @@ static SpriteFont LoadBMFont(const char *fileName)
int fontSize = 0; int fontSize = 0;
int texWidth, texHeight; int texWidth, texHeight;
char texFileName[128]; char texFileName[129];
int charsCount = 0; int charsCount = 0;
int base; // Useless data int base; // Useless data
@ -805,10 +800,10 @@ static SpriteFont LoadBMFont(const char *fileName)
if (font.texture.id == 0) if (font.texture.id == 0)
{ {
UnloadSpriteFont(font); UnloadFont(font);
font = GetDefaultFont(); font = GetDefaultFont();
} }
else TraceLog(LOG_INFO, "[%s] SpriteFont loaded successfully", fileName); else TraceLog(LOG_INFO, "[%s] Font loaded successfully", fileName);
return font; return font;
} }
@ -817,7 +812,7 @@ static SpriteFont LoadBMFont(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
// Generate a sprite font from TTF file data (font size required) // Generate a sprite font from TTF file data (font size required)
// TODO: Review texture packing method and generation (use oversampling) // TODO: Review texture packing method and generation (use oversampling)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
{ {
#define MAX_TTF_SIZE 16 // Maximum ttf file size in MB #define MAX_TTF_SIZE 16 // Maximum ttf file size in MB
@ -835,7 +830,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in
unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned!
stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount);
SpriteFont font = { 0 }; Font font = { 0 };
FILE *ttfFile = fopen(fileName, "rb"); FILE *ttfFile = fopen(fileName, "rb");

View file

@ -13,42 +13,42 @@ func (c *CharInfo) cptr() *C.CharInfo {
} }
// cptr returns C pointer // cptr returns C pointer
func (s *SpriteFont) cptr() *C.SpriteFont { func (s *Font) cptr() *C.Font {
return (*C.SpriteFont)(unsafe.Pointer(s)) return (*C.Font)(unsafe.Pointer(s))
} }
// GetDefaultFont - Get the default SpriteFont // GetDefaultFont - Get the default Font
func GetDefaultFont() SpriteFont { func GetDefaultFont() Font {
ret := C.GetDefaultFont() ret := C.GetDefaultFont()
v := newSpriteFontFromPointer(unsafe.Pointer(&ret)) v := newFontFromPointer(unsafe.Pointer(&ret))
return v return v
} }
// LoadSpriteFont - Load a SpriteFont image into GPU memory (VRAM) // LoadFont - Load a Font image into GPU memory (VRAM)
func LoadSpriteFont(fileName string) SpriteFont { func LoadFont(fileName string) Font {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName)) defer C.free(unsafe.Pointer(cfileName))
ret := C.LoadSpriteFont(cfileName) ret := C.LoadFont(cfileName)
v := newSpriteFontFromPointer(unsafe.Pointer(&ret)) v := newFontFromPointer(unsafe.Pointer(&ret))
return v return v
} }
// LoadSpriteFontEx - Load SpriteFont from file with extended parameters // LoadFontEx - Load Font from file with extended parameters
func LoadSpriteFontEx(fileName string, fontSize int32, charsCount int32, fontChars *int32) SpriteFont { func LoadFontEx(fileName string, fontSize int32, charsCount int32, fontChars *int32) Font {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName)) defer C.free(unsafe.Pointer(cfileName))
cfontSize := (C.int)(fontSize) cfontSize := (C.int)(fontSize)
ccharsCount := (C.int)(charsCount) ccharsCount := (C.int)(charsCount)
cfontChars := (*C.int)(unsafe.Pointer(fontChars)) cfontChars := (*C.int)(unsafe.Pointer(fontChars))
ret := C.LoadSpriteFontEx(cfileName, cfontSize, ccharsCount, cfontChars) ret := C.LoadFontEx(cfileName, cfontSize, ccharsCount, cfontChars)
v := newSpriteFontFromPointer(unsafe.Pointer(&ret)) v := newFontFromPointer(unsafe.Pointer(&ret))
return v return v
} }
// UnloadSpriteFont - Unload SpriteFont from GPU memory (VRAM) // UnloadFont - Unload Font from GPU memory (VRAM)
func UnloadSpriteFont(spriteFont SpriteFont) { func UnloadFont(font Font) {
cspriteFont := spriteFont.cptr() cfont := font.cptr()
C.UnloadSpriteFont(*cspriteFont) C.UnloadFont(*cfont)
} }
// DrawText - Draw text (using default font) // DrawText - Draw text (using default font)
@ -62,16 +62,16 @@ func DrawText(text string, posX int32, posY int32, fontSize int32, color Color)
C.DrawText(ctext, cposX, cposY, cfontSize, *ccolor) C.DrawText(ctext, cposX, cposY, cfontSize, *ccolor)
} }
// DrawTextEx - Draw text using SpriteFont and additional parameters // DrawTextEx - Draw text using Font and additional parameters
func DrawTextEx(spriteFont SpriteFont, text string, position Vector2, fontSize float32, spacing int32, tint Color) { func DrawTextEx(font Font, text string, position Vector2, fontSize float32, spacing float32, tint Color) {
cspriteFont := spriteFont.cptr() cfont := font.cptr()
ctext := C.CString(text) ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(ctext))
cposition := position.cptr() cposition := position.cptr()
cfontSize := (C.float)(fontSize) cfontSize := (C.float)(fontSize)
cspacing := (C.int)(spacing) cspacing := (C.float)(spacing)
ctint := tint.cptr() ctint := tint.cptr()
C.DrawTextEx(*cspriteFont, ctext, *cposition, cfontSize, cspacing, *ctint) C.DrawTextEx(*cfont, ctext, *cposition, cfontSize, cspacing, *ctint)
} }
// MeasureText - Measure string width for default font // MeasureText - Measure string width for default font
@ -84,14 +84,14 @@ func MeasureText(text string, fontSize int32) int32 {
return v return v
} }
// MeasureTextEx - Measure string size for SpriteFont // MeasureTextEx - Measure string size for Font
func MeasureTextEx(spriteFont SpriteFont, text string, fontSize float32, spacing int32) Vector2 { func MeasureTextEx(font Font, text string, fontSize float32, spacing float32) Vector2 {
cspriteFont := spriteFont.cptr() cfont := font.cptr()
ctext := C.CString(text) ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(ctext))
cfontSize := (C.float)(fontSize) cfontSize := (C.float)(fontSize)
cspacing := (C.int)(spacing) cspacing := (C.float)(spacing)
ret := C.MeasureTextEx(*cspriteFont, ctext, cfontSize, cspacing) ret := C.MeasureTextEx(*cfont, ctext, cfontSize, cspacing)
v := newVector2FromPointer(unsafe.Pointer(&ret)) v := newVector2FromPointer(unsafe.Pointer(&ret))
return v return v
} }

View file

@ -52,17 +52,7 @@
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
* *
**********************************************************************************************/ **********************************************************************************************/
#include "config.h"
// Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_PNG
#define SUPPORT_FILEFORMAT_DDS
#define SUPPORT_FILEFORMAT_HDR
#define SUPPORT_FILEFORMAT_KTX
#define SUPPORT_FILEFORMAT_ASTC
#define SUPPORT_IMAGE_MANIPULATION
#define SUPPORT_IMAGE_GENERATION
//-------------------------------------------------
#include "raylib.h" #include "raylib.h"
@ -572,17 +562,13 @@ void UpdateTexture(Texture2D texture, const void *pixels)
rlUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels); rlUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels);
} }
// Save image to a PNG file // Export image as a PNG file
void SaveImageAs(const char *fileName, Image image) void ExportImage(const char *fileName, Image image)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// NOTE: Getting Color array as RGBA unsigned char values // NOTE: Getting Color array as RGBA unsigned char values
unsigned char *imgData = (unsigned char *)GetImageData(image); unsigned char *imgData = (unsigned char *)GetImageData(image);
SavePNG(fileName, imgData, image.width, image.height, 4); SavePNG(fileName, imgData, image.width, image.height, 4);
free(imgData); free(imgData);
TraceLog(LOG_INFO, "Image saved: %s", fileName);
#endif
} }
// Copy an image to a new image // Copy an image to a new image
@ -677,7 +663,7 @@ void ImageFormat(Image *image, int newFormat)
Color *pixels = GetImageData(*image); Color *pixels = GetImageData(*image);
free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end...
image->data = NULL;
image->format = newFormat; image->format = newFormat;
int k = 0; int k = 0;
@ -727,7 +713,7 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char));
for (int i = 0; i < image->width*image->height*3; i += 3, k++) for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
{ {
((unsigned char *)image->data)[i] = pixels[k].r; ((unsigned char *)image->data)[i] = pixels[k].r;
((unsigned char *)image->data)[i + 1] = pixels[k].g; ((unsigned char *)image->data)[i + 1] = pixels[k].g;
@ -780,7 +766,7 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char));
for (int i = 0; i < image->width*image->height*3; i += 3, k++) for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
{ {
((unsigned char *)image->data)[i] = pixels[k].r; ((unsigned char *)image->data)[i] = pixels[k].r;
((unsigned char *)image->data)[i + 1] = pixels[k].g; ((unsigned char *)image->data)[i + 1] = pixels[k].g;
@ -801,7 +787,7 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (float *)malloc(image->width*image->height*3*sizeof(float)); image->data = (float *)malloc(image->width*image->height*3*sizeof(float));
for (int i = 0; i < image->width*image->height*3; i += 3, k++) for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
{ {
((float *)image->data)[i] = (float)pixels[k].r/255.0f; ((float *)image->data)[i] = (float)pixels[k].r/255.0f;
((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f;
@ -812,7 +798,7 @@ void ImageFormat(Image *image, int newFormat)
{ {
image->data = (float *)malloc(image->width*image->height*4*sizeof(float)); image->data = (float *)malloc(image->width*image->height*4*sizeof(float));
for (int i = 0; i < image->width*image->height*4; i += 4, k++) for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
{ {
((float *)image->data)[i] = (float)pixels[k].r/255.0f; ((float *)image->data)[i] = (float)pixels[k].r/255.0f;
((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f;
@ -824,12 +810,13 @@ void ImageFormat(Image *image, int newFormat)
} }
free(pixels); free(pixels);
pixels = NULL;
// In case original image had mipmaps, generate mipmaps for formated image // In case original image had mipmaps, generate mipmaps for formated image
// NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
if (image->mipmaps > 1) if (image->mipmaps > 1)
{ {
image->mipmaps = 1; image->mipmaps = 1;
assert(image->data != NULL);
ImageMipmaps(image); ImageMipmaps(image);
} }
} }
@ -990,13 +977,13 @@ void ImageCrop(Image *image, Rectangle crop)
{ {
// Start the cropping process // Start the cropping process
Color *pixels = GetImageData(*image); // Get data as Color pixels array Color *pixels = GetImageData(*image); // Get data as Color pixels array
Color *cropPixels = (Color *)malloc(crop.width*crop.height*sizeof(Color)); Color *cropPixels = (Color *)malloc((int)crop.width*(int)crop.height*sizeof(Color));
for (int j = crop.y; j < (crop.y + crop.height); j++) for (int j = (int)crop.y; j < (int)(crop.y + crop.height); j++)
{ {
for (int i = crop.x; i < (crop.x + crop.width); i++) for (int i = (int)crop.x; i < (int)(crop.x + crop.width); i++)
{ {
cropPixels[(j - crop.y)*crop.width + (i - crop.x)] = pixels[j*image->width + i]; cropPixels[(j - (int)crop.y)*(int)crop.width + (i - (int)crop.x)] = pixels[j*image->width + i];
} }
} }
@ -1006,7 +993,7 @@ void ImageCrop(Image *image, Rectangle crop)
UnloadImage(*image); UnloadImage(*image);
*image = LoadImageEx(cropPixels, crop.width, crop.height); *image = LoadImageEx(cropPixels, (int)crop.width, (int)crop.height);
free(cropPixels); free(cropPixels);
@ -1325,24 +1312,38 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
UnloadImage(srcCopy); // Source copy not required any more... UnloadImage(srcCopy); // Source copy not required any more...
Color srcCol, dstCol; Vector4 fsrc, fdst, fout; // float based versions of pixel data
// Blit pixels, copy source image into destination // Blit pixels, copy source image into destination
// TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping... // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping...
for (int j = dstRec.y; j < (dstRec.y + dstRec.height); j++) for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++)
{ {
for (int i = dstRec.x; i < (dstRec.x + dstRec.width); i++) for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++)
{ {
// Alpha blending implementation // Alpha blending (https://en.wikipedia.org/wiki/Alpha_compositing)
dstCol = dstPixels[j*dst->width + i];
srcCol = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)];
dstCol.r = ((srcCol.a*(srcCol.r - dstCol.r)) >> 8) + dstCol.r; fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]);
dstCol.g = ((srcCol.a*(srcCol.g - dstCol.g)) >> 8) + dstCol.g; fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]);
dstCol.b = ((srcCol.a*(srcCol.b - dstCol.b)) >> 8) + dstCol.b;
dstCol.a = ((srcCol.a*(srcCol.a - dstCol.a)) >> 8) + dstCol.a;
dstPixels[j*dst->width + i] = dstCol; fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w);
if (fout.w <= 0.0f)
{
fout.x = 0.0f;
fout.y = 0.0f;
fout.z = 0.0f;
}
else
{
fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w;
fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w;
fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
}
dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f),
(unsigned char)(fout.y*255.0f),
(unsigned char)(fout.z*255.0f),
(unsigned char)(fout.w*255.0f) };
// TODO: Support other blending options // TODO: Support other blending options
} }
@ -1350,7 +1351,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
UnloadImage(*dst); // NOTE: Only dst->data is unloaded UnloadImage(*dst); // NOTE: Only dst->data is unloaded
*dst = LoadImageEx(dstPixels, dst->width, dst->height); *dst = LoadImageEx(dstPixels, (int)dst->width, (int)dst->height);
ImageFormat(dst, dst->format); ImageFormat(dst, dst->format);
free(srcPixels); free(srcPixels);
@ -1362,15 +1363,15 @@ Image ImageText(const char *text, int fontSize, Color color)
{ {
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
if (fontSize < defaultFontSize) fontSize = defaultFontSize; if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize/defaultFontSize; int spacing = (float)fontSize/defaultFontSize;
Image imText = ImageTextEx(GetDefaultFont(), text, (float)fontSize, spacing, color); Image imText = ImageTextEx(GetDefaultFont(), text, (float)fontSize, (float)spacing, color);
return imText; return imText;
} }
// Create an image from text (custom sprite font) // Create an image from text (custom sprite font)
Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint) Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
{ {
int length = strlen(text); int length = strlen(text);
int posX = 0; int posX = 0;
@ -1384,7 +1385,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
// NOTE: glGetTexImage() not available in OpenGL ES // NOTE: glGetTexImage() not available in OpenGL ES
// TODO: This is horrible, retrieving font texture from GPU!!! // TODO: This is horrible, retrieving font texture from GPU!!!
// Define ImageFont struct? or include Image spritefont in SpriteFont struct? // Define ImageFont struct? or include Image spritefont in Font struct?
Image imFont = GetTextureData(font.texture); Image imFont = GetTextureData(font.texture);
ImageColorTint(&imFont, tint); // Apply color tint to font ImageColorTint(&imFont, tint); // Apply color tint to font
@ -1445,20 +1446,32 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
return imText; return imText;
} }
// Draw rectangle within an image
void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color)
{
Image imRec = GenImageColor(rec.width, rec.height, color);
Rectangle dstRec = { position.x, position.y, imRec.width, imRec.height };
ImageDraw(dst, imRec, rec, dstRec);
UnloadImage(imRec);
}
// Draw text (default font) within an image (destination) // Draw text (default font) within an image (destination)
void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color)
{ {
// NOTE: For default font, sapcing is set to desired font size / default font size (10) // NOTE: For default font, sapcing is set to desired font size / default font size (10)
ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, fontSize/10, color); ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, (float)fontSize/10, color);
} }
// Draw text (custom sprite font) within an image (destination) // Draw text (custom sprite font) within an image (destination)
void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color) void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color)
{ {
Image imText = ImageTextEx(font, text, fontSize, spacing, color); Image imText = ImageTextEx(font, text, fontSize, spacing, color);
Rectangle srcRec = { 0, 0, imText.width, imText.height }; Rectangle srcRec = { 0, 0, imText.width, imText.height };
Rectangle dstRec = { (int)position.x, (int)position.y, imText.width, imText.height }; Rectangle dstRec = { position.x, position.y, imText.width, imText.height };
ImageDraw(dst, imText, srcRec, dstRec); ImageDraw(dst, imText, srcRec, dstRec);
@ -1896,20 +1909,9 @@ Image GenImageCellular(int width, int height, int tileSize)
// Generate GPU mipmaps for a texture // Generate GPU mipmaps for a texture
void GenTextureMipmaps(Texture2D *texture) void GenTextureMipmaps(Texture2D *texture)
{ {
#if defined(PLATFORM_WEB) // NOTE: NPOT textures support check inside function
// Calculate next power-of-two values // On WebGL (OpenGL ES 2.0) NPOT textures support is limited
int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2)));
int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2)));
// Check if texture is POT
if ((potWidth != texture->width) || (potHeight != texture->height))
{
TraceLog(LOG_WARNING, "Limited NPOT support, no mipmaps available for NPOT textures");
}
else rlGenerateMipmaps(texture);
#else
rlGenerateMipmaps(texture); rlGenerateMipmaps(texture);
#endif
} }
// Set texture scaling filter mode // Set texture scaling filter mode
@ -2018,7 +2020,7 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
{ {
Rectangle sourceRec = { 0, 0, texture.width, texture.height }; Rectangle sourceRec = { 0, 0, texture.width, texture.height };
Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale }; Rectangle destRec = { position.x, position.y, texture.width*scale, texture.height*scale };
Vector2 origin = { 0, 0 }; Vector2 origin = { 0, 0 };
DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint);
@ -2027,7 +2029,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc
// Draw a part of a texture (defined by a rectangle) // Draw a part of a texture (defined by a rectangle)
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
{ {
Rectangle destRec = { (int)position.x, (int)position.y, abs(sourceRec.width), abs(sourceRec.height) }; Rectangle destRec = { position.x, position.y, sourceRec.width, sourceRec.height };
Vector2 origin = { 0, 0 }; Vector2 origin = { 0, 0 };
DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint); DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
@ -2046,7 +2048,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
rlEnableTexture(texture.id); rlEnableTexture(texture.id);
rlPushMatrix(); rlPushMatrix();
rlTranslatef((float)destRec.x, (float)destRec.y, 0); rlTranslatef(destRec.x, destRec.y, 0);
rlRotatef(rotation, 0, 0, 1); rlRotatef(rotation, 0, 0, 1);
rlTranslatef(-origin.x, -origin.y, 0); rlTranslatef(-origin.x, -origin.y, 0);
@ -2055,20 +2057,20 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// Bottom-left corner for texture and quad // Bottom-left corner for texture and quad
rlTexCoord2f((float)sourceRec.x/texture.width, (float)sourceRec.y/texture.height); rlTexCoord2f(sourceRec.x/texture.width, sourceRec.y/texture.height);
rlVertex2f(0.0f, 0.0f); rlVertex2f(0.0f, 0.0f);
// Bottom-right corner for texture and quad // Bottom-right corner for texture and quad
rlTexCoord2f((float)sourceRec.x/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height); rlTexCoord2f(sourceRec.x/texture.width, (sourceRec.y + sourceRec.height)/texture.height);
rlVertex2f(0.0f, (float)destRec.height); rlVertex2f(0.0f, destRec.height);
// Top-right corner for texture and quad // Top-right corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height); rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, (sourceRec.y + sourceRec.height)/texture.height);
rlVertex2f((float)destRec.width, (float)destRec.height); rlVertex2f(destRec.width, destRec.height);
// Top-left corner for texture and quad // Top-left corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)sourceRec.y/texture.height); rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, sourceRec.y/texture.height);
rlVertex2f((float)destRec.width, 0.0f); rlVertex2f(destRec.width, 0.0f);
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();

View file

@ -143,13 +143,13 @@ func UpdateTexture(texture Texture2D, pixels []byte) {
C.UpdateTexture(*ctexture, cpixels) C.UpdateTexture(*ctexture, cpixels)
} }
// SaveImageAs - Save image to a PNG file // ExportImage - Export image as a PNG file
func SaveImageAs(name string, image Image) { func ExportImage(name string, image Image) {
cname := C.CString(name) cname := C.CString(name)
defer C.free(unsafe.Pointer(cname)) defer C.free(unsafe.Pointer(cname))
cimage := image.cptr() cimage := image.cptr()
C.SaveImageAs(cname, *cimage) C.ExportImage(cname, *cimage)
} }
// ImageToPOT - Convert image to POT (power-of-two) // ImageToPOT - Convert image to POT (power-of-two)
@ -160,7 +160,7 @@ func ImageToPOT(image *Image, fillColor Color) {
} }
// ImageFormat - Convert image data to desired format // ImageFormat - Convert image data to desired format
func ImageFormat(image *Image, newFormat int32) { func ImageFormat(image *Image, newFormat PixelFormat) {
cimage := image.cptr() cimage := image.cptr()
cnewFormat := (C.int)(newFormat) cnewFormat := (C.int)(newFormat)
C.ImageFormat(cimage, cnewFormat) C.ImageFormat(cimage, cnewFormat)
@ -253,12 +253,12 @@ func ImageText(text string, fontSize int32, color Color) *Image {
} }
// ImageTextEx - Create an image from text (custom sprite font) // ImageTextEx - Create an image from text (custom sprite font)
func ImageTextEx(font SpriteFont, text string, fontSize float32, spacing int32, tint Color) *Image { func ImageTextEx(font Font, text string, fontSize, spacing float32, tint Color) *Image {
cfont := font.cptr() cfont := font.cptr()
ctext := C.CString(text) ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(ctext))
cfontSize := (C.float)(fontSize) cfontSize := (C.float)(fontSize)
cspacing := (C.int)(spacing) cspacing := (C.float)(spacing)
ctint := tint.cptr() ctint := tint.cptr()
ret := C.ImageTextEx(*cfont, ctext, cfontSize, cspacing, *ctint) ret := C.ImageTextEx(*cfont, ctext, cfontSize, cspacing, *ctint)
v := newImageFromPointer(unsafe.Pointer(&ret)) v := newImageFromPointer(unsafe.Pointer(&ret))
@ -274,6 +274,15 @@ func ImageDraw(dst, src *Image, srcRec, dstRec Rectangle) {
C.ImageDraw(cdst, *csrc, *csrcRec, *cdstRec) C.ImageDraw(cdst, *csrc, *csrcRec, *cdstRec)
} }
// ImageDrawRectangle - Draw rectangle within an image
func ImageDrawRectangle(dst *Image, position Vector2, rec Rectangle, color Color) {
cdst := dst.cptr()
cposition := position.cptr()
crec := rec.cptr()
ccolor := color.cptr()
C.ImageDrawRectangle(cdst, *cposition, *crec, *ccolor)
}
// ImageDrawText - Draw text (default font) within an image (destination) // ImageDrawText - Draw text (default font) within an image (destination)
func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, color Color) { func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, color Color) {
cdst := dst.cptr() cdst := dst.cptr()
@ -286,14 +295,14 @@ func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, co
} }
// ImageDrawTextEx - Draw text (custom sprite font) within an image (destination) // ImageDrawTextEx - Draw text (custom sprite font) within an image (destination)
func ImageDrawTextEx(dst *Image, position Vector2, font SpriteFont, text string, fontSize float32, spacing int32, color Color) { func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontSize, spacing float32, color Color) {
cdst := dst.cptr() cdst := dst.cptr()
cposition := position.cptr() cposition := position.cptr()
cfont := font.cptr() cfont := font.cptr()
ctext := C.CString(text) ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(ctext))
cfontSize := (C.float)(fontSize) cfontSize := (C.float)(fontSize)
cspacing := (C.int)(spacing) cspacing := (C.float)(spacing)
ccolor := color.cptr() ccolor := color.cptr()
C.ImageDrawTextEx(cdst, *cposition, *cfont, ctext, cfontSize, cspacing, *ccolor) C.ImageDrawTextEx(cdst, *cposition, *cfont, ctext, cfontSize, cspacing, *ccolor)
} }

View file

@ -41,7 +41,7 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#define SUPPORT_TRACELOG // Output tracelog messages #include "config.h"
#include "raylib.h" // WARNING: Required for: LogType enum #include "raylib.h" // WARNING: Required for: LogType enum
#include "utils.h" #include "utils.h"
@ -141,13 +141,14 @@ void TraceLog(int msgType, const char *text, ...)
#endif // SUPPORT_TRACELOG #endif // SUPPORT_TRACELOG
} }
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
#if defined(SUPPORT_SAVE_BMP) #if defined(SUPPORT_SAVE_BMP)
// Creates a BMP image file from an array of pixel data // Creates a BMP image file from an array of pixel data
void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize) void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
stbi_write_bmp(fileName, width, height, compSize, imgData); stbi_write_bmp(fileName, width, height, compSize, imgData);
TraceLog(LOG_INFO, "BMP Image saved: %s", fileName);
#endif
} }
#endif #endif
@ -155,9 +156,11 @@ void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height
// Creates a PNG image file from an array of pixel data // Creates a PNG image file from an array of pixel data
void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize) void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
stbi_write_png(fileName, width, height, compSize, imgData, width*compSize); stbi_write_png(fileName, width, height, compSize, imgData, width*compSize);
} TraceLog(LOG_INFO, "PNG Image saved: %s", fileName);
#endif #endif
}
#endif #endif
// Keep track of memory allocated // Keep track of memory allocated

View file

@ -32,7 +32,9 @@
#include <android/asset_manager.h> // Required for: AAssetManager #include <android/asset_manager.h> // Required for: AAssetManager
#endif #endif
#define SUPPORT_SAVE_PNG #ifndef SUPPORT_SAVE_PNG
#define SUPPORT_SAVE_PNG 1
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Some basic Defines // Some basic Defines