Update C sources and examples

This commit is contained in:
Milan Nikolic 2017-04-24 18:25:27 +02:00
parent 3b28d17b95
commit 8f1ad11c49
100 changed files with 2081 additions and 1686 deletions

View file

@ -0,0 +1,58 @@
package main
import (
"github.com/gen2brain/raylib-go/raylib"
)
func main() {
screenWidth := int32(1080)
screenHeight := int32(600)
// NOTE: screenWidth/screenHeight should match VR device aspect ratio
raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator")
// NOTE: default device (simulator)
raylib.InitVrSimulator(raylib.HmdOculusRiftCv1) // Init VR device (Oculus Rift CV1)
camera := raylib.Camera{}
camera.Position = raylib.NewVector3(5.0, 2.0, 5.0) // Camera position
camera.Target = raylib.NewVector3(0.0, 2.0, 0.0) // Camera looking at point
camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) // Camera up vector (rotation towards target)
camera.Fovy = 60.0 // Camera field-of-view Y
cubePosition := raylib.NewVector3(0.0, 0.0, 0.0)
raylib.SetCameraMode(camera, raylib.CameraFirstPerson) // Set first person camera mode
raylib.SetTargetFPS(90)
for !raylib.WindowShouldClose() {
raylib.UpdateCamera(&camera) // Update camera (simulator mode)
raylib.BeginDrawing()
raylib.ClearBackground(raylib.RayWhite)
raylib.BeginVrDrawing()
raylib.Begin3dMode(camera)
raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red)
raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon)
raylib.DrawGrid(40, 1.0)
raylib.End3dMode()
raylib.EndVrDrawing()
raylib.DrawFPS(10, 10)
raylib.EndDrawing()
}
raylib.CloseVrSimulator() // Close VR simulator
raylib.CloseWindow()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

View file

@ -10,7 +10,7 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes and texture shaders") raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes and texture shaders")
sonic := raylib.LoadTexture("sonic.png") fudesumi := raylib.LoadTexture("fudesumi.png")
// NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version // NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
shader := raylib.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs") shader := raylib.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs")
@ -57,16 +57,18 @@ func main() {
// Activate our custom shader to be applied on next shapes/textures drawings // Activate our custom shader to be applied on next shapes/textures drawings
raylib.BeginShaderMode(shader) raylib.BeginShaderMode(shader)
raylib.DrawTexture(sonic, 380, -10, raylib.White) // Using custom shader raylib.DrawTexture(fudesumi, 500, -30, raylib.White) // Using custom shader
// Activate our default shader for next drawings // Activate our default shader for next drawings
raylib.EndShaderMode() raylib.EndShaderMode()
raylib.DrawText("(c) Fudesumi sprite by Eiden Marsal", 380, screenHeight-20, 10, raylib.Gray)
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadShader(shader) // Unload shader raylib.UnloadShader(shader) // Unload shader
raylib.UnloadTexture(sonic) // Unload texture raylib.UnloadTexture(fudesumi) // Unload texture
raylib.CloseWindow() // Close window and OpenGL context raylib.CloseWindow() // Close window and OpenGL context
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

View file

@ -0,0 +1,36 @@
package main
import (
"github.com/gen2brain/raylib-go/raylib"
)
func main() {
screenWidth := int32(800)
screenHeight := int32(450)
raylib.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - cubic-bezier lines")
start := raylib.NewVector2(0, 0)
end := raylib.NewVector2(float32(screenWidth), float32(screenHeight))
raylib.SetTargetFPS(60)
for !raylib.WindowShouldClose() {
if raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
start = raylib.GetMousePosition()
} else if raylib.IsMouseButtonDown(raylib.MouseRightButton) {
end = raylib.GetMousePosition()
}
raylib.BeginDrawing()
raylib.ClearBackground(raylib.RayWhite)
raylib.DrawText("USE MOUSE LEFT-RIGHT CLICK to DEFINE LINE START and END POINTS", 15, 20, 20, raylib.Gray)
raylib.DrawLineBezier(start, end, 2.0, raylib.Red)
raylib.EndDrawing()
}
raylib.CloseWindow()
}

View file

@ -1,140 +0,0 @@
package main
import (
"github.com/gen2brain/raylib-go/raylib"
)
func main() {
screenWidth := int32(800)
screenHeight := int32(450)
raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - font selector")
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
fonts := make([]raylib.SpriteFont, 8) // SpriteFont array
fonts[0] = raylib.LoadSpriteFont("fonts/alagard.rbmf") // SpriteFont loading
fonts[1] = raylib.LoadSpriteFont("fonts/pixelplay.rbmf") // SpriteFont loading
fonts[2] = raylib.LoadSpriteFont("fonts/mecha.rbmf") // SpriteFont loading
fonts[3] = raylib.LoadSpriteFont("fonts/setback.rbmf") // SpriteFont loading
fonts[4] = raylib.LoadSpriteFont("fonts/romulus.rbmf") // SpriteFont loading
fonts[5] = raylib.LoadSpriteFont("fonts/pixantiqua.rbmf") // SpriteFont loading
fonts[6] = raylib.LoadSpriteFont("fonts/alpha_beta.rbmf") // SpriteFont loading
fonts[7] = raylib.LoadSpriteFont("fonts/jupiter_crash.rbmf") // SpriteFont loading
currentFont := 0 // Selected font
colors := [8]raylib.Color{raylib.Maroon, raylib.Orange, raylib.DarkGreen, raylib.DarkBlue, raylib.DarkPurple, raylib.Lime, raylib.Gold, raylib.Red}
fontNames := [8]string{"[0] Alagard", "[1] PixelPlay", "[2] MECHA", "[3] Setback", "[4] Romulus", "[5] PixAntiqua", "[6] Alpha Beta", "[7] Jupiter Crash"}
text := "THIS is THE FONT you SELECTED!" // Main text
textSize := raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].BaseSize)*3, 1)
mousePoint := raylib.Vector2{}
btnNextOutColor := raylib.DarkBlue // Button color (outside line)
btnNextInColor := raylib.SkyBlue // Button color (inside)
framesCounter := 0 // Useful to count frames button is 'active' = clicked
positionY := int32(180) // Text selector and button Y position
btnNextRec := raylib.NewRectangle(673, positionY, 109, 44) // Button rectangle (useful for collision)
raylib.SetTargetFPS(60)
for !raylib.WindowShouldClose() {
// Update
// Keyboard-based font selection (easy)
if raylib.IsKeyPressed(raylib.KeyRight) {
if currentFont < 7 {
currentFont++
}
}
if raylib.IsKeyPressed(raylib.KeyLeft) {
if currentFont > 0 {
currentFont--
}
}
if raylib.IsKeyPressed('0') {
currentFont = 0
} else if raylib.IsKeyPressed('1') {
currentFont = 1
} else if raylib.IsKeyPressed('2') {
currentFont = 2
} else if raylib.IsKeyPressed('3') {
currentFont = 3
} else if raylib.IsKeyPressed('4') {
currentFont = 4
} else if raylib.IsKeyPressed('5') {
currentFont = 5
} else if raylib.IsKeyPressed('6') {
currentFont = 6
} else if raylib.IsKeyPressed('7') {
currentFont = 7
}
// Mouse-based font selection (NEXT button logic)
mousePoint = raylib.GetMousePosition()
if raylib.CheckCollisionPointRec(mousePoint, btnNextRec) {
// Mouse hover button logic
if framesCounter == 0 {
btnNextOutColor = raylib.DarkPurple
btnNextInColor = raylib.Purple
}
if raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
framesCounter = 20 // Frames button is 'active'
btnNextOutColor = raylib.Maroon
btnNextInColor = raylib.Red
}
} else {
// Mouse not hover button
btnNextOutColor = raylib.DarkBlue
btnNextInColor = raylib.SkyBlue
}
if framesCounter > 0 {
framesCounter--
}
if framesCounter == 1 { // We change font on frame 1
currentFont++
if currentFont > 7 {
currentFont = 0
}
}
// Text measurement for better positioning on screen
textSize = raylib.MeasureTextEx(fonts[currentFont], text, float32(fonts[currentFont].BaseSize)*3, 1)
// Draw
raylib.BeginDrawing()
raylib.ClearBackground(raylib.RayWhite)
raylib.DrawText("font selector - use arroys, button or numbers", 160, 80, 20, raylib.DarkGray)
raylib.DrawLine(120, 120, 680, 120, raylib.DarkGray)
raylib.DrawRectangle(18, positionY, 644, 44, raylib.DarkGray)
raylib.DrawRectangle(20, positionY+2, 640, 40, raylib.LightGray)
raylib.DrawText(fontNames[currentFont], 30, positionY+13, 20, raylib.Black)
raylib.DrawText("< >", 610, positionY+8, 30, raylib.Black)
raylib.DrawRectangleRec(btnNextRec, btnNextOutColor)
raylib.DrawRectangle(675, positionY+2, 105, 40, btnNextInColor)
raylib.DrawText("NEXT", 700, positionY+13, 20, btnNextOutColor)
raylib.DrawTextEx(fonts[currentFont], text, raylib.NewVector2(float32(screenWidth)/2-textSize.X/2, 260+(70-textSize.Y)/2), float32(fonts[currentFont].BaseSize*3), 1, colors[currentFont])
raylib.EndDrawing()
}
raylib.CloseWindow()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -4,21 +4,23 @@ import (
"github.com/gen2brain/raylib-go/raylib" "github.com/gen2brain/raylib-go/raylib"
) )
const maxFonts = 8
func main() { func main() {
screenWidth := int32(800) screenWidth := int32(800)
screenHeight := int32(450) screenHeight := int32(450)
raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - rBMF fonts") raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts")
fonts := make([]raylib.SpriteFont, 8) fonts := make([]raylib.SpriteFont, maxFonts)
fonts[0] = raylib.LoadSpriteFont("fonts/alagard.rbmf") fonts[0] = raylib.LoadSpriteFont("fonts/alagard.png")
fonts[1] = raylib.LoadSpriteFont("fonts/pixelplay.rbmf") fonts[1] = raylib.LoadSpriteFont("fonts/pixelplay.png")
fonts[2] = raylib.LoadSpriteFont("fonts/mecha.rbmf") fonts[2] = raylib.LoadSpriteFont("fonts/mecha.png")
fonts[3] = raylib.LoadSpriteFont("fonts/setback.rbmf") fonts[3] = raylib.LoadSpriteFont("fonts/setback.png")
fonts[4] = raylib.LoadSpriteFont("fonts/romulus.rbmf") fonts[4] = raylib.LoadSpriteFont("fonts/romulus.png")
fonts[5] = raylib.LoadSpriteFont("fonts/pixantiqua.rbmf") fonts[5] = raylib.LoadSpriteFont("fonts/pixantiqua.png")
fonts[6] = raylib.LoadSpriteFont("fonts/alpha_beta.rbmf") fonts[6] = raylib.LoadSpriteFont("fonts/alpha_beta.png")
fonts[7] = raylib.LoadSpriteFont("fonts/jupiter_crash.rbmf") fonts[7] = raylib.LoadSpriteFont("fonts/jupiter_crash.png")
messages := []string{ messages := []string{
"ALAGARD FONT designed by Hewett Tsoi", "ALAGARD FONT designed by Hewett Tsoi",
@ -32,15 +34,20 @@ func main() {
} }
spacings := []int32{2, 4, 8, 4, 3, 4, 4, 1} spacings := []int32{2, 4, 8, 4, 3, 4, 4, 1}
positions := make([]raylib.Vector2, 8) positions := make([]raylib.Vector2, maxFonts)
var i int32 var i int32
for i = 0; i < 8; i++ { for i = 0; i < maxFonts; i++ {
x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2) x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2)
y := 60 + fonts[i].BaseSize + 45*i y := 60 + fonts[i].BaseSize + 45*i
positions[i] = raylib.NewVector2(float32(x), float32(y)) positions[i] = raylib.NewVector2(float32(x), float32(y))
} }
// Small Y position corrections
positions[3].Y += 8
positions[4].Y += 2
positions[7].Y -= 8
colors := []raylib.Color{raylib.Maroon, raylib.Orange, raylib.DarkGreen, raylib.DarkBlue, raylib.DarkPurple, raylib.Lime, raylib.Gold, raylib.DarkBrown} colors := []raylib.Color{raylib.Maroon, raylib.Orange, raylib.DarkGreen, raylib.DarkBlue, raylib.DarkPurple, raylib.Lime, raylib.Gold, raylib.DarkBrown}
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
@ -52,14 +59,14 @@ func main() {
raylib.DrawText("free fonts included with raylib", 250, 20, 20, raylib.DarkGray) raylib.DrawText("free fonts included with raylib", 250, 20, 20, raylib.DarkGray)
raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray) raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray)
for i = 0; i < 8; i++ { for i = 0; i < maxFonts; i++ {
raylib.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].BaseSize*2), spacings[i], colors[i]) raylib.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].BaseSize*2), spacings[i], colors[i])
} }
raylib.EndDrawing() raylib.EndDrawing()
} }
for i = 0; i < 8; i++ { for i = 0; i < maxFonts; i++ {
raylib.UnloadSpriteFont(fonts[i]) raylib.UnloadSpriteFont(fonts[i])
} }

View file

@ -19,7 +19,7 @@ func main() {
fontChars := int32(0) fontChars := int32(0)
// TTF SpriteFont loading with custom generation parameters // TTF SpriteFont loading with custom generation parameters
font := raylib.LoadSpriteFontTTF("fonts/KAISG.ttf", 96, 0, &fontChars) font := raylib.LoadSpriteFontEx("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
@ -69,7 +69,7 @@ func main() {
if count == 1 { // Only support one ttf file dropped if count == 1 { // Only support one ttf file dropped
raylib.UnloadSpriteFont(font) raylib.UnloadSpriteFont(font)
font = raylib.LoadSpriteFontTTF(droppedFiles[0], fontSize, 0, &fontChars) font = raylib.LoadSpriteFontEx(droppedFiles[0], fontSize, 0, &fontChars)
raylib.ClearDroppedFiles() raylib.ClearDroppedFiles()
} }
} }

View file

@ -1,220 +0,0 @@
package main
import (
"fmt"
"github.com/gen2brain/raylib-go/raylib"
)
const numTextures = 24
// Formats
const (
PngR8g8b8a8 = iota
PvrGrayscale
PvrGrayAlpha
PvrR5g6b5
PvrR5g5b5a1
PvrR4g4b4a4
DdsR5g6b5
DdsR5g5b5a1
DdsR4g4b4a4
DdsR8g8b8a8
DdsDxt1Rgb
DdsDxt1Rgba
DdsDxt3Rgba
DdsDxt5Rgba
PkmEtc1Rgb
PkmEtc2Rgb
PkmEtc2EacRgba
KtxEtc1Rgb
KtxEtc2Rgb
KtxEtc2EacRgba
Astc4x4Ldr
Astc8x8Ldr
PvrPvrtRgb
PvrPvrtRgba
)
var formatText = []string{
"PNG_R8G8B8A8",
"PVR_GRAYSCALE",
"PVR_GRAY_ALPHA",
"PVR_R5G6B5",
"PVR_R5G5B5A1",
"PVR_R4G4B4A4",
"DDS_R5G6B5",
"DDS_R5G5B5A1",
"DDS_R4G4B4A4",
"DDS_R8G8B8A8",
"DDS_DXT1_RGB",
"DDS_DXT1_RGBA",
"DDS_DXT3_RGBA",
"DDS_DXT5_RGBA",
"PKM_ETC1_RGB",
"PKM_ETC2_RGB",
"PKM_ETC2_EAC_RGBA",
"KTX_ETC1_RGB",
"KTX_ETC2_RGB",
"KTX_ETC2_EAC_RGBA",
"ASTC_4x4_LDR",
"ASTC_8x8_LDR",
"PVR_PVRT_RGB",
"PVR_PVRT_RGBA",
}
func main() {
screenWidth := int32(800)
screenHeight := int32(450)
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture formats loading")
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
sonic := make([]raylib.Texture2D, numTextures)
sonic[PngR8g8b8a8] = raylib.LoadTexture("texture_formats/sonic.png")
// Load UNCOMPRESSED PVR texture data
sonic[PvrGrayscale] = raylib.LoadTexture("texture_formats/sonic_GRAYSCALE.pvr")
sonic[PvrGrayAlpha] = raylib.LoadTexture("texture_formats/sonic_L8A8.pvr")
sonic[PvrR5g6b5] = raylib.LoadTexture("texture_formats/sonic_R5G6B5.pvr")
sonic[PvrR5g5b5a1] = raylib.LoadTexture("texture_formats/sonic_R5G5B5A1.pvr")
sonic[PvrR4g4b4a4] = raylib.LoadTexture("texture_formats/sonic_R4G4B4A4.pvr")
// Load UNCOMPRESSED DDS texture data
sonic[DdsR5g6b5] = raylib.LoadTexture("texture_formats/sonic_R5G6B5.dds")
sonic[DdsR5g5b5a1] = raylib.LoadTexture("texture_formats/sonic_A1R5G5B5.dds")
sonic[DdsR4g4b4a4] = raylib.LoadTexture("texture_formats/sonic_A4R4G4B4.dds")
sonic[DdsR8g8b8a8] = raylib.LoadTexture("texture_formats/sonic_A8R8G8B8.dds")
// Load COMPRESSED DXT DDS texture data (if supported)
sonic[DdsDxt1Rgb] = raylib.LoadTexture("texture_formats/sonic_DXT1_RGB.dds")
sonic[DdsDxt1Rgba] = raylib.LoadTexture("texture_formats/sonic_DXT1_RGBA.dds")
sonic[DdsDxt3Rgba] = raylib.LoadTexture("texture_formats/sonic_DXT3_RGBA.dds")
sonic[DdsDxt5Rgba] = raylib.LoadTexture("texture_formats/sonic_DXT5_RGBA.dds")
// Load COMPRESSED ETC texture data (if supported)
sonic[PkmEtc1Rgb] = raylib.LoadTexture("texture_formats/sonic_ETC1_RGB.pkm")
sonic[PkmEtc2Rgb] = raylib.LoadTexture("texture_formats/sonic_ETC2_RGB.pkm")
sonic[PkmEtc2EacRgba] = raylib.LoadTexture("texture_formats/sonic_ETC2_EAC_RGBA.pkm")
sonic[KtxEtc1Rgb] = raylib.LoadTexture("texture_formats/sonic_ETC1_RGB.ktx")
sonic[KtxEtc2Rgb] = raylib.LoadTexture("texture_formats/sonic_ETC2_RGB.ktx")
sonic[KtxEtc2EacRgba] = raylib.LoadTexture("texture_formats/sonic_ETC2_EAC_RGBA.ktx")
// Load COMPRESSED ASTC texture data (if supported)
sonic[Astc4x4Ldr] = raylib.LoadTexture("texture_formats/sonic_ASTC_4x4_ldr.astc")
sonic[Astc8x8Ldr] = raylib.LoadTexture("texture_formats/sonic_ASTC_8x8_ldr.astc")
// Load COMPRESSED PVR texture data (if supported)
sonic[PvrPvrtRgb] = raylib.LoadTexture("texture_formats/sonic_PVRT_RGB.pvr")
sonic[PvrPvrtRgba] = raylib.LoadTexture("texture_formats/sonic_PVRT_RGBA.pvr")
selectedFormat := PngR8g8b8a8
selectRecs := make([]raylib.Rectangle, numTextures)
for i := 0; i < numTextures; i++ {
if i < numTextures/2 {
selectRecs[i] = raylib.NewRectangle(40, int32(30+32*i), 150, 30)
} else {
selectRecs[i] = raylib.NewRectangle(40+152, int32(30+32*(i-numTextures/2)), 150, 30)
}
}
// Texture sizes in KB
var textureSizes = [numTextures]int{
512 * 512 * 32 / 8 / 1024, //PNG_R8G8B8A8 (32 bpp)
512 * 512 * 8 / 8 / 1024, //PVR_GRAYSCALE (8 bpp)
512 * 512 * 16 / 8 / 1024, //PVR_GRAY_ALPHA (16 bpp)
512 * 512 * 16 / 8 / 1024, //PVR_R5G6B5 (16 bpp)
512 * 512 * 16 / 8 / 1024, //PVR_R5G5B5A1 (16 bpp)
512 * 512 * 16 / 8 / 1024, //PVR_R4G4B4A4 (16 bpp)
512 * 512 * 16 / 8 / 1024, //DDS_R5G6B5 (16 bpp)
512 * 512 * 16 / 8 / 1024, //DDS_R5G5B5A1 (16 bpp)
512 * 512 * 16 / 8 / 1024, //DDS_R4G4B4A4 (16 bpp)
512 * 512 * 32 / 8 / 1024, //DDS_R8G8B8A8 (32 bpp)
512 * 512 * 4 / 8 / 1024, //DDS_DXT1_RGB (4 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //DDS_DXT1_RGBA (4 bpp) -Compressed-
512 * 512 * 8 / 8 / 1024, //DDS_DXT3_RGBA (8 bpp) -Compressed-
512 * 512 * 8 / 8 / 1024, //DDS_DXT5_RGBA (8 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //PKM_ETC1_RGB (4 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //PKM_ETC2_RGB (4 bpp) -Compressed-
512 * 512 * 8 / 8 / 1024, //PKM_ETC2_EAC_RGBA (8 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //KTX_ETC1_RGB (4 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //KTX_ETC2_RGB (4 bpp) -Compressed-
512 * 512 * 8 / 8 / 1024, //KTX_ETC2_EAC_RGBA (8 bpp) -Compressed-
512 * 512 * 8 / 8 / 1024, //ASTC_4x4_LDR (8 bpp) -Compressed-
512 * 512 * 2 / 8 / 1024, //ASTC_8x8_LDR (2 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //PVR_PVRT_RGB (4 bpp) -Compressed-
512 * 512 * 4 / 8 / 1024, //PVR_PVRT_RGBA (4 bpp) -Compressed-
}
raylib.SetTargetFPS(60)
for !raylib.WindowShouldClose() {
// Update
if raylib.IsKeyPressed(raylib.KeyDown) {
selectedFormat++
if selectedFormat >= numTextures {
selectedFormat = 0
}
} else if raylib.IsKeyPressed(raylib.KeyUp) {
selectedFormat--
if selectedFormat < 0 {
selectedFormat = numTextures - 1
}
} else if raylib.IsKeyPressed(raylib.KeyRight) {
if selectedFormat < numTextures/2 {
selectedFormat += numTextures / 2
}
} else if raylib.IsKeyPressed(raylib.KeyLeft) {
if selectedFormat >= numTextures/2 {
selectedFormat -= numTextures / 2
}
}
// Draw
raylib.BeginDrawing()
raylib.ClearBackground(raylib.RayWhite)
// Draw rectangles
for i := 0; i < numTextures; i++ {
if i == selectedFormat {
raylib.DrawRectangleRec(selectRecs[i], raylib.SkyBlue)
raylib.DrawRectangleLines(selectRecs[i].X, selectRecs[i].Y, selectRecs[i].Width, selectRecs[i].Height, raylib.Blue)
raylib.DrawText(formatText[i], selectRecs[i].X+selectRecs[i].Width/2-raylib.MeasureText(formatText[i], 10)/2, selectRecs[i].Y+11, 10, raylib.DarkBlue)
} else {
raylib.DrawRectangleRec(selectRecs[i], raylib.LightGray)
raylib.DrawRectangleLines(selectRecs[i].X, selectRecs[i].Y, selectRecs[i].Width, selectRecs[i].Height, raylib.Gray)
raylib.DrawText(formatText[i], selectRecs[i].X+selectRecs[i].Width/2-raylib.MeasureText(formatText[i], 10)/2, selectRecs[i].Y+11, 10, raylib.DarkGray)
}
}
// Draw selected texture
if sonic[selectedFormat].ID != 0 {
raylib.DrawTexture(sonic[selectedFormat], 350, -10, raylib.White)
} else {
raylib.DrawRectangleLines(488, 165, 200, 110, raylib.DarkGray)
raylib.DrawText("FORMAT", 550, 180, 20, raylib.Maroon)
raylib.DrawText("NOT SUPPORTED", 500, 210, 20, raylib.Maroon)
raylib.DrawText("ON YOUR GPU", 520, 240, 20, raylib.Maroon)
}
raylib.DrawText("Select texture format (use cursor keys):", 40, 10, 10, raylib.DarkGray)
raylib.DrawText("Required GPU memory size (VRAM):", 40, 427, 10, raylib.DarkGray)
raylib.DrawText(fmt.Sprintf("%4.0d KB", textureSizes[selectedFormat]), 240, 420, 20, raylib.DarkBlue)
raylib.EndDrawing()
}
for i := 0; i < numTextures; i++ {
raylib.UnloadTexture(sonic[i])
}
raylib.CloseWindow()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

View file

@ -22,7 +22,7 @@ func main() {
screenHeight := int32(450) screenHeight := int32(450)
//raylib.SetConfigFlags(raylib.FlagVsyncHint) //raylib.SetConfigFlags(raylib.FlagVsyncHint)
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - particles trail blending") raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - particles blending")
// Particles pool, reuse them! // Particles pool, reuse them!
mouseTail := make([]particle, maxParticles) mouseTail := make([]particle, maxParticles)

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

View file

@ -12,10 +12,10 @@ 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)
// Load RAW image data (512x512, 32bit RGBA, no file header) // Load RAW image data (384x512, 32bit RGBA, no file header)
sonicRaw := raylib.LoadImageRaw("texture_formats/sonic_R8G8B8A8.raw", 512, 512, raylib.UncompressedR8g8b8a8, 0) fudesumiRaw := raylib.LoadImageRaw("texture_formats/fudesumi.raw", 384, 512, raylib.UncompressedR8g8b8a8, 0)
sonic := raylib.LoadTextureFromImage(sonicRaw) // Upload CPU (RAM) image to GPU (VRAM) fudesumi := raylib.LoadTextureFromImage(fudesumiRaw) // Upload CPU (RAM) image to GPU (VRAM)
raylib.UnloadImage(sonicRaw) // Unload CPU (RAM) image data raylib.UnloadImage(fudesumiRaw) // Unload CPU (RAM) image data
// Generate a checked texture by code (1024x1024 pixels) // Generate a checked texture by code (1024x1024 pixels)
width := 1024 width := 1024
@ -27,9 +27,9 @@ func main() {
for y := 0; y < height; y++ { for y := 0; y < height; y++ {
for x := 0; x < width; x++ { for x := 0; x < width; x++ {
if ((x/32+y/32)/1)%2 == 0 { if ((x/32+y/32)/1)%2 == 0 {
pixels[y*height+x] = raylib.DarkBlue pixels[y*height+x] = raylib.Orange
} else { } else {
pixels[y*height+x] = raylib.SkyBlue pixels[y*height+x] = raylib.Gold
} }
} }
} }
@ -46,18 +46,18 @@ func main() {
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.DrawTexture(checked, screenWidth/2-checked.Width/2, screenHeight/2-checked.Height/2, raylib.Fade(raylib.White, 0.3)) raylib.DrawTexture(checked, screenWidth/2-checked.Width/2, screenHeight/2-checked.Height/2, raylib.Fade(raylib.White, 0.5))
raylib.DrawTexture(sonic, 330, -20, raylib.White) raylib.DrawTexture(fudesumi, 430, -30, raylib.White)
raylib.DrawText("CHECKED TEXTURE ", 84, 100, 30, raylib.DarkBlue) raylib.DrawText("CHECKED TEXTURE ", 84, 100, 30, raylib.Brown)
raylib.DrawText("GENERATED by CODE", 72, 164, 30, raylib.DarkBlue) raylib.DrawText("GENERATED by CODE", 72, 164, 30, raylib.Brown)
raylib.DrawText("and RAW IMAGE LOADING", 46, 226, 30, raylib.DarkBlue) raylib.DrawText("and RAW IMAGE LOADING", 46, 226, 30, raylib.Brown)
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadTexture(sonic) // Texture unloading raylib.UnloadTexture(fudesumi) // Texture unloading
raylib.UnloadTexture(checked) // Texture unloading raylib.UnloadTexture(checked) // Texture unloading
raylib.CloseWindow() raylib.CloseWindow()
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View file

@ -1,9 +1,16 @@
package main package main
import ( import (
"fmt"
"github.com/gen2brain/raylib-go/raylib" "github.com/gen2brain/raylib-go/raylib"
) )
const (
maxFrameSpeed = 15
minFrameSpeed = 1
)
func main() { func main() {
screenWidth := int32(800) screenWidth := int32(800)
screenHeight := int32(450) screenHeight := int32(450)
@ -11,47 +18,70 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing")
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
guybrush := raylib.LoadTexture("guybrush.png") // Texture loading scarfy := raylib.LoadTexture("scarfy.png") // Texture loading
position := raylib.NewVector2(350.0, 240.0) position := raylib.NewVector2(350.0, 280.0)
frameRec := raylib.NewRectangle(0, 0, guybrush.Width/7, guybrush.Height) frameRec := raylib.NewRectangle(0, 0, scarfy.Width/6, scarfy.Height)
currentFrame := int32(0) currentFrame := int32(0)
framesCounter := 0
framesSpeed := 8 // Number of spritesheet frames shown by second
raylib.SetTargetFPS(60) raylib.SetTargetFPS(60)
for !raylib.WindowShouldClose() { for !raylib.WindowShouldClose() {
if raylib.IsKeyPressed(raylib.KeyRight) { framesCounter++
if framesCounter >= (60 / framesSpeed) {
framesCounter = 0
currentFrame++ currentFrame++
if currentFrame > 6 { if currentFrame > 5 {
currentFrame = 0 currentFrame = 0
} }
frameRec.X = currentFrame * guybrush.Width / 7 frameRec.X = currentFrame * scarfy.Width / 6
}
if raylib.IsKeyPressed(raylib.KeyRight) {
framesSpeed++
} else if raylib.IsKeyPressed(raylib.KeyLeft) {
framesSpeed--
}
if framesSpeed > maxFrameSpeed {
framesSpeed = maxFrameSpeed
} else if framesSpeed < minFrameSpeed {
framesSpeed = minFrameSpeed
} }
raylib.BeginDrawing() raylib.BeginDrawing()
raylib.ClearBackground(raylib.RayWhite) raylib.ClearBackground(raylib.RayWhite)
raylib.DrawTexture(guybrush, 35, 40, raylib.White) raylib.DrawTexture(scarfy, 15, 40, raylib.White)
raylib.DrawRectangleLines(35, 40, guybrush.Width, guybrush.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.DrawTextureRec(guybrush, frameRec, position, raylib.White) // Draw part of the texture raylib.DrawText("FRAME SPEED: ", 165, 210, 10, raylib.DarkGray)
raylib.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, raylib.DarkGray)
raylib.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, raylib.DarkGray)
raylib.DrawRectangleLines(35+frameRec.X, 40+frameRec.Y, frameRec.Width, frameRec.Height, raylib.Red) for i := 0; i < maxFrameSpeed; i++ {
if i < framesSpeed {
raylib.DrawRectangle(int32(250+21*i), 205, 20, 20, raylib.Red)
}
raylib.DrawRectangleLines(int32(250+21*i), 205, 20, 20, raylib.Maroon)
}
raylib.DrawText("PRESS RIGHT KEY TO", 540, 310, 10, raylib.Gray) raylib.DrawTextureRec(scarfy, frameRec, position, raylib.White) // Draw part of the texture
raylib.DrawText("CHANGE DRAWING RECTANGLE", 520, 330, 10, raylib.Gray)
raylib.DrawText("Guybrush Ulysses Threepwood,", 100, 300, 10, raylib.Gray) raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray)
raylib.DrawText("main character of the Monkey Island series", 80, 320, 10, raylib.Gray)
raylib.DrawText("of computer adventure games by LucasArts.", 80, 340, 10, raylib.Gray)
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadTexture(guybrush) raylib.UnloadTexture(scarfy)
raylib.CloseWindow() raylib.CloseWindow()
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View file

@ -11,10 +11,10 @@ func main() {
raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] examples - texture source and destination rectangles") raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] examples - texture source and destination rectangles")
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
guybrush := raylib.LoadTexture("guybrush.png") // Texture loading scarfy := raylib.LoadTexture("scarfy.png") // Texture loading
frameWidth := guybrush.Width / 7 frameWidth := scarfy.Width / 7
frameHeight := guybrush.Height frameHeight := 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, int32(frameWidth), int32(frameHeight))
@ -43,15 +43,17 @@ func main() {
// destRec defines the rectangle where our texture part will fit (scaling it to fit) // destRec defines the rectangle where our texture part will fit (scaling it to fit)
// origin defines the point of the texture used as reference for rotation and scaling // origin defines the point of the texture used as reference for rotation and scaling
// rotation defines the texture rotation (using origin as rotation point) // rotation defines the texture rotation (using origin as rotation point)
raylib.DrawTexturePro(guybrush, 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(destRec.X, 0, destRec.X, screenHeight, raylib.Gray)
raylib.DrawLine(0, destRec.Y, screenWidth, destRec.Y, raylib.Gray) raylib.DrawLine(0, destRec.Y, screenWidth, destRec.Y, raylib.Gray)
raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray)
raylib.EndDrawing() raylib.EndDrawing()
} }
raylib.UnloadTexture(guybrush) raylib.UnloadTexture(scarfy)
raylib.CloseWindow() raylib.CloseWindow()
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,26 +1,22 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.audio * raylib.audio - Basic funtionality to work with audio
* *
* This module provides basic functionality to work with audio: * FEATURES:
* Manage audio device (init/close) * - Manage audio device (init/close)
* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) * - Load and unload audio files
* Play/Stop/Pause/Resume loaded audio * - Format wave data (sample rate, size, channels)
* Manage mixing channels * - Play/Stop/Pause/Resume loaded audio
* Manage raw audio context * - Manage mixing channels
* * - Manage raw audio context
* NOTES:
*
* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS)
* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32)
* *
* CONFIGURATION: * CONFIGURATION:
* *
* #define AUDIO_STANDALONE * #define AUDIO_STANDALONE
* If defined, the module can be used as standalone library (independently of raylib). * Define to use the module as standalone library (independently of raylib).
* Required types and functions are defined in the same module. * Required types and functions are defined in the same module.
* *
* #define SUPPORT_FILEFORMAT_WAV / SUPPORT_LOAD_WAV / ENABLE_LOAD_WAV * #define SUPPORT_FILEFORMAT_WAV
* #define SUPPORT_FILEFORMAT_OGG * #define SUPPORT_FILEFORMAT_OGG
* #define SUPPORT_FILEFORMAT_XM * #define SUPPORT_FILEFORMAT_XM
* #define SUPPORT_FILEFORMAT_MOD * #define SUPPORT_FILEFORMAT_MOD
@ -28,7 +24,9 @@
* 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
* *
* #define SUPPORT_RAW_AUDIO_BUFFERS * LIMITATIONS:
* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS)
* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32)
* *
* DEPENDENCIES: * DEPENDENCIES:
* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) * OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html)
@ -38,17 +36,16 @@
* dr_flac - FLAC audio file loading * dr_flac - FLAC audio file loading
* *
* CONTRIBUTORS: * CONTRIBUTORS:
* * Joshua Reisenauer (github: @kd7tck):
* Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: * - XM audio module support (jar_xm)
* XM audio module support (jar_xm) * - MOD audio module support (jar_mod)
* MOD audio module support (jar_mod) * - Mixing channels support
* Mixing channels support * - Raw audio context support
* Raw audio context support
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -67,14 +64,19 @@
* *
**********************************************************************************************/ **********************************************************************************************/
//#define AUDIO_STANDALONE // NOTE: To use the audio module as standalone lib, just uncomment this line // Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_WAV
#define SUPPORT_FILEFORMAT_OGG
#define SUPPORT_FILEFORMAT_XM
//-------------------------------------------------
#if defined(AUDIO_STANDALONE) #if defined(AUDIO_STANDALONE)
#include "audio.h" #include "audio.h"
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
#else #else
#include "raylib.h" #include "raylib.h"
#include "utils.h" // Required for: fopen() Android mapping, TraceLog() #include "utils.h" // Required for: fopen() Android mapping
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
@ -93,18 +95,26 @@
#include <string.h> // Required for: strcmp(), strncmp() #include <string.h> // Required for: strcmp(), strncmp()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
//#define STB_VORBIS_HEADER_ONLY #if defined(SUPPORT_FILEFORMAT_OGG)
#include "external/stb_vorbis.h" // OGG loading functions //#define STB_VORBIS_HEADER_ONLY
#include "external/stb_vorbis.h" // OGG loading functions
#endif
#define JAR_XM_IMPLEMENTATION #if defined(SUPPORT_FILEFORMAT_XM)
#include "external/jar_xm.h" // XM loading functions #define JAR_XM_IMPLEMENTATION
#include "external/jar_xm.h" // XM loading functions
#endif
#define JAR_MOD_IMPLEMENTATION #if defined(SUPPORT_FILEFORMAT_MOD)
#include "external/jar_mod.h" // MOD loading functions #define JAR_MOD_IMPLEMENTATION
#include "external/jar_mod.h" // MOD loading functions
#endif
#define DR_FLAC_IMPLEMENTATION #if defined(SUPPORT_FILEFORMAT_FLAC)
#define DR_FLAC_NO_WIN32_IO #define DR_FLAC_IMPLEMENTATION
#include "external/dr_flac.h" // FLAC loading functions #define DR_FLAC_NO_WIN32_IO
#include "external/dr_flac.h" // FLAC loading functions
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#undef bool #undef bool
@ -139,10 +149,18 @@ typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_AUDIO_FLAC, MUSIC_MODULE_XM, MUSIC_MOD
// Music type (file streaming from memory) // Music type (file streaming from memory)
typedef struct MusicData { typedef struct MusicData {
MusicContextType ctxType; // Type of music context (OGG, XM, MOD) MusicContextType ctxType; // Type of music context (OGG, XM, MOD)
#if defined(SUPPORT_FILEFORMAT_OGG)
stb_vorbis *ctxOgg; // OGG audio context stb_vorbis *ctxOgg; // OGG audio context
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
drflac *ctxFlac; // FLAC audio context drflac *ctxFlac; // FLAC audio context
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
jar_xm_context_t *ctxXm; // XM chiptune context jar_xm_context_t *ctxXm; // XM chiptune context
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
jar_mod_context_t ctxMod; // MOD chiptune context jar_mod_context_t ctxMod; // MOD chiptune context
#endif
AudioStream stream; // Audio stream (double buffering) AudioStream stream; // Audio stream (double buffering)
@ -163,13 +181,19 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_WAV)
static Wave LoadWAV(const char *fileName); // Load WAV file static Wave LoadWAV(const char *fileName); // Load WAV file
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
static Wave LoadOGG(const char *fileName); // Load OGG file static Wave LoadOGG(const char *fileName); // Load OGG file
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
static Wave LoadFLAC(const char *fileName); // Load FLAC file static Wave LoadFLAC(const char *fileName); // Load FLAC file
#endif
#if defined(AUDIO_STANDALONE) #if defined(AUDIO_STANDALONE)
const char *GetExtension(const char *fileName); // Get the extension for a filename bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) void TraceLog(int msgType, const char *text, ...); // Outputs trace log message (INFO, ERROR, WARNING)
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -259,10 +283,15 @@ Wave LoadWave(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName); if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName); #if defined(SUPPORT_FILEFORMAT_OGG)
else if (strcmp(GetExtension(fileName), "flac") == 0) wave = LoadFLAC(fileName); else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName);
else if (strcmp(GetExtension(fileName),"rres") == 0) #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac")) wave = LoadFLAC(fileName);
#endif
#if !defined(AUDIO_STANDALONE)
else if (IsFileExtension(fileName, ".rres"))
{ {
RRES rres = LoadResource(fileName, 0); RRES rres = LoadResource(fileName, 0);
@ -273,7 +302,8 @@ Wave LoadWave(const char *fileName)
UnloadResource(rres); UnloadResource(rres);
} }
else TraceLog(WARNING, "[%s] File extension not recognized, it can't be loaded", fileName); #endif
else TraceLog(WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
return wave; return wave;
} }
@ -640,7 +670,7 @@ Music LoadMusicStream(const char *fileName)
{ {
Music music = (MusicData *)malloc(sizeof(MusicData)); Music music = (MusicData *)malloc(sizeof(MusicData));
if (strcmp(GetExtension(fileName), "ogg") == 0) if (IsFileExtension(fileName, ".ogg"))
{ {
// Open ogg audio stream // Open ogg audio stream
music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL); music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL);
@ -663,7 +693,8 @@ Music LoadMusicStream(const char *fileName)
TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
} }
} }
else if (strcmp(GetExtension(fileName), "flac") == 0) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac"))
{ {
music->ctxFlac = drflac_open_file(fileName); music->ctxFlac = drflac_open_file(fileName);
@ -682,7 +713,9 @@ Music LoadMusicStream(const char *fileName)
TraceLog(DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels); TraceLog(DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels);
} }
} }
else if (strcmp(GetExtension(fileName), "xm") == 0) #endif
#if defined(SUPPORT_FILEFORMAT_XM)
else if (IsFileExtension(fileName, ".xm"))
{ {
int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName); int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName);
@ -702,7 +735,9 @@ Music LoadMusicStream(const char *fileName)
} }
else TraceLog(WARNING, "[%s] XM file could not be opened", fileName); else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
} }
else if (strcmp(GetExtension(fileName), "mod") == 0) #endif
#if defined(SUPPORT_FILEFORMAT_MOD)
else if (IsFileExtension(fileName, ".mod"))
{ {
jar_mod_init(&music->ctxMod); jar_mod_init(&music->ctxMod);
@ -719,7 +754,8 @@ Music LoadMusicStream(const char *fileName)
} }
else TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); else TraceLog(WARNING, "[%s] MOD file could not be opened", fileName);
} }
else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); #endif
else TraceLog(WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
return music; return music;
} }
@ -730,9 +766,15 @@ void UnloadMusicStream(Music music)
CloseAudioStream(music->stream); CloseAudioStream(music->stream);
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm); else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm);
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod);
#endif
free(music); free(music);
} }
@ -777,8 +819,15 @@ void StopMusicStream(Music music)
switch (music->ctxType) switch (music->ctxType)
{ {
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break;
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_MODULE_FLAC: /* TODO: Restart FLAC context */ break;
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: /* TODO: Restart XM context */ break; case MUSIC_MODULE_XM: /* TODO: Restart XM context */ break;
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD: jar_mod_seek_start(&music->ctxMod); break; case MUSIC_MODULE_MOD: jar_mod_seek_start(&music->ctxMod); break;
#endif
default: break; default: break;
} }
@ -820,14 +869,20 @@ void UpdateMusicStream(Music music)
int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels);
} break; } break;
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: case MUSIC_AUDIO_FLAC:
{ {
// NOTE: Returns the number of samples to process // NOTE: Returns the number of samples to process
unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm);
} break; } break;
#endif
#if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break;
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break;
#endif
default: break; default: break;
} }
@ -1066,6 +1121,7 @@ void StopAudioStream(AudioStream stream)
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_WAV)
// Load WAV file into Wave structure // Load WAV file into Wave structure
static Wave LoadWAV(const char *fileName) static Wave LoadWAV(const char *fileName)
{ {
@ -1182,7 +1238,9 @@ static Wave LoadWAV(const char *fileName)
return wave; return wave;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
// Load OGG file into Wave structure // Load OGG file into Wave structure
// NOTE: Using stb_vorbis library // NOTE: Using stb_vorbis library
static Wave LoadOGG(const char *fileName) static Wave LoadOGG(const char *fileName)
@ -1206,7 +1264,7 @@ static Wave LoadOGG(const char *fileName)
wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile); wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile);
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio length is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
wave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short)); wave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short));
@ -1222,7 +1280,9 @@ static Wave LoadOGG(const char *fileName)
return wave; return wave;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
// Load FLAC file into Wave structure // Load FLAC file into Wave structure
// NOTE: Using dr_flac library // NOTE: Using dr_flac library
static Wave LoadFLAC(const char *fileName) static Wave LoadFLAC(const char *fileName)
@ -1244,15 +1304,22 @@ static Wave LoadFLAC(const char *fileName)
return wave; return wave;
} }
#endif
// Some required functions for audio standalone module version // Some required functions for audio standalone module version
#if defined(AUDIO_STANDALONE) #if defined(AUDIO_STANDALONE)
// Get the extension for a filename // Check file extension
const char *GetExtension(const char *fileName) bool IsFileExtension(const char *fileName, const char *ext)
{ {
const char *dot = strrchr(fileName, '.'); bool result = false;
if (!dot || dot == fileName) return ""; const char *fileExt;
return (dot + 1);
if ((fileExt = strrchr(fileName, '.')) != NULL)
{
if (strcmp(fileExt, ext) == 0) result = true;
}
return result;
} }
// Outputs a trace log message (INFO, ERROR, WARNING) // Outputs a trace log message (INFO, ERROR, WARNING)

View file

@ -1,31 +1,37 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.audio * raylib.audio - Basic funtionality to work with audio
* *
* This module provides basic functionality to work with audio: * FEATURES:
* Manage audio device (init/close) * - Manage audio device (init/close)
* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) * - Load and unload audio files
* Play/Stop/Pause/Resume loaded audio * - Format wave data (sample rate, size, channels)
* Manage mixing channels * - Play/Stop/Pause/Resume loaded audio
* Manage raw audio context * - Manage mixing channels
* - Manage raw audio context
*
* LIMITATIONS:
* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS)
* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32)
* *
* DEPENDENCIES: * DEPENDENCIES:
* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) * OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html)
* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/)
* jar_xm - XM module file loading * jar_xm - XM module file loading (#define SUPPORT_FILEFORMAT_XM)
* jar_mod - MOD audio file loading * jar_mod - MOD audio file loading (#define SUPPORT_FILEFORMAT_MOD)
* dr_flac - FLAC audio file loading * dr_flac - FLAC audio file loading (#define SUPPORT_FILEFORMAT_FLAC)
* *
* Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: * CONTRIBUTORS:
* XM audio module support (jar_xm) * Joshua Reisenauer (github: @kd7tck):
* MOD audio module support (jar_mod) * - XM audio module support (jar_xm)
* Mixing channels support * - MOD audio module support (jar_mod)
* Raw audio context support * - Mixing channels support
* - Raw audio context support
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -117,7 +123,7 @@ Wave LoadWave(const char *fileName); // Load wave dat
Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
Sound LoadSound(const char *fileName); // Load sound from file Sound LoadSound(const char *fileName); // Load sound from file
Sound LoadSoundFromWave(Wave wave); // Load sound from wave data Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
void UpdateSound(Sound sound, const void *data, int samplesCount); // Update sound buffer with new data void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
void UnloadWave(Wave wave); // Unload wave data void UnloadWave(Wave wave); // Unload wave data
void UnloadSound(Sound sound); // Unload sound void UnloadSound(Sound sound); // Unload sound
void PlaySound(Sound sound); // Play a sound void PlaySound(Sound sound); // Play a sound
@ -145,10 +151,11 @@ void SetMusicLoopCount(Music music, float count); // Set music loo
float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
// Raw audio stream functions
AudioStream InitAudioStream(unsigned int sampleRate, AudioStream InitAudioStream(unsigned int sampleRate,
unsigned int sampleSize, 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)
void UpdateAudioStream(AudioStream stream, void *data, int samplesCount); // Update audio stream buffers with data void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
void CloseAudioStream(AudioStream stream); // Close audio stream and free memory void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
void PlayAudioStream(AudioStream stream); // Play audio stream void PlayAudioStream(AudioStream stream); // Play audio stream

View file

@ -1,6 +1,6 @@
/******************************************************************************************* /*******************************************************************************************
* *
* raylib Camera System - Camera Modes Setup and Control Functions * raylib.camera - Camera system with multiple modes support
* *
* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) * NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
* *
@ -22,7 +22,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2015-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2015-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.

View file

@ -2,7 +2,14 @@
* *
* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms
* *
* The following platforms are supported: Windows, Linux, Mac (OSX), Android, Raspberry Pi, HTML5, Oculus Rift CV1 * PLATFORMS SUPPORTED:
* - Windows (win32/Win64)
* - Linux (tested on Ubuntu)
* - Mac (OSX)
* - Android (API Level 9 or greater)
* - Raspberry Pi (Raspbian)
* - HTML5 (Chrome, Firefox)
* - Oculus Rift CV1
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -22,13 +29,15 @@
* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js * Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js
* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code. * using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code.
* *
* #define LOAD_DEFAULT_FONT (defined by default) * #define SUPPORT_DEFAULT_FONT (default)
* Default font is loaded on window initialization to be available for the user to render simple text. * 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 (module: text) * NOTE: If enabled, uses external module functions to load default raylib font (module: text)
* *
* #define INCLUDE_CAMERA_SYSTEM / SUPPORT_CAMERA_SYSTEM * #define SUPPORT_CAMERA_SYSTEM
* Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
* *
* #define INCLUDE_GESTURES_SYSTEM / SUPPORT_GESTURES_SYSTEM * #define SUPPORT_GESTURES_SYSTEM
* Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag
* *
* #define SUPPORT_MOUSE_GESTURES * #define SUPPORT_MOUSE_GESTURES
* Mouse gestures are directly mapped like touches and processed by gestures system. * Mouse gestures are directly mapped like touches and processed by gestures system.
@ -42,7 +51,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -61,19 +70,29 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_DEFAULT_FONT
#define SUPPORT_MOUSE_GESTURES
#define SUPPORT_CAMERA_SYSTEM
#define SUPPORT_GESTURES_SYSTEM
//-------------------------------------------------
#include "raylib.h" #include "raylib.h"
#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, TraceLog() #include "utils.h" // Required for: fopen() Android mapping
#define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation) #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) #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 #include "raymath.h" // Required for: Vector3 and Matrix functions
#define GESTURES_IMPLEMENTATION #if defined(SUPPORT_GESTURES_SYSTEM)
#include "gestures.h" // Gestures detection functionality #define GESTURES_IMPLEMENTATION
#include "gestures.h" // Gestures detection functionality
#endif
#if !defined(PLATFORM_ANDROID) #if defined(SUPPORT_CAMERA_SYSTEM) && !defined(PLATFORM_ANDROID)
#define CAMERA_IMPLEMENTATION #define CAMERA_IMPLEMENTATION
#include "camera.h" // Camera system functionality #include "camera.h" // Camera system functionality
#endif #endif
@ -83,10 +102,10 @@
#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 Begin3dMode() to set perspective]
#include <string.h> // Required for: 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
#if defined __linux || defined(PLATFORM_WEB) #if defined __linux__ || defined(PLATFORM_WEB)
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX #include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
#elif defined __APPLE__ #elif defined __APPLE__
#include <unistd.h> // Required for: usleep() #include <unistd.h> // Required for: usleep()
@ -96,7 +115,7 @@
//#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
#ifdef __linux #ifdef __linux__
#define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
#define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window #define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window
#include <GLFW/glfw3native.h> // which are required for hiding mouse #include <GLFW/glfw3native.h> // which are required for hiding mouse
@ -140,8 +159,6 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define STORAGE_FILENAME "storage.data"
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
// Old device inputs system // Old device inputs system
#define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
@ -161,7 +178,7 @@
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
#define LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) #define STORAGE_FILENAME "storage.data"
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -259,7 +276,10 @@ 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
#if defined(SUPPORT_GESTURES_SYSTEM)
static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen
#endif
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
static char **dropFilesPath; // Store dropped files paths as strings static char **dropFilesPath; // Store dropped files paths as strings
@ -277,7 +297,7 @@ static bool showLogo = false; // Track if showing logo at init is
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core) // Other Modules Functions Declaration (required by core)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(LOAD_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow() extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow()
extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory
#endif #endif
@ -296,9 +316,6 @@ static void PollInputEvents(void); // Register user events
static void SwapBuffers(void); // Copy back buffer to front buffers static void SwapBuffers(void); // Copy back buffer to front buffers
static void LogoAnimation(void); // Plays raylib logo appearing animation static void LogoAnimation(void); // Plays raylib logo appearing animation
static void SetupViewport(void); // Set viewport parameters static void SetupViewport(void); // Set viewport parameters
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
static void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@ -323,7 +340,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData); static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData);
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData); static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
#endif #endif
@ -359,7 +378,7 @@ void InitWindow(int width, int height, const char *title)
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
InitGraphicsDevice(width, height); InitGraphicsDevice(width, height);
#if defined(LOAD_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)
LoadDefaultFont(); LoadDefaultFont();
@ -379,15 +398,21 @@ void InitWindow(int width, int height, const char *title)
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback);
// NOTE: Some code examples // Support keyboard events
emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// Support mouse events
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
// Support touch events
emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
//emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch); //emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch);
//emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); //emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback);
// Support gamepad (not provided by GLFW3 on emscripten) // Support gamepad events (not provided by GLFW3 on emscripten)
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback); emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
#endif #endif
@ -471,7 +496,7 @@ void InitWindow(int width, int height, void *state)
// Close Window and Terminate Context // Close Window and Terminate Context
void CloseWindow(void) void CloseWindow(void)
{ {
#if defined(LOAD_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
UnloadDefaultFont(); UnloadDefaultFont();
#endif #endif
@ -621,7 +646,7 @@ int GetScreenHeight(void)
void ShowCursor() void ShowCursor()
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
#ifdef __linux #ifdef __linux__
XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window));
#else #else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
@ -634,7 +659,7 @@ void ShowCursor()
void HideCursor() void HideCursor()
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
#ifdef __linux #ifdef __linux__
XColor col; XColor col;
const char nil[] = {0}; const char nil[] = {0};
@ -958,6 +983,12 @@ Color Fade(Color color, float alpha)
return (Color){color.r, color.g, color.b, (unsigned char)colorAlpha}; return (Color){color.r, color.g, color.b, (unsigned char)colorAlpha};
} }
// Activates raylib logo at startup
void ShowLogo(void)
{
showLogo = true;
}
// Enable some window/system configurations // Enable some window/system configurations
void SetConfigFlags(char flags) void SetConfigFlags(char flags)
{ {
@ -967,10 +998,40 @@ void SetConfigFlags(char flags)
if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true; if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true;
} }
// Activates raylib logo at startup // Takes a screenshot and saves it in the same folder as executable
void ShowLogo(void) void TakeScreenshot(void)
{ {
showLogo = true; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
char buffer[20]; // Buffer to store file name
unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight);
sprintf(buffer, "screenshot%03i.png", shotNum);
// Save image as PNG
SavePNG(buffer, imgData, renderWidth, renderHeight, 4);
free(imgData);
shotNum++;
TraceLog(INFO, "[%s] Screenshot taken #03i", buffer, shotNum);
#endif
}
// Check file extension
bool IsFileExtension(const char *fileName, const char *ext)
{
bool result = false;
const char *fileExt;
if ((fileExt = strrchr(fileName, '.')) != NULL)
{
if (strcmp(fileExt, ext) == 0) result = true;
}
return result;
} }
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
@ -2004,6 +2065,9 @@ static double GetTime(void)
} }
// Wait for some milliseconds (stop program execution) // Wait for some milliseconds (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
// http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
static void Wait(float ms) static void Wait(float ms)
{ {
//#define SUPPORT_BUSY_WAIT_LOOP //#define SUPPORT_BUSY_WAIT_LOOP
@ -2015,8 +2079,8 @@ static void Wait(float ms)
while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime(); while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime();
#else #else
#if defined _WIN32 #if defined _WIN32
Sleep(ms); Sleep((unsigned int)ms);
#elif defined __linux || defined(PLATFORM_WEB) #elif defined __linux__ || defined(PLATFORM_WEB)
struct timespec req = { 0 }; struct timespec req = { 0 };
time_t sec = (int)(ms/1000.0f); time_t sec = (int)(ms/1000.0f);
ms -= (sec*1000); ms -= (sec*1000);
@ -2064,9 +2128,11 @@ static bool GetMouseButtonStatus(int button)
// Poll (store) all input events // Poll (store) all input events
static void PollInputEvents(void) static void PollInputEvents(void)
{ {
#if defined(SUPPORT_GESTURES_SYSTEM)
// NOTE: Gestures update must be called every frame to reset gestures correctly // NOTE: Gestures update must be called every frame to reset gestures correctly
// because ProcessGestureEvent() is just called on an event, not every frame // because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures(); UpdateGestures();
#endif
// Reset last key pressed registered // Reset last key pressed registered
lastKeyPressed = -1; lastKeyPressed = -1;
@ -2237,28 +2303,6 @@ static void SwapBuffers(void)
#endif #endif
} }
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Takes a screenshot and saves it in the same folder as executable
static void TakeScreenshot(void)
{
static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
char buffer[20]; // Buffer to store file name
unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight);
sprintf(buffer, "screenshot%03i.png", shotNum);
// Save image as PNG
SavePNG(buffer, imgData, renderWidth, renderHeight, 4);
free(imgData);
shotNum++;
TraceLog(INFO, "[%s] Screenshot taken!", buffer);
}
#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// GLFW3 Error Callback, runs on GLFW3 error // GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description) static void ErrorCallback(int error, const char *description)
@ -2296,8 +2340,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
{ {
currentMouseState[button] = action; currentMouseState[button] = action;
#define ENABLE_MOUSE_GESTURES #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
#if defined(ENABLE_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures // Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent; GestureEvent gestureEvent;
@ -2328,8 +2371,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
// GLFW3 Cursor Position Callback, runs on mouse move // GLFW3 Cursor Position Callback, runs on mouse move
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
{ {
#define ENABLE_MOUSE_GESTURES #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
#if defined(ENABLE_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures // Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent; GestureEvent gestureEvent;
@ -2459,7 +2501,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight); InitGraphicsDevice(screenWidth, screenHeight);
#if defined(LOAD_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)
LoadDefaultFont(); LoadDefaultFont();
@ -2663,8 +2705,39 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
return 0; return 0;
} }
// Register keyboard input events
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
{
if ((eventType == EMSCRIPTEN_EVENT_KEYPRESS) && (strcmp(keyEvent->code, "Escape") == 0))
{
emscripten_exit_pointerlock();
}
return 0;
}
// Register mouse input events
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
{
if (eventType == EMSCRIPTEN_EVENT_CLICK)
{
EmscriptenPointerlockChangeEvent plce;
emscripten_get_pointerlock_status(&plce);
if (!plce.isActive) emscripten_request_pointerlock(0, 1);
else
{
emscripten_exit_pointerlock();
emscripten_get_pointerlock_status(&plce);
//if (plce.isActive) TraceLog(WARNING, "Pointer lock exit did not work!");
}
}
return 0;
}
// Register touch input events // Register touch input events
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{ {
/* /*
for (int i = 0; i < touchEvent->numTouches; i++) for (int i = 0; i < touchEvent->numTouches; i++)

View file

@ -665,15 +665,20 @@ func Fade(color Color, alpha float32) Color {
return v return v
} }
// ShowLogo - Activates raylib logo at startup (can be done with flags)
func ShowLogo() {
C.ShowLogo()
}
// SetConfigFlags - Setup some window configuration flags // SetConfigFlags - Setup some window configuration flags
func SetConfigFlags(flags byte) { func SetConfigFlags(flags byte) {
cflags := (C.char)(flags) cflags := (C.char)(flags)
C.SetConfigFlags(cflags) C.SetConfigFlags(cflags)
} }
// ShowLogo - Activates raylib logo at startup (can be done with flags) // TakeScreenshot - Takes a screenshot and saves it in the same folder as executable
func ShowLogo() { func TakeScreenshot() {
C.ShowLogo() C.TakeScreenshot()
} }
// StorageSaveValue - Storage save integer value (to defined position) // StorageSaveValue - Storage save integer value (to defined position)

View file

@ -1,4 +1,4 @@
/* stb_image - v2.14 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.15 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -21,7 +21,7 @@
avoid problematic images and only need the trivial interface avoid problematic images and only need the trivial interface
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
PNG 1/2/4/8-bit-per-channel (16 bpc not supported) PNG 1/2/4/8/16-bit-per-channel
TGA (not sure what subset, if a subset) TGA (not sure what subset, if a subset)
BMP non-1bpp, non-RLE BMP non-1bpp, non-RLE
@ -42,110 +42,14 @@
Full documentation under "DOCUMENTATION" below. Full documentation under "DOCUMENTATION" below.
Revision 2.00 release notes: LICENSE
- Progressive JPEG is now supported. See end of file for license information.
- PPM and PGM binary formats are now supported, thanks to Ken Miller. RECENT REVISION HISTORY:
- x86 platforms now make use of SSE2 SIMD instructions for 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
JPEG decoding, and ARM platforms can use NEON SIMD if requested. 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
This work was done by Fabian "ryg" Giesen. SSE2 is used by
default, but NEON must be enabled explicitly; see docs.
With other JPEG optimizations included in this version, we see
2x speedup on a JPEG on an x86 machine, and a 1.5x speedup
on a JPEG on an ARM machine, relative to previous versions of this
library. The same results will not obtain for all JPGs and for all
x86/ARM machines. (Note that progressive JPEGs are significantly
slower to decode than regular JPEGs.) This doesn't mean that this
is the fastest JPEG decoder in the land; rather, it brings it
closer to parity with standard libraries. If you want the fastest
decode, look elsewhere. (See "Philosophy" section of docs below.)
See final bullet items below for more info on SIMD.
- Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing
the memory allocator. Unlike other STBI libraries, these macros don't
support a context parameter, so if you need to pass a context in to
the allocator, you'll have to store it in a global or a thread-local
variable.
- Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and
STBI_NO_LINEAR.
STBI_NO_HDR: suppress implementation of .hdr reader format
STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API
- You can suppress implementation of any of the decoders to reduce
your code footprint by #defining one or more of the following
symbols before creating the implementation.
STBI_NO_JPEG
STBI_NO_PNG
STBI_NO_BMP
STBI_NO_PSD
STBI_NO_TGA
STBI_NO_GIF
STBI_NO_HDR
STBI_NO_PIC
STBI_NO_PNM (.ppm and .pgm)
- You can request *only* certain decoders and suppress all other ones
(this will be more forward-compatible, as addition of new decoders
doesn't require you to disable them explicitly):
STBI_ONLY_JPEG
STBI_ONLY_PNG
STBI_ONLY_BMP
STBI_ONLY_PSD
STBI_ONLY_TGA
STBI_ONLY_GIF
STBI_ONLY_HDR
STBI_ONLY_PIC
STBI_ONLY_PNM (.ppm and .pgm)
Note that you can define multiples of these, and you will get all
of them ("only x" and "only y" is interpreted to mean "only x&y").
- If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
- Compilation of all SIMD code can be suppressed with
#define STBI_NO_SIMD
It should not be necessary to disable SIMD unless you have issues
compiling (e.g. using an x86 compiler which doesn't support SSE
intrinsics or that doesn't support the method used to detect
SSE2 support at run-time), and even those can be reported as
bugs so I can refine the built-in compile-time checking to be
smarter.
- The old STBI_SIMD system which allowed installing a user-defined
IDCT etc. has been removed. If you need this, don't upgrade. My
assumption is that almost nobody was doing this, and those who
were will find the built-in SIMD more satisfactory anyway.
- RGB values computed for JPEG images are slightly different from
previous versions of stb_image. (This is due to using less
integer precision in SIMD.) The C code has been adjusted so
that the same RGB values will be computed regardless of whether
SIMD support is available, so your app should always produce
consistent results. But these results are slightly different from
previous versions. (Specifically, about 3% of available YCbCr values
will compute different RGB results from pre-1.49 versions by +-1;
most of the deviating values are one smaller in the G channel.)
- If you must produce consistent results with previous versions of
stb_image, #define STBI_JPEG_OLD and you will get the same results
you used to; however, you will not get the SIMD speedups for
the YCbCr-to-RGB conversion step (although you should still see
significant JPEG speedup from the other changes).
Please note that STBI_JPEG_OLD is a temporary feature; it will be
removed in future versions of the library. It is only intended for
near-term back-compatibility use.
Latest revision history:
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
@ -174,32 +78,26 @@
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) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit TGA) socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Optimizations & bugfixes
Fabian "ryg" Giesen Fabian "ryg" Giesen
Arseny Kapoulkine Arseny Kapoulkine
Bug & warning fixes Bug & warning fixes
Marc LeBlanc David Woo Guillaume George Martins Mozeiko Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
Dave Moore Roy Eltham Hayaki Saito Phil Jordan Dave Moore Roy Eltham Hayaki Saito Nathan Reed
Won Chun Luke Graham Johan Duparc Nathan Reed Won Chun Luke Graham Johan Duparc Nick Verigakis
the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson
Janez Zemva John Bartholomew Michal Cichon github:svdijk Janez Zemva John Bartholomew Michal Cichon github:rlyeh
Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson Jonathan Blow Ken Hamada Tero Hanninen github:romigrou
Laurent Gomila Cort Stratton Sergio Gonzalez github:romigrou Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk
Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar
Ryamond Barbiero Paul Du Bois Engin Manap github:snagar Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex
Michaelangel007@github Oriol Ferrer Mesia Dale Weiler github:Zelex Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
Philipp Wiesemann Josh Tobin github:rlyeh github:grim210@github Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
Blazej Dariusz Roszkowski github:sammyhw Blazej Dariusz Roszkowski Gregory Mullen github:phprus
LICENSE
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
*/ */
@ -274,13 +172,13 @@ publish, and distribute this file as you see fit.
// and for best performance I may provide less-easy-to-use APIs that give higher // and for best performance I may provide less-easy-to-use APIs that give higher
// performance, in addition to the easy to use ones. Nevertheless, it's important // performance, in addition to the easy to use ones. Nevertheless, it's important
// to keep in mind that from the standpoint of you, a client of this library, // to keep in mind that from the standpoint of you, a client of this library,
// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. // all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
// //
// Some secondary priorities arise directly from the first two, some of which // Some secondary priorities arise directly from the first two, some of which
// make more explicit reasons why performance can't be emphasized. // make more explicit reasons why performance can't be emphasized.
// //
// - Portable ("ease of use") // - Portable ("ease of use")
// - Small footprint ("easy to maintain") // - Small source code footprint ("easy to maintain")
// - No dependencies ("ease of use") // - No dependencies ("ease of use")
// //
// =========================================================================== // ===========================================================================
@ -312,13 +210,6 @@ publish, and distribute this file as you see fit.
// (at least this is true for iOS and Android). Therefore, the NEON support is // (at least this is true for iOS and Android). Therefore, the NEON support is
// toggled by a build flag: define STBI_NEON to get NEON loops. // toggled by a build flag: define STBI_NEON to get NEON loops.
// //
// The output of the JPEG decoder is slightly different from versions where
// SIMD support was introduced (that is, for versions before 1.49). The
// difference is only +-1 in the 8-bit RGB channels, and only on a small
// fraction of pixels. You can force the pre-1.49 behavior by defining
// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path
// and hence cost some performance.
//
// If for some reason you do not want to use any of SIMD code, or if // If for some reason you do not want to use any of SIMD code, or if
// you have issues compiling it, you can disable it entirely by // you have issues compiling it, you can disable it entirely by
// defining STBI_NO_SIMD. // defining STBI_NO_SIMD.
@ -374,20 +265,47 @@ publish, and distribute this file as you see fit.
// says there's premultiplied data (currently only happens in iPhone images, // says there's premultiplied data (currently only happens in iPhone images,
// and only if iPhone convert-to-rgb processing is on). // and only if iPhone convert-to-rgb processing is on).
// //
// ===========================================================================
//
// ADDITIONAL CONFIGURATION
//
// - You can suppress implementation of any of the decoders to reduce
// your code footprint by #defining one or more of the following
// symbols before creating the implementation.
//
// STBI_NO_JPEG
// STBI_NO_PNG
// STBI_NO_BMP
// STBI_NO_PSD
// STBI_NO_TGA
// STBI_NO_GIF
// STBI_NO_HDR
// STBI_NO_PIC
// STBI_NO_PNM (.ppm and .pgm)
//
// - You can request *only* certain decoders and suppress all other ones
// (this will be more forward-compatible, as addition of new decoders
// doesn't require you to disable them explicitly):
//
// STBI_ONLY_JPEG
// STBI_ONLY_PNG
// STBI_ONLY_BMP
// STBI_ONLY_PSD
// STBI_ONLY_TGA
// STBI_ONLY_GIF
// STBI_ONLY_HDR
// STBI_ONLY_PIC
// STBI_ONLY_PNM (.ppm and .pgm)
//
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
//
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
#include <stdio.h> #include <stdio.h>
#endif // STBI_NO_STDIO #endif // STBI_NO_STDIO
#define STBI_NO_HDR // RaySan: not required by raylib
//#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
// NOTE: Added to work with raylib on Android
#if defined(PLATFORM_ANDROID)
#include "utils.h" // RaySan: Android fopen function map
#endif
#define STBI_VERSION 1 #define STBI_VERSION 1
enum enum
@ -666,12 +584,14 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#define STBI__X86_TARGET #define STBI__X86_TARGET
#endif #endif
#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) #if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
// NOTE: not clear do we actually need this for the 64-bit path?
// gcc doesn't support sse2 intrinsics unless you compile with -msse2, // gcc doesn't support sse2 intrinsics unless you compile with -msse2,
// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; // which in turn means it gets to use SSE2 everywhere. This is unfortunate,
// this is just broken and gcc are jerks for not fixing it properly // but previous attempts to provide the SSE2 functions with runtime
// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) // detection caused numerous issues. The way architecture extensions are
// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
// New behavior: if compiled with -msse2, we use SSE2 without any
// detection; if not, we don't use it at all.
#define STBI_NO_SIMD #define STBI_NO_SIMD
#endif #endif
@ -729,14 +649,10 @@ static int stbi__sse2_available()
static int stbi__sse2_available() static int stbi__sse2_available()
{ {
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later // If we're even attempting to compile this on GCC/Clang, that means
// GCC 4.8+ has a nice way to do this // -msse2 is on, which means the compiler is allowed to use SSE2
return __builtin_cpu_supports("sse2"); // instructions at will, and so are we.
#else return 1;
// portable way to do this, preferably without using GCC inline ASM?
// just bail for now.
return 0;
#endif
} }
#endif #endif
#endif #endif
@ -1738,7 +1654,7 @@ typedef struct
stbi__context *s; stbi__context *s;
stbi__huffman huff_dc[4]; stbi__huffman huff_dc[4];
stbi__huffman huff_ac[4]; stbi__huffman huff_ac[4];
stbi_uc dequant[4][64]; stbi__uint16 dequant[4][64];
stbi__int16 fast_ac[4][1 << FAST_BITS]; stbi__int16 fast_ac[4][1 << FAST_BITS];
// sizes for components, interleaved MCUs // sizes for components, interleaved MCUs
@ -1774,6 +1690,8 @@ typedef struct
int succ_high; int succ_high;
int succ_low; int succ_low;
int eob_run; int eob_run;
int jfif;
int app14_color_transform; // Adobe APP14 tag
int rgb; int rgb;
int scan_n, order[4]; int scan_n, order[4];
@ -1844,7 +1762,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
// magnitude code followed by receive_extend code // magnitude code followed by receive_extend code
int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
int m = 1 << (magbits - 1); int m = 1 << (magbits - 1);
if (k < m) k += (-1 << 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 << 8) + (run << 4) + (len + magbits));
@ -1859,6 +1777,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
int b = j->nomore ? 0 : stbi__get8(j->s); 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
if (c != 0) { if (c != 0) {
j->marker = (unsigned char) c; j->marker = (unsigned char) c;
j->nomore = 1; j->nomore = 1;
@ -1983,7 +1902,7 @@ static stbi_uc stbi__jpeg_dezigzag[64+15] =
}; };
// decode one 64-entry block-- // decode one 64-entry block--
static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
{ {
int diff,dc,k; int diff,dc,k;
int t; int t;
@ -2692,7 +2611,7 @@ static stbi_uc stbi__get_marker(stbi__jpeg *j)
x = stbi__get8(j->s); x = stbi__get8(j->s);
if (x != 0xff) return STBI__MARKER_none; if (x != 0xff) return STBI__MARKER_none;
while (x == 0xff) while (x == 0xff)
x = stbi__get8(j->s); x = stbi__get8(j->s); // consume repeated 0xff fill bytes
return x; return x;
} }
@ -2707,7 +2626,7 @@ static void stbi__jpeg_reset(stbi__jpeg *j)
j->code_bits = 0; j->code_bits = 0;
j->code_buffer = 0; j->code_buffer = 0;
j->nomore = 0; j->nomore = 0;
j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
j->marker = STBI__MARKER_none; j->marker = STBI__MARKER_none;
j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
j->eob_run = 0; j->eob_run = 0;
@ -2839,7 +2758,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
} }
} }
static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
{ {
int i; int i;
for (i=0; i < 64; ++i) for (i=0; i < 64; ++i)
@ -2881,13 +2800,14 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
L = stbi__get16be(z->s)-2; L = stbi__get16be(z->s)-2;
while (L > 0) { while (L > 0) {
int q = stbi__get8(z->s); int q = stbi__get8(z->s);
int p = q >> 4; int p = q >> 4, sixteen = (p != 0);
int t = q & 15,i; int t = q & 15,i;
if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
for (i=0; i < 64; ++i) for (i=0; i < 64; ++i)
z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); z->dequant[t][stbi__jpeg_dezigzag[i]] = sixteen ? stbi__get16be(z->s) : stbi__get8(z->s);
L -= 65; L -= (sixteen ? 129 : 65);
} }
return L==0; return L==0;
@ -2920,12 +2840,50 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
} }
return L==0; return L==0;
} }
// check for comment block or APP blocks // check for comment block or APP blocks
if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
stbi__skip(z->s, stbi__get16be(z->s)-2); L = stbi__get16be(z->s);
if (L < 2) {
if (m == 0xFE)
return stbi__err("bad COM len","Corrupt JPEG");
else
return stbi__err("bad APP len","Corrupt JPEG");
}
L -= 2;
if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
static const unsigned char tag[5] = {'J','F','I','F','\0'};
int ok = 1;
int i;
for (i=0; i < 5; ++i)
if (stbi__get8(z->s) != tag[i])
ok = 0;
L -= 5;
if (ok)
z->jfif = 1;
} else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
int ok = 1;
int i;
for (i=0; i < 6; ++i)
if (stbi__get8(z->s) != tag[i])
ok = 0;
L -= 6;
if (ok) {
stbi__get8(z->s); // version
stbi__get16be(z->s); // flags0
stbi__get16be(z->s); // flags1
z->app14_color_transform = stbi__get8(z->s); // color transform
L -= 6;
}
}
stbi__skip(z->s, L);
return 1; return 1;
} }
return 0;
return stbi__err("unknown marker","Corrupt JPEG");
} }
// after we see SOS // after we see SOS
@ -2999,7 +2957,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
c = stbi__get8(s); c = stbi__get8(s);
if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
s->img_n = c; s->img_n = c;
for (i=0; i < c; ++i) { for (i=0; i < c; ++i) {
z->img_comp[i].data = NULL; z->img_comp[i].data = NULL;
@ -3012,13 +2970,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
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 unsigned char rgb[3] = { 'R', 'G', 'B' };
z->img_comp[i].id = stbi__get8(s); z->img_comp[i].id = stbi__get8(s);
if (z->img_comp[i].id != i+1) // JFIF requires if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
if (z->img_comp[i].id != i) { // some version of jpegtran outputs non-JFIF-compliant files! ++z->rgb;
// somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format)
if (z->img_comp[i].id != rgb[i])
return stbi__err("bad component ID","Corrupt JPEG");
++z->rgb;
}
q = stbi__get8(s); q = stbi__get8(s);
z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
@ -3090,6 +3043,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
{ {
int m; int m;
z->jfif = 0;
z->app14_color_transform = -1; // valid values are 0,1,2
z->marker = STBI__MARKER_none; // initialize cached marker to empty z->marker = STBI__MARKER_none; // initialize cached marker to empty
m = stbi__get_marker(z); m = stbi__get_marker(z);
if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
@ -3131,12 +3086,15 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
if (x == 255) { if (x == 255) {
j->marker = stbi__get8(j->s); j->marker = stbi__get8(j->s);
break; break;
} else if (x != 0) {
return stbi__err("junk before marker", "Corrupt JPEG");
} }
} }
// if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
} }
} else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s);
if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG");
if (NL != j->s->img_y) 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;
} }
@ -3355,38 +3313,9 @@ static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_
return out; return out;
} }
#ifdef STBI_JPEG_OLD
// this is the same YCbCr-to-RGB calculation that stb_image has used
// historically before the algorithm changes in 1.49
#define float2fixed(x) ((int) ((x) * 65536 + 0.5))
static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
{
int i;
for (i=0; i < count; ++i) {
int y_fixed = (y[i] << 16) + 32768; // rounding
int r,g,b;
int cr = pcr[i] - 128;
int cb = pcb[i] - 128;
r = y_fixed + cr*float2fixed(1.40200f);
g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
b = y_fixed + cb*float2fixed(1.77200f);
r >>= 16;
g >>= 16;
b >>= 16;
if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
out[0] = (stbi_uc)r;
out[1] = (stbi_uc)g;
out[2] = (stbi_uc)b;
out[3] = 255;
out += step;
}
}
#else
// this is a reduced-precision calculation of YCbCr-to-RGB introduced // this is a reduced-precision calculation of YCbCr-to-RGB introduced
// to make sure the code produces the same results in both SIMD and scalar // to make sure the code produces the same results in both SIMD and scalar
#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) #define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8)
static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
{ {
int i; int i;
@ -3395,9 +3324,9 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc
int r,g,b; int r,g,b;
int cr = pcr[i] - 128; int cr = pcr[i] - 128;
int cb = pcb[i] - 128; int cb = pcb[i] - 128;
r = y_fixed + cr* float2fixed(1.40200f); r = y_fixed + cr* stbi__float2fixed(1.40200f);
g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
b = y_fixed + cb* float2fixed(1.77200f); b = y_fixed + cb* stbi__float2fixed(1.77200f);
r >>= 20; r >>= 20;
g >>= 20; g >>= 20;
b >>= 20; b >>= 20;
@ -3411,7 +3340,6 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc
out += step; out += step;
} }
} }
#endif
#if defined(STBI_SSE2) || defined(STBI_NEON) #if defined(STBI_SSE2) || defined(STBI_NEON)
static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
@ -3530,9 +3458,9 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons
int r,g,b; int r,g,b;
int cr = pcr[i] - 128; int cr = pcr[i] - 128;
int cb = pcb[i] - 128; int cb = pcb[i] - 128;
r = y_fixed + cr* float2fixed(1.40200f); r = y_fixed + cr* stbi__float2fixed(1.40200f);
g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
b = y_fixed + cb* float2fixed(1.77200f); b = y_fixed + cb* stbi__float2fixed(1.77200f);
r >>= 20; r >>= 20;
g >>= 20; g >>= 20;
b >>= 20; b >>= 20;
@ -3558,18 +3486,14 @@ static void stbi__setup_jpeg(stbi__jpeg *j)
#ifdef STBI_SSE2 #ifdef STBI_SSE2
if (stbi__sse2_available()) { if (stbi__sse2_available()) {
j->idct_block_kernel = stbi__idct_simd; j->idct_block_kernel = stbi__idct_simd;
#ifndef STBI_JPEG_OLD
j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
#endif
j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
} }
#endif #endif
#ifdef STBI_NEON #ifdef STBI_NEON
j->idct_block_kernel = stbi__idct_simd; j->idct_block_kernel = stbi__idct_simd;
#ifndef STBI_JPEG_OLD
j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
#endif
j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
#endif #endif
} }
@ -3590,9 +3514,16 @@ typedef struct
int ypos; // which pre-expansion row we're on int ypos; // which pre-expansion row we're on
} stbi__resample; } stbi__resample;
// fast 0..255 * 0..255 => 0..255 rounded multiplication
static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
{
unsigned int t = x*y + 128;
return (stbi_uc) ((t + (t >>8)) >> 8);
}
static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
{ {
int n, decode_n; int n, decode_n, is_rgb;
z->s->img_n = 0; // make stbi__cleanup_jpeg safe z->s->img_n = 0; // make stbi__cleanup_jpeg safe
// validate req_comp // validate req_comp
@ -3602,9 +3533,11 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
// determine actual number of components to generate // determine actual number of components to generate
n = req_comp ? req_comp : z->s->img_n; n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
if (z->s->img_n == 3 && n < 3) is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
if (z->s->img_n == 3 && n < 3 && !is_rgb)
decode_n = 1; decode_n = 1;
else else
decode_n = z->s->img_n; decode_n = z->s->img_n;
@ -3664,7 +3597,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
if (n >= 3) { if (n >= 3) {
stbi_uc *y = coutput[0]; stbi_uc *y = coutput[0];
if (z->s->img_n == 3) { if (z->s->img_n == 3) {
if (z->rgb == 3) { if (is_rgb) {
for (i=0; i < z->s->img_x; ++i) { for (i=0; i < z->s->img_x; ++i) {
out[0] = y[i]; out[0] = y[i];
out[1] = coutput[1][i]; out[1] = coutput[1][i];
@ -3675,6 +3608,28 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
} else { } else {
z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
} }
} else if (z->s->img_n == 4) {
if (z->app14_color_transform == 0) { // CMYK
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
out[0] = stbi__blinn_8x8(coutput[0][i], k);
out[1] = stbi__blinn_8x8(coutput[1][i], k);
out[2] = stbi__blinn_8x8(coutput[2][i], k);
out[3] = 255;
out += n;
}
} else if (z->app14_color_transform == 2) { // YCCK
z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
out[0] = stbi__blinn_8x8(255 - out[0], k);
out[1] = stbi__blinn_8x8(255 - out[1], k);
out[2] = stbi__blinn_8x8(255 - out[2], k);
out += n;
}
} else { // YCbCr + alpha? Ignore the fourth channel for now
z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
}
} else } else
for (i=0; i < z->s->img_x; ++i) { for (i=0; i < z->s->img_x; ++i) {
out[0] = out[1] = out[2] = y[i]; out[0] = out[1] = out[2] = y[i];
@ -3682,17 +3637,45 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
out += n; out += n;
} }
} else { } else {
stbi_uc *y = coutput[0]; if (is_rgb) {
if (n == 1) if (n == 1)
for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; for (i=0; i < z->s->img_x; ++i)
else *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; else {
for (i=0; i < z->s->img_x; ++i, out += 2) {
out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
out[1] = 255;
}
}
} else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
stbi_uc r = stbi__blinn_8x8(coutput[0][i], k);
stbi_uc g = stbi__blinn_8x8(coutput[1][i], k);
stbi_uc b = stbi__blinn_8x8(coutput[2][i], k);
out[0] = stbi__compute_y(r, g, b);
out[1] = 255;
out += n;
}
} else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
for (i=0; i < z->s->img_x; ++i) {
out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
out[1] = 255;
out += n;
}
} else {
stbi_uc *y = coutput[0];
if (n == 1)
for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
else
for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
}
} }
} }
stbi__cleanup_jpeg(z); stbi__cleanup_jpeg(z);
*out_x = z->s->img_x; *out_x = z->s->img_x;
*out_y = z->s->img_y; *out_y = z->s->img_y;
if (comp) *comp = z->s->img_n; // report original components, not output if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
return output; return output;
} }
} }
@ -3701,6 +3684,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
{ {
unsigned char* result; unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
STBI_NOTUSED(ri);
j->s = s; j->s = s;
stbi__setup_jpeg(j); stbi__setup_jpeg(j);
result = load_jpeg_image(j, x,y,comp,req_comp); result = load_jpeg_image(j, x,y,comp,req_comp);
@ -3711,11 +3695,12 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
static int stbi__jpeg_test(stbi__context *s) static int stbi__jpeg_test(stbi__context *s)
{ {
int r; int r;
stbi__jpeg j; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
j.s = s; j->s = s;
stbi__setup_jpeg(&j); stbi__setup_jpeg(j);
r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
stbi__rewind(s); stbi__rewind(s);
STBI_FREE(j);
return r; return r;
} }
@ -3727,7 +3712,7 @@ static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
} }
if (x) *x = j->s->img_x; if (x) *x = j->s->img_x;
if (y) *y = j->s->img_y; if (y) *y = j->s->img_y;
if (comp) *comp = j->s->img_n; if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
return 1; return 1;
} }
@ -3784,7 +3769,7 @@ stbi_inline static int stbi__bit_reverse(int v, int bits)
return stbi__bitreverse16(v) >> (16-bits); return stbi__bitreverse16(v) >> (16-bits);
} }
static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
{ {
int i,k=0; int i,k=0;
int code, next_code[16], sizes[17]; int code, next_code[16], sizes[17];
@ -4074,9 +4059,24 @@ static int stbi__parse_zlib_header(stbi__zbuf *a)
return 1; return 1;
} }
// @TODO: should statically initialize these for optimal thread safety static const stbi_uc stbi__zdefault_length[288] =
static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; {
static void stbi__init_zdefaults(void) 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
};
static const stbi_uc stbi__zdefault_distance[32] =
{
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
};
/*
Init algorithm:
{ {
int i; // use <= to match clearly with spec int i; // use <= to match clearly with spec
for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
@ -4086,6 +4086,7 @@ static void stbi__init_zdefaults(void)
for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
} }
*/
static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
{ {
@ -4104,7 +4105,6 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
} else { } else {
if (type == 1) { if (type == 1) {
// use fixed code lengths // use fixed code lengths
if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();
if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
} else { } else {
@ -4305,7 +4305,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
for (j=0; j < y; ++j) { for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j; stbi_uc *cur = a->out + stride*j;
stbi_uc *prior = cur - stride; stbi_uc *prior;
int filter = *raw++; int filter = *raw++;
if (filter > 4) if (filter > 4)
@ -4317,6 +4317,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
filter_bytes = 1; filter_bytes = 1;
width = img_width_bytes; width = img_width_bytes;
} }
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
// if first row, use special filter that doesn't sample previous row // if first row, use special filter that doesn't sample previous row
if (j == 0) filter = first_row_filter[filter]; if (j == 0) filter = first_row_filter[filter];
@ -4709,7 +4710,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
@ -5979,9 +5980,11 @@ static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *c
static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
{ {
stbi_uc *result; stbi_uc *result;
int i, x,y; int i, x,y, internal_comp;
STBI_NOTUSED(ri); STBI_NOTUSED(ri);
if (!comp) comp = &internal_comp;
for (i=0; i<92; ++i) for (i=0; i<92; ++i)
stbi__get8(s); stbi__get8(s);
@ -6600,6 +6603,11 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
char buffer[STBI__HDR_BUFLEN]; char buffer[STBI__HDR_BUFLEN];
char *token; char *token;
int valid = 0; int valid = 0;
int dummy;
if (!x) x = &dummy;
if (!y) y = &dummy;
if (!comp) comp = &dummy;
if (stbi__hdr_test(s) == 0) { if (stbi__hdr_test(s) == 0) {
stbi__rewind( s ); stbi__rewind( s );
@ -6646,9 +6654,9 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
stbi__rewind( s ); stbi__rewind( s );
if (p == NULL) if (p == NULL)
return 0; return 0;
*x = s->img_x; if (x) *x = s->img_x;
*y = s->img_y; if (y) *y = s->img_y;
*comp = info.ma ? 4 : 3; if (comp) *comp = info.ma ? 4 : 3;
return 1; return 1;
} }
#endif #endif
@ -6656,7 +6664,10 @@ 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; int channelCount, dummy;
if (!x) x = &dummy;
if (!y) y = &dummy;
if (!comp) comp = &dummy;
if (stbi__get32be(s) != 0x38425053) { if (stbi__get32be(s) != 0x38425053) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
@ -6689,9 +6700,13 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_PIC #ifndef STBI_NO_PIC
static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int act_comp=0,num_packets=0,chained; int act_comp=0,num_packets=0,chained,dummy;
stbi__pic_packet packets[10]; stbi__pic_packet packets[10];
if (!x) x = &dummy;
if (!y) y = &dummy;
if (!comp) comp = &dummy;
if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
stbi__rewind(s); stbi__rewind(s);
return 0; return 0;
@ -6777,7 +6792,7 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
*x = s->img_x; *x = s->img_x;
*y = s->img_y; *y = s->img_y;
*comp = s->img_n; if (comp) *comp = s->img_n;
if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
return stbi__errpuc("too large", "PNM too large"); return stbi__errpuc("too large", "PNM too large");
@ -6831,16 +6846,20 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c)
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int maxv; int maxv, dummy;
char c, p, t; char c, p, t;
stbi__rewind( s ); if (!x) x = &dummy;
if (!y) y = &dummy;
if (!comp) comp = &dummy;
stbi__rewind(s);
// Get identifier // Get identifier
p = (char) stbi__get8(s); p = (char) stbi__get8(s);
t = (char) stbi__get8(s); t = (char) stbi__get8(s);
if (p != 'P' || (t != '5' && t != '6')) { if (p != 'P' || (t != '5' && t != '6')) {
stbi__rewind( s ); stbi__rewind(s);
return 0; return 0;
} }
@ -6947,6 +6966,11 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/* /*
revision history: revision history:
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
warning fixes; disable run-time SSE detection on gcc;
uniform handling of optional "return" values;
thread-safe initialization of zlib tables
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) allocate large structures on the stack 2.11 (2016-04-02) allocate large structures on the stack
@ -7108,3 +7132,46 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
0.50 (2006-11-19) 0.50 (2006-11-19)
first released version first released version
*/ */
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -1,4 +1,4 @@
/* stb_image_resize - v0.92 - public domain image resizing /* stb_image_resize - v0.94 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014 by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb http://github.com/nothings/stb
@ -107,8 +107,8 @@
industry, it is still uncommon in the videogame/real-time world. industry, it is still uncommon in the videogame/real-time world.
If you linearly filter non-premultiplied alpha, strange effects If you linearly filter non-premultiplied alpha, strange effects
occur. (For example, the average of 1% opaque bright green occur. (For example, the 50/50 average of 99% transparent bright green
and 99% opaque black produces 50% transparent dark green when and 1% transparent black produces 50% transparent dark green when
non-premultiplied, whereas premultiplied it produces 50% non-premultiplied, whereas premultiplied it produces 50%
transparent near-black. The former introduces green energy transparent near-black. The former introduces green energy
that doesn't exist in the source image.) that doesn't exist in the source image.)
@ -152,20 +152,20 @@
(For example, graphics hardware does not apply sRGB conversion (For example, graphics hardware does not apply sRGB conversion
to the alpha channel.) to the alpha channel.)
ADDITIONAL CONTRIBUTORS CONTRIBUTORS
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix Aras Pranckevicius: bugfix
REVISIONS REVISIONS
0.94 (2017-03-18) fixed warnings
0.93 (2017-03-03) fixed bug with certain combinations of heights
0.92 (2017-01-02) fix integer overflow on large (>2GB) images 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
0.90 (2014-09-17) first released version 0.90 (2014-09-17) first released version
LICENSE LICENSE
See end of file for license information.
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
TODO TODO
Don't decode all of the image data when only processing a partial tile Don't decode all of the image data when only processing a partial tile
@ -533,10 +533,11 @@ typedef struct
int horizontal_num_contributors; int horizontal_num_contributors;
int vertical_num_contributors; int vertical_num_contributors;
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_num_entries; // Total number of entries in the ring buffer.
int ring_buffer_first_scanline; int ring_buffer_first_scanline;
int ring_buffer_last_scanline; int ring_buffer_last_scanline;
int ring_buffer_begin_index; int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
float* ring_buffer; float* ring_buffer;
float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
@ -551,16 +552,17 @@ typedef struct
int encode_buffer_size; int encode_buffer_size;
} stbir__info; } stbir__info;
static const float stbir__max_uint8_as_float = 255.0f;
static const float stbir__max_uint16_as_float = 65535.0f;
static const double stbir__max_uint32_as_float = 4294967295.0;
static stbir__inline int stbir__min(int a, int b) static stbir__inline int stbir__min(int a, int b)
{ {
return a < b ? a : b; return a < b ? a : b;
} }
static stbir__inline int stbir__max(int a, int b)
{
return a > b ? a : b;
}
static stbir__inline float stbir__saturate(float x) static stbir__inline float stbir__saturate(float x)
{ {
if (x < 0) if (x < 0)
@ -1027,7 +1029,7 @@ static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radi
*out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
} }
static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
{ {
int i; int i;
float total_filter = 0; float total_filter = 0;
@ -1077,7 +1079,7 @@ static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbi
} }
} }
static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
{ {
int i; int i;
@ -1107,7 +1109,7 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
} }
} }
static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
{ {
int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
@ -1184,7 +1186,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
// Each scan line uses the same kernel values so we should calculate the kernel // Each scan line uses the same kernel values so we should calculate the kernel
// values once and then we can use them for every scan line. // values once and then we can use them for every scan line.
static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
{ {
int n; int n;
int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
@ -1201,7 +1203,7 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
stbir__calculate_coefficients_upsample(stbir_info, filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
} }
} }
else else
@ -1217,10 +1219,10 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
stbir__calculate_coefficients_downsample(stbir_info, filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
} }
stbir__normalize_downsample_coefficients(stbir_info, contributors, coefficients, filter, scale_ratio, shift, input_size, output_size); stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
} }
} }
@ -1270,7 +1272,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / 255; decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
} }
break; break;
@ -1283,7 +1285,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / 255; decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
} }
break; break;
@ -1293,7 +1295,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535; decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
} }
break; break;
@ -1303,10 +1305,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535); decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / 65535; decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
} }
break; break;
@ -1316,7 +1318,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295); decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
} }
break; break;
@ -1326,10 +1328,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295)); decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / 4294967295); decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
} }
break; break;
@ -1411,6 +1413,8 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
int ring_buffer_index; int ring_buffer_index;
float* ring_buffer; float* ring_buffer;
stbir_info->ring_buffer_last_scanline = n;
if (stbir_info->ring_buffer_begin_index < 0) if (stbir_info->ring_buffer_begin_index < 0)
{ {
ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
@ -1418,24 +1422,21 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
} }
else else
{ {
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline) + 1) % stbir_info->vertical_filter_pixel_width; ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
} }
ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
stbir_info->ring_buffer_last_scanline = n;
return ring_buffer; return ring_buffer;
} }
static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n, float* output_buffer) static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
{ {
int x, k; int x, k;
int output_w = stbir_info->output_w; int output_w = stbir_info->output_w;
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
int channels = stbir_info->channels; int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info); float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
@ -1515,12 +1516,10 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
} }
} }
static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n, float* output_buffer) static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
{ {
int x, k; int x, k;
int input_w = stbir_info->input_w; int input_w = stbir_info->input_w;
int output_w = stbir_info->output_w;
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
int channels = stbir_info->channels; int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info); float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
@ -1654,9 +1653,9 @@ static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
// Now resample it into the ring buffer. // Now resample it into the ring buffer.
if (stbir__use_width_upsampling(stbir_info)) if (stbir__use_width_upsampling(stbir_info))
stbir__resample_horizontal_upsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n)); stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
else else
stbir__resample_horizontal_downsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n)); stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
// Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
} }
@ -1670,17 +1669,17 @@ static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n
// Now resample it into the horizontal buffer. // Now resample it into the horizontal buffer.
if (stbir__use_width_upsampling(stbir_info)) if (stbir__use_width_upsampling(stbir_info))
stbir__resample_horizontal_upsample(stbir_info, n, stbir_info->horizontal_buffer); stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
else else
stbir__resample_horizontal_downsample(stbir_info, n, stbir_info->horizontal_buffer); stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
// Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
} }
// Get the specified scan line from the ring buffer. // Get the specified scan line from the ring buffer.
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_size, int ring_buffer_length) static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
{ {
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_size; int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
} }
@ -1715,19 +1714,23 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
// build a table of all channels that need colorspace correction, so // build a table of all channels that need colorspace correction, so
// we don't perform colorspace correction on channels that don't need it. // we don't perform colorspace correction on channels that don't need it.
for (x=0, num_nonalpha=0; x < channels; ++x) for (x = 0, num_nonalpha = 0; x < channels; ++x)
{
if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
nonalpha[num_nonalpha++] = x; {
nonalpha[num_nonalpha++] = (stbir_uint16)x;
}
}
#define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
#define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
#ifdef STBIR__SATURATE_INT #ifdef STBIR__SATURATE_INT
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 )) #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
#define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535)) #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
#else #else
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 ) #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
#define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535) #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
#endif #endif
switch (decode) switch (decode)
@ -1782,7 +1785,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < num_nonalpha; n++) for (n = 0; n < num_nonalpha; n++)
{ {
int index = pixel_index + nonalpha[n]; int index = pixel_index + nonalpha[n];
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535); ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
} }
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
@ -1799,7 +1802,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++) for (n = 0; n < channels; n++)
{ {
int index = pixel_index + n; int index = pixel_index + n;
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * 4294967295); ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
} }
} }
break; break;
@ -1812,11 +1815,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < num_nonalpha; n++) for (n = 0; n < num_nonalpha; n++)
{ {
int index = pixel_index + nonalpha[n]; int index = pixel_index + nonalpha[n];
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295); ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
} }
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295); ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
} }
break; break;
@ -1855,7 +1858,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
} }
} }
static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out) static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
{ {
int x, k; int x, k;
int output_w = stbir_info->output_w; int output_w = stbir_info->output_w;
@ -1865,7 +1868,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
int alpha_channel = stbir_info->alpha_channel; int alpha_channel = stbir_info->alpha_channel;
int type = stbir_info->type; int type = stbir_info->type;
int colorspace = stbir_info->colorspace; int colorspace = stbir_info->colorspace;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width; int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
void* output_data = stbir_info->output_data; void* output_data = stbir_info->output_data;
float* encode_buffer = stbir_info->encode_buffer; float* encode_buffer = stbir_info->encode_buffer;
int decode = STBIR__DECODE(type, colorspace); int decode = STBIR__DECODE(type, colorspace);
@ -1876,7 +1879,6 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
float* ring_buffer = stbir_info->ring_buffer; float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1, output_row_start; int n0,n1, output_row_start;
@ -1900,7 +1902,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) for (x = 0; x < output_w; ++x)
{ {
@ -1913,7 +1915,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) for (x = 0; x < output_w; ++x)
{ {
@ -1927,7 +1929,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) for (x = 0; x < output_w; ++x)
{ {
@ -1942,7 +1944,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) for (x = 0; x < output_w; ++x)
{ {
@ -1958,7 +1960,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) for (x = 0; x < output_w; ++x)
{ {
@ -1973,16 +1975,14 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
} }
static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out) static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
{ {
int x, k; int x, k;
int output_w = stbir_info->output_w; int output_w = stbir_info->output_w;
int output_h = stbir_info->output_h;
stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
float* vertical_coefficients = stbir_info->vertical_coefficients; float* vertical_coefficients = stbir_info->vertical_coefficients;
int channels = stbir_info->channels; int channels = stbir_info->channels;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width; int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
void* output_data = stbir_info->output_data;
float* horizontal_buffer = stbir_info->horizontal_buffer; float* horizontal_buffer = stbir_info->horizontal_buffer;
int coefficient_width = stbir_info->vertical_coefficient_width; int coefficient_width = stbir_info->vertical_coefficient_width;
int contributor = n + stbir_info->vertical_filter_pixel_margin; int contributor = n + stbir_info->vertical_filter_pixel_margin;
@ -1990,7 +1990,6 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
float* ring_buffer = stbir_info->ring_buffer; float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1; int n0,n1;
@ -2005,7 +2004,7 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
int coefficient_group = coefficient_width * contributor; int coefficient_group = coefficient_width * contributor;
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length); float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
switch (channels) { switch (channels) {
case 1: case 1:
@ -2071,7 +2070,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
STBIR_ASSERT(in_last_scanline - in_first_scanline <= stbir_info->vertical_filter_pixel_width); STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (stbir_info->ring_buffer_begin_index >= 0) if (stbir_info->ring_buffer_begin_index >= 0)
{ {
@ -2090,7 +2089,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
else else
{ {
stbir_info->ring_buffer_first_scanline++; stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width; stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
} }
} }
} }
@ -2103,7 +2102,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
// Now all buffers should be ready to write a row of vertical sampling. // Now all buffers should be ready to write a row of vertical sampling.
stbir__resample_vertical_upsample(stbir_info, y, in_first_scanline, in_last_scanline, in_center_of_out); stbir__resample_vertical_upsample(stbir_info, y);
STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
} }
@ -2148,7 +2147,7 @@ static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessar
else else
{ {
stbir_info->ring_buffer_first_scanline++; stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width; stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
} }
} }
} }
@ -2172,7 +2171,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
STBIR_ASSERT(out_last_scanline - out_first_scanline <= stbir_info->vertical_filter_pixel_width); STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (out_last_scanline < 0 || out_first_scanline >= output_h) if (out_last_scanline < 0 || out_first_scanline >= output_h)
continue; continue;
@ -2189,7 +2188,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
// Now the horizontal buffer is ready to write to all ring buffer rows. // Now the horizontal buffer is ready to write to all ring buffer rows.
stbir__resample_vertical_downsample(stbir_info, y, out_first_scanline, out_last_scanline, out_center_of_in); stbir__resample_vertical_downsample(stbir_info, y);
} }
stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
@ -2246,13 +2245,16 @@ static stbir_uint32 stbir__calculate_memory(stbir__info *info)
info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
// One extra entry because floating point precision problems sometimes cause an extra to be necessary.
info->ring_buffer_num_entries = filter_height + 1;
info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
info->ring_buffer_size = info->output_w * info->channels * filter_height * sizeof(float); info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
info->encode_buffer_size = info->output_w * info->channels * sizeof(float); info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
STBIR_ASSERT(info->horizontal_filter != 0); STBIR_ASSERT(info->horizontal_filter != 0);
@ -2390,8 +2392,8 @@ static int stbir__resize_allocated(stbir__info *info,
// This signals that the ring buffer is empty // This signals that the ring buffer is empty
info->ring_buffer_begin_index = -1; info->ring_buffer_begin_index = -1;
stbir__calculate_filters(info, info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
stbir__calculate_filters(info, info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
STBIR_PROGRESS_REPORT(0); STBIR_PROGRESS_REPORT(0);
@ -2578,3 +2580,45 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
} }
#endif // STB_IMAGE_RESIZE_IMPLEMENTATION #endif // STB_IMAGE_RESIZE_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -1,4 +1,4 @@
/* stb_image_write - v1.03 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -104,12 +104,11 @@ CREDITS:
Filip Wasil Filip Wasil
Thatcher Ulrich Thatcher Ulrich
github:poppolopoppo github:poppolopoppo
Patrick Boettcher
LICENSE LICENSE
This software is dual-licensed to the public domain and under the following See end of file for license information.
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
*/ */
@ -294,10 +293,8 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
s->func(s->context, &d[comp - 1], 1); s->func(s->context, &d[comp - 1], 1);
switch (comp) { switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
case 1: case 1:
s->func(s->context,d,1);
break;
case 2:
if (expand_mono) if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else else
@ -897,6 +894,7 @@ static unsigned char stbiw__paeth(int a, int b, int c)
return STBIW_UCHAR(c); return STBIW_UCHAR(c);
} }
// @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) unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{ {
int ctype[5] = { -1, 0, 4, 2, 6 }; int ctype[5] = { -1, 0, 4, 2, 6 };
@ -913,10 +911,10 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
for (j=0; j < y; ++j) { 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 ? mapping : firstmap; int *mymap = (j != 0) ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff; int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) { for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) { for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
int type = mymap[k],est=0; int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j; unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i) for (i=0; i < n; ++i)
@ -1018,6 +1016,9 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.04 (2017-03-03)
monochrome BMP expansion
1.03 ???
1.02 (2016-04-02) 1.02 (2016-04-02)
avoid allocating large structures on the stack avoid allocating large structures on the stack
1.01 (2016-01-16) 1.01 (2016-01-16)
@ -1047,3 +1048,45 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
first public release first public release
0.90 first internal release 0.90 first internal release
*/ */
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -1,4 +1,4 @@
// stb_rect_pack.h - v0.10 - public domain - rectangle packing // stb_rect_pack.h - v0.11 - public domain - rectangle packing
// Sean Barrett 2014 // Sean Barrett 2014
// //
// Useful for e.g. packing rectangular textures into an atlas. // Useful for e.g. packing rectangular textures into an atlas.
@ -27,11 +27,14 @@
// Sean Barrett // Sean Barrett
// Minor features // Minor features
// Martins Mozeiko // Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes // Bugfixes / warning fixes
// Jeremy Jaussaud // Jeremy Jaussaud
// //
// Version history: // Version history:
// //
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings // 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
@ -43,9 +46,7 @@
// //
// LICENSE // LICENSE
// //
// This software is dual-licensed to the public domain and under the following // See end of file for license information.
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -77,7 +78,7 @@ typedef int stbrp_coord;
typedef unsigned short stbrp_coord; typedef unsigned short stbrp_coord;
#endif #endif
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type // Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there // 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them. // are 'num_rects' many of them.
@ -98,6 +99,9 @@ STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int
// arrays will probably produce worse packing results than calling it // arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is // a single time with the full rectangle array, but the option is
// available. // available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect struct stbrp_rect
{ {
@ -544,9 +548,9 @@ static int rect_original_order(const void *a, const void *b)
#define STBRP__MAXVAL 0xffff #define STBRP__MAXVAL 0xffff
#endif #endif
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{ {
int i; int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting // we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) { for (i=0; i < num_rects; ++i) {
@ -576,8 +580,56 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
// unsort // unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags // set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
} }
#endif #endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -1,4 +1,4 @@
// stb_truetype.h - v1.14 - public domain // stb_truetype.h - v1.15 - 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:
@ -50,10 +50,13 @@
// Higor Euripedes // Higor Euripedes
// Thomas Fields // Thomas Fields
// Derek Vinyard // Derek Vinyard
// Cort Stratton
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts, num-fonts-in-TTC function // 1.15 (2017-03-03) make more arguments const
// 1.14 (2017-01-16) num-fonts-in-TTC function
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
// 1.11 (2016-04-02) fix unused-variable warning // 1.11 (2016-04-02) fix unused-variable warning
// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
@ -69,9 +72,7 @@
// //
// LICENSE // LICENSE
// //
// This software is dual-licensed to the public domain and under the following // See end of file for license information.
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
// //
// USAGE // USAGE
// //
@ -494,7 +495,7 @@ typedef struct
float x1,y1,s1,t1; // bottom-right float x1,y1,s1,t1; // bottom-right
} stbtt_aligned_quad; } stbtt_aligned_quad;
STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space float *xpos, float *ypos, // pointers to current position in screen pixel space
stbtt_aligned_quad *q, // output: quad to draw stbtt_aligned_quad *q, // output: quad to draw
@ -594,7 +595,7 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
// To use with PackFontRangesGather etc., you must set it before calls // To use with PackFontRangesGather etc., you must set it before calls
// call to PackFontRangesGatherRects. // call to PackFontRangesGatherRects.
STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space float *xpos, float *ypos, // pointers to current position in screen pixel space
stbtt_aligned_quad *q, // output: quad to draw stbtt_aligned_quad *q, // output: quad to draw
@ -3287,11 +3288,11 @@ static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // fo
return bottom_y; return bottom_y;
} }
STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
{ {
float d3d_bias = opengl_fillrule ? 0 : -0.5f; float d3d_bias = opengl_fillrule ? 0 : -0.5f;
float ipw = 1.0f / pw, iph = 1.0f / ph; float ipw = 1.0f / pw, iph = 1.0f / ph;
stbtt_bakedchar *b = chardata + char_index; const stbtt_bakedchar *b = chardata + char_index;
int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
@ -3735,10 +3736,10 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontda
return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
} }
STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
{ {
float ipw = 1.0f / pw, iph = 1.0f / ph; float ipw = 1.0f / pw, iph = 1.0f / ph;
stbtt_packedchar *b = chardata + char_index; const stbtt_packedchar *b = chardata + char_index;
if (align_to_integer) { if (align_to_integer) {
float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
@ -4016,3 +4017,45 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
// 0.2 (2009-03-11) Fix unsigned/signed char warnings // 0.2 (2009-03-11) Fix unsigned/signed char warnings
// 0.1 (2009-03-09) First public release // 0.1 (2009-03-09) First public release
// //
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -162,21 +162,23 @@
#endif #endif
#ifndef STB_VORBIS_NO_CRT #ifndef STB_VORBIS_NO_CRT
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh))
#include <malloc.h> // find definition of alloca if it's not in stdlib.h:
#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) #if defined(_MSC_VER) || defined(__MINGW32__)
#include <alloca.h> #include <malloc.h>
#endif #endif
#endif #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
#include <alloca.h>
#endif
#else // STB_VORBIS_NO_CRT #else // STB_VORBIS_NO_CRT
#define NULL 0 #define NULL 0
#define malloc(s) 0 #define malloc(s) 0
#define free(s) ((void) 0) #define free(s) ((void) 0)
#define realloc(s) 0 #define realloc(s) 0
#endif // STB_VORBIS_NO_CRT #endif // STB_VORBIS_NO_CRT
#include <limits.h> #include <limits.h>
@ -597,17 +599,18 @@ static int ilog(int32 n)
{ {
static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
if (n < 0) return 0; // signed n returns 0
// 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)
if (n < (1 << 14)) if (n < (1 << 14))
if (n < (1 << 4)) return 0 + log2_4[n ]; if (n < (1 << 4)) return 0 + log2_4[n ];
else if (n < (1 << 9)) return 5 + log2_4[n >> 5]; else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
else return 10 + log2_4[n >> 10]; else return 10 + log2_4[n >> 10];
else if (n < (1 << 24)) else if (n < (1 << 24))
if (n < (1 << 19)) return 15 + log2_4[n >> 15]; if (n < (1 << 19)) return 15 + log2_4[n >> 15];
else return 20 + log2_4[n >> 20]; else return 20 + log2_4[n >> 20];
else if (n < (1 << 29)) return 25 + log2_4[n >> 25]; else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
else if (n < (1 << 31)) return 30 + log2_4[n >> 30]; else return 30 + log2_4[n >> 30];
else return 0; // signed n returns 0
} }
#ifndef M_PI #ifndef M_PI
@ -880,13 +883,13 @@ static void neighbors(uint16 *x, int n, int *plow, int *phigh)
// this has been repurposed so y is now the original index instead of y // this has been repurposed so y is now the original index instead of y
typedef struct typedef struct
{ {
uint16 x,y; uint16 x,id;
} Point; } stbv__floor_ordering;
static int STBV_CDECL point_compare(const void *p, const void *q) static int STBV_CDECL point_compare(const void *p, const void *q)
{ {
Point *a = (Point *) p; stbv__floor_ordering *a = (stbv__floor_ordering *) p;
Point *b = (Point *) q; stbv__floor_ordering *b = (stbv__floor_ordering *) q;
return a->x < b->x ? -1 : a->x > b->x; return a->x < b->x ? -1 : a->x > b->x;
} }
@ -3095,11 +3098,13 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
return right - left; return right - left;
} }
static void vorbis_pump_first_frame(stb_vorbis *f) static int vorbis_pump_first_frame(stb_vorbis *f)
{ {
int len, right, left; int len, right, left, res;
if (vorbis_decode_packet(f, &len, &left, &right)) res = vorbis_decode_packet(f, &len, &left, &right);
if (res)
vorbis_finish_frame(f, len, left, right); vorbis_finish_frame(f, len, left, right);
return res;
} }
#ifndef STB_VORBIS_NO_PUSHDATA_API #ifndef STB_VORBIS_NO_PUSHDATA_API
@ -3482,7 +3487,7 @@ static int start_decoder(vorb *f)
g->book_list[j] = get_bits(f,8); g->book_list[j] = get_bits(f,8);
return error(f, VORBIS_feature_not_supported); return error(f, VORBIS_feature_not_supported);
} else { } else {
Point p[31*8+2]; stbv__floor_ordering p[31*8+2];
Floor1 *g = &f->floor_config[i].floor1; Floor1 *g = &f->floor_config[i].floor1;
int max_class = -1; int max_class = -1;
g->partitions = get_bits(f, 5); g->partitions = get_bits(f, 5);
@ -3518,11 +3523,11 @@ static int start_decoder(vorb *f)
// precompute the sorting // precompute the sorting
for (j=0; j < g->values; ++j) { for (j=0; j < g->values; ++j) {
p[j].x = g->Xlist[j]; p[j].x = g->Xlist[j];
p[j].y = j; p[j].id = j;
} }
qsort(p, g->values, sizeof(p[0]), point_compare); qsort(p, g->values, sizeof(p[0]), point_compare);
for (j=0; j < g->values; ++j) for (j=0; j < g->values; ++j)
g->sorted_order[j] = (uint8) p[j].y; g->sorted_order[j] = (uint8) p[j].id;
// precompute the neighbors // precompute the neighbors
for (j=2; j < g->values; ++j) { for (j=2; j < g->values; ++j) {
int low,hi; int low,hi;
@ -4226,8 +4231,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
// starting from the start is handled differently // starting from the start is handled differently
if (sample_number <= left.last_decoded_sample) { if (sample_number <= left.last_decoded_sample) {
stb_vorbis_seek_start(f); if (stb_vorbis_seek_start(f))
return 1; return 1;
return 0;
} }
while (left.page_end != right.page_start) { while (left.page_end != right.page_start) {
@ -4328,7 +4334,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
skip(f, f->segments[i]); skip(f, f->segments[i]);
// start decoding (optimizable - this frame is generally discarded) // start decoding (optimizable - this frame is generally discarded)
vorbis_pump_first_frame(f); if (!vorbis_pump_first_frame(f))
return 0;
if (f->current_loc > sample_number)
return error(f, VORBIS_seek_failed);
return 1; return 1;
error: error:
@ -4419,14 +4428,14 @@ int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
return 1; return 1;
} }
void stb_vorbis_seek_start(stb_vorbis *f) int stb_vorbis_seek_start(stb_vorbis *f)
{ {
if (IS_PUSH_MODE(f)) { error(f, VORBIS_invalid_api_mixing); return; } if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); }
set_file_offset(f, f->first_audio_page_offset); set_file_offset(f, f->first_audio_page_offset);
f->previous_length = 0; f->previous_length = 0;
f->first_decode = TRUE; f->first_decode = TRUE;
f->next_seg = -1; f->next_seg = -1;
vorbis_pump_first_frame(f); return vorbis_pump_first_frame(f);
} }
unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
@ -4591,6 +4600,7 @@ stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *err
if (f) { if (f) {
*f = p; *f = p;
vorbis_pump_first_frame(f); vorbis_pump_first_frame(f);
if (error) *error = VORBIS__no_error;
return f; return f;
} }
} }
@ -4956,6 +4966,7 @@ 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.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;
avoid discarding last frame of audio data avoid discarding last frame of audio data
@ -5008,3 +5019,46 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
*/ */
#endif // STB_VORBIS_HEADER_ONLY #endif // STB_VORBIS_HEADER_ONLY
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

View file

@ -1,4 +1,4 @@
// Ogg Vorbis audio decoder - v1.09 - public domain // Ogg Vorbis audio decoder - v1.10 - 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.
@ -9,12 +9,7 @@
// //
// LICENSE // LICENSE
// //
// This software is dual-licensed to the public domain and under the following // See end of file for license information.
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// No warranty for any purpose is expressed or implied by the author (nor
// by RAD Game Tools). Report bugs and send enhancements to the author.
// //
// Limitations: // Limitations:
// //
@ -37,6 +32,7 @@
// manxorist@github saga musix // manxorist@github saga musix
// //
// Partial history: // Partial history:
// 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
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame // 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const // 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
@ -280,7 +276,7 @@ extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
// do not need to seek to EXACTLY the target sample when using get_samples_*, // do not need to seek to EXACTLY the target sample when using get_samples_*,
// you can also use seek_frame(). // you can also use seek_frame().
extern void stb_vorbis_seek_start(stb_vorbis *f); extern int stb_vorbis_seek_start(stb_vorbis *f);
// this function is equivalent to stb_vorbis_seek(f,0) // this function is equivalent to stb_vorbis_seek(f,0)
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * raylib.gestures - Gestures system, gestures processing based on input events (touch/mouse)
* *
* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables) * NOTE: Memory footprint of this library is aproximately 128 bytes (global variables)
* *
@ -24,7 +24,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -147,7 +147,7 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
// Functions required to query time on Windows // Functions required to query time on Windows
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
#elif defined(__linux) #elif defined(__linux__)
#include <sys/time.h> // Required for: timespec #include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime() #include <time.h> // Required for: clock_gettime()
#endif #endif
@ -213,8 +213,11 @@ static unsigned int enabledGestures = 0b0000001111111111;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE)
// Some required math functions provided by raymath.h
static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition);
static float Vector2Distance(Vector2 v1, Vector2 v2); static float Vector2Distance(Vector2 v1, Vector2 v2);
#endif
static double GetCurrentTime(void); static double GetCurrentTime(void);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -477,13 +480,11 @@ float GetGesturePinchAngle(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE)
// Returns angle from two-points vector with X-axis // Returns angle from two-points vector with X-axis
static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) static float Vector2Angle(Vector2 v1, Vector2 v2)
{ {
float angle; float angle = angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
angle = atan2f(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x)*(180.0f/PI);
if (angle < 0) angle += 360.0f; if (angle < 0) angle += 360.0f;
@ -502,6 +503,7 @@ static float Vector2Distance(Vector2 v1, Vector2 v2)
return result; return result;
} }
#endif
// Time measure returned are milliseconds // Time measure returned are milliseconds
static double GetCurrentTime(void) static double GetCurrentTime(void)
@ -517,7 +519,7 @@ static double GetCurrentTime(void)
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
#endif #endif
#if defined(__linux) #if defined(__linux__)
// NOTE: Only for Linux-based systems // NOTE: Only for Linux-based systems
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);

View file

@ -1,17 +1,19 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.models - Basic functions to draw 3d shapes and 3d models * raylib.models - Basic functions to deal with 3d shapes and 3d models
* *
* CONFIGURATION: * CONFIGURATION:
* *
* #define SUPPORT_FILEFORMAT_OBJ / SUPPORT_LOAD_OBJ * #define SUPPORT_FILEFORMAT_OBJ
* Selected desired fileformats to be supported for loading.
* *
* #define SUPPORT_FILEFORMAT_MTL * #define SUPPORT_FILEFORMAT_MTL
* Selected desired fileformats to be supported for loading.
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -30,6 +32,12 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_OBJ
#define SUPPORT_FILEFORMAT_MTL
//-------------------------------------------------
#include "raylib.h" #include "raylib.h"
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
@ -61,8 +69,12 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_OBJ)
static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data
#endif
#if defined(SUPPORT_FILEFORMAT_MTL)
static Material LoadMTL(const char *fileName); // Load MTL material data static Material LoadMTL(const char *fileName); // Load MTL material data
#endif
static Mesh GenMeshHeightmap(Image image, Vector3 size); static Mesh GenMeshHeightmap(Image image, Vector3 size);
static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
@ -580,8 +592,11 @@ Mesh LoadMesh(const char *fileName)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
if (strcmp(GetExtension(fileName), "obj") == 0) mesh = LoadOBJ(fileName); #if defined(SUPPORT_FILEFORMAT_OBJ)
else TraceLog(WARNING, "[%s] Mesh extension not recognized, it can't be loaded", fileName); if (IsFileExtension(fileName, ".obj")) mesh = LoadOBJ(fileName);
#else
TraceLog(WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName);
#endif
if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded"); if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded");
else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
@ -592,13 +607,13 @@ Mesh LoadMesh(const char *fileName)
} }
// Load mesh from vertex data // Load mesh from vertex data
// NOTE: All vertex data arrays must be same size: numVertex // NOTE: All vertex data arrays must be same size: vertexCount
Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData) Mesh LoadMeshEx(int vertexCount, float *vData, float *vtData, float *vnData, Color *cData)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
mesh.vertexCount = numVertex; mesh.vertexCount = vertexCount;
mesh.triangleCount = numVertex/3; mesh.triangleCount = vertexCount/3;
mesh.vertices = vData; mesh.vertices = vData;
mesh.texcoords = vtData; mesh.texcoords = vtData;
mesh.texcoords2 = NULL; mesh.texcoords2 = NULL;
@ -690,8 +705,11 @@ Material LoadMaterial(const char *fileName)
{ {
Material material = { 0 }; Material material = { 0 };
if (strcmp(GetExtension(fileName), "mtl") == 0) material = LoadMTL(fileName); #if defined(SUPPORT_FILEFORMAT_MTL)
else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName); if (IsFileExtension(fileName, ".mtl")) material = LoadMTL(fileName);
#else
TraceLog(WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName);
#endif
return material; return material;
} }
@ -736,9 +754,9 @@ static 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 numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels int triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
mesh.vertexCount = numTriangles*3; mesh.vertexCount = 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));
@ -1588,6 +1606,7 @@ BoundingBox CalculateBoundingBox(Mesh mesh)
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_OBJ)
// Load OBJ mesh data // Load OBJ mesh data
static Mesh LoadOBJ(const char *fileName) static Mesh LoadOBJ(const char *fileName)
{ {
@ -1596,10 +1615,10 @@ static Mesh LoadOBJ(const char *fileName)
char dataType; char dataType;
char comments[200]; char comments[200];
int numVertex = 0; int vertexCount = 0;
int numNormals = 0; int normalCount = 0;
int numTexCoords = 0; int texcoordCount = 0;
int numTriangles = 0; int triangleCount = 0;
FILE *objFile; FILE *objFile;
@ -1611,7 +1630,7 @@ static Mesh LoadOBJ(const char *fileName)
return mesh; return mesh;
} }
// First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles // First reading pass: Get vertexCount, normalCount, texcoordCount, triangleCount
// NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
// NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
while (!feof(objFile)) while (!feof(objFile))
@ -1635,40 +1654,40 @@ static Mesh LoadOBJ(const char *fileName)
if (dataType == 't') // Read texCoord if (dataType == 't') // Read texCoord
{ {
numTexCoords++; texcoordCount++;
fgets(comments, 200, objFile); fgets(comments, 200, objFile);
} }
else if (dataType == 'n') // Read normals else if (dataType == 'n') // Read normals
{ {
numNormals++; normalCount++;
fgets(comments, 200, objFile); fgets(comments, 200, objFile);
} }
else // Read vertex else // Read vertex
{ {
numVertex++; vertexCount++;
fgets(comments, 200, objFile); fgets(comments, 200, objFile);
} }
} break; } break;
case 'f': case 'f':
{ {
numTriangles++; triangleCount++;
fgets(comments, 200, objFile); fgets(comments, 200, objFile);
} break; } break;
default: break; default: break;
} }
} }
TraceLog(DEBUG, "[%s] Model num vertices: %i", fileName, numVertex); TraceLog(DEBUG, "[%s] Model vertices: %i", fileName, vertexCount);
TraceLog(DEBUG, "[%s] Model num texcoords: %i", fileName, numTexCoords); TraceLog(DEBUG, "[%s] Model texcoords: %i", fileName, texcoordCount);
TraceLog(DEBUG, "[%s] Model num normals: %i", fileName, numNormals); TraceLog(DEBUG, "[%s] Model normals: %i", fileName, normalCount);
TraceLog(DEBUG, "[%s] Model num triangles: %i", fileName, numTriangles); TraceLog(DEBUG, "[%s] Model triangles: %i", fileName, triangleCount);
// Once we know the number of vertices to store, we create required arrays // Once we know the number of vertices to store, we create required arrays
Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3)); Vector3 *midVertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3));
Vector3 *midNormals = NULL; Vector3 *midNormals = NULL;
if (numNormals > 0) midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3)); if (normalCount > 0) midNormals = (Vector3 *)malloc(normalCount*sizeof(Vector3));
Vector2 *midTexCoords = NULL; Vector2 *midTexCoords = NULL;
if (numTexCoords > 0) midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2)); if (texcoordCount > 0) midTexCoords = (Vector2 *)malloc(texcoordCount*sizeof(Vector2));
int countVertex = 0; int countVertex = 0;
int countNormals = 0; int countNormals = 0;
@ -1719,7 +1738,7 @@ static Mesh LoadOBJ(const char *fileName)
// At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals // At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals
// Now we can organize that data into our Mesh struct // Now we can organize that data into our Mesh struct
mesh.vertexCount = numTriangles*3; mesh.vertexCount = triangleCount*3;
// Additional arrays to store vertex data as floats // Additional arrays to store vertex data as floats
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
@ -1731,11 +1750,11 @@ static Mesh LoadOBJ(const char *fileName)
int tcCounter = 0; // Used to count texcoords float by float int tcCounter = 0; // Used to count texcoords float by float
int nCounter = 0; // Used to count normals float by float int nCounter = 0; // Used to count normals float by float
int vNum[3], vtNum[3], vnNum[3]; // Used to store triangle indices for v, vt, vn int vCount[3], vtCount[3], vnCount[3]; // Used to store triangle indices for v, vt, vn
rewind(objFile); // Return to the beginning of the file, to read again rewind(objFile); // Return to the beginning of the file, to read again
if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName); if (normalCount == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
// Third reading pass: Get faces (triangles) data and fill VertexArray // Third reading pass: Get faces (triangles) data and fill VertexArray
while (!feof(objFile)) while (!feof(objFile))
@ -1749,43 +1768,43 @@ static Mesh LoadOBJ(const char *fileName)
{ {
// NOTE: It could be that OBJ does not have normals or texcoords defined! // NOTE: It could be that OBJ does not have normals or texcoords defined!
if ((numNormals == 0) && (numTexCoords == 0)) fscanf(objFile, "%i %i %i", &vNum[0], &vNum[1], &vNum[2]); if ((normalCount == 0) && (texcoordCount == 0)) fscanf(objFile, "%i %i %i", &vCount[0], &vCount[1], &vCount[2]);
else if (numNormals == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vNum[0], &vtNum[0], &vNum[1], &vtNum[1], &vNum[2], &vtNum[2]); else if (normalCount == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vCount[0], &vtCount[0], &vCount[1], &vtCount[1], &vCount[2], &vtCount[2]);
else if (numTexCoords == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vNum[0], &vnNum[0], &vNum[1], &vnNum[1], &vNum[2], &vnNum[2]); else if (texcoordCount == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vCount[0], &vnCount[0], &vCount[1], &vnCount[1], &vCount[2], &vnCount[2]);
else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vNum[0], &vtNum[0], &vnNum[0], &vNum[1], &vtNum[1], &vnNum[1], &vNum[2], &vtNum[2], &vnNum[2]); else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vCount[0], &vtCount[0], &vnCount[0], &vCount[1], &vtCount[1], &vnCount[1], &vCount[2], &vtCount[2], &vnCount[2]);
mesh.vertices[vCounter] = midVertices[vNum[0]-1].x; mesh.vertices[vCounter] = midVertices[vCount[0]-1].x;
mesh.vertices[vCounter + 1] = midVertices[vNum[0]-1].y; mesh.vertices[vCounter + 1] = midVertices[vCount[0]-1].y;
mesh.vertices[vCounter + 2] = midVertices[vNum[0]-1].z; mesh.vertices[vCounter + 2] = midVertices[vCount[0]-1].z;
vCounter += 3; vCounter += 3;
mesh.vertices[vCounter] = midVertices[vNum[1]-1].x; mesh.vertices[vCounter] = midVertices[vCount[1]-1].x;
mesh.vertices[vCounter + 1] = midVertices[vNum[1]-1].y; mesh.vertices[vCounter + 1] = midVertices[vCount[1]-1].y;
mesh.vertices[vCounter + 2] = midVertices[vNum[1]-1].z; mesh.vertices[vCounter + 2] = midVertices[vCount[1]-1].z;
vCounter += 3; vCounter += 3;
mesh.vertices[vCounter] = midVertices[vNum[2]-1].x; mesh.vertices[vCounter] = midVertices[vCount[2]-1].x;
mesh.vertices[vCounter + 1] = midVertices[vNum[2]-1].y; mesh.vertices[vCounter + 1] = midVertices[vCount[2]-1].y;
mesh.vertices[vCounter + 2] = midVertices[vNum[2]-1].z; mesh.vertices[vCounter + 2] = midVertices[vCount[2]-1].z;
vCounter += 3; vCounter += 3;
if (numNormals > 0) if (normalCount > 0)
{ {
mesh.normals[nCounter] = midNormals[vnNum[0]-1].x; mesh.normals[nCounter] = midNormals[vnCount[0]-1].x;
mesh.normals[nCounter + 1] = midNormals[vnNum[0]-1].y; mesh.normals[nCounter + 1] = midNormals[vnCount[0]-1].y;
mesh.normals[nCounter + 2] = midNormals[vnNum[0]-1].z; mesh.normals[nCounter + 2] = midNormals[vnCount[0]-1].z;
nCounter += 3; nCounter += 3;
mesh.normals[nCounter] = midNormals[vnNum[1]-1].x; mesh.normals[nCounter] = midNormals[vnCount[1]-1].x;
mesh.normals[nCounter + 1] = midNormals[vnNum[1]-1].y; mesh.normals[nCounter + 1] = midNormals[vnCount[1]-1].y;
mesh.normals[nCounter + 2] = midNormals[vnNum[1]-1].z; mesh.normals[nCounter + 2] = midNormals[vnCount[1]-1].z;
nCounter += 3; nCounter += 3;
mesh.normals[nCounter] = midNormals[vnNum[2]-1].x; mesh.normals[nCounter] = midNormals[vnCount[2]-1].x;
mesh.normals[nCounter + 1] = midNormals[vnNum[2]-1].y; mesh.normals[nCounter + 1] = midNormals[vnCount[2]-1].y;
mesh.normals[nCounter + 2] = midNormals[vnNum[2]-1].z; mesh.normals[nCounter + 2] = midNormals[vnCount[2]-1].z;
nCounter += 3; nCounter += 3;
} }
else else
{ {
// 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 = VectorCrossProduct(VectorSubtract(midVertices[vNum[1]-1], midVertices[vNum[0]-1]), VectorSubtract(midVertices[vNum[2]-1], midVertices[vNum[0]-1])); Vector3 norm = VectorCrossProduct(VectorSubtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), VectorSubtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1]));
VectorNormalize(&norm); VectorNormalize(&norm);
mesh.normals[nCounter] = norm.x; mesh.normals[nCounter] = norm.x;
@ -1802,18 +1821,18 @@ static Mesh LoadOBJ(const char *fileName)
nCounter += 3; nCounter += 3;
} }
if (numTexCoords > 0) if (texcoordCount > 0)
{ {
// NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work! // NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work!
// NOTE: Texture coordinates are Y flipped upside-down // NOTE: Texture coordinates are Y flipped upside-down
mesh.texcoords[tcCounter] = midTexCoords[vtNum[0]-1].x; mesh.texcoords[tcCounter] = midTexCoords[vtCount[0]-1].x;
mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[0]-1].y; mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[0]-1].y;
tcCounter += 2; tcCounter += 2;
mesh.texcoords[tcCounter] = midTexCoords[vtNum[1]-1].x; mesh.texcoords[tcCounter] = midTexCoords[vtCount[1]-1].x;
mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[1]-1].y; mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[1]-1].y;
tcCounter += 2; tcCounter += 2;
mesh.texcoords[tcCounter] = midTexCoords[vtNum[2]-1].x; mesh.texcoords[tcCounter] = midTexCoords[vtCount[2]-1].x;
mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[2]-1].y; mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[2]-1].y;
tcCounter += 2; tcCounter += 2;
} }
} break; } break;
@ -1824,7 +1843,77 @@ static Mesh LoadOBJ(const char *fileName)
fclose(objFile); fclose(objFile);
// Security check, just in case no normals or no texcoords defined in OBJ // Security check, just in case no normals or no texcoords defined in OBJ
if (numTexCoords == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f; 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 = VectorSubtract(v1, v0);
Vector3 deltaPos2 = VectorSubtract(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 = VectorSubtract(t1, t2);
VectorScale(&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 = VectorSubtract(b1, b2);
VectorScale(&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);
@ -1836,7 +1925,9 @@ static Mesh LoadOBJ(const char *fileName)
return mesh; return mesh;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_MTL)
// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/) // Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/)
// NOTE: Texture map parameters are not supported // NOTE: Texture map parameters are not supported
static Material LoadMTL(const char *fileName) static Material LoadMTL(const char *fileName)
@ -2000,3 +2091,4 @@ static Material LoadMTL(const char *fileName)
return material; return material;
} }
#endif

View file

@ -1,43 +1,45 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib v1.7.0 (www.raylib.com) * raylib v1.7.0
* *
* A simple and easy-to-use library to learn videogames programming * A simple and easy-to-use library to learn videogames programming (www.raylib.com)
* *
* FEATURES: * FEATURES:
* Library written in plain C code (C99) * - Library written in plain C code (C99)
* Uses PascalCase/camelCase notation * - Uses PascalCase/camelCase notation
* Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) * - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0)
* 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 bitmap fonts, AngelCode fonts, TTF) * - Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF)
* Multiple textures support, including compressed formats and mipmaps generation * - Multiple textures support, including compressed formats and mipmaps generation
* Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps * - Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps
* Powerful math module for Vector, Matrix and Quaternion operations: [raymath] * - Powerful math module for Vector, Matrix and Quaternion operations: [raymath]
* Audio loading and playing with streaming support and mixing channels [audio] * - Audio loading and playing with streaming support and mixing channels: [audio]
* VR stereo rendering support with configurable HMD device parameters * - VR stereo rendering support with configurable HMD device parameters
* Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1 * - Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1
* Custom color palette for fancy visuals on raywhite background * - Custom color palette for fancy visuals on raywhite background
* Minimal external dependencies (GLFW3, OpenGL, OpenAL) * - Minimal external dependencies (GLFW3, OpenGL, OpenAL)
* Complete binding for Lua [rlua] * - Complete bindings for Lua, Go and Pascal
* *
* NOTES: * NOTES:
* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) * 32bit Colors - All defined color are always RGBA (struct Color is 4 byte)
* One custom default font could be loaded automatically when InitWindow() [core] * One custom default font could be loaded automatically when InitWindow() [core]
* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads * If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads
* If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined) * If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined)
* *
* DEPENDENCIES: * DEPENDENCIES:
* GLFW3 (www.glfw.org) for window/context management and input [core] * GLFW3 (www.glfw.org) for window/context management and input [core]
* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] * GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl]
* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures] * OpenAL Soft for audio device/context management [audio]
* stb_image_write (Sean Barret) for image writting (PNG) [utils] *
* stb_truetype (Sean Barret) for ttf fonts loading [text] * OPTIONAL DEPENDENCIES:
* stb_vorbis (Sean Barret) for ogg audio loading [audio] * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures]
* jar_xm (Joshua Reisenauer) for XM audio module loading [audio] * stb_image_write (Sean Barret) for image writting (PNG) [utils]
* jar_mod (Joshua Reisenauer) for MOD audio module loading [audio] * stb_truetype (Sean Barret) for ttf fonts loading [text]
* dr_flac (David Reid) for FLAC audio file loading [audio] * stb_vorbis (Sean Barret) for ogg audio loading [audio]
* OpenAL Soft for audio device/context management [audio] * jar_xm (Joshua Reisenauer) for XM audio module loading [audio]
* tinfl for data decompression (DEFLATE algorithm) [utils] * jar_mod (Joshua Reisenauer) for MOD audio module loading [audio]
* dr_flac (David Reid) for FLAC audio file loading [audio]
* tinfl for data decompression (DEFLATE algorithm) [rres]
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
@ -45,7 +47,7 @@
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software: * BSD-like license that allows static linking with closed source software:
* *
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2013-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -72,7 +74,6 @@
//#define PLATFORM_ANDROID // Android device //#define PLATFORM_ANDROID // Android device
//#define PLATFORM_RPI // Raspberry Pi //#define PLATFORM_RPI // Raspberry Pi
//#define PLATFORM_WEB // HTML5 (emscripten, asm.js) //#define PLATFORM_WEB // HTML5 (emscripten, asm.js)
//#define RLGL_OCULUS_SUPPORT // Oculus Rift CV1 (complementary to PLATFORM_DESKTOP)
// Security check in case no PLATFORM_* defined // Security check in case no PLATFORM_* defined
#if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB) #if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB)
@ -293,7 +294,7 @@
#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo) #define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#ifndef __cplusplus #ifndef __cplusplus
// Boolean type // Boolean type
@ -514,6 +515,34 @@ typedef struct AudioStream {
unsigned int buffers[2]; // OpenAL audio buffers (double buffering) unsigned int buffers[2]; // OpenAL audio buffers (double buffering)
} AudioStream; } AudioStream;
// rRES data returned when reading a resource,
// it contains all required data for user (24 byte)
typedef struct RRESData {
unsigned int type; // Resource type (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
void *data; // Resource data pointer (4 byte)
} RRESData;
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES;
//----------------------------------------------------------------------------------
// Enumerators Definition
//----------------------------------------------------------------------------------
// Trace log type
typedef enum {
INFO = 0,
WARNING,
ERROR,
DEBUG,
OTHER
} LogType;
// Texture formats // Texture formats
// NOTE: Support depends on OpenGL version and platform // NOTE: Support depends on OpenGL version and platform
typedef enum { typedef enum {
@ -550,10 +579,18 @@ typedef enum {
} TextureFilterMode; } TextureFilterMode;
// Texture parameters: wrap mode // Texture parameters: wrap mode
typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; typedef enum {
WRAP_REPEAT = 0,
WRAP_CLAMP,
WRAP_MIRROR
} TextureWrapMode;
// Color blending modes (pre-defined) // Color blending modes (pre-defined)
typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; typedef enum {
BLEND_ALPHA = 0,
BLEND_ADDITIVE,
BLEND_MULTIPLIED
} BlendMode;
// Gestures type // Gestures type
// NOTE: It could be used as flags to enable only some gestures // NOTE: It could be used as flags to enable only some gestures
@ -593,19 +630,6 @@ typedef enum {
HMD_FOVE_VR, HMD_FOVE_VR,
} VrDevice; } VrDevice;
// rRES data returned when reading a resource,
// it contains all required data for user (24 byte)
typedef struct RRESData {
unsigned int type; // Resource type (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
void *data; // Resource data pointer (4 byte)
} RRESData;
// RRESData type // RRESData type
typedef enum { typedef enum {
RRES_TYPE_RAW = 0, RRES_TYPE_RAW = 0,
@ -618,9 +642,6 @@ typedef enum {
RRES_TYPE_DIRECTORY RRES_TYPE_DIRECTORY
} RRESDataType; } RRESDataType;
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
@ -685,9 +706,11 @@ RLAPI float *MatrixToFloat(Matrix mat); // Converts Ma
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
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
RLAPI void SetConfigFlags(char flags); // Setup some window configuration flags
RLAPI void ShowLogo(void); // Activates raylib logo at startup (can be done with flags) RLAPI void ShowLogo(void); // Activates raylib logo at startup (can be done with flags)
//RLAPI void TraceLog(int logType, const char *text, ...); // Trace log messages showing (INFO, WARNING, ERROR, DEBUG) RLAPI void SetConfigFlags(char flags); // Setup some window configuration flags
RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (INFO, WARNING, ERROR, DEBUG)
RLAPI void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
RLAPI bool IsFileDropped(void); // Check if a file have been dropped into window RLAPI bool IsFileDropped(void); // Check if a file have been dropped into window
RLAPI char **GetDroppedFiles(int *count); // Retrieve dropped files into window RLAPI char **GetDroppedFiles(int *count); // Retrieve dropped files into window
@ -843,7 +866,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM)
RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from TTF font file with generation parameters RLAPI SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from file with extended parameters
RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM) RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM)
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)
@ -889,7 +912,6 @@ RLAPI void UnloadMesh(Mesh *mesh);
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM) RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
RLAPI Material LoadMaterial(const char *fileName); // Load material from file RLAPI Material LoadMaterial(const char *fileName); // Load material from file
RLAPI Material LoadMaterialEx(Shader shader, Texture2D diffuse, Color color); // Load material from basic shading data
RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)

View file

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raymath v1.0 - Some useful functions to work with Vector3, Matrix and Quaternions * raymath v1.0 - Math functions to work with Vector3, Matrix and Quaternions
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -112,45 +112,67 @@ typedef struct Quaternion {
#ifndef RAYMATH_EXTERN_INLINE #ifndef RAYMATH_EXTERN_INLINE
//------------------------------------------------------------------------------------
// Functions Declaration - math utils
//------------------------------------------------------------------------------------
RMDEF float Clamp(float value, float min, float max); // Clamp float value
//------------------------------------------------------------------------------------
// Functions Declaration to work with Vector2
//------------------------------------------------------------------------------------
RMDEF Vector2 Vector2Zero(void); // Vector with components value 0.0f
RMDEF Vector2 Vector2One(void); // Vector with components value 1.0f
RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2); // Add two vectors (v1 + v2)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2); // Subtract two vectors (v1 - v2)
RMDEF float Vector2Lenght(Vector2 v); // Calculate vector lenght
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2); // Calculate two vectors dot product
RMDEF float Vector2Distance(Vector2 v1, Vector2 v2); // Calculate distance between two vectors
RMDEF float Vector2Angle(Vector2 v1, Vector2 v2); // Calculate angle between two vectors in X-axis
RMDEF void Vector2Scale(Vector2 *v, float scale); // Scale vector (multiply by value)
RMDEF void Vector2Negate(Vector2 *v); // Negate vector
RMDEF void Vector2Divide(Vector2 *v, float div); // Divide vector by a float value
RMDEF void Vector2Normalize(Vector2 *v); // Normalize provided vector
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration to work with Vector3 // Functions Declaration to work with Vector3
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2); // Add two vectors RMDEF Vector3 VectorZero(void); // Vector with components value 0.0f
RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2); // Substract two vectors RMDEF Vector3 VectorOne(void); // Vector with components value 1.0f
RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2); // Calculate two vectors cross product RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2); // Add two vectors
RMDEF Vector3 VectorPerpendicular(Vector3 v); // Calculate one vector perpendicular vector RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2); // Substract two vectors
RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2); // Calculate two vectors dot product RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2); // Calculate two vectors cross product
RMDEF float VectorLength(const Vector3 v); // Calculate vector lenght RMDEF Vector3 VectorPerpendicular(Vector3 v); // Calculate one vector perpendicular vector
RMDEF void VectorScale(Vector3 *v, float scale); // Scale provided vector RMDEF float VectorLength(const Vector3 v); // Calculate vector lenght
RMDEF void VectorNegate(Vector3 *v); // Negate provided vector (invert direction) RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2); // Calculate two vectors dot product
RMDEF void VectorNormalize(Vector3 *v); // Normalize provided vector RMDEF float VectorDistance(Vector3 v1, Vector3 v2); // Calculate distance between two points
RMDEF float VectorDistance(Vector3 v1, Vector3 v2); // Calculate distance between two points RMDEF void VectorScale(Vector3 *v, float scale); // Scale provided vector
RMDEF void VectorNegate(Vector3 *v); // Negate provided vector (invert direction)
RMDEF void VectorNormalize(Vector3 *v); // Normalize provided vector
RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix
RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors
RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal
RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components
RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components
RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components RMDEF Vector3 VectorBarycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc
RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components
RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration to work with Matrix // Functions Declaration to work with Matrix
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RMDEF float MatrixDeterminant(Matrix mat); // Compute matrix determinant RMDEF float MatrixDeterminant(Matrix mat); // Compute matrix determinant
RMDEF float MatrixTrace(Matrix mat); // Returns the trace of the matrix (sum of the values along the diagonal) RMDEF float MatrixTrace(Matrix mat); // Returns the trace of the matrix (sum of the values along the diagonal)
RMDEF void MatrixTranspose(Matrix *mat); // Transposes provided matrix RMDEF void MatrixTranspose(Matrix *mat); // Transposes provided matrix
RMDEF void MatrixInvert(Matrix *mat); // Invert provided matrix RMDEF void MatrixInvert(Matrix *mat); // Invert provided matrix
RMDEF void MatrixNormalize(Matrix *mat); // Normalize provided matrix RMDEF void MatrixNormalize(Matrix *mat); // Normalize provided matrix
RMDEF Matrix MatrixIdentity(void); // Returns identity matrix RMDEF Matrix MatrixIdentity(void); // Returns identity matrix
RMDEF Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices RMDEF Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices
RMDEF Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right) RMDEF Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right)
RMDEF Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix RMDEF Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix
RMDEF Matrix MatrixRotate(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis (angle in radians) RMDEF Matrix MatrixRotate(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis (angle in radians)
RMDEF Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians) RMDEF Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians) RMDEF Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians) RMDEF Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians)
RMDEF Matrix MatrixScale(float x, float y, float z); // Returns scaling matrix RMDEF Matrix MatrixScale(float x, float y, float z); // Returns scaling matrix
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right); // Returns two matrix multiplication RMDEF Matrix MatrixMultiply(Matrix left, Matrix right); // Returns two matrix multiplication
RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far); // Returns perspective projection matrix RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far); // Returns perspective projection matrix
RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far); // Returns perspective projection matrix RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far); // Returns perspective projection matrix
RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far); // Returns orthographic projection matrix RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far); // Returns orthographic projection matrix
@ -159,9 +181,9 @@ RMDEF Matrix MatrixLookAt(Vector3 position, Vector3 target, Vector3 up); // Ret
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration to work with Quaternions // Functions Declaration to work with Quaternions
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RMDEF float QuaternionLength(Quaternion quat); // Compute the length of a quaternion RMDEF float QuaternionLength(Quaternion quat); // Compute the length of a quaternion
RMDEF void QuaternionNormalize(Quaternion *q); // Normalize provided quaternion RMDEF void QuaternionNormalize(Quaternion *q); // Normalize provided quaternion
RMDEF void QuaternionInvert(Quaternion *quat); // Invert provided quaternion RMDEF void QuaternionInvert(Quaternion *quat); // Invert provided quaternion
RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions
RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix
@ -179,32 +201,113 @@ RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transfo
#include <math.h> // Required for: sinf(), cosf(), tan(), fabs() #include <math.h> // Required for: sinf(), cosf(), tan(), fabs()
//----------------------------------------------------------------------------------
// Module Functions Definition - Utils math
//----------------------------------------------------------------------------------
// Clamp float value
RMDEF float Clamp(float value, float min, float max)
{
const float res = value < min ? min : value;
return res > max ? max : res;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Vector2 math
//----------------------------------------------------------------------------------
// Vector with components value 0.0f
RMDEF Vector2 Vector2Zero(void) { return (Vector2){ 0.0f, 0.0f }; }
// Vector with components value 1.0f
RMDEF Vector2 Vector2One(void) { return (Vector2){ 1.0f, 1.0f }; }
// Add two vectors (v1 + v2)
RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
{
return (Vector2){ v1.x + v2.x, v1.y + v2.y };
}
// Subtract two vectors (v1 - v2)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
{
return (Vector2){ v1.x - v2.x, v1.y - v2.y };
}
// Calculate vector lenght
RMDEF float Vector2Lenght(Vector2 v)
{
return sqrtf((v.x*v.x) + (v.y*v.y));
}
// Calculate two vectors dot product
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
{
return (v1.x*v2.x + v1.y*v2.y);
}
// Calculate distance between two vectors
RMDEF float Vector2Distance(Vector2 v1, Vector2 v2)
{
return sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
}
// Calculate angle from two vectors in X-axis
RMDEF float Vector2Angle(Vector2 v1, Vector2 v2)
{
float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
if (angle < 0) angle += 360.0f;
return angle;
}
// Scale vector (multiply by value)
RMDEF void Vector2Scale(Vector2 *v, float scale)
{
v->x *= scale;
v->y *= scale;
}
// Negate vector
RMDEF void Vector2Negate(Vector2 *v)
{
v->x = -v->x;
v->y = -v->y;
}
// Divide vector by a float value
RMDEF void Vector2Divide(Vector2 *v, float div)
{
*v = (Vector2){v->x/div, v->y/div};
}
// Normalize provided vector
RMDEF void Vector2Normalize(Vector2 *v)
{
Vector2Divide(v, Vector2Lenght(*v));
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Vector3 math // Module Functions Definition - Vector3 math
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Vector with components value 0.0f
RMDEF Vector3 VectorZero(void) { return (Vector3){ 0.0f, 0.0f, 0.0f }; }
// Vector with components value 1.0f
RMDEF Vector3 VectorOne(void) { return (Vector3){ 1.0f, 1.0f, 1.0f }; }
// Add two vectors // Add two vectors
RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2) RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2)
{ {
Vector3 result; return (Vector3){ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
result.x = v1.x + v2.x;
result.y = v1.y + v2.y;
result.z = v1.z + v2.z;
return result;
} }
// Substract two vectors // Substract two vectors
RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2) RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2)
{ {
Vector3 result; return (Vector3){ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
result.x = v1.x - v2.x;
result.y = v1.y - v2.y;
result.z = v1.z - v2.z;
return result;
} }
// Calculate two vectors cross product // Calculate two vectors cross product
@ -233,7 +336,7 @@ RMDEF Vector3 VectorPerpendicular(Vector3 v)
cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f}; cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f};
} }
if(fabsf(v.z) < min) if (fabsf(v.z) < min)
{ {
cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f}; cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f};
} }
@ -243,24 +346,26 @@ RMDEF Vector3 VectorPerpendicular(Vector3 v)
return result; return result;
} }
// Calculate two vectors dot product
RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2)
{
float result;
result = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
return result;
}
// Calculate vector lenght // Calculate vector lenght
RMDEF float VectorLength(const Vector3 v) RMDEF float VectorLength(const Vector3 v)
{ {
float length; return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
}
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); // Calculate two vectors dot product
RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2)
{
return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
}
return length; // Calculate distance between two vectors
RMDEF float VectorDistance(Vector3 v1, Vector3 v2)
{
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
float dz = v2.z - v1.z;
return sqrtf(dx*dx + dy*dy + dz*dz);
} }
// Scale provided vector // Scale provided vector
@ -295,19 +400,18 @@ RMDEF void VectorNormalize(Vector3 *v)
v->z *= ilength; v->z *= ilength;
} }
// Calculate distance between two points // Transforms a Vector3 by a given Matrix
RMDEF float VectorDistance(Vector3 v1, Vector3 v2) // TODO: Review math (matrix transpose required?)
RMDEF void VectorTransform(Vector3 *v, Matrix mat)
{ {
float result; float x = v->x;
float y = v->y;
float z = v->z;
float dx = v2.x - v1.x; v->x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
float dy = v2.y - v1.y; v->y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
float dz = v2.z - v1.z; v->z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;
};
result = sqrtf(dx*dx + dy*dy + dz*dz);
return result;
}
// Calculate linear interpolation between two vectors // Calculate linear interpolation between two vectors
RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount) RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
@ -339,27 +443,6 @@ RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal)
return result; return result;
} }
// Transforms a Vector3 by a given Matrix
// TODO: Review math (matrix transpose required?)
RMDEF void VectorTransform(Vector3 *v, Matrix mat)
{
float x = v->x;
float y = v->y;
float z = v->z;
v->x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
v->y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
v->z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;
};
// Return a Vector3 init to zero
RMDEF Vector3 VectorZero(void)
{
Vector3 zero = { 0.0f, 0.0f, 0.0f };
return zero;
}
// Return min value for each pair of components // Return min value for each pair of components
RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2) RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2)
{ {
@ -386,7 +469,7 @@ RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2)
// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c) // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
// NOTE: Assumes P is on the plane of the triangle // NOTE: Assumes P is on the plane of the triangle
RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) RMDEF Vector3 VectorBarycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
{ {
//Vector v0 = b - a, v1 = c - a, v2 = p - a; //Vector v0 = b - a, v1 = c - a, v2 = p - a;
@ -663,49 +746,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
return result; return result;
} }
/*
// Another implementation for MatrixRotate...
RMDEF Matrix MatrixRotate(float angle, float x, float y, float z)
{
Matrix result = MatrixIdentity();
float c = cosf(angle); // cosine
float s = sinf(angle); // sine
float c1 = 1.0f - c; // 1 - c
float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
m1 = result.m1, m5 = result.m5, m9 = result.m9, m13 = result.m13,
m2 = result.m2, m6 = result.m6, m10 = result.m10, m14 = result.m14;
// build rotation matrix
float r0 = x*x*c1 + c;
float r1 = x*y*c1 + z*s;
float r2 = x*z*c1 - y*s;
float r4 = x*y*c1 - z*s;
float r5 = y*y*c1 + c;
float r6 = y*z*c1 + x*s;
float r8 = x*z*c1 + y*s;
float r9 = y*z*c1 - x*s;
float r10= z*z*c1 + c;
// multiply rotation matrix
result.m0 = r0*m0 + r4*m1 + r8*m2;
result.m1 = r1*m0 + r5*m1 + r9*m2;
result.m2 = r2*m0 + r6*m1 + r10*m2;
result.m4 = r0*m4 + r4*m5 + r8*m6;
result.m5 = r1*m4 + r5*m5 + r9*m6;
result.m6 = r2*m4 + r6*m5 + r10*m6;
result.m8 = r0*m8 + r4*m9 + r8*m10;
result.m9 = r1*m8 + r5*m9 + r9*m10;
result.m10 = r2*m8 + r6*m9 + r10*m10;
result.m12 = r0*m12+ r4*m13 + r8*m14;
result.m13 = r1*m12+ r5*m13 + r9*m14;
result.m14 = r2*m12+ r6*m13 + r10*m14;
return result;
}
*/
// Returns x-rotation matrix (angle in radians) // Returns x-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateX(float angle) RMDEF Matrix MatrixRotateX(float angle)
{ {

View file

@ -2,10 +2,8 @@
* *
* rlgl - raylib OpenGL abstraction layer * rlgl - raylib OpenGL abstraction layer
* *
* DESCRIPTION: * rlgl is a wrapper for multiple OpenGL versions (1.1, 2.1, 3.3 Core, ES 2.0) to
* * pseudo-OpenGL 1.1 style functions (rlVertex, rlTranslate, rlRotate...).
* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to
* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0).
* *
* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal * When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal
* VBO buffers (and VAOs if available). It requires calling 3 functions: * VBO buffers (and VAOs if available). It requires calling 3 functions:
@ -16,32 +14,19 @@
* CONFIGURATION: * CONFIGURATION:
* *
* #define GRAPHICS_API_OPENGL_11 * #define GRAPHICS_API_OPENGL_11
* Use OpenGL 1.1 backend
*
* #define GRAPHICS_API_OPENGL_21 * #define GRAPHICS_API_OPENGL_21
* Use OpenGL 2.1 backend
*
* #define GRAPHICS_API_OPENGL_33 * #define GRAPHICS_API_OPENGL_33
* Use OpenGL 3.3 Core profile backend
*
* #define GRAPHICS_API_OPENGL_ES2 * #define GRAPHICS_API_OPENGL_ES2
* Use OpenGL ES 2.0 backend * Use selected OpenGL backend
* *
* #define RLGL_STANDALONE * #define RLGL_STANDALONE
* Use rlgl as standalone library (no raylib dependency) * Use rlgl as standalone library (no raylib dependency)
* *
* #define RLGL_NO_DISTORTION_SHADER * #define SUPPORT_VR_SIMULATOR
* Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion * Support VR simulation functionality (stereo rendering)
* *
* #define SUPPORT_SHADER_DEFAULT / ENABLE_SHADER_DEFAULT * #define SUPPORT_DISTORTION_SHADER
* * Include stereo rendering distortion shader (shader_distortion.h)
* #define SUPPORT_SHADER_DISTORTION
*
* #define SUPPORT_VR_SIMULATION
*
* #define SUPPORT_STEREO_RENDERING
*
* #define RLGL_NO_DEFAULT_SHADER
* *
* DEPENDENCIES: * DEPENDENCIES:
* raymath - 3D math functionality (Vector3, Matrix, Quaternion) * raymath - 3D math functionality (Vector3, Matrix, Quaternion)
@ -50,7 +35,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -69,6 +54,12 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_VR_SIMULATOR
#define SUPPORT_DISTORTION_SHADER
//-------------------------------------------------
#include "rlgl.h" #include "rlgl.h"
#include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on LoadText()] #include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on LoadText()]
@ -115,7 +106,7 @@
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()] #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()]
#endif #endif
#if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_DISTORTION_SHADER) #if !defined(GRAPHICS_API_OPENGL_11) && defined(SUPPORT_DISTORTION_SHADER)
#include "shader_distortion.h" // Distortion shader to be embedded #include "shader_distortion.h" // Distortion shader to be embedded
#endif #endif
@ -231,6 +222,7 @@ typedef struct DrawCall {
//Guint fboId; //Guint fboId;
} DrawCall; } DrawCall;
#if defined(SUPPORT_VR_SIMULATOR)
// Head-Mounted-Display device parameters // Head-Mounted-Display device parameters
typedef struct VrDeviceInfo { typedef struct VrDeviceInfo {
int hResolution; // HMD horizontal resolution in pixels int hResolution; // HMD horizontal resolution in pixels
@ -253,6 +245,7 @@ typedef struct VrStereoConfig {
Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices
Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices
} VrStereoConfig; } VrStereoConfig;
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
@ -266,7 +259,7 @@ static Matrix projection;
static Matrix *currentMatrix; static Matrix *currentMatrix;
static int currentMatrixMode; static int currentMatrixMode;
static DrawMode currentDrawMode; static int currentDrawMode;
static float currentDepth = -1.0f; static float currentDepth = -1.0f;
@ -295,7 +288,17 @@ static bool texCompETC1Supported = false; // ETC1 texture compression support
static bool texCompETC2Supported = false; // ETC2/EAC texture compression support static bool texCompETC2Supported = false; // ETC2/EAC texture compression support
static bool texCompPVRTSupported = false; // PVR texture compression support static bool texCompPVRTSupported = false; // PVR texture compression support
static bool texCompASTCSupported = false; // ASTC texture compression support static bool texCompASTCSupported = false; // ASTC texture compression support
#endif
#if defined(SUPPORT_VR_SIMULATOR)
// VR global variables
static VrDeviceInfo hmd; // Current VR device info
static VrStereoConfig vrConfig; // VR stereo configuration for simulator
static bool vrSimulatorReady = false; // VR simulator ready flag
static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag
// NOTE: This flag is useful to render data over stereo image (i.e. FPS)
#endif // defined(SUPPORT_VR_SIMULATOR)
#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Extension supported flag: Anisotropic filtering // Extension supported flag: Anisotropic filtering
static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support
@ -304,13 +307,6 @@ static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supp
// Extension supported flag: Clamp mirror wrap mode // Extension supported flag: Clamp mirror wrap mode
static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported
// VR global variables
static VrDeviceInfo hmd; // Current VR device info
static VrStereoConfig vrConfig; // VR stereo configuration for simulator
static bool vrSimulatorReady = false; // VR simulator ready flag
static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag
// NOTE: This flag is useful to render data over stereo image (i.e. FPS)
#if defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: VAO functionality is exposed through extensions (OES) // NOTE: VAO functionality is exposed through extensions (OES)
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays; static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays;
@ -348,13 +344,13 @@ static void UpdateDefaultBuffers(void); // Update default internal buffers (
static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data
static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU
// Configure stereo rendering (including distortion shader) with HMD device parameters #if defined(SUPPORT_VR_SIMULATOR)
static void SetStereoConfig(VrDeviceInfo info); static void SetStereoConfig(VrDeviceInfo info); // Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye
// Set internal projection and modelview matrix depending on eyes tracking data
static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView);
#endif #endif
#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight);
@ -1335,7 +1331,7 @@ Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view)
} }
// Convert image data to OpenGL texture (returns OpenGL valid Id) // Convert image data to OpenGL texture (returns OpenGL valid Id)
unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount) unsigned int rlglLoadTexture(void *data, int width, int height, int format, int mipmapCount)
{ {
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
@ -1343,39 +1339,39 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
// Check texture format support by OpenGL 1.1 (compressed textures not supported) // Check texture format support by OpenGL 1.1 (compressed textures not supported)
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
if (textureFormat >= 8) if (format >= COMPRESSED_DXT1_RGB)
{ {
TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats"); TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats");
return id; return id;
} }
#endif #endif
if ((!texCompDXTSupported) && ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT1_RGBA) || if ((!texCompDXTSupported) && ((format == COMPRESSED_DXT1_RGB) || (format == COMPRESSED_DXT1_RGBA) ||
(textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA))) (format == COMPRESSED_DXT3_RGBA) || (format == COMPRESSED_DXT5_RGBA)))
{ {
TraceLog(WARNING, "DXT compressed texture format not supported"); TraceLog(WARNING, "DXT compressed texture format not supported");
return id; return id;
} }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ((!texCompETC1Supported) && (textureFormat == COMPRESSED_ETC1_RGB)) if ((!texCompETC1Supported) && (format == COMPRESSED_ETC1_RGB))
{ {
TraceLog(WARNING, "ETC1 compressed texture format not supported"); TraceLog(WARNING, "ETC1 compressed texture format not supported");
return id; return id;
} }
if ((!texCompETC2Supported) && ((textureFormat == COMPRESSED_ETC2_RGB) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA))) if ((!texCompETC2Supported) && ((format == COMPRESSED_ETC2_RGB) || (format == COMPRESSED_ETC2_EAC_RGBA)))
{ {
TraceLog(WARNING, "ETC2 compressed texture format not supported"); TraceLog(WARNING, "ETC2 compressed texture format not supported");
return id; return id;
} }
if ((!texCompPVRTSupported) && ((textureFormat == COMPRESSED_PVRT_RGB) || (textureFormat == COMPRESSED_PVRT_RGBA))) if ((!texCompPVRTSupported) && ((format == COMPRESSED_PVRT_RGB) || (format == COMPRESSED_PVRT_RGBA)))
{ {
TraceLog(WARNING, "PVRT compressed texture format not supported"); TraceLog(WARNING, "PVRT compressed texture format not supported");
return id; return id;
} }
if ((!texCompASTCSupported) && ((textureFormat == COMPRESSED_ASTC_4x4_RGBA) || (textureFormat == COMPRESSED_ASTC_8x8_RGBA))) if ((!texCompASTCSupported) && ((format == COMPRESSED_ASTC_4x4_RGBA) || (format == COMPRESSED_ASTC_8x8_RGBA)))
{ {
TraceLog(WARNING, "ASTC compressed texture format not supported"); TraceLog(WARNING, "ASTC compressed texture format not supported");
return id; return id;
@ -1403,7 +1399,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE // GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE // GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
switch (textureFormat) switch (format)
{ {
case UNCOMPRESSED_GRAYSCALE: case UNCOMPRESSED_GRAYSCALE:
{ {
@ -1444,7 +1440,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
} }
#elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2) #elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
switch (textureFormat) switch (format)
{ {
case UNCOMPRESSED_GRAYSCALE: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break; case UNCOMPRESSED_GRAYSCALE: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_GRAY_ALPHA: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; case UNCOMPRESSED_GRAY_ALPHA: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
@ -2077,12 +2073,16 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
} }
int eyesCount = 1; int eyesCount = 1;
#if defined(SUPPORT_VR_SIMULATOR)
if (vrStereoRender) eyesCount = 2; if (vrStereoRender) eyesCount = 2;
#endif
for (int eye = 0; eye < eyesCount; eye++) for (int eye = 0; eye < eyesCount; eye++)
{ {
if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); if (eyesCount == 1) modelview = matModelView;
else modelview = matModelView; #if defined(SUPPORT_VR_SIMULATOR)
else SetStereoView(eye, matProjection, matModelView);
#endif
// Calculate model-view-projection matrix (MVP) // Calculate model-view-projection matrix (MVP)
Matrix matMVP = MatrixMultiply(modelview, projection); // Transform to screen-space coordinates Matrix matMVP = MatrixMultiply(modelview, projection); // Transform to screen-space coordinates
@ -2250,7 +2250,7 @@ void *rlglReadTexturePixels(Texture2D texture)
pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char)); pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char));
// NOTE: Despite FBO color texture is RGB, we read data as RGBA... reading as RGB doesn't work... o__O // NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture...
glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Re-attach internal FBO color texture before deleting it // Re-attach internal FBO color texture before deleting it
@ -2543,6 +2543,7 @@ void EndBlendMode(void)
BeginBlendMode(BLEND_ALPHA); BeginBlendMode(BLEND_ALPHA);
} }
#if defined(SUPPORT_VR_SIMULATOR)
// Init VR simulator for selected device // Init VR simulator for selected device
// NOTE: It modifies the global variable: VrDeviceInfo hmd // NOTE: It modifies the global variable: VrDeviceInfo hmd
void InitVrSimulator(int vrDevice) void InitVrSimulator(int vrDevice)
@ -2568,7 +2569,7 @@ void InitVrSimulator(int vrDevice)
hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2
hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3
TraceLog(WARNING, "Initializing VR Simulator (Oculus Rift DK2)"); TraceLog(INFO, "Initializing VR Simulator (Oculus Rift DK2)");
} }
else if ((vrDevice == HMD_DEFAULT_DEVICE) || (vrDevice == HMD_OCULUS_RIFT_CV1)) else if ((vrDevice == HMD_DEFAULT_DEVICE) || (vrDevice == HMD_OCULUS_RIFT_CV1))
{ {
@ -2595,11 +2596,11 @@ void InitVrSimulator(int vrDevice)
hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2
hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3
TraceLog(WARNING, "Initializing VR Simulator (Oculus Rift CV1)"); TraceLog(INFO, "Initializing VR Simulator (Oculus Rift CV1)");
} }
else else
{ {
TraceLog(WARNING, "VR Simulator doesn't support current device yet,"); TraceLog(WARNING, "VR Simulator doesn't support selected device parameters,");
TraceLog(WARNING, "using default VR Simulator parameters"); TraceLog(WARNING, "using default VR Simulator parameters");
} }
@ -2607,9 +2608,11 @@ void InitVrSimulator(int vrDevice)
// NOTE: screen size should match HMD aspect ratio // NOTE: screen size should match HMD aspect ratio
vrConfig.stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight); vrConfig.stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight);
#if defined(SUPPORT_DISTORTION_SHADER)
// Load distortion shader (initialized by default with Oculus Rift CV1 parameters) // Load distortion shader (initialized by default with Oculus Rift CV1 parameters)
vrConfig.distortionShader.id = LoadShaderProgram(vDistortionShaderStr, fDistortionShaderStr); vrConfig.distortionShader.id = LoadShaderProgram(vDistortionShaderStr, fDistortionShaderStr);
if (vrConfig.distortionShader.id != 0) LoadDefaultShaderLocations(&vrConfig.distortionShader); if (vrConfig.distortionShader.id != 0) LoadDefaultShaderLocations(&vrConfig.distortionShader);
#endif
SetStereoConfig(hmd); SetStereoConfig(hmd);
@ -2628,7 +2631,9 @@ void CloseVrSimulator(void)
if (vrSimulatorReady) if (vrSimulatorReady)
{ {
rlDeleteRenderTextures(vrConfig.stereoFbo); // Unload stereo framebuffer and texture rlDeleteRenderTextures(vrConfig.stereoFbo); // Unload stereo framebuffer and texture
#if defined(SUPPORT_DISTORTION_SHADER)
UnloadShader(vrConfig.distortionShader); // Unload distortion shader UnloadShader(vrConfig.distortionShader); // Unload distortion shader
#endif
} }
#endif #endif
} }
@ -2636,7 +2641,11 @@ void CloseVrSimulator(void)
// Detect if VR simulator is running // Detect if VR simulator is running
bool IsVrSimulatorReady(void) bool IsVrSimulatorReady(void)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
return vrSimulatorReady; return vrSimulatorReady;
#else
return false;
#endif
} }
// Enable/Disable VR experience (device or simulator) // Enable/Disable VR experience (device or simulator)
@ -2711,8 +2720,12 @@ void EndVrDrawing(void)
rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix
rlLoadIdentity(); // Reset internal modelview matrix rlLoadIdentity(); // Reset internal modelview matrix
#if defined(SUPPORT_DISTORTION_SHADER)
// Draw RenderTexture (stereoFbo) using distortion shader // Draw RenderTexture (stereoFbo) using distortion shader
currentShader = vrConfig.distortionShader; currentShader = vrConfig.distortionShader;
#else
currentShader = GetDefaultShader();
#endif
rlEnableTexture(vrConfig.stereoFbo.texture.id); rlEnableTexture(vrConfig.stereoFbo.texture.id);
@ -2758,6 +2771,7 @@ void EndVrDrawing(void)
} }
#endif #endif
} }
#endif // SUPPORT_VR_SIMULATOR
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
@ -3303,11 +3317,15 @@ static void DrawDefaultBuffers()
Matrix matModelView = modelview; Matrix matModelView = modelview;
int eyesCount = 1; int eyesCount = 1;
#if defined(SUPPORT_VR_SIMULATOR)
if (vrStereoRender) eyesCount = 2; if (vrStereoRender) eyesCount = 2;
#endif
for (int eye = 0; eye < eyesCount; eye++) for (int eye = 0; eye < eyesCount; eye++)
{ {
#if defined(SUPPORT_VR_SIMULATOR)
if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView);
#endif
// Set current shader and upload current MVP matrix // Set current shader and upload current MVP matrix
if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0))
@ -3513,6 +3531,7 @@ static void UnloadDefaultBuffers(void)
free(quads.indices); free(quads.indices);
} }
#if defined(SUPPORT_VR_SIMULATOR)
// Configure stereo rendering (including distortion shader) with HMD device parameters // Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetStereoConfig(VrDeviceInfo hmd) static void SetStereoConfig(VrDeviceInfo hmd)
{ {
@ -3547,6 +3566,7 @@ static void SetStereoConfig(VrDeviceInfo hmd)
TraceLog(DEBUG, "VR: Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]); TraceLog(DEBUG, "VR: Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]);
TraceLog(DEBUG, "VR: Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]); TraceLog(DEBUG, "VR: Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]);
#if defined(SUPPORT_DISTORTION_SHADER)
// Update distortion shader with lens and distortion-scale parameters // Update distortion shader with lens and distortion-scale parameters
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2);
@ -3557,6 +3577,7 @@ static void SetStereoConfig(VrDeviceInfo hmd)
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.distortionK, 4); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.distortionK, 4);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, 4); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, 4);
#endif
// Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)*RAD2DEG // Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)*RAD2DEG
// ...but with lens distortion it is increased (see Oculus SDK Documentation) // ...but with lens distortion it is increased (see Oculus SDK Documentation)
@ -3602,6 +3623,8 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView)
SetMatrixModelview(eyeModelView); SetMatrixModelview(eyeModelView);
SetMatrixProjection(eyeProjection); SetMatrixProjection(eyeProjection);
} }
#endif // defined(SUPPORT_VR_SIMULATOR)
#endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)

View file

@ -2,8 +2,8 @@
* *
* rlgl - raylib OpenGL abstraction layer * rlgl - raylib OpenGL abstraction layer
* *
* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to * rlgl is a wrapper for multiple OpenGL versions (1.1, 2.1, 3.3 Core, ES 2.0) to
* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). * pseudo-OpenGL 1.1 style functions (rlVertex, rlTranslate, rlRotate...).
* *
* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal * When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal
* VBO buffers (and VAOs if available). It requires calling 3 functions: * VBO buffers (and VAOs if available). It requires calling 3 functions:
@ -11,18 +11,29 @@
* rlglDraw() - Process internal buffers and send required draw calls * rlglDraw() - Process internal buffers and send required draw calls
* rlglClose() - De-initialize internal buffers data and other auxiliar resources * rlglClose() - De-initialize internal buffers data and other auxiliar resources
* *
* External libs: * CONFIGURATION:
*
* #define GRAPHICS_API_OPENGL_11
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
* #define GRAPHICS_API_OPENGL_ES2
* Use selected OpenGL backend
*
* #define RLGL_STANDALONE
* Use rlgl as standalone library (no raylib dependency)
*
* #define SUPPORT_VR_SIMULATION / SUPPORT_STEREO_RENDERING
* Support VR simulation functionality (stereo rendering)
*
* #define SUPPORT_SHADER_DISTORTION
* Include stereo rendering distortion shader (shader_distortion.h)
*
* DEPENDENCIES:
* raymath - 3D math functionality (Vector3, Matrix, Quaternion) * raymath - 3D math functionality (Vector3, Matrix, Quaternion)
* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) * GLAD - OpenGL extensions loading (OpenGL 3.3 Core only)
* *
* Module Configuration Flags:
* GRAPHICS_API_OPENGL_11 - Use OpenGL 1.1 backend
* GRAPHICS_API_OPENGL_21 - Use OpenGL 2.1 backend
* GRAPHICS_API_OPENGL_33 - Use OpenGL 3.3 Core profile backend
* GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend
*
* RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency)
* *
* LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
* *
@ -124,15 +135,21 @@
#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE #define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE
#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT #define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT
// Matrix modes (equivalent to OpenGL)
#define RL_MODELVIEW 0x1700 // GL_MODELVIEW
#define RL_PROJECTION 0x1701 // GL_PROJECTION
#define RL_TEXTURE 0x1702 // GL_TEXTURE
// Primitive assembly draw modes
#define RL_LINES 0x0001 // GL_LINES
#define RL_TRIANGLES 0x0004 // GL_TRIANGLES
#define RL_QUADS 0x0007 // GL_QUADS
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion;
typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode;
typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
typedef unsigned char byte; typedef unsigned char byte;
#if defined(RLGL_STANDALONE) #if defined(RLGL_STANDALONE)
@ -349,7 +366,7 @@ void rlglClose(void); // De-init rlgl
void rlglDraw(void); // Draw VAO/VBO void rlglDraw(void); // Draw VAO/VBO
void rlglLoadExtensions(void *loader); // Load OpenGL extensions void rlglLoadExtensions(void *loader); // Load OpenGL extensions
unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU unsigned int rlglLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
void rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture void rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture

View file

@ -1,8 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* rres - raylib Resource custom format management functions * rres v1.0 - raylib resource (rRES) custom fileformat management functions
*
* Basic functions to load/save rRES resource files
* *
* CONFIGURATION: * CONFIGURATION:
* *

View file

@ -13,7 +13,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.

View file

@ -5,12 +5,11 @@
* CONFIGURATION: * CONFIGURATION:
* *
* #define SUPPORT_FILEFORMAT_FNT * #define SUPPORT_FILEFORMAT_FNT
* #define SUPPORT_FILEFORMAT_TTF / INCLUDE_STB_TRUETYPE * #define SUPPORT_FILEFORMAT_TTF
* #define SUPPORT_FILEFORMAT_IMAGE_FONT
* 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
* *
* #define INCLUDE_DEFAULT_FONT / SUPPORT_DEFAULT_FONT * #define SUPPORT_DEFAULT_FONT
* *
* DEPENDENCIES: * DEPENDENCIES:
* stb_truetype - Load TTF file and rasterize characters data * stb_truetype - Load TTF file and rasterize characters data
@ -18,7 +17,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -37,6 +36,13 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default supported features
//-------------------------------------
#define SUPPORT_DEFAULT_FONT
#define SUPPORT_FILEFORMAT_FNT
#define SUPPORT_FILEFORMAT_TTF
//-------------------------------------
#include "raylib.h" #include "raylib.h"
#include <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
@ -44,12 +50,14 @@
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
#include "utils.h" // Required for: GetExtension() #include "utils.h" // Required for: fopen() Android mapping
// Following libs are used on LoadTTF() #if defined(SUPPORT_FILEFORMAT_TTF)
#define STBTT_STATIC // Define stb_truetype functions static to this module // Following libs are used on LoadTTF()
#define STB_TRUETYPE_IMPLEMENTATION #define STBTT_STATIC // Define stb_truetype functions static to this module
#include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() #define STB_TRUETYPE_IMPLEMENTATION
#include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap()
#endif
// Rectangle packing functions (not used at the moment) // Rectangle packing functions (not used at the moment)
//#define STB_RECT_PACK_IMPLEMENTATION //#define STB_RECT_PACK_IMPLEMENTATION
@ -61,8 +69,6 @@
#define MAX_FORMATTEXT_LENGTH 64 #define MAX_FORMATTEXT_LENGTH 64
#define MAX_SUBTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 64
#define BIT_CHECK(a,b) ((a) & (1 << (b)))
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -71,8 +77,10 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global variables // Global variables
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT)
static SpriteFont defaultFont; // Default font provided by raylib static SpriteFont 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
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by text) // Other Modules Functions Declaration (required by text)
@ -85,18 +93,28 @@ static SpriteFont defaultFont; // Default font provided by raylib
static int GetCharIndex(SpriteFont font, int letter); static int GetCharIndex(SpriteFont font, int letter);
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) #if defined(SUPPORT_FILEFORMAT_FNT)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif
#if defined(SUPPORT_FILEFORMAT_TTF)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data
#endif
#if defined(SUPPORT_DEFAULT_FONT)
extern void LoadDefaultFont(void); extern void LoadDefaultFont(void);
extern void UnloadDefaultFont(void); extern void UnloadDefaultFont(void);
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT)
// Load raylib default font
extern void LoadDefaultFont(void) extern void LoadDefaultFont(void)
{ {
#define BIT_CHECK(a,b) ((a) & (1 << (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
@ -241,16 +259,23 @@ extern void LoadDefaultFont(void)
TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
} }
// Unload raylib default font
extern void UnloadDefaultFont(void) extern void UnloadDefaultFont(void)
{ {
UnloadTexture(defaultFont.texture); UnloadTexture(defaultFont.texture);
free(defaultFont.chars); free(defaultFont.chars);
} }
#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() SpriteFont GetDefaultFont()
{ {
#if defined(SUPPORT_DEFAULT_FONT)
return defaultFont; return defaultFont;
#else
SpriteFont font = { 0 };
return font;
#endif
} }
// Load SpriteFont from file into GPU memory (VRAM) // Load SpriteFont from file into GPU memory (VRAM)
@ -264,10 +289,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
// Check file extension // Check file extension
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); // TODO: DELETE... SOON... if (IsFileExtension(fileName, ".rres"))
else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName);
else if (strcmp(GetExtension(fileName),"rres") == 0)
{ {
// TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA)
RRES rres = LoadResource(fileName, 0); RRES rres = LoadResource(fileName, 0);
@ -293,6 +315,12 @@ SpriteFont LoadSpriteFont(const char *fileName)
// TODO: Do not free rres.data memory (chars info data!) // TODO: Do not free rres.data memory (chars info data!)
//UnloadResource(rres[0]); //UnloadResource(rres[0]);
} }
#if defined(SUPPORT_FILEFORMAT_TTF)
else if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
#endif
#if defined(SUPPORT_FILEFORMAT_FNT)
else if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName);
#endif
else else
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
@ -313,11 +341,12 @@ SpriteFont LoadSpriteFont(const char *fileName)
// Load SpriteFont from TTF font file with generation parameters // Load SpriteFont 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 LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars)
{ {
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
if (strcmp(GetExtension(fileName),"ttf") == 0) #if defined(SUPPORT_FILEFORMAT_TTF)
if (IsFileExtension(fileName, ".ttf"))
{ {
if ((fontChars == NULL) || (charsCount == 0)) if ((fontChars == NULL) || (charsCount == 0))
{ {
@ -331,6 +360,7 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount,
} }
else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars); else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars);
} }
#endif
if (spriteFont.texture.id == 0) if (spriteFont.texture.id == 0)
{ {
@ -345,7 +375,7 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount,
void UnloadSpriteFont(SpriteFont spriteFont) void UnloadSpriteFont(SpriteFont spriteFont)
{ {
// NOTE: Make sure spriteFont is not default font (fallback) // NOTE: Make sure spriteFont is not default font (fallback)
if (spriteFont.texture.id != defaultFont.texture.id) if (spriteFont.texture.id != GetDefaultFont().texture.id)
{ {
UnloadTexture(spriteFont.texture); UnloadTexture(spriteFont.texture);
free(spriteFont.chars); free(spriteFont.chars);
@ -360,7 +390,7 @@ void UnloadSpriteFont(SpriteFont spriteFont)
void DrawText(const char *text, int posX, int posY, int fontSize, Color color) void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
{ {
// Check if default font has been loaded // Check if default font has been loaded
if (defaultFont.texture.id != 0) if (GetDefaultFont().texture.id != 0)
{ {
Vector2 position = { (float)posX, (float)posY }; Vector2 position = { (float)posX, (float)posY };
@ -471,7 +501,7 @@ int MeasureText(const char *text, int fontSize)
Vector2 vec = { 0.0f, 0.0f }; Vector2 vec = { 0.0f, 0.0f };
// Check if default font has been loaded // Check if default font has been loaded
if (defaultFont.texture.id != 0) if (GetDefaultFont().texture.id != 0)
{ {
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;
@ -688,144 +718,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
return spriteFont; return spriteFont;
} }
// Load a rBMF font file (raylib BitMap Font) #if defined(SUPPORT_FILEFORMAT_FNT)
static SpriteFont LoadRBMF(const char *fileName)
{
// rBMF Info Header (16 bytes)
typedef struct {
char id[4]; // rBMF file identifier
char version; // rBMF file version
// 4 MSB --> main version
// 4 LSB --> subversion
char firstChar; // First character in the font
// NOTE: Depending on charDataType, it could be useless
short imgWidth; // Image width - always POT (power-of-two)
short imgHeight; // Image height - always POT (power-of-two)
short numChars; // Number of characters contained
short charHeight; // Characters height - the same for all characters
char compType; // Compression type:
// 4 MSB --> image data compression
// 4 LSB --> chars data compression
char charsDataType; // Char data type provided
} rbmfInfoHeader;
SpriteFont spriteFont = { 0 };
// REMOVE SOON!!!
/*
rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL;
unsigned char *rbmfCharWidthData = NULL;
int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
FILE *rbmfFile = fopen(fileName, "rb"); // Define a pointer to bitmap file and open it in read-binary mode
if (rbmfFile == NULL)
{
TraceLog(WARNING, "[%s] rBMF font file could not be opened, using default font", fileName);
spriteFont = GetDefaultFont();
}
else
{
fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
TraceLog(DEBUG, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
spriteFont.numChars = (int)rbmfHeader.numChars;
int numPixelBits = rbmfHeader.imgWidth*rbmfHeader.imgHeight/32;
rbmfFileData = (unsigned int *)malloc(numPixelBits*sizeof(unsigned int));
for (int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars*sizeof(unsigned char));
for (int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
// Re-construct image from rbmfFileData
//-----------------------------------------
Color *imagePixels = (Color *)malloc(rbmfHeader.imgWidth*rbmfHeader.imgHeight*sizeof(Color));
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
// Fill image data (convert from bit to pixel!)
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i += 32)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(rbmfFileData[counter], j)) imagePixels[i+j] = WHITE;
}
counter++;
}
Image image = LoadImageEx(imagePixels, rbmfHeader.imgWidth, rbmfHeader.imgHeight);
ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA);
free(imagePixels);
TraceLog(DEBUG, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
// Create spritefont with all data read from rbmf file
spriteFont.texture = LoadTextureFromImage(image);
UnloadImage(image); // Unload image data
//TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName);
// Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
for (int i = 0; i < spriteFont.charsCount; i++)
{
spriteFont.chars[i].value = (int)rbmfHeader.firstChar + i;
spriteFont.chars[i].rec.x = currentPosX;
spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i];
spriteFont.chars[i].rec.height = (int)rbmfHeader.charHeight;
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
spriteFont.chars[i].offsetX = 0;
spriteFont.chars[i].offsetY = 0;
spriteFont.chars[i].advanceX = 0;
testPosX += (spriteFont.chars[i].rec.width + charsDivisor);
if (testPosX > spriteFont.texture.width)
{
currentLine++;
currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX;
spriteFont.chars[i].rec.x = charsDivisor;
spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
}
else currentPosX = testPosX;
}
spriteFont.baseSize = spriteFont.charRecs[0].height;
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
}
fclose(rbmfFile);
free(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData);
*/
return spriteFont;
}
// Load a BMFont file (AngelCode font file) // Load a BMFont file (AngelCode font file)
static SpriteFont LoadBMFont(const char *fileName) static SpriteFont LoadBMFont(const char *fileName)
{ {
@ -943,7 +836,9 @@ static SpriteFont LoadBMFont(const char *fileName)
return font; return font;
} }
#endif
#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 SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
@ -1036,3 +931,4 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in
return font; return font;
} }
#endif

View file

@ -68,7 +68,7 @@ func GetDefaultFont() SpriteFont {
return v return v
} }
// LoadSpriteFont - Load a SpriteFont image into GPU memory // LoadSpriteFont - Load a SpriteFont image into GPU memory (VRAM)
func LoadSpriteFont(fileName string) SpriteFont { func LoadSpriteFont(fileName string) SpriteFont {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName)) defer C.free(unsafe.Pointer(cfileName))
@ -77,19 +77,19 @@ func LoadSpriteFont(fileName string) SpriteFont {
return v return v
} }
// LoadSpriteFontTTF - Load a SpriteFont from TTF font with parameters // LoadSpriteFontEx - Load SpriteFont from file with extended parameters
func LoadSpriteFontTTF(fileName string, fontSize int32, charsCount int32, fontChars *int32) SpriteFont { func LoadSpriteFontEx(fileName string, fontSize int32, charsCount int32, fontChars *int32) SpriteFont {
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.LoadSpriteFontTTF(cfileName, cfontSize, ccharsCount, cfontChars) ret := C.LoadSpriteFontEx(cfileName, cfontSize, ccharsCount, cfontChars)
v := NewSpriteFontFromPointer(unsafe.Pointer(&ret)) v := NewSpriteFontFromPointer(unsafe.Pointer(&ret))
return v return v
} }
// UnloadSpriteFont - Unload SpriteFont from GPU memory // UnloadSpriteFont - Unload SpriteFont from GPU memory (VRAM)
func UnloadSpriteFont(spriteFont SpriteFont) { func UnloadSpriteFont(spriteFont SpriteFont) {
cspriteFont := spriteFont.cptr() cspriteFont := spriteFont.cptr()
C.UnloadSpriteFont(*cspriteFont) C.UnloadSpriteFont(*cspriteFont)

View file

@ -4,24 +4,24 @@
* *
* CONFIGURATION: * CONFIGURATION:
* *
* #define SUPPORT_STB_IMAGE / INCLUDE_STB_IMAGE * #define SUPPORT_FILEFORMAT_BMP
* * #define SUPPORT_FILEFORMAT_PNG
* #define SUPPORT_FILEFORMAT_BMP / SUPPORT_LOAD_BMP
* #define SUPPORT_FILEFORMAT_PNG / SUPPORT_LOAD_PNG
* #define SUPPORT_FILEFORMAT_TGA * #define SUPPORT_FILEFORMAT_TGA
* #define SUPPORT_FILEFORMAT_JPG / ENABLE_LOAD_JPG * #define SUPPORT_FILEFORMAT_JPG
* #define SUPPORT_FILEFORMAT_GIF * #define SUPPORT_FILEFORMAT_GIF
* #define SUPPORT_FILEFORMAT_PSD
* #define SUPPORT_FILEFORMAT_HDR * #define SUPPORT_FILEFORMAT_HDR
* #define SUPPORT_FILEFORMAT_DDS / ENABLE_LOAD_DDS * #define SUPPORT_FILEFORMAT_DDS
* #define SUPPORT_FILEFORMAT_PKM * #define SUPPORT_FILEFORMAT_PKM
* #define SUPPORT_FILEFORMAT_KTX * #define SUPPORT_FILEFORMAT_KTX
* #define SUPPORT_FILEFORMAT_PVR * #define SUPPORT_FILEFORMAT_PVR
* #define SUPPORT_FILEFORMAT_ASTC * #define SUPPORT_FILEFORMAT_ASTC
* Selected desired fileformats to be supported for loading. Some of those formats are * Selecte desired fileformats to be supported for image data 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
* *
* #define SUPPORT_IMAGE_RESIZE / INCLUDE_STB_IMAGE_RESIZE
* #define SUPPORT_IMAGE_MANIPULATION * #define SUPPORT_IMAGE_MANIPULATION
* 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()
* *
* DEPENDENCIES: * DEPENDENCIES:
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
@ -31,7 +31,7 @@
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -50,6 +50,12 @@
* *
**********************************************************************************************/ **********************************************************************************************/
// Default configuration flags (supported features)
//-------------------------------------------------
#define SUPPORT_FILEFORMAT_PNG
#define SUPPORT_IMAGE_MANIPULATION
//-------------------------------------------------
#include "raylib.h" #include "raylib.h"
#include <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
@ -59,25 +65,48 @@
// Required for: rlglLoadTexture() rlDeleteTextures(), // Required for: rlglLoadTexture() rlDeleteTextures(),
// rlglGenerateMipmaps(), some funcs for DrawTexturePro() // rlglGenerateMipmaps(), some funcs for DrawTexturePro()
#include "utils.h" // Required for: fopen() Android mapping, TraceLog() #include "utils.h" // Required for: fopen() Android mapping
// Support only desired texture formats, by default: JPEG, PNG, BMP, TGA // Support only desired texture formats on stb_image
//#define STBI_NO_JPEG // Image format .jpg and .jpeg #if !defined(SUPPORT_FILEFORMAT_BMP)
//#define STBI_NO_PNG #define STBI_NO_BMP
//#define STBI_NO_BMP #endif
//#define STBI_NO_TGA #if !defined(SUPPORT_FILEFORMAT_PNG)
#define STBI_NO_PSD #define STBI_NO_PNG
#define STBI_NO_GIF #endif
#define STBI_NO_HDR #if !defined(SUPPORT_FILEFORMAT_TGA)
#define STBI_NO_TGA
#endif
#if !defined(SUPPORT_FILEFORMAT_JPG)
#define STBI_NO_JPEG // Image format .jpg and .jpeg
#endif
#if !defined(SUPPORT_FILEFORMAT_PSD)
#define STBI_NO_PSD
#endif
#if !defined(SUPPORT_FILEFORMAT_GIF)
#define STBI_NO_GIF
#endif
#if !defined(SUPPORT_FILEFORMAT_HDR)
#define STBI_NO_HDR
#endif
// Image fileformats not supported by default
#define STBI_NO_PIC #define STBI_NO_PIC
#define STBI_NO_PNM // Image format .ppm and .pgm #define STBI_NO_PNM // Image format .ppm and .pgm
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" // Required for: stbi_load()
// NOTE: Used to read image data (multiple formats support)
#define STB_IMAGE_RESIZE_IMPLEMENTATION #if (defined(SUPPORT_FILEFORMAT_BMP) || defined(SUPPORT_FILEFORMAT_PNG) || defined(SUPPORT_FILEFORMAT_TGA) || \
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() defined(SUPPORT_FILEFORMAT_JPG) || defined(SUPPORT_FILEFORMAT_PSD) || defined(SUPPORT_FILEFORMAT_GIF) || \
// NOTE: Used for image scaling on ImageResize() defined(SUPPORT_FILEFORMAT_HDR))
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" // Required for: stbi_load()
// NOTE: Used to read image data (multiple formats support)
#endif
#if defined(SUPPORT_IMAGE_MANIPULATION)
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8()
// NOTE: Used for image scaling on ImageResize()
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
@ -102,11 +131,21 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_DDS)
static Image LoadDDS(const char *fileName); // Load DDS file static Image LoadDDS(const char *fileName); // Load DDS file
#endif
#if defined(SUPPORT_FILEFORMAT_PKM)
static Image LoadPKM(const char *fileName); // Load PKM file static Image LoadPKM(const char *fileName); // Load PKM file
#endif
#if defined(SUPPORT_FILEFORMAT_KTX)
static Image LoadKTX(const char *fileName); // Load KTX file static Image LoadKTX(const char *fileName); // Load KTX file
#endif
#if defined(SUPPORT_FILEFORMAT_PVR)
static Image LoadPVR(const char *fileName); // Load PVR file static Image LoadPVR(const char *fileName); // Load PVR file
#endif
#if defined(SUPPORT_FILEFORMAT_ASTC)
static Image LoadASTC(const char *fileName); // Load ASTC file static Image LoadASTC(const char *fileName); // Load ASTC file
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition // Module Functions Definition
@ -124,43 +163,7 @@ Image LoadImage(const char *fileName)
image.mipmaps = 0; image.mipmaps = 0;
image.format = 0; image.format = 0;
if ((strcmp(GetExtension(fileName),"png") == 0) || if (IsFileExtension(fileName, ".rres"))
(strcmp(GetExtension(fileName),"bmp") == 0) ||
(strcmp(GetExtension(fileName),"tga") == 0) ||
(strcmp(GetExtension(fileName),"jpg") == 0)
#ifndef STBI_NO_GIF
|| (strcmp(GetExtension(fileName),"gif") == 0)
#endif
#ifndef STBI_NO_PSD
|| (strcmp(GetExtension(fileName),"psd") == 0)
#endif
#ifndef STBI_NO_PIC
|| (strcmp(GetExtension(fileName),"pic") == 0)
#endif
)
{
int imgWidth = 0;
int imgHeight = 0;
int imgBpp = 0;
// NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...)
image.data = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 0);
image.width = imgWidth;
image.height = imgHeight;
image.mipmaps = 1;
if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
}
else if (strcmp(GetExtension(fileName),"dds") == 0) image = LoadDDS(fileName);
else if (strcmp(GetExtension(fileName),"pkm") == 0) image = LoadPKM(fileName);
else if (strcmp(GetExtension(fileName),"ktx") == 0) image = LoadKTX(fileName);
else if (strcmp(GetExtension(fileName),"pvr") == 0) image = LoadPVR(fileName);
else if (strcmp(GetExtension(fileName),"astc") == 0) image = LoadASTC(fileName);
else if (strcmp(GetExtension(fileName),"rres") == 0)
{ {
RRES rres = LoadResource(fileName, 0); RRES rres = LoadResource(fileName, 0);
@ -171,6 +174,60 @@ Image LoadImage(const char *fileName)
UnloadResource(rres); UnloadResource(rres);
} }
else if ((IsFileExtension(fileName, ".png"))
#if defined(SUPPORT_FILEFORMAT_BMP)
|| (IsFileExtension(fileName, ".bmp"))
#endif
#if defined(SUPPORT_FILEFORMAT_TGA)
|| (IsFileExtension(fileName, ".tga"))
#endif
#if defined(SUPPORT_FILEFORMAT_JPG)
|| (IsFileExtension(fileName, ".jpg"))
#endif
#if defined(SUPPORT_FILEFORMAT_DDS)
|| (IsFileExtension(fileName, ".gif"))
#endif
#if defined(SUPPORT_FILEFORMAT_PSD)
|| (IsFileExtension(fileName, ".psd"))
#endif
)
{
int imgWidth = 0;
int imgHeight = 0;
int imgBpp = 0;
FILE *imFile = fopen(fileName, "rb");
// NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...)
image.data = stbi_load_from_file(imFile, &imgWidth, &imgHeight, &imgBpp, 0);
fclose(imFile);
image.width = imgWidth;
image.height = imgHeight;
image.mipmaps = 1;
if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
}
#if defined(SUPPORT_FILEFORMAT_DDS)
else if (IsFileExtension(fileName, ".dds")) image = LoadDDS(fileName);
#endif
#if defined(SUPPORT_FILEFORMAT_PKM)
else if (IsFileExtension(fileName, ".pkm")) image = LoadPKM(fileName);
#endif
#if defined(SUPPORT_FILEFORMAT_KTX)
else if (IsFileExtension(fileName, ".ktx")) image = LoadKTX(fileName);
#endif
#if defined(SUPPORT_FILEFORMAT_PVR)
else if (IsFileExtension(fileName, ".pvr")) image = LoadPVR(fileName);
#endif
#if defined(SUPPORT_FILEFORMAT_ASTC)
else if (IsFileExtension(fileName, ".astc")) image = LoadASTC(fileName);
#endif
else TraceLog(WARNING, "[%s] Image fileformat not supported", fileName);
if (image.data != NULL) TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height); if (image.data != NULL) TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
else TraceLog(WARNING, "[%s] Image could not be loaded", fileName); else TraceLog(WARNING, "[%s] Image could not be loaded", fileName);
@ -323,6 +380,8 @@ Texture2D LoadTextureFromImage(Image image)
texture.mipmaps = image.mipmaps; texture.mipmaps = image.mipmaps;
texture.format = image.format; texture.format = image.format;
TraceLog(INFO, "[TEX %i] Parameters: %ix%i, %i mips, format %i", texture.id, texture.width, texture.height, texture.mipmaps, texture.format);
return texture; return texture;
} }
@ -463,12 +522,14 @@ Image GetTextureData(Texture2D texture)
image.width = texture.width; image.width = texture.width;
image.height = texture.height; image.height = texture.height;
image.mipmaps = 1; image.mipmaps = 1;
#if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: Data retrieved on OpenGL ES 2.0 comes as RGB (from framebuffer) if (rlGetVersion() == OPENGL_ES_20)
image.format = UNCOMPRESSED_R8G8B8A8; {
#else // NOTE: Data retrieved on OpenGL ES 2.0 comes as RGBA (from framebuffer)
image.format = texture.format; image.format = UNCOMPRESSED_R8G8B8A8;
#endif }
else image.format = texture.format;
TraceLog(INFO, "Texture pixel data obtained successfully"); TraceLog(INFO, "Texture pixel data obtained successfully");
} }
else TraceLog(WARNING, "Texture pixel data could not be obtained"); else TraceLog(WARNING, "Texture pixel data could not be obtained");
@ -664,115 +725,6 @@ void ImageAlphaMask(Image *image, Image alphaMask)
} }
} }
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
// NOTE: In case selected bpp do not represent an known 16bit format,
// dithered data is stored in the LSB part of the unsigned short
void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(WARNING, "Compressed data formats can not be dithered");
return;
}
if ((rBpp+gBpp+bBpp+aBpp) > 16)
{
TraceLog(WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
}
else
{
Color *pixels = GetImageData(*image);
free(image->data); // free old image data
if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8))
{
TraceLog(WARNING, "Image format is already 16bpp or lower, dithering could have no effect");
}
// Define new image format, check if desired bpp match internal known format
if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5;
else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1;
else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4;
else
{
image->format = 0;
TraceLog(WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
}
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
Color oldPixel = WHITE;
Color newPixel = WHITE;
int rError, gError, bError;
unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
}
if (y < (image->height - 1))
{
pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
}
rPixel = (unsigned short)newPixel.r;
gPixel = (unsigned short)newPixel.g;
bPixel = (unsigned short)newPixel.b;
aPixel = (unsigned short)newPixel.a;
((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
free(pixels);
}
}
// Convert image to POT (power-of-two) // Convert image to POT (power-of-two)
// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) // NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
void ImageToPOT(Image *image, Color fillColor) void ImageToPOT(Image *image, Color fillColor)
@ -818,6 +770,7 @@ void ImageToPOT(Image *image, Color fillColor)
} }
} }
#if defined(SUPPORT_IMAGE_MANIPULATION)
// Copy an image to a new image // Copy an image to a new image
Image ImageCopy(Image image) Image ImageCopy(Image image)
{ {
@ -1203,6 +1156,115 @@ void ImageFlipHorizontal(Image *image)
image->data = processed.data; image->data = processed.data;
} }
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
// NOTE: In case selected bpp do not represent an known 16bit format,
// dithered data is stored in the LSB part of the unsigned short
void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(WARNING, "Compressed data formats can not be dithered");
return;
}
if ((rBpp+gBpp+bBpp+aBpp) > 16)
{
TraceLog(WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
}
else
{
Color *pixels = GetImageData(*image);
free(image->data); // free old image data
if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8))
{
TraceLog(WARNING, "Image format is already 16bpp or lower, dithering could have no effect");
}
// Define new image format, check if desired bpp match internal known format
if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5;
else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1;
else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4;
else
{
image->format = 0;
TraceLog(WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
}
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
Color oldPixel = WHITE;
Color newPixel = WHITE;
int rError, gError, bError;
unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
}
if (y < (image->height - 1))
{
pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
}
rPixel = (unsigned short)newPixel.r;
gPixel = (unsigned short)newPixel.g;
bPixel = (unsigned short)newPixel.b;
aPixel = (unsigned short)newPixel.a;
((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
free(pixels);
}
}
// Modify image color: tint // Modify image color: tint
void ImageColorTint(Image *image, Color color) void ImageColorTint(Image *image, Color color)
{ {
@ -1359,6 +1421,7 @@ void ImageColorBrightness(Image *image, int brightness)
image->data = processed.data; image->data = processed.data;
} }
#endif // SUPPORT_IMAGE_MANIPULATION
// Generate GPU mipmaps for a texture // Generate GPU mipmaps for a texture
void GenTextureMipmaps(Texture2D *texture) void GenTextureMipmaps(Texture2D *texture)
@ -1547,6 +1610,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_DDS)
// Loading DDS image data (compressed or uncompressed) // Loading DDS image data (compressed or uncompressed)
static Image LoadDDS(const char *fileName) static Image LoadDDS(const char *fileName)
{ {
@ -1744,7 +1808,9 @@ static Image LoadDDS(const char *fileName)
return image; return image;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_PKM)
// Loading PKM image data (ETC1/ETC2 compression) // Loading PKM image data (ETC1/ETC2 compression)
// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps) // NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps) // PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
@ -1836,7 +1902,9 @@ static Image LoadPKM(const char *fileName)
return image; return image;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_KTX)
// Load KTX compressed image data (ETC1/ETC2 compression) // Load KTX compressed image data (ETC1/ETC2 compression)
static Image LoadKTX(const char *fileName) static Image LoadKTX(const char *fileName)
{ {
@ -1929,7 +1997,9 @@ static Image LoadKTX(const char *fileName)
return image; return image;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_PVR)
// Loading PVR image data (uncompressed or PVRT compression) // Loading PVR image data (uncompressed or PVRT compression)
// NOTE: PVR v2 not supported, use PVR v3 instead // NOTE: PVR v2 not supported, use PVR v3 instead
static Image LoadPVR(const char *fileName) static Image LoadPVR(const char *fileName)
@ -2087,7 +2157,9 @@ static Image LoadPVR(const char *fileName)
return image; return image;
} }
#endif
#if defined(SUPPORT_FILEFORMAT_ASTC)
// Load ASTC compressed image data (ASTC compression) // Load ASTC compressed image data (ASTC compression)
static Image LoadASTC(const char *fileName) static Image LoadASTC(const char *fileName)
{ {
@ -2170,3 +2242,4 @@ static Image LoadASTC(const char *fileName)
return image; return image;
} }
#endif

View file

@ -4,22 +4,28 @@
* *
* CONFIGURATION: * CONFIGURATION:
* *
* #define SUPPORT_SAVE_PNG * #define SUPPORT_SAVE_PNG (defined by default)
* Enable saving PNG fileformat * Support saving image data as PNG fileformat
* NOTE: Requires stb_image_write library * NOTE: Requires stb_image_write library
* *
* #define SUPPORT_SAVE_BMP * #define SUPPORT_SAVE_BMP
* Support saving image data as BMP fileformat
* NOTE: Requires stb_image_write library
* *
* #define DO_NOT_TRACE_DEBUG_MSGS * #define SUPPORT_TRACELOG
* Avoid showing DEBUG TraceLog() messages * Show TraceLog() output messages
* NOTE: By default DEBUG traces not shown
*
* #define SUPPORT_TRACELOG_DEBUG
* Show TraceLog() DEBUG messages
* *
* DEPENDENCIES: * DEPENDENCIES:
* stb_image_write - PNG writting functions * stb_image_write - BMP/PNG writting functions
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -38,6 +44,9 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#define SUPPORT_TRACELOG // Output tracelog messages
//#define SUPPORT_TRACELOG_DEBUG // Avoid DEBUG messages tracing
#include "utils.h" #include "utils.h"
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
@ -59,9 +68,6 @@
#define RRES_IMPLEMENTATION #define RRES_IMPLEMENTATION
#include "rres.h" #include "rres.h"
//#define NO_TRACELOG // Avoid TraceLog() output (any type)
#define DO_NOT_TRACE_DEBUG_MSGS // Avoid DEBUG messages tracing
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -82,15 +88,16 @@ static int android_close(void *cookie);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Utilities // Module Functions Definition - Utilities
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Outputs a trace log message
// Output trace log messages
void TraceLog(int msgType, const char *text, ...) void TraceLog(int msgType, const char *text, ...)
{ {
#if !defined(NO_TRACELOG) #if defined(SUPPORT_TRACELOG)
static char buffer[128]; static char buffer[128];
int traceDebugMsgs = 1; int traceDebugMsgs = 0;
#ifdef DO_NOT_TRACE_DEBUG_MSGS #if defined(SUPPORT_TRACELOG_DEBUG)
traceDebugMsgs = 0; traceDebugMsgs = 1;
#endif #endif
switch(msgType) switch(msgType)
@ -125,22 +132,37 @@ void TraceLog(int msgType, const char *text, ...)
if (msgType == ERROR) exit(1); // If ERROR message, exit program if (msgType == ERROR) exit(1); // If ERROR message, exit program
#endif // NO_TRACELOG #endif // SUPPORT_TRACELOG
} }
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
#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)
{ {
stbi_write_bmp(fileName, width, height, compSize, imgData); stbi_write_bmp(fileName, width, height, compSize, imgData);
} }
#endif
#if defined(SUPPORT_SAVE_PNG)
// 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)
{ {
stbi_write_png(fileName, width, height, compSize, imgData, width*compSize); stbi_write_png(fileName, width, height, compSize, imgData, width*compSize);
} }
#endif #endif
#endif
// Keep track of memory allocated
// NOTE: mallocType defines the type of data allocated
/*
void RecordMalloc(int mallocType, int mallocSize, const char *msg)
{
// TODO: Investigate how to record memory allocation data...
// Maybe creating my own malloc function...
}
*/
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
// Initialize asset manager from android app // Initialize asset manager from android app
@ -162,24 +184,6 @@ FILE *android_fopen(const char *fileName, const char *mode)
} }
#endif #endif
// Keep track of memory allocated
// NOTE: mallocType defines the type of data allocated
/*
void RecordMalloc(int mallocType, int mallocSize, const char *msg)
{
// TODO: Investigate how to record memory allocation data...
// Maybe creating my own malloc function...
}
*/
// Get the extension for a filename
const char *GetExtension(const char *fileName)
{
const char *dot = strrchr(fileName, '.');
if (!dot || dot == fileName) return "";
return (dot + 1);
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View file

@ -10,8 +10,8 @@ import (
// Log message types // Log message types
const ( const (
LogInfo = iota LogInfo = iota
LogError
LogWarning LogWarning
LogError
LogDebug LogDebug
) )
@ -22,16 +22,16 @@ func SetDebug(enabled bool) {
traceDebugMsgs = enabled traceDebugMsgs = enabled
} }
// TraceLog - Trace log messages showing (INFO, WARNING, ERROR, DEBUG) // TraceLog - Show trace log messages (INFO, WARNING, ERROR, DEBUG)
func TraceLog(msgType int, text string, v ...interface{}) { func TraceLog(msgType int, text string, v ...interface{}) {
switch msgType { switch msgType {
case LogInfo: case LogInfo:
fmt.Printf("INFO: "+text+"\n", v...) fmt.Printf("INFO: "+text+"\n", v...)
case LogWarning:
fmt.Printf("WARNING: "+text+"\n", v...)
case LogError: case LogError:
fmt.Printf("ERROR: "+text+"\n", v...) fmt.Printf("ERROR: "+text+"\n", v...)
os.Exit(1) os.Exit(1)
case LogWarning:
fmt.Printf("WARNING: "+text+"\n", v...)
case LogDebug: case LogDebug:
if traceDebugMsgs { if traceDebugMsgs {
fmt.Printf("DEBUG: "+text+"\n", v...) fmt.Printf("DEBUG: "+text+"\n", v...)

View file

@ -1,10 +1,11 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.utils * raylib.utils - Some common utility functions
* *
* Some utility functions
* *
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * LICENSE: zlib/libpng
*
* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
@ -33,6 +34,8 @@
#include "rres.h" #include "rres.h"
#define SUPPORT_SAVE_PNG
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Some basic Defines // Some basic Defines
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -43,8 +46,6 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
@ -57,17 +58,18 @@ extern "C" { // Prevents name mangling of functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Declaration // Module Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message
const char *GetExtension(const char *fileName); // Returns extension of a filename
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
#if defined(SUPPORT_SAVE_BMP)
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);
#endif
#if defined(SUPPORT_SAVE_PNG)
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);
#endif #endif
#endif
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen()
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus